00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <popt.h>
00028 #ifdef HAVE_COLORBLIND
00029 #include <colorblind.h>
00030 #endif
00031 #include <gdk/gdkwindow.h>
00032 #include <gtk/gtk.h>
00033 #ifdef USE_GDKPIXBUF_RENDER_TO_DRAWABLE
00034 #include <gdk/gdkpixbuf.h>
00035 #else
00036 #include <gdk/gdk.h>
00037 #endif
00038 #include <gdk/gdkx.h>
00039 #include <gdk/gdkrgb.h>
00040 #include <libbonobo.h>
00041 #include <X11/Xlib.h>
00042 #include <X11/Xutil.h>
00043 #include <X11/cursorfont.h>
00044 #include <X11/extensions/XTest.h>
00045 #include <math.h>
00046
00047 #undef ZOOM_REGION_DEBUG
00048
00049 #include "zoom-region.h"
00050 #include "zoom-region-private.h"
00051 #include "magnifier.h"
00052 #include "magnifier-private.h"
00053
00054 #define DEBUG_CLIENT_CALLS
00055
00056 #ifdef DEBUG_CLIENT_CALLS
00057 static gboolean client_debug = FALSE;
00058 #define DBG(a) if (client_debug) { (a); }
00059 #else
00060 #define DBG(a)
00061 #endif
00062
00063 static GObjectClass *parent_class = NULL;
00064
00065 enum {
00066 ZOOM_REGION_MANAGED_PROP,
00067 ZOOM_REGION_POLL_MOUSE_PROP,
00068 ZOOM_REGION_SMOOTHSCROLL_PROP,
00069 ZOOM_REGION_COLORBLIND_PROP,
00070 ZOOM_REGION_INVERT_PROP,
00071 ZOOM_REGION_SMOOTHING_PROP,
00072 ZOOM_REGION_CONTRASTR_PROP,
00073 ZOOM_REGION_CONTRASTG_PROP,
00074 ZOOM_REGION_CONTRASTB_PROP,
00075 ZOOM_REGION_BRIGHTR_PROP,
00076 ZOOM_REGION_BRIGHTG_PROP,
00077 ZOOM_REGION_BRIGHTB_PROP,
00078 ZOOM_REGION_XSCALE_PROP,
00079 ZOOM_REGION_YSCALE_PROP,
00080 ZOOM_REGION_BORDERSIZE_PROP,
00081 ZOOM_REGION_BORDERCOLOR_PROP,
00082 ZOOM_REGION_XALIGN_PROP,
00083 ZOOM_REGION_YALIGN_PROP,
00084 ZOOM_REGION_VIEWPORT_PROP,
00085 ZOOM_REGION_TESTPATTERN_PROP,
00086 ZOOM_REGION_TIMING_TEST_PROP,
00087 ZOOM_REGION_TIMING_OUTPUT_PROP,
00088 ZOOM_REGION_TIMING_PAN_RATE_PROP,
00089 ZOOM_REGION_EXIT_MAGNIFIER
00090 } PropIdx;
00091
00092 #ifdef DEBUG_CLIENT_CALLS
00093 gchar* prop_names[ZOOM_REGION_EXIT_MAGNIFIER + 1] =
00094 {
00095 "MANAGED",
00096 "POLLMOUSE"
00097 "SMOOTHSCROLL",
00098 "INVERT",
00099 "SMOOTHING",
00100 "CONTRASTR",
00101 "CONTRASTG",
00102 "CONTRASTB",
00103 "XSCALE",
00104 "YSCALE",
00105 "BORDERSIZE",
00106 "BORDERCOLOR",
00107 "XALIGN",
00108 "YALIGN",
00109 "VIEWPORT",
00110 "TESTPATTERN",
00111 "TIMING_TEST",
00112 "TIMING_OUTPUT",
00113 "TIMING_PAN_RATE",
00114 "EXIT_MAGNIFIER"
00115 };
00116 #endif
00117
00118 typedef enum {
00119 ZOOM_REGION_ERROR_NONE,
00120 ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE,
00121 ZOOM_REGION_ERROR_TOO_BIG
00122 } ZoomRegionPixmapCreationError;
00123
00124 static float timing_scale_max = 0;
00125 static float timing_idle_max = 0;
00126 static float timing_frame_max = 0;
00127 static float cps_max = 0;
00128 static float nrr_max = 0;
00129 static float update_nrr_max = 0;
00130 static gboolean reset_timing = FALSE;
00131 static gboolean timing_test = FALSE;
00132
00133 static guint pending_idle_handler = 0;
00134 static gboolean processing_updates = FALSE;
00135 static gboolean timing_start = FALSE;
00136
00137 #ifdef TEST_XTST_CURSOR
00138 static Cursor *x_cursors;
00139 static Window cursor_window = None;
00140 #endif
00141
00142 static gboolean can_coalesce = TRUE ;
00143
00144 static void zoom_region_sync (ZoomRegion *region);
00145 static void zoom_region_finalize (GObject *object);
00146 static void zoom_region_update (ZoomRegion *zoom_region,
00147 const GdkRectangle rect);
00148 static void zoom_region_queue_update (ZoomRegion *zoom_region,
00149 const GdkRectangle rect);
00150
00151 static int zoom_region_process_updates (gpointer data);
00152 static void zoom_region_paint (ZoomRegion *zoom_region, GdkRectangle *rect);
00153 static void zoom_region_paint_pixmap (ZoomRegion *zoom_region, GdkRectangle *rect);
00154 static int zoom_region_update_pointer_timeout (gpointer data);
00155 static GdkRectangle zoom_region_rect_from_bounds (ZoomRegion *zoom_region,
00156 const GNOME_Magnifier_RectBounds *bounds);
00157 static ZoomRegionPixmapCreationError zoom_region_create_pixmap (ZoomRegion *zoom_region);
00158 static GdkRectangle zoom_region_update_pixmap (ZoomRegion *zoom_region, const GdkRectangle update_rect, GdkRectangle *paint_rect);
00159
00160 void
00161 reset_timing_stats()
00162 {
00163 timing_scale_max = 0;
00164 timing_idle_max = 0;
00165 timing_frame_max = 0;
00166 cps_max = 0;
00167 nrr_max = 0;
00168 update_nrr_max = 0;
00169 mag_timing.num_scale_samples = 0;
00170 mag_timing.num_idle_samples = 0;
00171 mag_timing.num_frame_samples = 0;
00172 mag_timing.num_line_samples = 0;
00173 mag_timing.scale_total = 0;
00174 mag_timing.idle_total = 0;
00175 mag_timing.frame_total = 0;
00176 mag_timing.update_pixels_total = 0;
00177 mag_timing.update_pixels_total = 0;
00178 mag_timing.dx_total = 0;
00179 mag_timing.dy_total = 0;
00180 mag_timing.last_frame_val = 0;
00181 mag_timing.last_dy = 0;
00182 g_timer_start (mag_timing.process);
00183 }
00184
00187 #undef DEBUG
00188 #ifdef DEBUG
00189 #define DEBUG_RECT(a, b) _debug_announce_rect (a, b)
00190 #else
00191 #define DEBUG_RECT(a, b)
00192 #endif
00193 static void
00194 _debug_announce_rect (char *msg, GdkRectangle rect)
00195 {
00196 fprintf (stderr, "%s: (%d,%d - %d,%d)\n",
00197 msg, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
00198 }
00199
00200 static gboolean
00201 _diff_pixbufs (const GdkPixbuf *a, const GdkPixbuf *b)
00202 {
00203 long i, j;
00204 int bits_per_byte = 8;
00205 guchar *pa = gdk_pixbuf_get_pixels (a);
00206 guchar *pb = gdk_pixbuf_get_pixels (b);
00207 guchar *cpa, *cpb;
00208 long rsa = gdk_pixbuf_get_rowstride (a);
00209 long rsb = gdk_pixbuf_get_rowstride (b);
00210 long rowbytes = gdk_pixbuf_get_width (a) *
00211 gdk_pixbuf_get_bits_per_sample (a) *
00212 gdk_pixbuf_get_n_channels (a)/ bits_per_byte;
00213 long n_rows = gdk_pixbuf_get_height (a);
00214
00215 if (gdk_pixbuf_get_height (b) != n_rows)
00216 return TRUE;
00217 if (gdk_pixbuf_get_width (b) != gdk_pixbuf_get_width (a))
00218 return TRUE;
00219 for (j = 0; j < n_rows; ++j)
00220 {
00221 cpa = pa + j * rsa;
00222 cpb = pb + j * rsb;
00223 for (i = 0; i < rowbytes; ++i)
00224 {
00225 if (*cpa != *cpb)
00226 {
00227 return TRUE;
00228 }
00229 cpa++;
00230 cpb++;
00231 }
00232 }
00233 return FALSE;
00234 }
00235
00238 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
00239
00248 static gboolean
00249 _combine_rects (GdkRectangle *a, GdkRectangle *b)
00250 {
00251 gboolean can_combine = FALSE;
00252 if ((a->x == b->x) && (a->x + a->width == b->x + b->width))
00253 {
00254 can_combine = TRUE;
00255 }
00256 else if ((a->y == b->y) && (a->y + a->height == b->y + b->height))
00257 {
00258 can_combine = TRUE;
00259 }
00260 if (can_combine)
00261 {
00262 GdkRectangle c;
00263
00264 if (gdk_rectangle_intersect (a, b, &c))
00265 {
00266 gdk_rectangle_union (a, b, &c);
00267 *a = c;
00268 can_combine = TRUE;
00269 }
00270 else
00271 {
00272 can_combine = FALSE;
00273 }
00274 }
00275 return can_combine;
00276 }
00277
00291 static gboolean
00292 _refactor_rects (GdkRectangle *p, GdkRectangle *n)
00293 {
00294 gboolean refactored = FALSE;
00295 GdkRectangle *a, *b;
00296 if (p->x == n->x)
00297 {
00298 if (p->width < n->width)
00299 {
00300 a = p;
00301 b = n;
00302 }
00303 else
00304 {
00305 a = n;
00306 b = p;
00307 }
00308 if (a->y == b->y + b->height)
00309 {
00310 a->y -= b->height;
00311 a->height += b->height;
00312 b->x += a->width;
00313 b->width -= a->width;
00314 refactored = TRUE;
00315 }
00316 else if (a->y + a->height == b->y)
00317 {
00318 a->height += b->height;
00319 b->x += a->width;
00320 b->width -= a->width;
00321 refactored = TRUE;
00322 }
00323 if (refactored) fprintf (stderr, "REFACTOR 1\n");
00324 }
00325 else if (p->y == n->y)
00326 {
00327 if (p->height < n->height)
00328 {
00329 a = p;
00330 b = n;
00331 }
00332 else
00333 {
00334 a = n;
00335 b = p;
00336 }
00337 if (a->x == b->x + b->width)
00338 {
00339 a->x -= b->width;
00340 a->width += b->width;
00341 b->y += a->height;
00342 b->height -= a->height;
00343 refactored = TRUE;
00344 }
00345 else if (a->x + a->width == b->x)
00346 {
00347 a->width += b->width;
00348 b->y += a->height;
00349 b->height -= a->height;
00350 refactored = TRUE;
00351 }
00352 if (refactored) fprintf (stderr, "REFACTOR 2\n");
00353 }
00354 else if (p->x + p->width == n->x + n->width)
00355 {
00356 if (p->width < n->width)
00357 {
00358 a = p;
00359 b = n;
00360 }
00361 else
00362 {
00363 a = n;
00364 b = p;
00365 }
00366 if (a->y == b->y + b->height)
00367 {
00368 a->y -= b->height;
00369 a->height += b->height;
00370 b->width -= a->width;
00371 refactored = TRUE;
00372 }
00373 else if (a->y + a->height == b->y)
00374 {
00375 a->height += b->height;
00376 b->width -= a->width;
00377 refactored = TRUE;
00378 }
00379 if (refactored) fprintf (stderr, "REFACTOR 3\n");
00380 }
00381 else if (p->y + p->height == n->y + n->height)
00382 {
00383 if (p->height < n->height)
00384 {
00385 a = p;
00386 b = n;
00387 }
00388 else
00389 {
00390 a = n;
00391 b = p;
00392 }
00393 if (a->x == b->x + b->width)
00394 {
00395 a->x -= b->width;
00396 a->width += b->width;
00397 b->height -= a->height;
00398 refactored = TRUE;
00399 }
00400 else if (a->x + a->width == b->x)
00401 {
00402 a->width += b->width;
00403 b->height -= a->height;
00404 refactored = TRUE;
00405 }
00406 if (refactored) fprintf (stderr, "REFACTOR 4\n");
00407 }
00408 return refactored;
00409 }
00410
00411 static GList*
00412 _combine_update_rects (GList *q, int lookahead_n)
00413 {
00414 int i = 0;
00415 GdkRectangle *a = q->data;
00416 GList *p = q;
00417 while (i < lookahead_n && p && p->next)
00418 {
00419 if (_combine_rects (a, q->next->data))
00420 {
00421 q = g_list_delete_link (q, p->next);
00422 }
00423 else
00424 {
00425 p = p->next;
00426 ++i;
00427 }
00428 }
00429 return q;
00430 }
00431 #endif
00432
00433
00434
00435 #define _is_horizontal_rect(r) ((r)->width > (r)->height)
00436 #define _is_vertical_rect(r) ((r)->height > (r)->width)
00437
00444 static GList *
00445 _coalesce_update_rects (GList *q, int min_coalesce_length)
00446 {
00447 GdkRectangle *v = NULL, *h = NULL;
00448 GList *compact_queue = NULL;
00449
00450 if (g_list_length (q) < min_coalesce_length)
00451 return g_list_copy (q);
00452 while (q)
00453 {
00454 if (_is_vertical_rect ((GdkRectangle *) (q->data)))
00455 {
00456 if (v) gdk_rectangle_union (v, q->data, v);
00457 else
00458 {
00459 v = g_new0 (GdkRectangle, 1);
00460 *v = *(GdkRectangle *)q->data;
00461 }
00462 }
00463 else if (_is_horizontal_rect ((GdkRectangle *) (q->data)))
00464 {
00465 if (h) gdk_rectangle_union (h, q->data, h);
00466 else
00467 {
00468 h = g_new0 (GdkRectangle, 1);
00469 *h = *(GdkRectangle *)q->data;
00470 }
00471 }
00472 else
00473 compact_queue = g_list_prepend (compact_queue, q->data);
00474 q = q->next;
00475 };
00476 if (v)
00477 compact_queue = g_list_prepend (compact_queue, v);
00478 if (h)
00479 compact_queue = g_list_prepend (compact_queue, h);
00480
00481
00482 return compact_queue;
00483 }
00484
00485 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
00486 static GList *
00487 _smartbutbroken_coalesce_update_rects (GList *q, int lookahead_n)
00488 {
00489 int i = 0, len;
00490 fprintf (stderr, "starting queue length = %d\n", g_list_length (q));
00491 do {
00492 GdkRectangle *a;
00493 len = g_list_length (q);
00494 q = _combine_update_rects (q, lookahead_n);
00495 a = q->data;
00496 while (i < lookahead_n && q && q->next)
00497 {
00498 if (_refactor_rects (a, q->next->data))
00499 break;
00500 else
00501 ++i;
00502 }
00503 q = _combine_update_rects (q, lookahead_n);
00504 } while (g_list_length (q) < len);
00505 fprintf (stderr, "ending queue length = %d\n", g_list_length (q));
00506 return q;
00507 }
00508 #endif
00509
00513 static GdkRectangle
00514 _rectangle_clip_to_rectangle (GdkRectangle area,
00515 GdkRectangle clip_rect)
00516 {
00517 GdkRectangle clipped;
00518 clipped.x = MAX (area.x, clip_rect.x);
00519 clipped.y = MAX (area.y, clip_rect.y);
00520 clipped.width = MIN ((area.x + area.width), (clip_rect.x + clip_rect.width)) - clipped.x;
00521 clipped.height = MIN ((area.y + area.height), (clip_rect.y + clip_rect.height)) - clipped.y;
00522 return clipped;
00523 }
00524
00525 static GdkRectangle
00526 _rectangle_clip_to_bounds (GdkRectangle area,
00527 GNOME_Magnifier_RectBounds *clip_bounds)
00528 {
00529 area.x = MAX (area.x, clip_bounds->x1);
00530 area.x = MIN (area.x, clip_bounds->x2);
00531 area.width = MIN (area.width, clip_bounds->x2 - area.x);
00532 area.y = MAX (area.y, clip_bounds->y1);
00533 area.y = MIN (area.y, clip_bounds->y2);
00534 area.height = MIN (area.height, clip_bounds->y2 - area.y);
00535 return area;
00536 }
00537
00538 static GdkRectangle
00539 zoom_region_clip_to_source (ZoomRegion *zoom_region,
00540 GdkRectangle area)
00541 {
00542 GNOME_Magnifier_RectBounds *source_rect_ptr;
00543 if (zoom_region && zoom_region->priv && zoom_region->priv->parent)
00544 {
00545 source_rect_ptr = &((Magnifier *)zoom_region->priv->parent)->source_bounds;
00546 DEBUG_RECT ("clipping to source bounds", zoom_region_rect_from_bounds (zoom_region, source_rect_ptr));
00547 return _rectangle_clip_to_bounds (area, source_rect_ptr);
00548 }
00549 return area;
00550 }
00551
00552 static GdkRectangle
00553 zoom_region_clip_to_exposed_target (ZoomRegion *zoom_region,
00554 GdkRectangle area)
00555 {
00556 GNOME_Magnifier_RectBounds onscreen_target, *source_area;
00557 source_area = &zoom_region->priv->source_area;
00558
00559 onscreen_target.x1 = MAX (floor (zoom_region->priv->exposed_bounds.x1
00560 / zoom_region->xscale),
00561 source_area->x1);
00562 onscreen_target.y1 = MAX (floor (zoom_region->priv->exposed_bounds.y1
00563 / zoom_region->yscale),
00564 source_area->y1);
00565 onscreen_target.x2 = MIN (ceil (zoom_region->priv->exposed_bounds.x2
00566 / zoom_region->xscale),
00567 source_area->x2);
00568 onscreen_target.y2 = MIN (ceil (zoom_region->priv->exposed_bounds.y2
00569 / zoom_region->yscale),
00570 source_area->y2);
00571
00572 return _rectangle_clip_to_bounds (area, &onscreen_target);
00573 }
00574
00575 static GdkRectangle
00576 zoom_region_clip_to_scaled_pixmap (ZoomRegion *zoom_region,
00577 GdkRectangle area)
00578 {
00579 GdkRectangle pixmap_area = {0, 0, 0, 0};
00580 if (zoom_region->priv && zoom_region->priv->pixmap)
00581 {
00582 gdk_drawable_get_size (zoom_region->priv->pixmap, &pixmap_area.width, &pixmap_area.height);
00583 return _rectangle_clip_to_rectangle (area, pixmap_area);
00584 }
00585 else
00586 return area;
00587 }
00588
00589 static GdkRectangle
00590 zoom_region_clip_to_window (ZoomRegion *zoom_region,
00591 GdkRectangle area)
00592 {
00593 GdkRectangle window_rect;
00594
00595
00596
00597 return area;
00598
00599 if (zoom_region->priv->w->window)
00600 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
00601 &window_rect.x,
00602 &window_rect.y);
00603 else
00604 {
00605 window_rect.x = 0;
00606 window_rect.y = 0;
00607 }
00608 return _rectangle_clip_to_rectangle (area, window_rect);
00609 }
00610
00611 static const GdkRectangle
00612 zoom_region_source_rect_from_view_bounds (ZoomRegion *zoom_region,
00613 const GNOME_Magnifier_RectBounds *view_bounds)
00614 {
00615 GdkRectangle source_rect;
00616 source_rect.x = floor ((view_bounds->x1 + zoom_region->priv->exposed_bounds.x1)
00617 / zoom_region->xscale);
00618 source_rect.y = floor ((view_bounds->y1 + zoom_region->priv->exposed_bounds.y1)
00619 / zoom_region->yscale);
00620 source_rect.width = ceil ((view_bounds->x2 - view_bounds->x1) / zoom_region->xscale) + 1;
00621 source_rect.height = ceil ((view_bounds->y2 - view_bounds->y1) / zoom_region->yscale) + 1;
00622 return source_rect;
00623 }
00624
00625 static GdkRectangle
00626 zoom_region_view_rect_from_source_rect (ZoomRegion *zoom_region,
00627 const GdkRectangle source_rect)
00628 {
00629 GdkRectangle view_rect;
00630 view_rect.x = source_rect.x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
00631 view_rect.y = source_rect.y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
00632 view_rect.width = source_rect.width * zoom_region->xscale;
00633 view_rect.height = source_rect.height * zoom_region->yscale;
00634 DEBUG_RECT ("source", source_rect);
00635 DEBUG_RECT ("converted to view-rect", view_rect);
00636 return view_rect;
00637 }
00638
00639 static GdkRectangle
00640 zoom_region_source_rect_from_view_rect (ZoomRegion *zoom_region,
00641 const GdkRectangle view_rect)
00642 {
00643 GdkRectangle source_rect;
00644 source_rect.x = floor ((view_rect.x + zoom_region->priv->exposed_bounds.x1)
00645 / zoom_region->xscale);
00646 source_rect.y = floor ((view_rect.y + zoom_region->priv->exposed_bounds.y1)
00647 / zoom_region->yscale);
00648 source_rect.width = ceil (view_rect.width / zoom_region->xscale) + 1;
00649 source_rect.height = ceil (view_rect.height / zoom_region->yscale) + 1;
00650 return source_rect;
00651 }
00652
00653 static GdkRectangle
00654 zoom_region_rect_from_bounds (ZoomRegion *zoom_region,
00655 const GNOME_Magnifier_RectBounds *bounds)
00656 {
00657 GdkRectangle rect;
00658 rect.x = bounds->x1;
00659 rect.y = bounds->y1;
00660 rect.width = bounds->x2 - bounds->x1;
00661 rect.height = bounds->y2 - bounds->y1;
00662 return rect;
00663 }
00664
00667 static CORBA_boolean
00668 zoom_region_update_scale (ZoomRegion *zoom_region, gdouble x, gdouble y)
00669 {
00670 gdouble x_old = zoom_region->xscale;
00671 gdouble y_old = zoom_region->yscale;
00672
00673 zoom_region->xscale = x;
00674 zoom_region->yscale = y;
00675
00676 if (zoom_region->priv->scaled_pixbuf)
00677 g_object_unref (zoom_region->priv->scaled_pixbuf);
00678 zoom_region->priv->scaled_pixbuf =
00679 gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, (zoom_region->priv->source_area.x2 - zoom_region->priv->source_area.x1) * zoom_region->xscale + 1, (zoom_region->priv->source_area.y2 - zoom_region->priv->source_area.y1) * zoom_region->yscale + 1);
00680
00681 if (zoom_region->priv->pixmap)
00682 g_object_unref (zoom_region->priv->pixmap);
00683
00684 if (zoom_region_create_pixmap (zoom_region) ==
00685 ZOOM_REGION_ERROR_TOO_BIG) {
00686 zoom_region->xscale = x_old;
00687 zoom_region->yscale = y_old;
00688 zoom_region_create_pixmap (zoom_region);
00689 g_object_unref (zoom_region->priv->scaled_pixbuf);
00690
00691
00692
00693 zoom_region->priv->scaled_pixbuf = gdk_pixbuf_new (
00694 GDK_COLORSPACE_RGB, FALSE, 8, (zoom_region->priv->source_area.x2 - zoom_region->priv->source_area.x1) * zoom_region->xscale + 1, (zoom_region->priv->source_area.y2 - zoom_region->priv->source_area.y1) * zoom_region->yscale + 1);
00695
00696 return CORBA_FALSE;
00697 }
00698 return CORBA_TRUE;
00699 }
00700
00701 static void
00702 zoom_region_queue_update (ZoomRegion *zoom_region,
00703 const GdkRectangle update_rect)
00704 {
00705 GdkRectangle *rect =
00706 g_new0 (GdkRectangle, 1);
00707 *rect = update_rect;
00708
00709 #ifdef ZOOM_REGION_DEBUG
00710 g_assert (zoom_region->alive);
00711 #endif
00712 DEBUG_RECT ("queueing update", *rect);
00713
00714 zoom_region->priv->q =
00715 g_list_prepend (zoom_region->priv->q, rect);
00716 if (zoom_region->priv && zoom_region->priv->update_handler_id == 0)
00717 zoom_region->priv->update_handler_id =
00718 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
00719 zoom_region_process_updates,
00720 zoom_region,
00721 NULL);
00722 }
00723
00724 static void
00725 zoom_region_update_current (ZoomRegion *zoom_region)
00726 {
00727 #ifdef ZOOM_REGION_DEBUG
00728 g_assert (zoom_region->alive);
00729 #endif
00730 if (zoom_region->priv)
00731 {
00732 gboolean pixmap_valid = GDK_IS_DRAWABLE (zoom_region->priv->pixmap);
00733 if (!pixmap_valid)
00734 pixmap_valid = (zoom_region_create_pixmap (zoom_region) == ZOOM_REGION_ERROR_NONE);
00735 if (pixmap_valid)
00736 zoom_region_update (zoom_region,
00737 zoom_region_source_rect_from_view_bounds (
00738 zoom_region,
00739 &zoom_region->viewport));
00740 }
00741 }
00742
00743 static GdkRectangle
00744 zoom_region_cursor_rect (ZoomRegion *zoom_region)
00745 {
00746 GdkRectangle rect = {0, 0, 0, 0};
00747 Magnifier *magnifier = zoom_region->priv->parent;
00748 GdkDrawable *cursor = NULL;
00749 if (magnifier)
00750 cursor = magnifier_get_cursor (magnifier);
00751 if (cursor)
00752 {
00753 rect.x = zoom_region->priv->last_cursor_pos.x;
00754 rect.y = zoom_region->priv->last_cursor_pos.y;
00755 rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
00756 rect.x -= magnifier->cursor_hotspot.x;
00757 rect.y -= magnifier->cursor_hotspot.y;
00758 gdk_drawable_get_size (cursor, &rect.width, &rect.height);
00759 }
00760 return rect;
00761 }
00762
00763 static void
00764 zoom_region_unpaint_crosswire_cursor (ZoomRegion *zoom_region,
00765 GdkRectangle *clip_rect)
00766 {
00767 Magnifier *magnifier = zoom_region->priv->parent;
00768 GdkRectangle vline_rect, hline_rect;
00769 GdkPoint cursor_pos;
00770
00771 #ifdef ZOOM_REGION_DEBUG
00772 g_assert (zoom_region->alive);
00773 #endif
00774 if (!magnifier || magnifier->crosswire_size <= 0) return;
00775
00776 cursor_pos = zoom_region->priv->last_drawn_crosswire_pos;
00777 vline_rect.x = cursor_pos.x - magnifier->crosswire_size/2;
00778 vline_rect.y = clip_rect ? clip_rect->y : 0;
00779 vline_rect.width = MAX (magnifier->crosswire_size, 1);
00780 vline_rect.height = clip_rect ? clip_rect->height : 4096;
00781 hline_rect.x = clip_rect ? clip_rect->x : 0;
00782 hline_rect.y = cursor_pos.y - magnifier->crosswire_size/2;
00783 hline_rect.width = clip_rect ? clip_rect->width : 4096;
00784 hline_rect.height = MAX (magnifier->crosswire_size, 1);
00785
00786 zoom_region_paint_pixmap (zoom_region, &vline_rect);
00787 zoom_region_paint_pixmap (zoom_region, &hline_rect);
00788 }
00789
00790 static void
00791 zoom_region_paint_crosswire_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect)
00792 {
00793 Magnifier *magnifier = zoom_region->priv->parent;
00794 static GdkColormap *cmap;
00795 static GdkColor last_color;
00796 static gboolean last_color_init = FALSE;
00797 GdkGCValues values;
00798 GdkRectangle rect;
00799 GdkDrawable *cursor;
00800 GdkColor color = {0, 0, 0, 0};
00801 int x_left_clip = 0, x_right_clip = 0, y_top_clip = 0, y_bottom_clip = 0;
00802 int csize = 0;
00803
00804 #ifdef ZOOM_REGION_DEBUG
00805 g_assert (zoom_region->alive);
00806 #endif
00807 if (!(magnifier &&
00808 zoom_region->priv->w->window &&
00809 GDK_IS_DRAWABLE (zoom_region->priv->w->window) &&
00810 magnifier->crosswire_size > 0)) return;
00811
00812 if (zoom_region->priv->crosswire_gc == NULL)
00813 {
00814 zoom_region->priv->crosswire_gc = gdk_gc_new (zoom_region->priv->w->window);
00815 cmap = gdk_gc_get_colormap(zoom_region->priv->crosswire_gc);
00816 last_color_init = FALSE;
00817 }
00818
00819 if (magnifier->crosswire_color == 0)
00820 {
00821 color.red = 0xFFFF;
00822 color.blue = 0xFFFF;
00823 color.green = 0xFFFF;
00824 values.function = GDK_INVERT;
00825 }
00826 else
00827 {
00828 color.red = (magnifier->crosswire_color & 0xFF0000) >> 8;
00829 color.green = (magnifier->crosswire_color & 0xFF00);
00830 color.blue = (magnifier->crosswire_color & 0xFF) << 8;
00831 values.function = GDK_COPY;
00832 }
00833
00834 values.foreground = color;
00835
00836
00837 if (!last_color_init || color.red != last_color.red ||
00838 color.blue != last_color.blue || color.green != last_color.green)
00839 {
00840 if (cmap)
00841 {
00842 gdk_rgb_find_color (cmap, &(values.foreground));
00843 gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
00844 }
00845 else
00846 {
00847 gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION);
00848 }
00849
00850 last_color.red = color.red;
00851 last_color.blue = color.blue;
00852 last_color.green = color.green;
00853 last_color_init = TRUE;
00854 }
00855
00856 rect.x = zoom_region->priv->last_cursor_pos.x;
00857 rect.y = zoom_region->priv->last_cursor_pos.y;
00858 rect.width = 0;
00859 rect.height = 0;
00860 rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
00861 if (clip_rect) gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, clip_rect);
00862 else gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, NULL);
00863
00864 if ((cursor = magnifier_get_cursor (magnifier))) {
00865 gdk_drawable_get_size (cursor, &csize, &csize);
00866 }
00867 if (magnifier->crosswire_clip)
00868 {
00869 y_top_clip = rect.y - magnifier->cursor_hotspot.y -
00870 magnifier->crosswire_size;
00871 y_bottom_clip = rect.y +
00872 (csize - magnifier->cursor_hotspot.y) +
00873 magnifier->crosswire_size;
00874 x_left_clip = rect.x - magnifier->cursor_hotspot.x -
00875 magnifier->crosswire_size;
00876 x_right_clip = rect.x +
00877 (csize - magnifier->cursor_hotspot.x) +
00878 magnifier->crosswire_size;
00879
00880 }
00881 if (magnifier->crosswire_size == 1)
00882 {
00883 if (magnifier->crosswire_clip)
00884 {
00885 gdk_draw_line (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, rect.x, 0,
00886 rect.x, y_top_clip);
00887 gdk_draw_line (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, 0, rect.y,
00888 x_left_clip, rect.y);
00889 }
00890 gdk_draw_line (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, rect.x,
00891 y_bottom_clip, rect.x, 4096);
00892 gdk_draw_line (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, x_right_clip,
00893 rect.y, 4096, rect.y);
00894 }
00895 else
00896 {
00897 if (magnifier->crosswire_clip )
00898 {
00899 gdk_draw_rectangle (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, TRUE,
00900 rect.x - magnifier->crosswire_size / 2,
00901 0, magnifier->crosswire_size, y_top_clip);
00902 gdk_draw_rectangle (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, TRUE, 0,
00903 rect.y - magnifier->crosswire_size / 2,
00904 x_left_clip, magnifier->crosswire_size);
00905 }
00906 gdk_draw_rectangle (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, TRUE,
00907 rect.x - magnifier->crosswire_size / 2,
00908 y_bottom_clip, magnifier->crosswire_size, 4096);
00909 gdk_draw_rectangle (zoom_region->priv->w->window, zoom_region->priv->crosswire_gc, TRUE, x_right_clip,
00910 rect.y - magnifier->crosswire_size / 2,
00911 4096, magnifier->crosswire_size);
00912 }
00913 }
00914
00915 static void
00916 zoom_region_unpaint_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect)
00917 {
00918 #ifdef ZOOM_REGION_DEBUG
00919 g_assert (zoom_region->alive);
00920 #endif
00921 zoom_region_paint_pixmap (zoom_region, &zoom_region->priv->cursor_backing_rect);
00922 }
00923
00924 static void
00925 zoom_region_paint_cursor (ZoomRegion *zoom_region,
00926 GdkRectangle *clip_rect)
00927 {
00928 GdkGCValues values;
00929 GdkRectangle rect, intersct;
00930 GdkRectangle fullscreen;
00931 Magnifier *magnifier = zoom_region->priv->parent;
00932 rect = zoom_region_cursor_rect (zoom_region);
00933 #ifdef ZOOM_REGION_DEBUG
00934 g_assert (zoom_region->alive);
00935 #endif
00936 if (clip_rect == NULL)
00937 {
00938 fullscreen = zoom_region_rect_from_bounds (zoom_region,
00939 &zoom_region->viewport);
00940 clip_rect = &fullscreen;
00941 }
00942
00943 zoom_region->priv->last_drawn_crosswire_pos.x = rect.x + magnifier->cursor_hotspot.x;
00944 zoom_region->priv->last_drawn_crosswire_pos.y = rect.y + magnifier->cursor_hotspot.y;
00945
00946 if (gdk_rectangle_intersect (clip_rect, &rect, &intersct))
00947 {
00948 int width = 0, height = 0;
00949
00950 GdkDrawable *cursor = magnifier_get_cursor (magnifier);
00951 if (!cursor)
00952 return;
00953 else if (!GDK_IS_DRAWABLE (cursor)) g_message ("cursor isn't DRAWABLE!");
00954 zoom_region->priv->cursor_backing_rect = rect;
00955 if (zoom_region->priv->cursor_backing_pixels) {
00956 gdk_drawable_get_size (zoom_region->priv->cursor_backing_pixels,
00957 &width, &height);
00958 }
00959 if (rect.width != width || rect.height != height)
00960 {
00961 if (zoom_region->priv->cursor_backing_pixels) {
00962 g_object_unref (zoom_region->priv->cursor_backing_pixels);
00963 }
00964 zoom_region->priv->cursor_backing_pixels =
00965 gdk_pixmap_new (zoom_region->priv->w->window,
00966 rect.width,
00967 rect.height,
00968 -1);
00969 }
00970 if (zoom_region->priv->w->window != NULL)
00971 {
00972 if (zoom_region->priv->default_gc == NULL)
00973 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
00974 gdk_draw_drawable (zoom_region->priv->cursor_backing_pixels,
00975 zoom_region->priv->default_gc,
00976 zoom_region->priv->w->window,
00977 rect.x,
00978 rect.y,
00979 0, 0,
00980 rect.width,
00981 rect.height);
00982 }
00983 DEBUG_RECT ("painting", rect);
00984 if (cursor && zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
00985 {
00986 if (zoom_region->priv->paint_cursor_gc == NULL)
00987 zoom_region->priv->paint_cursor_gc = gdk_gc_new (zoom_region->priv->w->window);
00988
00989 gdk_gc_set_clip_rectangle (zoom_region->priv->paint_cursor_gc, clip_rect);
00990 values.clip_x_origin = rect.x;
00991 values.clip_y_origin = rect.y;
00992 values.clip_mask = magnifier->priv->cursor_mask;
00993 gdk_gc_set_values(zoom_region->priv->paint_cursor_gc, &values, GDK_GC_CLIP_X_ORIGIN |
00994 GDK_GC_CLIP_Y_ORIGIN | GDK_GC_CLIP_MASK);
00995
00996 gdk_draw_rectangle (zoom_region->priv->w->window,
00997 zoom_region->priv->paint_cursor_gc,
00998 TRUE,
00999 rect.x, rect.y, rect.width, rect.height);
01000
01001 gdk_draw_drawable (zoom_region->priv->w->window,
01002 zoom_region->priv->paint_cursor_gc,
01003 cursor,
01004 0, 0,
01005 rect.x,
01006 rect.y,
01007 rect.width,
01008 rect.height);
01009 }
01010 }
01011 }
01012
01017 static void
01018 zoom_region_coalesce_updates (ZoomRegion *zoom_region)
01019 {
01020
01021 GList *q;
01022 int lookahead_n = 4;
01023 int max_qlen = 50;
01024
01025 if (zoom_region->priv && zoom_region->priv->q && g_list_length (zoom_region->priv->q) > max_qlen)
01026 {
01027 g_list_free (zoom_region->priv->q);
01028 zoom_region->priv->q = NULL;
01029
01030 zoom_region_queue_update (zoom_region, zoom_region_rect_from_bounds
01031 (zoom_region, &zoom_region->priv->source_area));
01032 }
01033 else
01034
01035 if (zoom_region->priv && zoom_region->priv->q &&
01036 (g_list_length (zoom_region->priv->q) > 1) && can_coalesce)
01037 {
01038 q = g_list_reverse (g_list_copy (zoom_region->priv->q));
01039 if (q)
01040 {
01041 GList *coalesce_copy;
01042 if (zoom_region->coalesce_func)
01043 {
01044 GList *new;
01045 coalesce_copy = (*zoom_region->coalesce_func) (q, lookahead_n);
01046 new = g_list_reverse (coalesce_copy);
01047 g_list_free (zoom_region->priv->q);
01048 zoom_region->priv->q = new;
01049 }
01050 g_list_free (q);
01051 }
01052 }
01053 }
01054
01055
01056 static void
01057 zoom_region_paint_border (ZoomRegion *zoom_region)
01058 {
01059 GdkColor color;
01060
01061 #ifdef ZOOM_REGION_DEBUG
01062 g_assert (zoom_region->alive);
01063 #endif
01064 if ((zoom_region->border_size > 0) &&
01065 (zoom_region->priv->border->window)) {
01066 color.red = (((zoom_region->border_color & 0xFF0000) >> 16) *
01067 65535) / 255;
01068 color.green = (((zoom_region->border_color & 0xFF00) >> 8) *
01069 65535) / 255;
01070 color.blue = ((zoom_region->border_color & 0xFF) * 65535) /
01071 255;
01072
01073 #ifdef DEBUG_BORDER
01074 fprintf (stderr, "border color triple RGB=%d|%d|%d\n",
01075 color.red, color.green, color.blue);
01076 #endif
01077
01078 gtk_widget_modify_bg (zoom_region->priv->border,
01079 GTK_STATE_NORMAL, &color);
01080 }
01081 }
01082
01083 static void
01084 zoom_region_paint_pixmap (ZoomRegion *zoom_region,
01085 GdkRectangle *area)
01086 {
01087 #ifdef ZOOM_REGION_DEBUG
01088 g_assert (zoom_region->alive);
01089 #endif
01090 g_assert (zoom_region->priv);
01091 g_assert (zoom_region->priv->w);
01092
01093 if (!GDK_IS_DRAWABLE (zoom_region->priv->w->window)) return;
01094 if (zoom_region->priv->default_gc == NULL)
01095 zoom_region->priv->default_gc = gdk_gc_new (zoom_region->priv->w->window);
01096
01097 if (zoom_region->priv->pixmap && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01098 {
01099 gdk_draw_drawable (zoom_region->priv->w->window,
01100 zoom_region->priv->default_gc,
01101 zoom_region->priv->pixmap,
01102 area->x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
01103 area->y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
01104 area->x,
01105 area->y,
01106 area->width,
01107 area->height);
01108 }
01109 }
01110
01114 static void
01115 zoom_region_paint (ZoomRegion *zoom_region,
01116 GdkRectangle *area)
01117 {
01118 GdkRectangle paint_area;
01119
01120 #ifdef ZOOM_REGION_DEBUG
01121 g_assert (zoom_region->alive);
01122 #endif
01123 DEBUG_RECT ("painting (clipped)", *area);
01124 paint_area = zoom_region_clip_to_window (zoom_region, *area);
01125 zoom_region_paint_pixmap (zoom_region, &paint_area);
01126 zoom_region_paint_cursor (zoom_region, &paint_area);
01127 zoom_region_paint_crosswire_cursor (zoom_region, &paint_area);
01128 }
01129
01130 static ZoomRegionPixmapCreationError
01131 zoom_region_create_pixmap (ZoomRegion *zoom_region)
01132 {
01133 #ifdef ZOOM_REGION_DEBUG
01134 g_assert (zoom_region->alive);
01135 #endif
01136 if (zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01137 {
01138 long width = (zoom_region->priv->source_area.x2 -
01139 zoom_region->priv->source_area.x1) * zoom_region->xscale;
01140 long height = (zoom_region->priv->source_area.y2 -
01141 zoom_region->priv->source_area.y1) * zoom_region->yscale;
01142 zoom_region->priv->pixmap =
01143 gdk_pixmap_new (
01144 zoom_region->priv->w->window,
01145 width,
01146 height,
01147 gdk_drawable_get_depth (
01148 zoom_region->priv->w->window));
01149
01150 if (magnifier_error_check ()) {
01151 zoom_region->priv->pixmap = NULL;
01152 return ZOOM_REGION_ERROR_TOO_BIG;
01153 }
01154
01155 DEBUG_RECT("viewport", zoom_region_source_rect_from_view_bounds
01156 (zoom_region, &zoom_region->viewport));
01157 DEBUG_RECT("source", zoom_region_rect_from_bounds
01158 (zoom_region, &((Magnifier*)zoom_region->priv->parent)->source_bounds));
01159
01160 zoom_region_update (zoom_region,
01161
01162
01163
01164
01165 zoom_region_rect_from_bounds
01166 (zoom_region,
01167 &((Magnifier *)zoom_region->priv->parent)->source_bounds));
01168 return ZOOM_REGION_ERROR_NONE;
01169 }
01170
01171 return ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE;
01172 }
01173
01174 static void
01175 zoom_region_expose_handler (GtkWindow * w,
01176 GdkEventExpose *event,
01177 gpointer data)
01178 {
01179 ZoomRegion *zoom_region = data;
01180 DEBUG_RECT ("expose", event->area);
01181
01182 #ifdef ZOOM_REGION_DEBUG
01183 g_assert (zoom_region->alive);
01184 #endif
01185 if (zoom_region->priv->pixmap == NULL)
01186 {
01187 ZoomRegionPixmapCreationError ret;
01188
01189 while ((ret = zoom_region_create_pixmap (zoom_region)) ==
01190 ZOOM_REGION_ERROR_TOO_BIG) {
01191 zoom_region->xscale -= 1.0;
01192 zoom_region->yscale -= 1.0;
01193 zoom_region->priv->pixmap = NULL;
01194 g_warning ("Scale factor too big to fit in memory; shrinking.");
01195 }
01196 if (ret == ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE)
01197 g_warning ("create-pixmap: no target drawable");
01198 }
01199 zoom_region_paint (zoom_region, &event->area);
01200 }
01201
01202 static void
01203 zoom_region_update_cursor (ZoomRegion *zoom_region, int dx, int dy,
01204 GdkRectangle *clip_rect)
01205 {
01206 #ifdef ZOOM_REGION_DEBUG
01207 g_assert (zoom_region->alive);
01208 #endif
01209 zoom_region_unpaint_crosswire_cursor (zoom_region, clip_rect);
01210 zoom_region_unpaint_cursor (zoom_region, clip_rect);
01211 zoom_region->priv->cursor_backing_rect.x += dx;
01212 zoom_region->priv->cursor_backing_rect.y += dy;
01213 zoom_region->priv->last_drawn_crosswire_pos.x += dx;
01214 zoom_region->priv->last_drawn_crosswire_pos.y += dy;
01215 zoom_region_paint_cursor (zoom_region, clip_rect);
01216 zoom_region_paint_crosswire_cursor (zoom_region, clip_rect);
01217 if (GTK_IS_WIDGET (zoom_region->priv->w) &&
01218 GDK_IS_WINDOW (zoom_region->priv->w->window))
01219 gdk_display_sync (gdk_drawable_get_display (
01220 zoom_region->priv->w->window));
01221 }
01222
01223 static gboolean
01224 zoom_region_calculate_scroll_rects (ZoomRegion *zoom_region,
01225 int dx, int dy,
01226 GdkRectangle *scroll_rect,
01227 GdkRectangle *expose_rect_h,
01228 GdkRectangle *expose_rect_v)
01229 {
01230 GdkWindow *window = NULL;
01231 GdkRectangle rect = {0, 0, 0, 0};
01232 gboolean retval = TRUE;
01233
01234 #ifdef ZOOM_REGION_DEBUG
01235 g_assert (zoom_region->alive);
01236 #endif
01237 rect.x = 0;
01238 rect.y = 0;
01239 if (zoom_region && zoom_region->priv->w &&
01240 zoom_region->priv->w->window)
01241 window = zoom_region->priv->w->window;
01242 else
01243 retval = FALSE;
01244 if (!window)
01245 retval = FALSE;
01246
01247 if (window != NULL)
01248 gdk_drawable_get_size (GDK_DRAWABLE (window),
01249 &rect.width,
01250 &rect.height);
01251
01252 if ((ABS (dx) >= rect.width) || (ABS (dy) >= rect.height)) {
01253 *scroll_rect = rect;
01254 DBG(fprintf (stderr, "deltas too big to scroll\n"));
01255 retval = FALSE;
01256 }
01257 else {
01258 scroll_rect->x = MAX (0, dx);
01259 scroll_rect->y = MAX (0, dy);
01260 scroll_rect->width = MIN (rect.width + dx, rect.width - dx);
01261 scroll_rect->height = MIN (rect.height + dy, rect.height - dy);
01262 }
01263
01264 expose_rect_h->x = 0;
01265 expose_rect_h->y = (scroll_rect->y == 0) ? scroll_rect->height : 0;
01266 expose_rect_h->width = rect.width;
01267 expose_rect_h->height = rect.height - scroll_rect->height;
01268
01269 expose_rect_v->x = (scroll_rect->x == 0) ? scroll_rect->width : 0;
01270 expose_rect_v->y = scroll_rect->y;
01271 expose_rect_v->width = rect.width - scroll_rect->width;
01272 expose_rect_v->height = scroll_rect->height;
01273
01274 return retval;
01275 }
01276
01277 static void
01278 zoom_region_scroll_fast (ZoomRegion *zoom_region, int dx, int dy,
01279 GdkRectangle *scroll_rect,
01280 GdkRectangle *expose_rect_h,
01281 GdkRectangle *expose_rect_v)
01282 {
01283 GdkWindow *window;
01284
01285 #ifdef ZOOM_REGION_DEBUG
01286 g_assert (zoom_region->alive);
01287 #endif
01288 if (zoom_region->priv->w && zoom_region->priv->w->window)
01289 window = zoom_region->priv->w->window;
01290 else {
01291 processing_updates = FALSE;
01292 return;
01293 }
01294 zoom_region_unpaint_crosswire_cursor (zoom_region, scroll_rect);
01295 zoom_region_unpaint_cursor (zoom_region, scroll_rect);
01296 gdk_window_scroll (window, dx, dy);
01297 zoom_region_paint_cursor (zoom_region, scroll_rect);
01298 zoom_region_paint_crosswire_cursor (zoom_region, scroll_rect);
01299 gdk_window_process_updates (window, FALSE);
01300
01301 if (zoom_region->smooth_scroll_policy >
01302 GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST)
01303 gdk_display_sync (gdk_drawable_get_display (window));
01304 }
01305
01306 static void
01307 zoom_region_scroll_smooth (ZoomRegion *zoom_region, int dx, int dy,
01308 GdkRectangle *scroll_rect,
01309 GdkRectangle *expose_rect_h,
01310 GdkRectangle *expose_rect_v)
01311 {
01312 GdkWindow *window = NULL;
01313 GdkRectangle window_rect;
01314
01315 #ifdef ZOOM_REGION_DEBUG
01316 g_assert (zoom_region->alive);
01317 #endif
01318 if (zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01319 window = zoom_region->priv->w->window;
01320 else
01321 return;
01322 window_rect.x = 0;
01323 window_rect.y = 0;
01324 gdk_drawable_get_size (GDK_DRAWABLE (window),
01325 &window_rect.width, &window_rect.height);
01326 gdk_window_begin_paint_rect (window, &window_rect);
01327 gdk_window_invalidate_rect (window, &window_rect, FALSE);
01328 gdk_window_process_updates (window, FALSE);
01329 gdk_window_end_paint (window);
01330 }
01331
01332 static void
01333 zoom_region_scroll (ZoomRegion *zoom_region, int dx, int dy)
01334 {
01335 GdkRectangle scroll_rect, expose_rect_h, expose_rect_v;
01336 gboolean can_scroll;
01337
01338 #ifdef ZOOM_REGION_DEBUG
01339 g_assert (zoom_region->alive);
01340 #endif
01341 if (timing_test) {
01342 mag_timing.num_line_samples++;
01343 mag_timing.dx = abs(dx);
01344 mag_timing.dy = abs(dy);
01345 mag_timing.dx_total += mag_timing.dx;
01346 mag_timing.dy_total += mag_timing.dy;
01347 if (zoom_region->timing_output) {
01348 fprintf(stderr, " Panning Increment (x) = %d (avg. %f) lines/frame\n",
01349 mag_timing.dx, (float)mag_timing.dx_total / (float)mag_timing.num_line_samples);
01350 fprintf(stderr, " Panning Increment (y) = %d (avg. %f) lines/frame\n",
01351 mag_timing.dy, (float)mag_timing.dy_total / (float)mag_timing.num_line_samples);
01352 }
01353 }
01354
01355
01356
01357
01358
01359 processing_updates = TRUE;
01360
01361 can_scroll = zoom_region_calculate_scroll_rects (zoom_region, dx, dy,
01362 &scroll_rect,
01363 &expose_rect_h,
01364 &expose_rect_v);
01365
01366 if (can_scroll) {
01367 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_h), NULL);
01368 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_v), NULL);
01369
01370 if (zoom_region->smooth_scroll_policy > GNOME_Magnifier_ZoomRegion_SCROLL_FAST) {
01371 zoom_region_scroll_smooth (zoom_region, dx, dy,
01372 &scroll_rect,
01373 &expose_rect_h,
01374 &expose_rect_v);
01375 } else {
01376 zoom_region_scroll_fast (zoom_region, dx, dy,
01377 &scroll_rect,
01378 &expose_rect_h,
01379 &expose_rect_v);
01380 }
01381 } else {
01382 zoom_region_queue_update (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, scroll_rect));
01383 }
01384 }
01385
01386 static void
01387 zoom_region_recompute_exposed_bounds (ZoomRegion *zoom_region)
01388 {
01389 zoom_region->priv->exposed_bounds.x2 = zoom_region->priv->exposed_bounds.x1
01390 + (zoom_region->viewport.x2 - zoom_region->viewport.x1);
01391 zoom_region->priv->exposed_bounds.y2 = zoom_region->priv->exposed_bounds.y1
01392 + (zoom_region->viewport.y2 - zoom_region->viewport.y1);
01393 }
01394
01395 static void
01396 zoom_region_set_cursor_pos (ZoomRegion *zoom_region, int x, int y)
01397 {
01398 if (zoom_region->priv)
01399 {
01400 zoom_region->priv->last_cursor_pos.x = x;
01401 zoom_region->priv->last_cursor_pos.y = y;
01402 }
01403 }
01404
01405 static gboolean
01406 zoom_region_update_pointer (ZoomRegion *zoom_region, gboolean draw_cursor)
01407 {
01408 Magnifier *magnifier;
01409 gint mouse_x_return, mouse_y_return;
01410 guint mask_return;
01411
01412 #ifdef ZOOM_REGION_DEBUG
01413 g_assert (zoom_region->alive);
01414 #endif
01415 if (!zoom_region->priv || !zoom_region->priv->parent
01416 || !zoom_region->poll_mouse)
01417 return FALSE;
01418
01419 magnifier = zoom_region->priv->parent;
01420
01421
01422 if (magnifier && magnifier->priv && magnifier_get_root (magnifier))
01423 {
01424 gdk_window_get_pointer (
01425 magnifier_get_root (magnifier),
01426 &mouse_x_return,
01427 &mouse_y_return,
01428 &mask_return);
01429
01430 if (zoom_region->priv->last_cursor_pos.x != mouse_x_return
01431 || zoom_region->priv->last_cursor_pos.y != mouse_y_return)
01432 {
01433 zoom_region_set_cursor_pos (zoom_region,
01434 mouse_x_return, mouse_y_return);
01435 if (draw_cursor)
01436 {
01437 GdkRectangle paint_area, *clip = NULL;
01438
01439 if (GTK_IS_WIDGET (zoom_region->priv->w) &&
01440 GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01441 {
01442 gdk_drawable_get_size (
01443 GDK_DRAWABLE (
01444 zoom_region->priv->w->window),
01445 &paint_area.width, &paint_area.height);
01446 paint_area.x = 0;
01447 paint_area.y = 0;
01448 clip = &paint_area;
01449 paint_area = zoom_region_clip_to_source (
01450 zoom_region, paint_area);
01451 }
01452 zoom_region_update_cursor (zoom_region, 0, 0, clip);
01453 }
01454 return TRUE;
01455 }
01456 }
01457 return FALSE;
01458 }
01459
01460 static int
01461 zoom_region_update_pointer_idle (gpointer data)
01462 {
01463 ZoomRegion *zoom_region = (ZoomRegion *) data;
01464
01465 if (zoom_region_update_pointer (zoom_region, TRUE))
01466 return TRUE;
01467 else {
01468 if (zoom_region->priv)
01469 zoom_region->priv->update_pointer_id =
01470 g_timeout_add_full (G_PRIORITY_DEFAULT,
01471 100,
01472 zoom_region_update_pointer_timeout,
01473 zoom_region,
01474 NULL);
01475 return FALSE;
01476 }
01477 }
01478
01479 static int
01480 zoom_region_update_pointer_timeout (gpointer data)
01481 {
01482 ZoomRegion *zoom_region = data;
01483
01484 if (zoom_region->priv && zoom_region_update_pointer (zoom_region, TRUE)) {
01485 zoom_region->priv->update_pointer_id =
01486 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
01487 zoom_region_update_pointer_idle,
01488 data,
01489 NULL);
01490 return FALSE;
01491 } else
01492 return TRUE;
01493 }
01494
01495 static void
01496 zoom_region_moveto (ZoomRegion *zoom_region,
01497 const long x, const long y)
01498 {
01499 long dx = x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
01500 long dy = y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
01501 #ifdef ZOOM_REGION_DEBUG
01502 g_assert (zoom_region->alive);
01503 #endif
01504
01505
01506 mag_timing.dx = 0;
01507 mag_timing.dy = 0;
01508
01509 if ((dx != 0) || (dy != 0)) {
01510 zoom_region_update_pointer (zoom_region, FALSE);
01511 zoom_region->priv->exposed_bounds.x1 = x * zoom_region->xscale;
01512 zoom_region->priv->exposed_bounds.y1 = y * zoom_region->yscale;
01513 zoom_region_recompute_exposed_bounds (zoom_region);
01514 zoom_region_scroll (zoom_region,
01515 -dx, -dy);
01516 }
01517 }
01518
01519
01520
01521
01522 static void
01523 zoom_region_process_pixbuf (ZoomRegion *zoom_region, GdkPixbuf *pixbuf)
01524 {
01525 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
01526 int i, j, t;
01527 int w = gdk_pixbuf_get_width (pixbuf);
01528 int h = gdk_pixbuf_get_height (pixbuf);
01529 int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
01530 guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
01531 guchar *pixels_row;
01532 #ifdef HAVE_COLORBLIND
01533 COLORBLIND_RUNTIME *cbr;
01534 COLORBLIND_XCOLOR *color;
01535 #endif
01536
01537 gboolean manipulate_contrast = FALSE;
01538 gboolean manipulate_brightness = FALSE;
01539 gboolean color_blind_filter = FALSE;
01540
01541 if (zoom_region->contrast_r != 0 || zoom_region->contrast_g != 0 ||
01542 zoom_region->contrast_b != 0) {
01543 manipulate_contrast = TRUE;
01544 }
01545
01546 if (zoom_region->bright_r != 0 || zoom_region->bright_g != 0 ||
01547 zoom_region->bright_b != 0) {
01548 manipulate_brightness = TRUE;
01549 }
01550
01551 #ifdef HAVE_COLORBLIND
01552 if (zoom_region->color_blind_filter !=
01553 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER) {
01554 color_blind_filter = TRUE;
01555 cbr = colorblind_create ();
01556 color = malloc (sizeof (COLORBLIND_XCOLOR));
01557 switch (zoom_region->color_blind_filter) {
01558 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER:
01559 break;
01560 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_RED:
01561 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_red);
01562 break;
01563 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_GREEN:
01564 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_green);
01565 break;
01566 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_BLUE:
01567 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_blue);
01568 break;
01569 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_RED:
01570 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_red);
01571 break;
01572 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_GREEN:
01573 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_green);
01574 break;
01575 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_BLUE:
01576 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_blue);
01577 break;
01578 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_POSITIVE:
01579 colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_positive);
01580 break;
01581 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_NEGATIVE:
01582 colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_negative);
01583 break;
01584 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE:
01585 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate);
01586 break;
01587 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE:
01588 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate);
01589 break;
01590 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_MONOCHRONE_OTHERS:
01591 colorblind_set_filter_type (cbr, colorblind_filter_t_monochrome_others);
01592 break;
01593 }
01594 }
01595 #endif
01596
01597 if (!manipulate_contrast && !zoom_region->invert &&
01598 !manipulate_brightness && !color_blind_filter)
01599 return;
01600
01601 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
01602 #define CLAMP_LOW_MID(v) (t = (v), CLAMP (t, 0, 127))
01603 #define CLAMP_MID_HIGH(v) (t = (v), CLAMP (t, 127, 255))
01604
01605 for (j = 0; j < h; ++j) {
01606 pixels_row = pixels;
01607 for (i = 0; i < w; ++i) {
01608 if (manipulate_contrast) {
01609
01610 if (pixels_row[0] <= 127)
01611 pixels_row[0] = CLAMP_LOW_MID (pixels_row[0] - zoom_region->contrast_r * 127);
01612 else
01613 pixels_row[0] = CLAMP_MID_HIGH (pixels_row[0] + zoom_region->contrast_r * 127);
01614
01615
01616 if (pixels_row[1] <= 127)
01617 pixels_row[1] = CLAMP_LOW_MID (pixels_row[1] - zoom_region->contrast_g * 127);
01618 else
01619 pixels_row[1] = CLAMP_MID_HIGH (pixels_row[1] + zoom_region->contrast_g * 127);
01620
01621
01622 if (pixels_row[2] <= 127)
01623 pixels_row[2] = CLAMP_LOW_MID (pixels_row[2] - zoom_region->contrast_b * 127);
01624 else
01625 pixels_row[2] = CLAMP_MID_HIGH (pixels_row[2] + zoom_region->contrast_b * 127);
01626 }
01627
01628 if (manipulate_brightness) {
01629
01630 pixels_row[0] = CLAMP_UCHAR (pixels_row[0] + zoom_region->bright_r * 255);
01631
01632
01633 pixels_row[1] = CLAMP_UCHAR (pixels_row[1] + zoom_region->bright_g * 255);
01634
01635
01636 pixels_row[2] = CLAMP_UCHAR (pixels_row[2] + zoom_region->bright_b * 255);
01637 }
01638
01639 if (zoom_region->invert) {
01640 pixels_row[0] = ~(pixels_row[0]);
01641 pixels_row[1] = ~(pixels_row[1]);
01642 pixels_row[2] = ~(pixels_row[2]);
01643 }
01644
01645 #ifdef HAVE_COLORBLIND
01646 if (color_blind_filter) {
01647 color->red = pixels_row[0];
01648 color->green = pixels_row[1];
01649 color->blue = pixels_row[2];
01650 if (colorblind_filter (cbr, color)) {
01651 pixels_row[0] = color->red;
01652 pixels_row[1] = color->green;
01653 pixels_row[2] = color->blue;
01654 }
01655 }
01656 #endif
01657
01658 pixels_row += n_channels;
01659 }
01660 pixels += rowstride;
01661 }
01662 }
01663
01664 static void
01665 zoom_region_post_process_pixbuf (ZoomRegion *zoom_region,
01666 GdkPixbuf *subimage,
01667 GdkPixbuf *scaled_image)
01668 {
01669
01679 }
01680
01681 static GdkPixbuf *
01682 zoom_region_get_source_subwindow (ZoomRegion *zoom_region,
01683 const GdkRectangle bounds)
01684 {
01685 int i, j, width, height;
01686 Magnifier *magnifier = zoom_region->priv->parent;
01687 GdkPixbuf *subimage = NULL;
01688
01689 #ifdef ZOOM_REGION_DEBUG
01690 g_assert (zoom_region->alive);
01691 #endif
01692 width = gdk_screen_get_width (
01693 gdk_display_get_screen (magnifier->source_display,
01694 magnifier->source_screen_num));
01695 height = gdk_screen_get_height (
01696 gdk_display_get_screen (magnifier->source_display,
01697 magnifier->source_screen_num));
01698
01699 if ((bounds.width <= 0) || (bounds.height <= 0))
01700 {
01701 return NULL;
01702 }
01703
01704 if (!zoom_region->priv->source_drawable)
01705 {
01706
01707 if (zoom_region->priv->test) {
01708 GdkImage *test_image = NULL;
01709
01710 test_image = gdk_image_new (GDK_IMAGE_FASTEST,
01711 gdk_visual_get_system (),
01712 width,
01713 height);
01714
01715 for (i = 0; i < width; ++i)
01716 for (j = 0; j < height; ++j)
01717 gdk_image_put_pixel (test_image, i, j, i*j);
01718
01719 zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01720
01721 if (zoom_region->priv->default_gc == NULL)
01722 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01723
01724 gdk_draw_image (zoom_region->priv->source_drawable,
01725 zoom_region->priv->default_gc,
01726 test_image,
01727 0, 0,
01728 0, 0,
01729 width, height);
01730 }
01731 else
01732 {
01733 zoom_region->priv->source_drawable = gdk_screen_get_root_window (
01734 gdk_display_get_screen (
01735 magnifier->source_display,
01736 magnifier->source_screen_num));
01737 }
01738 if (zoom_region->cache_source)
01739 {
01740 zoom_region->priv->source_pixbuf_cache =
01741 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01742 FALSE,
01743 8,
01744 width, height);
01745 }
01746 }
01747 DEBUG_RECT ("getting subimage from ", bounds);
01748
01749 subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01750 gdk_colormap_get_system (),
01751 bounds.x,
01752 bounds.y,
01753 0,
01754 0,
01755 bounds.width,
01756 bounds.height);
01757
01758
01759
01760 if (!subimage)
01761 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01762
01763
01764 if (zoom_region->cache_source && subimage) {
01765 GdkPixbuf *cache_subpixbuf =
01766 gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01767 bounds.x, bounds.y, bounds.width, bounds.height);
01768 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01769 gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01770 zoom_region->priv->source_pixbuf_cache,
01771 bounds.x, bounds.y);
01772 }
01773 else
01774 {
01775 if (subimage)
01776 g_object_unref (subimage);
01777 subimage = NULL;
01778 }
01779 g_object_unref (cache_subpixbuf);
01780 }
01781 return subimage;
01782 }
01783
01784 static GdkRectangle
01785 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01786 const GdkRectangle update_rect,
01787 GdkRectangle *p_rect)
01788 {
01789 GdkPixbuf *subimage;
01790 GdkRectangle source_rect;
01791
01792 #ifdef ZOOM_REGION_DEBUG
01793 g_assert (zoom_region->alive);
01794 #endif
01795 DEBUG_RECT ("unclipped update rect", update_rect);
01796 source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01797 DEBUG_RECT ("clipped to source", source_rect);
01798 source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01799 DEBUG_RECT ("update rect clipped to exposed target", source_rect);
01800
01801 subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01802
01803 if (subimage)
01804 {
01805 GdkRectangle paint_rect;
01806 g_timer_start (mag_timing.scale);
01807 DEBUG_RECT ("source rect", source_rect);
01808 paint_rect = zoom_region_view_rect_from_source_rect (zoom_region, source_rect);
01809 if (p_rect) {
01810 *p_rect = paint_rect;
01811 }
01812
01813 DEBUG_RECT ("paint rect", paint_rect);
01814
01815 zoom_region_process_pixbuf (zoom_region, subimage);
01816
01821 gdk_pixbuf_scale (subimage,
01822 zoom_region->priv->scaled_pixbuf,
01823 0,
01824 0,
01825 paint_rect.width,
01826 paint_rect.height,
01827 0,
01828 0,
01829 zoom_region->xscale,
01830 zoom_region->yscale,
01831 zoom_region->priv->gdk_interp_type);
01832
01833 zoom_region_post_process_pixbuf (zoom_region, subimage,
01834 zoom_region->priv->scaled_pixbuf);
01835 if (zoom_region->priv->default_gc == NULL)
01836 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01837
01838 #ifndef USE_GDK_PIXBUF_RENDER_TO_DRAWABLE
01839 if (GDK_IS_DRAWABLE (zoom_region->priv->pixmap))
01840 gdk_draw_pixbuf (zoom_region->priv->pixmap,
01841 zoom_region->priv->default_gc,
01842 zoom_region->priv->scaled_pixbuf,
01843 0,
01844 0,
01845 paint_rect.x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
01846 paint_rect.y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
01847 paint_rect.width,
01848 paint_rect.height,
01849 GDK_RGB_DITHER_NONE,
01850 0,
01851 0);
01852 else
01853 g_warning ("updating non-drawable pixmap: region %p", zoom_region);
01854 #else
01855 gdk_pixbuf_render_to_drawable (zoom_region->priv->scaled_pixbuf,
01856 zoom_region->priv->pixmap,
01857 zoom_region->priv->default_gc,
01858 0,
01859 0,
01860 paint_rect.x + zoom_region->priv->exposed_bounds.x1,
01861 paint_rect.y + zoom_region->priv->exposed_bounds.y1,
01862 paint_rect.width,
01863 paint_rect.height,
01864 GDK_RGB_DITHER_NONE,
01865 0,
01866 0);
01867 #endif
01868 if (magnifier_error_check ())
01869 g_warning ("Could not render scaled image to drawable; out of memory!\n");
01870 g_object_unref (subimage);
01871
01872 g_timer_stop (mag_timing.scale);
01873 }
01874 return source_rect;
01875 }
01876
01883 static void
01884 zoom_region_update (ZoomRegion *zoom_region,
01885 const GdkRectangle update_rect)
01886 {
01887 GdkRectangle paint_rect = {0, 0, 0, 0};
01888 if (zoom_region->priv->w && zoom_region->priv->w->window) {
01889 GdkRectangle source_rect = zoom_region_update_pixmap (zoom_region, update_rect, &paint_rect);
01890 if (paint_rect.x != 0 || paint_rect.y != 0 ||
01891 paint_rect.width != 0 || paint_rect.height != 0) {
01892 gdk_window_begin_paint_rect (
01893 zoom_region->priv->w->window, &paint_rect);
01894 zoom_region_paint (zoom_region, &paint_rect);
01895 gdk_window_end_paint (zoom_region->priv->w->window);
01896 }
01897 if (timing_test) {
01898 mag_timing.num_scale_samples++;
01899
01900 gulong microseconds;
01901
01902 mag_timing.scale_val =
01903 g_timer_elapsed (mag_timing.scale,
01904 µseconds);
01905 mag_timing.scale_total += mag_timing.scale_val;
01906
01907 if (mag_timing.scale_val != 0 && (timing_scale_max == 0 ||
01908 (1.0/(float)mag_timing.scale_val) > (1.0/(float)timing_scale_max)))
01909 timing_scale_max = mag_timing.scale_val;
01910 if ((source_rect.height * source_rect.width / mag_timing.scale_val) > update_nrr_max)
01911 update_nrr_max = source_rect.height * source_rect.width / mag_timing.scale_val;
01912
01913 mag_timing.update_pixels_total += source_rect.height * source_rect.width;
01914
01915 if (zoom_region->timing_output) {
01916 fprintf(stderr, " Update Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
01917 mag_timing.scale_val, (mag_timing.scale_total /
01918 mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total);
01919 fprintf(stderr, " Update Pixels = %ld (avg. %ld) pixels/frame\n",
01920 (long) source_rect.height * source_rect.width,
01921 mag_timing.update_pixels_total / mag_timing.num_scale_samples);
01922 fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n",
01923 1.0/(mag_timing.scale_total / mag_timing.num_scale_samples), 1.0/(float)timing_scale_max);
01924 fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n",
01925 ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
01926 update_nrr_max / 1000000.0);
01927 }
01928 }
01929 } else {
01930 fprintf (stderr, "update on uninitialized zoom region!\n");
01931 }
01932 }
01933
01934 static void
01935 zoom_region_init_window (ZoomRegion *zoom_region)
01936 {
01937 GtkFixed *parent;
01938 GtkWidget *zoomer, *border;
01939 DBG(fprintf (stderr, "window not yet created...\n"));
01940 parent = GTK_FIXED (
01941 ((Magnifier *)zoom_region->priv->parent)->priv->canvas);
01942 zoomer = gtk_drawing_area_new ();
01943 border = gtk_drawing_area_new ();
01944 zoom_region->priv->border = border;
01945 zoom_region->priv->w = zoomer;
01946
01947 #ifdef ZOOM_REGION_DEBUG
01948 g_assert (zoom_region->alive);
01949 #endif
01950 gtk_widget_set_size_request (GTK_WIDGET (border),
01951 zoom_region->viewport.x2 -
01952 zoom_region->viewport.x1,
01953 zoom_region->viewport.y2 -
01954 zoom_region->viewport.y1);
01955 gtk_widget_set_size_request (GTK_WIDGET (zoomer),
01956 zoom_region->viewport.x2 -
01957 zoom_region->viewport.x1 -
01958 zoom_region->border_size * 2,
01959 zoom_region->viewport.y2 -
01960 zoom_region->viewport.y1 -
01961 zoom_region->border_size * 2);
01962 gtk_fixed_put (parent, border,
01963 zoom_region->viewport.x1,
01964 zoom_region->viewport.y1);
01965 gtk_fixed_put (parent, zoomer,
01966 zoom_region->viewport.x1 + zoom_region->border_size,
01967 zoom_region->viewport.y1 + zoom_region->border_size);
01968 gtk_widget_show (GTK_WIDGET (border));
01969 gtk_widget_show (GTK_WIDGET (zoomer));
01970 gtk_widget_show (GTK_WIDGET (parent));
01971 zoom_region->priv->expose_handler_id =
01972 g_signal_connect (G_OBJECT (zoom_region->priv->w),
01973 "expose_event",
01974 G_CALLBACK (zoom_region_expose_handler),
01975 zoom_region);
01976 DBG(fprintf (stderr, "New window created\n"));
01977 }
01978
01979 static int
01980 zoom_region_process_updates (gpointer data)
01981 {
01982 ZoomRegion *zoom_region = (ZoomRegion *) data;
01983
01984
01985 zoom_region_coalesce_updates (zoom_region);
01986
01987 if (zoom_region->priv->q != NULL) {
01988 GList *last = g_list_last (zoom_region->priv->q);
01989 #ifdef ZOOM_REGION_DEBUG
01990 fprintf (stderr, "qlen=%d\n", g_list_length (zoom_region->priv->q));
01991 #endif
01992 if (last) {
01993 zoom_region->priv->q = g_list_remove_link (zoom_region->priv->q,
01994 last);
01995 zoom_region_update (zoom_region,
01996 * (GdkRectangle *) last->data);
01997 g_list_free (last);
01998 #ifdef DEBUG
01999 fputs (".\n", stderr);
02000 #endif
02001 }
02002 return TRUE;
02003 }
02004 else
02005 {
02006 if (zoom_region->priv)
02007 zoom_region->priv->update_handler_id = 0;
02008 return FALSE;
02009 }
02010 }
02011
02012 void
02013 timing_report(ZoomRegion *zoom_region)
02014 {
02015 float frame_avg;
02016 float x_scroll_incr, y_scroll_incr;
02017 int width, height, x, y;
02018
02019 if (timing_test) {
02020 width = (zoom_region->viewport.x2 -
02021 zoom_region->viewport.x1) / zoom_region->xscale;
02022 height = (zoom_region->viewport.y2 -
02023 zoom_region->viewport.y1) / zoom_region->yscale;
02024
02025 frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples;
02026
02027 x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
02028 y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
02029
02030 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
02031 &x, &y);
02032
02033 fprintf(stderr, " Frames Processed = %ld\n",
02034 mag_timing.num_frame_samples + 1);
02035 fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y,
02036 gdk_drawable_get_depth (zoom_region->priv->w->window));
02037 fprintf(stderr, " Zoom Factor (x/y) = %f/%f\n", zoom_region->xscale,
02038 zoom_region->yscale);
02039 if (mag_timing.num_scale_samples != 0) {
02040 fprintf(stderr, " Update Duration = (avg. %f) (max. %f) (tot. %f) seconds\n",
02041 (mag_timing.scale_total / mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total);
02042 fprintf(stderr, " Update Pixels = (avg. %ld) pixels/frame\n",
02043 mag_timing.update_pixels_total / mag_timing.num_scale_samples);
02044 fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n",
02045 1.0/((float)mag_timing.scale_total / (float)mag_timing.num_scale_samples),
02046 1.0/(float)timing_scale_max);
02047 fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n",
02048 ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
02049 update_nrr_max / 1000000.0);
02050 }
02051 fprintf(stderr, " Pan Latency = (avg. %f) (max. %f) seconds\n",
02052 (mag_timing.idle_total / mag_timing.num_idle_samples), timing_idle_max);
02053 fprintf(stderr, " Total Frame Duration = (avg. %f) (max. %f) (tot. %f) seconds\n",
02054 frame_avg, timing_frame_max, mag_timing.frame_total);
02055 fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n",
02056 1.0 / (mag_timing.frame_total / mag_timing.num_frame_samples), cps_max);
02057 fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n",
02058 x_scroll_incr, mag_timing.dx_total);
02059 fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n",
02060 y_scroll_incr, mag_timing.dy_total);
02061 fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n",
02062 x_scroll_incr / frame_avg);
02063 fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n",
02064 y_scroll_incr / frame_avg);
02065
02066 fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n\n",
02067 (height * width *
02068 ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
02069 nrr_max / 1000000.0);
02070 }
02071 }
02072
02073 static void
02074 zoom_region_time_frame(ZoomRegion *zoom_region, Magnifier *magnifier)
02075 {
02076 float frame_avg;
02077 float x_scroll_incr, y_scroll_incr;
02078 int width = magnifier->target_bounds.x2 - magnifier->target_bounds.x1;
02079 int height = magnifier->target_bounds.y2 - magnifier->target_bounds.y1;
02080
02081 mag_timing.num_frame_samples++;
02082 g_timer_stop (mag_timing.frame);
02083
02084 gulong microseconds;
02085
02086 mag_timing.frame_val = g_timer_elapsed (mag_timing.frame,
02087 µseconds);
02088
02089 mag_timing.frame_total += mag_timing.frame_val;
02090 if (mag_timing.frame_val > timing_frame_max)
02091 timing_frame_max = mag_timing.frame_val;
02092 if (mag_timing.frame_val != 0 && 1.0/mag_timing.frame_val > cps_max)
02093 cps_max = 1.0/mag_timing.frame_val;
02094
02095 frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples;
02096
02097 x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
02098 y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
02099
02100 if ((height * width / mag_timing.frame_val) > nrr_max)
02101 nrr_max = height * width / mag_timing.frame_val;
02102
02103 if (zoom_region->timing_output) {
02104 fprintf(stderr, " Total Frame Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
02105 mag_timing.frame_val, frame_avg, timing_frame_max, mag_timing.frame_total);
02106 fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n",
02107 1.0 /frame_avg, cps_max);
02108 fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n",
02109 x_scroll_incr, mag_timing.dx_total);
02110 fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n",
02111 y_scroll_incr, mag_timing.dy_total);
02112 fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n",
02113 x_scroll_incr / frame_avg);
02114 fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n",
02115 y_scroll_incr / frame_avg);
02116
02117 fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n",
02118 (height * width *
02119 ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
02120 nrr_max / 1000000.0);
02121 }
02122
02123 mag_timing.last_frame_val = mag_timing.frame_val;
02124 mag_timing.last_dy = mag_timing.dy;
02125
02126 if (reset_timing) {
02127 fprintf(stderr, "\n### Updates summary:\n\n");
02128 timing_report (zoom_region);
02129 fprintf(stderr, "\n### Updates finished, starting panning test\n");
02130 reset_timing_stats();
02131 reset_timing = FALSE;
02132 }
02133 }
02134
02135 static void
02136 zoom_region_sync (ZoomRegion *zoom_region)
02137 {
02138 while (zoom_region->priv->q)
02139 zoom_region_process_updates (zoom_region);
02140 }
02141
02142 static gboolean
02143 gdk_timing_idle (gpointer data)
02144 {
02145 ZoomRegion *zoom_region = data;
02146
02147
02148 processing_updates = FALSE;
02149 g_timer_stop (mag_timing.idle);
02150
02151 if (timing_test) {
02152 mag_timing.num_idle_samples++;
02153
02154 gulong microseconds;
02155
02156 mag_timing.idle_val = g_timer_elapsed (mag_timing.idle,
02157 µseconds);
02158 mag_timing.idle_total += mag_timing.idle_val;
02159
02160 if (mag_timing.idle_val > timing_idle_max)
02161 timing_idle_max = mag_timing.idle_val;
02162
02163 if (zoom_region->timing_output) {
02164 fprintf(stderr, " Pan Latency = %f (avg. %f) (max. %f) seconds\n",
02165 mag_timing.idle_val, (mag_timing.idle_total /
02166 mag_timing.num_idle_samples), timing_idle_max);
02167 }
02168 }
02169
02170 return FALSE;
02171 }
02172
02173 static void
02174 zoom_region_align (ZoomRegion *zoom_region)
02175 {
02176 Magnifier *magnifier = zoom_region->priv->parent;
02177 long x = 0, y = 0;
02178 long width, height;
02179
02180 if (timing_start)
02181 zoom_region_time_frame(zoom_region, magnifier);
02182
02183 if (timing_test) {
02184 g_timer_start (mag_timing.frame);
02185
02186 if (zoom_region->timing_output) {
02187 gint x, y;
02188
02189 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
02190 &x, &y);
02191
02192 fprintf(stderr, "\nTiming Information - ROI = (%d, %d) (%d, %d):\n",
02193 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
02194 zoom_region->roi.y2);
02195 fprintf(stderr, " Frame Number = %ld\n",
02196 mag_timing.num_frame_samples + 1);
02197 fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y,
02198 gdk_drawable_get_depth (zoom_region->priv->w->window));
02199 }
02200
02201
02202
02203
02204
02205 if (!timing_start)
02206 g_timer_start (mag_timing.process);
02207
02208 timing_start = TRUE;
02209 }
02210
02211 g_timer_start (mag_timing.idle);
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230 g_idle_add_full (GDK_PRIORITY_REDRAW + 1,
02231 gdk_timing_idle, zoom_region, NULL);
02232
02233 width = (zoom_region->viewport.x2 -
02234 zoom_region->viewport.x1) / zoom_region->xscale;
02235 height = (zoom_region->viewport.y2 -
02236 zoom_region->viewport.y1) / zoom_region->yscale;
02237
02238 switch (zoom_region->x_align_policy) {
02239 case GNOME_Magnifier_ZoomRegion_ALIGN_MAX:
02240 x = zoom_region->roi.x2 - width;
02241 break;
02242 case GNOME_Magnifier_ZoomRegion_ALIGN_MIN:
02243 x = zoom_region->roi.x1;
02244 break;
02245 case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER:
02246 default:
02247 x = ((zoom_region->roi.x1 + zoom_region->roi.x2) - width ) / 2;
02248 }
02249
02250 switch (zoom_region->y_align_policy) {
02251 case GNOME_Magnifier_ZoomRegion_ALIGN_MAX:
02252 y = zoom_region->roi.y2 - height;
02253 break;
02254 case GNOME_Magnifier_ZoomRegion_ALIGN_MIN:
02255 y = zoom_region->roi.y1;
02256 break;
02257 case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER:
02258 default:
02259 y = ((zoom_region->roi.y1 + zoom_region->roi.y2) - height ) / 2;
02260 }
02261
02262 zoom_region_moveto (zoom_region, x, y);
02263 }
02264
02265 static void
02266 zoom_region_set_viewport (ZoomRegion *zoom_region,
02267 const GNOME_Magnifier_RectBounds *viewport)
02268 {
02269 #ifdef ZOOM_REGION_DEBUG
02270 g_assert (zoom_region->alive);
02271 #endif
02272 if (zoom_region->viewport.x1 == viewport->x1 &&
02273 zoom_region->viewport.y1 == viewport->y1 &&
02274 zoom_region->viewport.x2 == viewport->x2 &&
02275 zoom_region->viewport.y2 == viewport->y2) {
02276 return;
02277 }
02278 zoom_region->viewport = *viewport;
02279 #ifdef DEBUG
02280 fprintf (stderr, "Setting viewport %d,%d - %d,%d\n",
02281 (int) viewport->x1, (int) viewport->y1,
02282 (int) viewport->x2, (int) viewport->y2);
02283 #endif
02284 zoom_region_align (zoom_region);
02285 if (!zoom_region->priv->w) {
02286 zoom_region_init_window (zoom_region);
02287 } else {
02288 CORBA_any *any;
02289 CORBA_Environment ev;
02290 Bonobo_PropertyBag properties;
02291 Magnifier *magnifier = (Magnifier *) zoom_region->priv->parent;
02292 GtkFixed *fixed = GTK_FIXED (magnifier->priv->canvas);
02293 gtk_fixed_move (fixed,
02294 zoom_region->priv->border,
02295 zoom_region->viewport.x1,
02296 zoom_region->viewport.y1);
02297 gtk_fixed_move (fixed,
02298 zoom_region->priv->w,
02299 zoom_region->viewport.x1 +
02300 zoom_region->border_size,
02301 zoom_region->viewport.y1 +
02302 zoom_region->border_size);
02303 gtk_widget_set_size_request (
02304 GTK_WIDGET (zoom_region->priv->border),
02305 zoom_region->viewport.x2 - zoom_region->viewport.x1,
02306 zoom_region->viewport.y2 - zoom_region->viewport.y1);
02307 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
02308 zoom_region->viewport.x2 -
02309 zoom_region->viewport.x1 -
02310 zoom_region->border_size * 2,
02311 zoom_region->viewport.y2 -
02312 zoom_region->viewport.y1 -
02313 zoom_region->border_size * 2);
02314 CORBA_exception_init (&ev);
02315 properties =
02316 GNOME_Magnifier_Magnifier_getProperties(
02317 BONOBO_OBJREF (
02318 (Magnifier *) zoom_region->priv->parent), &ev);
02319 if (!BONOBO_EX (&ev))
02320 any = Bonobo_PropertyBag_getValue (
02321 properties, "source-display-bounds", &ev);
02322 if (!BONOBO_EX (&ev))
02323 zoom_region->priv->source_area =
02324 *((GNOME_Magnifier_RectBounds *) any->_value);
02325 if (zoom_region->priv->pixmap)
02326 g_object_unref (zoom_region->priv->pixmap);
02327 zoom_region_create_pixmap (zoom_region);
02328 if (zoom_region->priv->scaled_pixbuf)
02329 g_object_unref (zoom_region->priv->scaled_pixbuf);
02330
02331 zoom_region->priv->scaled_pixbuf =
02332 gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
02333 (zoom_region->priv->source_area.x2 -
02334 zoom_region->priv->source_area.x1) * zoom_region->xscale + 1,
02335 (zoom_region->priv->source_area.y2 -
02336 zoom_region->priv->source_area.y1) * zoom_region->yscale + 1);
02337 }
02338 zoom_region_queue_update (zoom_region,
02339 zoom_region_source_rect_from_view_bounds (
02340 zoom_region, &zoom_region->viewport));
02341 }
02342
02343 static void
02344 zoom_region_get_property (BonoboPropertyBag *bag,
02345 BonoboArg *arg,
02346 guint arg_id,
02347 CORBA_Environment *ev,
02348 gpointer user_data)
02349 {
02350 ZoomRegion *zoom_region = user_data;
02351
02352 #ifdef ZOOM_REGION_DEBUG
02353 g_assert (zoom_region->alive);
02354 #endif
02355 DBG (fprintf (stderr, "Get zoom-region property: %s\n", prop_names[arg_id]));
02356
02357 switch (arg_id) {
02358 case ZOOM_REGION_MANAGED_PROP:
02359 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->is_managed);
02360 break;
02361 case ZOOM_REGION_POLL_MOUSE_PROP:
02362 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->poll_mouse);
02363 break;
02364 case ZOOM_REGION_INVERT_PROP:
02365 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->invert);
02366 break;
02367 case ZOOM_REGION_SMOOTHSCROLL_PROP:
02368 BONOBO_ARG_SET_SHORT (arg, zoom_region->smooth_scroll_policy);
02369 break;
02370 case ZOOM_REGION_COLORBLIND_PROP:
02371 BONOBO_ARG_SET_SHORT (arg, zoom_region->color_blind_filter);
02372 break;
02373 case ZOOM_REGION_TESTPATTERN_PROP:
02374 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->priv->test);
02375 break;
02376 case ZOOM_REGION_SMOOTHING_PROP:
02377 BONOBO_ARG_SET_STRING (arg, zoom_region->smoothing);
02378 break;
02379 case ZOOM_REGION_CONTRASTR_PROP:
02380 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_r);
02381 break;
02382 case ZOOM_REGION_CONTRASTG_PROP:
02383 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_g);
02384 break;
02385 case ZOOM_REGION_CONTRASTB_PROP:
02386 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_b);
02387 break;
02388 case ZOOM_REGION_BRIGHTR_PROP:
02389 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_r);
02390 break;
02391 case ZOOM_REGION_BRIGHTG_PROP:
02392 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_g);
02393 break;
02394 case ZOOM_REGION_BRIGHTB_PROP:
02395 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_b);
02396 break;
02397 case ZOOM_REGION_XSCALE_PROP:
02398 BONOBO_ARG_SET_FLOAT (arg, zoom_region->xscale);
02399 break;
02400 case ZOOM_REGION_YSCALE_PROP:
02401 BONOBO_ARG_SET_FLOAT (arg, zoom_region->yscale);
02402 break;
02403 case ZOOM_REGION_BORDERSIZE_PROP:
02404 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size);
02405 break;
02406 case ZOOM_REGION_XALIGN_PROP:
02407
02408 BONOBO_ARG_SET_INT (arg, zoom_region->x_align_policy);
02409 break;
02410 case ZOOM_REGION_YALIGN_PROP:
02411 BONOBO_ARG_SET_INT (arg, zoom_region->y_align_policy);
02412 break;
02413 case ZOOM_REGION_BORDERCOLOR_PROP:
02414 BONOBO_ARG_SET_LONG (arg,
02415 zoom_region->border_color);
02416 break;
02417 case ZOOM_REGION_VIEWPORT_PROP:
02418 BONOBO_ARG_SET_GENERAL (arg, zoom_region->viewport,
02419 TC_GNOME_Magnifier_RectBounds,
02420 GNOME_Magnifier_RectBounds,
02421 NULL);
02422 break;
02423 case ZOOM_REGION_TIMING_TEST_PROP:
02424 BONOBO_ARG_SET_INT (arg, zoom_region->timing_iterations);
02425 break;
02426 case ZOOM_REGION_TIMING_OUTPUT_PROP:
02427 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->timing_output);
02428 break;
02429 case ZOOM_REGION_TIMING_PAN_RATE_PROP:
02430 BONOBO_ARG_SET_INT (arg, zoom_region->timing_pan_rate);
02431 break;
02432 case ZOOM_REGION_EXIT_MAGNIFIER:
02433 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->exit_magnifier);
02434 break;
02435 default:
02436 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
02437 };
02438 }
02439
02440 static void
02441 zoom_region_set_property (BonoboPropertyBag *bag,
02442 BonoboArg *arg,
02443 guint arg_id,
02444 CORBA_Environment *ev,
02445 gpointer user_data)
02446 {
02447 ZoomRegion *zoom_region = user_data;
02448 GNOME_Magnifier_RectBounds bounds;
02449 gfloat t;
02450
02451 #ifdef ZOOM_REGION_DEBUG
02452 g_assert (zoom_region->alive);
02453 #endif
02454 DBG (fprintf (stderr, "Set zoom-region property: %s\n", prop_names[arg_id]));
02455
02456 switch (arg_id) {
02457 case ZOOM_REGION_MANAGED_PROP:
02458 zoom_region->is_managed = BONOBO_ARG_GET_BOOLEAN (arg);
02459 break;
02460 case ZOOM_REGION_POLL_MOUSE_PROP:
02461 zoom_region->poll_mouse = BONOBO_ARG_GET_BOOLEAN (arg);
02462 if (zoom_region->poll_mouse)
02463 {
02464 g_message ("Adding polling timer");
02465 zoom_region->priv->update_pointer_id =
02466 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
02467 200,
02468 zoom_region_update_pointer_timeout,
02469 zoom_region,
02470 NULL);
02471 }
02472 else if (zoom_region->priv->update_pointer_id)
02473 {
02474 g_message ("Removing polling timer");
02475 g_source_remove (zoom_region->priv->update_pointer_id);
02476 zoom_region->priv->update_pointer_id = 0;
02477 }
02478 break;
02479 case ZOOM_REGION_INVERT_PROP:
02480 zoom_region->invert = BONOBO_ARG_GET_BOOLEAN (arg);
02481 zoom_region_update_current (zoom_region);
02482 break;
02483 case ZOOM_REGION_SMOOTHSCROLL_PROP:
02484 zoom_region->smooth_scroll_policy = BONOBO_ARG_GET_SHORT (arg);
02485 break;
02486 case ZOOM_REGION_COLORBLIND_PROP:
02487 zoom_region->color_blind_filter = BONOBO_ARG_GET_SHORT (arg);
02488 zoom_region_update_current (zoom_region);
02489 break;
02490 case ZOOM_REGION_SMOOTHING_PROP:
02491 zoom_region->smoothing = BONOBO_ARG_GET_STRING (arg);
02492 if (!strncmp (zoom_region->smoothing, "bilinear", 8))
02493 zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR;
02494 else
02495 zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST;
02496 zoom_region_update_current (zoom_region);
02497 break;
02498 case ZOOM_REGION_TESTPATTERN_PROP:
02499 zoom_region->priv->test = BONOBO_ARG_GET_BOOLEAN (arg);
02500 if (zoom_region->priv->source_drawable) {
02501 g_object_unref (zoom_region->priv->source_drawable);
02502 zoom_region->priv->source_drawable = NULL;
02503 }
02504 zoom_region_update_current (zoom_region);
02505 break;
02506 #define CLAMP_B_C(v) (t = (v), CLAMP (t, -1, 1));
02507 case ZOOM_REGION_CONTRASTR_PROP:
02508 zoom_region->contrast_r =
02509 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02510 zoom_region_update_current (zoom_region);
02511 break;
02512 case ZOOM_REGION_CONTRASTG_PROP:
02513 zoom_region->contrast_g =
02514 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02515 zoom_region_update_current (zoom_region);
02516 break;
02517 case ZOOM_REGION_CONTRASTB_PROP:
02518 zoom_region->contrast_b =
02519 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02520 zoom_region_update_current (zoom_region);
02521 break;
02522 case ZOOM_REGION_BRIGHTR_PROP:
02523 zoom_region->bright_r =
02524 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02525 zoom_region_update_current (zoom_region);
02526 break;
02527 case ZOOM_REGION_BRIGHTG_PROP:
02528 zoom_region->bright_g =
02529 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02530 zoom_region_update_current (zoom_region);
02531 break;
02532 case ZOOM_REGION_BRIGHTB_PROP:
02533 zoom_region->bright_b =
02534 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02535 zoom_region_update_current (zoom_region);
02536 break;
02537 case ZOOM_REGION_XSCALE_PROP:
02538 (void) zoom_region_update_scale (zoom_region,
02539 BONOBO_ARG_GET_FLOAT (arg),
02540 zoom_region->yscale);
02541 zoom_region_update_current (zoom_region);
02542 break;
02543 case ZOOM_REGION_YSCALE_PROP:
02544 (void) zoom_region_update_scale (zoom_region,
02545 zoom_region->xscale,
02546 BONOBO_ARG_GET_FLOAT (arg));
02547 zoom_region_update_current (zoom_region);
02548 break;
02549 case ZOOM_REGION_BORDERSIZE_PROP:
02550 zoom_region->border_size = BONOBO_ARG_GET_LONG (arg);
02551 gtk_widget_set_size_request (
02552 GTK_WIDGET (zoom_region->priv->border),
02553 zoom_region->viewport.x2 -
02554 zoom_region->viewport.x1,
02555 zoom_region->viewport.y2 -
02556 zoom_region->viewport.y1);
02557 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
02558 zoom_region->viewport.x2 -
02559 zoom_region->viewport.x1 -
02560 zoom_region->border_size * 2,
02561 zoom_region->viewport.y2 -
02562 zoom_region->viewport.y1 -
02563 zoom_region->border_size * 2);
02564 gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->border, zoom_region->viewport.x1, zoom_region->viewport.y1);
02565 gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->w, zoom_region->viewport.x1 + zoom_region->border_size, zoom_region->viewport.y1 + zoom_region->border_size);
02566 break;
02567 case ZOOM_REGION_BORDERCOLOR_PROP:
02568 zoom_region->border_color =
02569 BONOBO_ARG_GET_LONG (arg);
02570 zoom_region_paint_border (zoom_region);
02571 break;
02572 case ZOOM_REGION_XALIGN_PROP:
02573 zoom_region->x_align_policy = BONOBO_ARG_GET_INT (arg);
02574 zoom_region_align (zoom_region);
02575 break;
02576 case ZOOM_REGION_YALIGN_PROP:
02577
02578 zoom_region->y_align_policy = BONOBO_ARG_GET_INT (arg);
02579 zoom_region_align (zoom_region);
02580 break;
02581 case ZOOM_REGION_VIEWPORT_PROP:
02582 bounds = BONOBO_ARG_GET_GENERAL (arg,
02583 TC_GNOME_Magnifier_RectBounds,
02584 GNOME_Magnifier_RectBounds,
02585 NULL);
02586 zoom_region_set_viewport (zoom_region, &bounds);
02587 break;
02588 case ZOOM_REGION_TIMING_TEST_PROP:
02589 zoom_region->timing_iterations = BONOBO_ARG_GET_INT (arg);
02590 timing_test = TRUE;
02591 break;
02592 case ZOOM_REGION_TIMING_OUTPUT_PROP:
02593 zoom_region->timing_output = BONOBO_ARG_GET_BOOLEAN (arg);
02594 break;
02595 case ZOOM_REGION_TIMING_PAN_RATE_PROP:
02596 zoom_region->timing_pan_rate = BONOBO_ARG_GET_INT (arg);
02597 timing_test = TRUE;
02598 break;
02599 case ZOOM_REGION_EXIT_MAGNIFIER:
02600 zoom_region->exit_magnifier = BONOBO_ARG_GET_BOOLEAN (arg);
02601 break;
02602 default:
02603 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
02604 };
02605 }
02606
02607 static int
02608 zoom_region_process_pending (gpointer data)
02609 {
02610 ZoomRegion *zoom_region = (ZoomRegion *) data;
02611
02612 #ifdef ZOOM_REGION_DEBUG
02613 g_assert (zoom_region->alive);
02614 #endif
02615 zoom_region_align (zoom_region);
02616 return FALSE;
02617 }
02618
02619 static int
02620 zoom_region_pan_test (gpointer data)
02621 {
02622 ZoomRegion *zoom_region = (ZoomRegion *) data;
02623 Magnifier *magnifier = zoom_region->priv->parent;
02624 GNOME_Magnifier_ZoomRegionList *zoom_regions;
02625 GNOME_Magnifier_RectBounds roi;
02626 CORBA_Environment ev;
02627 static int counter = 0;
02628 static gboolean finished_update = !TRUE;
02629 static float last_pixels_at_speed = -1;
02630 float pixels_at_speed;
02631 float total_time;
02632 int screen_height, height;
02633 int pixel_position;
02634 int pixel_direction;
02635
02636 screen_height = gdk_screen_get_height (
02637 gdk_display_get_screen (magnifier->source_display,
02638 magnifier->source_screen_num));
02639
02640 height = (zoom_region->viewport.y2 -
02641 zoom_region->viewport.y1) / zoom_region->yscale;
02642
02643 roi.x1 = zoom_region->roi.x1;
02644 roi.x2 = zoom_region->roi.x2;
02645
02646 g_timer_stop (mag_timing.process);
02647
02648 gulong microseconds;
02649
02650 total_time = g_timer_elapsed (mag_timing.process, µseconds);
02651
02652 if (mag_timing.frame_total != 0.0)
02653 pixels_at_speed = total_time * zoom_region->timing_pan_rate;
02654 else
02655 pixels_at_speed = 0.0;
02656
02657
02658 if ((int)(last_pixels_at_speed) == (int)(pixels_at_speed))
02659 return TRUE;
02660
02661 pixel_position = (int)(pixels_at_speed) % (screen_height - height);
02662 counter = (int)(pixels_at_speed) / (screen_height - height);
02663 pixel_direction = counter % 2;
02664
02665 if (!finished_update) {
02666 if ((int)(pixels_at_speed) > (zoom_region->roi.y1 + height))
02667 roi.y1 = zoom_region->roi.y1 + height;
02668 else
02669 roi.y1 = (int)(pixels_at_speed);
02670
02671 if (roi.y1 >= screen_height - height) {
02672 roi.y1 = screen_height - height;
02673 }
02674 } else {
02675 if (pixel_direction == 0)
02676 roi.y1 = screen_height - height - pixel_position;
02677 else
02678 roi.y1 = pixel_position;
02679 }
02680
02681 roi.y2 = roi.y1 + height;
02682 magnifier->priv->cursor_x = (roi.x2 + roi.x1) / 2;
02683 magnifier->priv->cursor_y = (roi.y2 + roi.y1) / 2;
02684
02685
02686 if (counter > zoom_region->timing_iterations - 1)
02687 zoom_region->exit_magnifier = TRUE;
02688
02689 zoom_regions = GNOME_Magnifier_Magnifier_getZoomRegions (
02690 BONOBO_OBJREF (magnifier), &ev);
02691
02692 if (zoom_regions && (zoom_regions->_length > 0)) {
02693 GNOME_Magnifier_ZoomRegion_setROI (
02694 zoom_regions->_buffer[0], &roi, &ev);
02695 }
02696
02697 if (!finished_update) {
02698 zoom_region_process_updates(zoom_region);
02699 if (roi.y1 == screen_height - height) {
02700 finished_update = TRUE;
02701 reset_timing = TRUE;
02702 }
02703 }
02704
02705 last_pixels_at_speed = pixels_at_speed;
02706
02707 return FALSE;
02708 }
02709
02710 static void
02711 impl_zoom_region_set_pointer_pos (PortableServer_Servant servant,
02712 const CORBA_long mouse_x,
02713 const CORBA_long mouse_y,
02714 CORBA_Environment *ev)
02715 {
02716 ZoomRegion *zoom_region =
02717 ZOOM_REGION (bonobo_object_from_servant (servant));
02718 GdkRectangle paint_area, *clip = NULL;
02719
02720 #ifdef ZOOM_REGION_DEBUG
02721 g_assert (zoom_region->alive);
02722 #endif
02723 DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
02724 (long) mouse_x, (long) mouse_y));
02725
02726 fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
02727 (long) mouse_x, (long) mouse_y);
02728
02729 zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y);
02730
02731 if (GTK_IS_WIDGET (zoom_region->priv->w) &&
02732 GDK_IS_DRAWABLE (zoom_region->priv->w->window))
02733 {
02734 gdk_drawable_get_size (
02735 GDK_DRAWABLE (
02736 zoom_region->priv->w->window),
02737 &paint_area.width, &paint_area.height);
02738 paint_area.x = 0;
02739 paint_area.y = 0;
02740 clip = &paint_area;
02741 paint_area = zoom_region_clip_to_source (
02742 zoom_region, paint_area);
02743 }
02744
02745
02746
02747
02748
02749 }
02750
02751 static void
02752 impl_zoom_region_set_contrast (PortableServer_Servant servant,
02753 const CORBA_float R,
02754 const CORBA_float G,
02755 const CORBA_float B,
02756 CORBA_Environment *ev)
02757 {
02758 ZoomRegion *zoom_region =
02759 ZOOM_REGION (bonobo_object_from_servant (servant));
02760
02761 #ifdef ZOOM_REGION_DEBUG
02762 g_assert (zoom_region->alive);
02763 #endif
02764 DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B));
02765
02766
02767 if (zoom_region->contrast_r == R &&
02768 zoom_region->contrast_g == G &&
02769 zoom_region->contrast_b == B)
02770 return;
02771
02772 zoom_region->contrast_r = R;
02773 zoom_region->contrast_g = G;
02774 zoom_region->contrast_b = B;
02775
02776 zoom_region_update_current (zoom_region);
02777 }
02778
02779 static void
02780 impl_zoom_region_get_contrast (PortableServer_Servant servant,
02781 CORBA_float *R,
02782 CORBA_float *G,
02783 CORBA_float *B,
02784 CORBA_Environment *ev)
02785 {
02786 ZoomRegion *zoom_region =
02787 ZOOM_REGION (bonobo_object_from_servant (servant));
02788
02789 #ifdef ZOOM_REGION_DEBUG
02790 g_assert (zoom_region->alive);
02791 #endif
02792
02793 *R = zoom_region->contrast_r;
02794 *G = zoom_region->contrast_g;
02795 *B = zoom_region->contrast_b;
02796 }
02797
02798 static void
02799 impl_zoom_region_set_brightness (PortableServer_Servant servant,
02800 const CORBA_float R,
02801 const CORBA_float G,
02802 const CORBA_float B,
02803 CORBA_Environment *ev)
02804 {
02805 ZoomRegion *zoom_region =
02806 ZOOM_REGION (bonobo_object_from_servant (servant));
02807
02808 #ifdef ZOOM_REGION_DEBUG
02809 g_assert (zoom_region->alive);
02810 #endif
02811 DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B));
02812
02813
02814 if (zoom_region->bright_r == R &&
02815 zoom_region->bright_g == G &&
02816 zoom_region->bright_b == B)
02817 return;
02818
02819 zoom_region->bright_r = R;
02820 zoom_region->bright_g = G;
02821 zoom_region->bright_b = B;
02822
02823 zoom_region_update_current (zoom_region);
02824 }
02825
02826 static void
02827 impl_zoom_region_get_brightness (PortableServer_Servant servant,
02828 CORBA_float *R,
02829 CORBA_float *G,
02830 CORBA_float *B,
02831 CORBA_Environment *ev)
02832 {
02833 ZoomRegion *zoom_region =
02834 ZOOM_REGION (bonobo_object_from_servant (servant));
02835
02836 #ifdef ZOOM_REGION_DEBUG
02837 g_assert (zoom_region->alive);
02838 #endif
02839
02840 *R = zoom_region->bright_r;
02841 *G = zoom_region->bright_g;
02842 *B = zoom_region->bright_b;
02843 }
02844
02845 static void
02846 impl_zoom_region_set_roi (PortableServer_Servant servant,
02847 const GNOME_Magnifier_RectBounds *bounds,
02848 CORBA_Environment *ev)
02849 {
02850 ZoomRegion *zoom_region =
02851 ZOOM_REGION (bonobo_object_from_servant (servant));
02852
02853 #ifdef ZOOM_REGION_DEBUG
02854 g_assert (zoom_region->alive);
02855 #endif
02856 DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n",
02857 bounds->x1, bounds->y1, bounds->x2, bounds->y2));
02858
02859 if ((zoom_region->roi.x1 == bounds->x1) &&
02860 (zoom_region->roi.x2 == bounds->x2) &&
02861 (zoom_region->roi.y1 == bounds->y1) &&
02862 (zoom_region->roi.y2 == bounds->y2)) {
02863 return;
02864 }
02865
02866
02867 if (!bounds || (bounds->x2 <= bounds->x1)
02868 || (bounds->y2 < bounds->y1) ||
02869 ((bounds->x1 + bounds->x2)/2 < 0) ||
02870 ((bounds->y1 + bounds->y2)/2 < 0))
02871 {
02872 g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n",
02873 bounds->x1, bounds->y1, bounds->x2, bounds->y2);
02874 return;
02875 }
02876
02877 zoom_region->roi = *bounds;
02878
02879 if (zoom_region->timing_pan_rate > 0) {
02880
02881 g_idle_add_full (GDK_PRIORITY_REDRAW + 3,
02882 zoom_region_pan_test, zoom_region, NULL);
02883 }
02884
02885 if (zoom_region->exit_magnifier) {
02886 if (timing_test) {
02887 fprintf(stderr, "\n### Timing Summary:\n\n");
02888 if (zoom_region->timing_pan_rate)
02889 fprintf(stderr, " Pan Rate = %d\n", zoom_region->timing_pan_rate);
02890 timing_report(zoom_region);
02891 }
02892 exit(0);
02893 }
02894
02895
02896
02897
02898
02899 if (processing_updates) {
02900
02901 if (pending_idle_handler != 0) {
02902 g_source_remove(pending_idle_handler);
02903 pending_idle_handler = 0;
02904 }
02905
02906
02907
02908 pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2,
02909 zoom_region_process_pending, zoom_region, NULL);
02910
02911 if (zoom_region->timing_output) {
02912 fprintf(stderr,
02913 "\n [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n",
02914 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
02915 zoom_region->roi.y2);
02916 }
02917 } else {
02918 zoom_region_align (zoom_region);
02919 }
02920 }
02921
02922 static CORBA_boolean
02923 impl_zoom_region_set_mag_factor (PortableServer_Servant servant,
02924 const CORBA_float mag_factor_x,
02925 const CORBA_float mag_factor_y,
02926 CORBA_Environment *ev)
02927 {
02928 ZoomRegion *zoom_region =
02929 ZOOM_REGION (bonobo_object_from_servant (servant));
02930
02931 #ifdef ZOOM_REGION_DEBUG
02932 g_assert (zoom_region->alive);
02933 #endif
02934 CORBA_any *any;
02935 CORBA_boolean retval = CORBA_TRUE;
02936
02937 if ((zoom_region->xscale == mag_factor_x) &&
02938 (zoom_region->yscale == mag_factor_y)) {
02939 return retval;
02940 }
02941
02942
02943 Bonobo_PropertyBag properties =
02944 GNOME_Magnifier_Magnifier_getProperties(
02945 BONOBO_OBJREF (
02946 (Magnifier *) zoom_region->priv->parent), ev);
02947 any = Bonobo_PropertyBag_getValue (
02948 properties, "source-display-bounds", ev);
02949 if (!BONOBO_EX (ev))
02950 zoom_region->priv->source_area =
02951 *((GNOME_Magnifier_RectBounds *) any->_value);
02952 else
02953 retval = CORBA_FALSE;
02954
02955 retval = zoom_region_update_scale (zoom_region,
02956 mag_factor_x, mag_factor_y);
02957
02958 zoom_region_update_current (zoom_region);
02959 zoom_region_sync (zoom_region);
02960
02961 bonobo_object_release_unref (properties, NULL);
02962 return retval;
02963 }
02964
02965 static void
02966 impl_zoom_region_get_mag_factor (PortableServer_Servant servant,
02967 CORBA_float *mag_factor_x,
02968 CORBA_float *mag_factor_y,
02969 CORBA_Environment *ev)
02970 {
02971 ZoomRegion *zoom_region =
02972 ZOOM_REGION (bonobo_object_from_servant (servant));
02973
02974 #ifdef ZOOM_REGION_DEBUG
02975 g_assert (zoom_region->alive);
02976 #endif
02977 *mag_factor_x = zoom_region->xscale;
02978 *mag_factor_y = zoom_region->yscale;
02979 }
02980
02981 static Bonobo_PropertyBag
02982 impl_zoom_region_get_properties (PortableServer_Servant servant,
02983 CORBA_Environment *ev)
02984 {
02985 ZoomRegion *zoom_region =
02986 ZOOM_REGION (bonobo_object_from_servant (servant));
02987
02988 #ifdef ZOOM_REGION_DEBUG
02989 g_assert (zoom_region->alive);
02990 #endif
02991 return bonobo_object_dup_ref (
02992 BONOBO_OBJREF (zoom_region->properties), ev);
02993 }
02994
02995 static void
02996 impl_zoom_region_mark_dirty (PortableServer_Servant servant,
02997 const GNOME_Magnifier_RectBounds *roi_dirty,
02998 CORBA_Environment *ev)
02999 {
03000 ZoomRegion *zoom_region =
03001 ZOOM_REGION (bonobo_object_from_servant (servant));
03002
03003 #ifdef ZOOM_REGION_DEBUG
03004 g_assert (zoom_region->alive);
03005 #endif
03006 DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds (
03007 zoom_region, roi_dirty) );
03008
03009 zoom_region_update_pointer (zoom_region, TRUE);
03010
03011 zoom_region_queue_update (zoom_region,
03012 zoom_region_clip_to_source (zoom_region,
03013 zoom_region_rect_from_bounds (zoom_region, roi_dirty)));
03014 }
03015
03016 static GNOME_Magnifier_RectBounds
03017 impl_zoom_region_get_roi (PortableServer_Servant servant,
03018 CORBA_Environment *ev)
03019 {
03020 ZoomRegion *zoom_region =
03021 ZOOM_REGION (bonobo_object_from_servant (servant));
03022
03023 #ifdef ZOOM_REGION_DEBUG
03024 g_assert (zoom_region->alive);
03025 #endif
03026 return zoom_region->roi;
03027 }
03028
03029 static void
03030 impl_zoom_region_move_resize (PortableServer_Servant servant,
03031 const GNOME_Magnifier_RectBounds *viewport_bounds,
03032 CORBA_Environment *ev)
03033 {
03034 ZoomRegion *zoom_region =
03035 ZOOM_REGION (bonobo_object_from_servant (servant));
03036
03037 #ifdef ZOOM_REGION_DEBUG
03038 g_assert (zoom_region->alive);
03039 #endif
03040 zoom_region_set_viewport (zoom_region, viewport_bounds);
03041 }
03042
03043
03044 static void
03045 zoom_region_do_dispose (ZoomRegion *zoom_region)
03046 {
03047 DBG(g_message ("disposing region %p", zoom_region));
03048 if (zoom_region->priv && zoom_region->priv->expose_handler_id &&
03049 GTK_IS_WIDGET (zoom_region->priv->w)) {
03050 g_signal_handler_disconnect (
03051 zoom_region->priv->w,
03052 zoom_region->priv->expose_handler_id);
03053 zoom_region->priv->expose_handler_id = 0;
03054 }
03055 if (zoom_region->priv && zoom_region->priv->update_pointer_id)
03056 g_source_remove (zoom_region->priv->update_pointer_id);
03057 if (zoom_region->priv && zoom_region->priv->update_handler_id)
03058 g_source_remove (zoom_region->priv->update_handler_id);
03059 g_idle_remove_by_data (zoom_region);
03060
03061 #ifdef ZOOM_REGION_DEBUG
03062 zoom_region->alive = FALSE;
03063 #endif
03064 }
03065
03066 static void
03067 impl_zoom_region_dispose (PortableServer_Servant servant,
03068 CORBA_Environment *ev)
03069 {
03070 ZoomRegion *zoom_region =
03071 ZOOM_REGION (bonobo_object_from_servant (servant));
03072 zoom_region_do_dispose (zoom_region);
03073 }
03074
03075
03076
03077 static void
03078 zoom_region_dispose (GObject *object)
03079 {
03080 ZoomRegion *zoom_region = ZOOM_REGION (object);
03081
03082 zoom_region_do_dispose (zoom_region);
03083
03084 BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
03085 }
03086
03087 static void
03088 zoom_region_class_init (ZoomRegionClass *klass)
03089 {
03090 GObjectClass * object_class = (GObjectClass *) klass;
03091 POA_GNOME_Magnifier_ZoomRegion__epv *epv = &klass->epv;
03092 parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT);
03093
03094 object_class->dispose = zoom_region_dispose;
03095 object_class->finalize = zoom_region_finalize;
03096
03097 epv->setMagFactor = impl_zoom_region_set_mag_factor;
03098 epv->getMagFactor = impl_zoom_region_get_mag_factor;
03099 epv->getProperties = impl_zoom_region_get_properties;
03100 epv->setROI = impl_zoom_region_set_roi;
03101 epv->setPointerPos = impl_zoom_region_set_pointer_pos;
03102 epv->markDirty = impl_zoom_region_mark_dirty;
03103 epv->getROI = impl_zoom_region_get_roi;
03104 epv->moveResize = impl_zoom_region_move_resize;
03105 epv->dispose = impl_zoom_region_dispose;
03106 epv->setContrast = impl_zoom_region_set_contrast;
03107 epv->getContrast = impl_zoom_region_get_contrast;
03108 epv->setBrightness = impl_zoom_region_set_brightness;
03109 epv->getBrightness = impl_zoom_region_get_brightness;
03110
03111 reset_timing_stats();
03112 #ifdef DEBUG_CLIENT_CALLS
03113 client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL);
03114 #endif
03115 }
03116
03117 static void
03118 zoom_region_properties_init (ZoomRegion *zoom_region)
03119 {
03120 BonoboArg *def;
03121
03122 zoom_region->properties =
03123 bonobo_property_bag_new_closure (
03124 g_cclosure_new_object (
03125 G_CALLBACK (zoom_region_get_property),
03126 G_OBJECT (zoom_region)),
03127 g_cclosure_new_object (
03128 G_CALLBACK (zoom_region_set_property),
03129 G_OBJECT (zoom_region)));
03130
03131 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03132 BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03133
03134 bonobo_property_bag_add (zoom_region->properties,
03135 "is-managed",
03136 ZOOM_REGION_MANAGED_PROP,
03137 BONOBO_ARG_BOOLEAN,
03138 def,
03139 "If false, zoom region does not auto-update, but is drawn into directly by the client",
03140 Bonobo_PROPERTY_READABLE |
03141 Bonobo_PROPERTY_WRITEABLE);
03142
03143 bonobo_arg_release (def);
03144 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03145 BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03146
03147 bonobo_property_bag_add (zoom_region->properties,
03148 "poll-mouse",
03149 ZOOM_REGION_POLL_MOUSE_PROP,
03150 BONOBO_ARG_BOOLEAN,
03151 NULL,
03152 "If false, zoom region does not poll for pointer location, but is (exclusively) given it by the client",
03153 Bonobo_PROPERTY_READABLE |
03154 Bonobo_PROPERTY_WRITEABLE);
03155
03156 bonobo_arg_release (def);
03157 def = bonobo_arg_new (BONOBO_ARG_SHORT);
03158 BONOBO_ARG_SET_SHORT (def, GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST);
03159
03160 bonobo_property_bag_add (zoom_region->properties,
03161 "smooth-scroll-policy",
03162 ZOOM_REGION_SMOOTHSCROLL_PROP,
03163 BONOBO_ARG_SHORT,
03164 def,
03165 "scrolling policy, slower versus faster",
03166 Bonobo_PROPERTY_READABLE |
03167 Bonobo_PROPERTY_WRITEABLE);
03168
03169 bonobo_arg_release (def);
03170 def = bonobo_arg_new (BONOBO_ARG_SHORT);
03171 BONOBO_ARG_SET_SHORT (
03172 def,
03173 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER);
03174
03175 bonobo_property_bag_add (zoom_region->properties,
03176 "color-blind-filter",
03177 ZOOM_REGION_COLORBLIND_PROP,
03178 BONOBO_ARG_SHORT,
03179 def,
03180 "color blind filter to apply in an image",
03181 Bonobo_PROPERTY_READABLE |
03182 Bonobo_PROPERTY_WRITEABLE);
03183
03184 bonobo_arg_release (def);
03185 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03186 BONOBO_ARG_SET_BOOLEAN (def, FALSE);
03187
03188 bonobo_property_bag_add (zoom_region->properties,
03189 "use-test-pattern",
03190 ZOOM_REGION_TESTPATTERN_PROP,
03191 BONOBO_ARG_BOOLEAN,
03192 def,
03193 "use test pattern for source",
03194 Bonobo_PROPERTY_READABLE |
03195 Bonobo_PROPERTY_WRITEABLE);
03196
03197 bonobo_arg_release (def);
03198 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03199 BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03200
03201 bonobo_property_bag_add (zoom_region->properties,
03202 "inverse-video",
03203 ZOOM_REGION_INVERT_PROP,
03204 BONOBO_ARG_BOOLEAN,
03205 def,
03206 "inverse video display",
03207 Bonobo_PROPERTY_READABLE |
03208 Bonobo_PROPERTY_WRITEABLE);
03209
03210 bonobo_arg_release (def);
03211
03212 bonobo_property_bag_add (zoom_region->properties,
03213 "smoothing-type",
03214 ZOOM_REGION_SMOOTHING_PROP,
03215 BONOBO_ARG_STRING,
03216 NULL,
03217 "image smoothing algorithm used",
03218 Bonobo_PROPERTY_READABLE |
03219 Bonobo_PROPERTY_WRITEABLE);
03220
03221 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03222 BONOBO_ARG_SET_FLOAT (def, 0.0);
03223
03224 bonobo_property_bag_add (zoom_region->properties,
03225 "red-contrast",
03226 ZOOM_REGION_CONTRASTR_PROP,
03227 BONOBO_ARG_FLOAT,
03228 def,
03229 "red image contrast ratio",
03230 Bonobo_PROPERTY_READABLE |
03231 Bonobo_PROPERTY_WRITEABLE);
03232 bonobo_arg_release (def);
03233
03234 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03235 BONOBO_ARG_SET_FLOAT (def, 0.0);
03236
03237 bonobo_property_bag_add (zoom_region->properties,
03238 "green-contrast",
03239 ZOOM_REGION_CONTRASTG_PROP,
03240 BONOBO_ARG_FLOAT,
03241 def,
03242 "green image contrast ratio",
03243 Bonobo_PROPERTY_READABLE |
03244 Bonobo_PROPERTY_WRITEABLE);
03245 bonobo_arg_release (def);
03246
03247 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03248 BONOBO_ARG_SET_FLOAT (def, 0.0);
03249
03250 bonobo_property_bag_add (zoom_region->properties,
03251 "blue-contrast",
03252 ZOOM_REGION_CONTRASTB_PROP,
03253 BONOBO_ARG_FLOAT,
03254 def,
03255 "blue image contrast ratio",
03256 Bonobo_PROPERTY_READABLE |
03257 Bonobo_PROPERTY_WRITEABLE);
03258 bonobo_arg_release (def);
03259
03260 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03261 BONOBO_ARG_SET_FLOAT (def, 0.0);
03262
03263 bonobo_property_bag_add (zoom_region->properties,
03264 "red-brightness",
03265 ZOOM_REGION_BRIGHTR_PROP,
03266 BONOBO_ARG_FLOAT,
03267 def,
03268 "red image brightness ratio",
03269 Bonobo_PROPERTY_READABLE |
03270 Bonobo_PROPERTY_WRITEABLE);
03271 bonobo_arg_release (def);
03272
03273 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03274 BONOBO_ARG_SET_FLOAT (def, 0.0);
03275
03276 bonobo_property_bag_add (zoom_region->properties,
03277 "green-brightness",
03278 ZOOM_REGION_BRIGHTG_PROP,
03279 BONOBO_ARG_FLOAT,
03280 def,
03281 "green image brightness ratio",
03282 Bonobo_PROPERTY_READABLE |
03283 Bonobo_PROPERTY_WRITEABLE);
03284 bonobo_arg_release (def);
03285
03286 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03287 BONOBO_ARG_SET_FLOAT (def, 0.0);
03288
03289 bonobo_property_bag_add (zoom_region->properties,
03290 "blue-brightness",
03291 ZOOM_REGION_BRIGHTB_PROP,
03292 BONOBO_ARG_FLOAT,
03293 def,
03294 "blue image brightness ratio",
03295 Bonobo_PROPERTY_READABLE |
03296 Bonobo_PROPERTY_WRITEABLE);
03297 bonobo_arg_release (def);
03298
03299 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03300 BONOBO_ARG_SET_FLOAT (def, 2.0);
03301
03302 bonobo_property_bag_add (zoom_region->properties,
03303 "mag-factor-x",
03304 ZOOM_REGION_XSCALE_PROP,
03305 BONOBO_ARG_FLOAT,
03306 def,
03307 "x scale factor",
03308 Bonobo_PROPERTY_READABLE |
03309 Bonobo_PROPERTY_WRITEABLE);
03310
03311 bonobo_arg_release (def);
03312 def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03313 BONOBO_ARG_SET_FLOAT (def, 2.0);
03314
03315 bonobo_property_bag_add (zoom_region->properties,
03316 "mag-factor-y",
03317 ZOOM_REGION_YSCALE_PROP,
03318 BONOBO_ARG_FLOAT,
03319 def,
03320 "y scale factor",
03321 Bonobo_PROPERTY_READABLE |
03322 Bonobo_PROPERTY_WRITEABLE);
03323
03324 bonobo_arg_release (def);
03325 def = bonobo_arg_new (BONOBO_ARG_LONG);
03326 BONOBO_ARG_SET_LONG (def, 0);
03327
03328 bonobo_property_bag_add (zoom_region->properties,
03329 "border-size",
03330 ZOOM_REGION_BORDERSIZE_PROP,
03331 BONOBO_ARG_LONG,
03332 def,
03333 "size of zoom-region borders, in pixels",
03334 Bonobo_PROPERTY_READABLE |
03335 Bonobo_PROPERTY_WRITEABLE);
03336
03337 bonobo_arg_release (def);
03338 def = bonobo_arg_new (BONOBO_ARG_LONG);
03339 BONOBO_ARG_SET_LONG (def, 0x00000000);
03340
03341 bonobo_property_bag_add (zoom_region->properties,
03342 "border-color",
03343 ZOOM_REGION_BORDERCOLOR_PROP,
03344 BONOBO_ARG_LONG,
03345 def,
03346 "border color, as RGBA32",
03347 Bonobo_PROPERTY_READABLE |
03348 Bonobo_PROPERTY_WRITEABLE);
03349
03350 bonobo_arg_release (def);
03351 def = bonobo_arg_new (BONOBO_ARG_INT);
03352 BONOBO_ARG_SET_INT (def, 0);
03353
03354 bonobo_property_bag_add (zoom_region->properties,
03355 "x-alignment",
03356 ZOOM_REGION_XALIGN_PROP,
03357 BONOBO_ARG_INT,
03358 def,
03359 "x-alignment policy for this region",
03360 Bonobo_PROPERTY_READABLE |
03361 Bonobo_PROPERTY_WRITEABLE);
03362
03363 bonobo_arg_release (def);
03364 def = bonobo_arg_new (BONOBO_ARG_INT);
03365 BONOBO_ARG_SET_INT (def, 0);
03366
03367 bonobo_property_bag_add (zoom_region->properties,
03368 "y-alignment",
03369 ZOOM_REGION_YALIGN_PROP,
03370 BONOBO_ARG_INT,
03371 def,
03372 "y-alignment policy for this region",
03373 Bonobo_PROPERTY_READABLE |
03374 Bonobo_PROPERTY_WRITEABLE);
03375 bonobo_arg_release (def);
03376
03377 bonobo_property_bag_add (zoom_region->properties,
03378 "viewport",
03379 ZOOM_REGION_VIEWPORT_PROP,
03380 TC_GNOME_Magnifier_RectBounds,
03381 NULL,
03382 "viewport bounding box",
03383 Bonobo_PROPERTY_READABLE |
03384 Bonobo_PROPERTY_WRITEABLE);
03385
03386 def = bonobo_arg_new (BONOBO_ARG_INT);
03387 BONOBO_ARG_SET_INT (def, 0);
03388
03389 bonobo_property_bag_add (zoom_region->properties,
03390 "timing-iterations",
03391 ZOOM_REGION_TIMING_TEST_PROP,
03392 BONOBO_ARG_INT,
03393 def,
03394 "timing iterations",
03395 Bonobo_PROPERTY_READABLE |
03396 Bonobo_PROPERTY_WRITEABLE);
03397 bonobo_arg_release (def);
03398
03399 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03400 BONOBO_ARG_SET_BOOLEAN (def, FALSE);
03401
03402 bonobo_property_bag_add (zoom_region->properties,
03403 "timing-output",
03404 ZOOM_REGION_TIMING_OUTPUT_PROP,
03405 BONOBO_ARG_BOOLEAN,
03406 def,
03407 "timing output",
03408 Bonobo_PROPERTY_READABLE |
03409 Bonobo_PROPERTY_WRITEABLE);
03410
03411 bonobo_arg_release (def);
03412
03413 def = bonobo_arg_new (BONOBO_ARG_INT);
03414 BONOBO_ARG_SET_INT (def, 0);
03415
03416 bonobo_property_bag_add (zoom_region->properties,
03417 "timing-pan-rate",
03418 ZOOM_REGION_TIMING_PAN_RATE_PROP,
03419 BONOBO_ARG_INT,
03420 def,
03421 "timing pan rate",
03422 Bonobo_PROPERTY_READABLE |
03423 Bonobo_PROPERTY_WRITEABLE);
03424 bonobo_arg_release (def);
03425
03426 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03427 BONOBO_ARG_SET_BOOLEAN (def, FALSE);
03428
03429 bonobo_property_bag_add (zoom_region->properties,
03430 "exit-magnifier",
03431 ZOOM_REGION_EXIT_MAGNIFIER,
03432 BONOBO_ARG_BOOLEAN,
03433 def,
03434 "timing output",
03435 Bonobo_PROPERTY_READABLE |
03436 Bonobo_PROPERTY_WRITEABLE);
03437
03438 bonobo_arg_release (def);
03439
03440 }
03441
03442 static void
03443 zoom_region_private_init (ZoomRegionPrivate *priv)
03444 {
03445 GdkRectangle rect = {0, 0, 0, 0};
03446 GNOME_Magnifier_RectBounds rectbounds = {0, 0, 0, 0};
03447 priv->parent = NULL;
03448 priv->w = NULL;
03449 priv->default_gc = NULL;
03450 priv->paint_cursor_gc = NULL;
03451 priv->crosswire_gc = NULL;
03452 priv->q = NULL;
03453 priv->scaled_pixbuf = NULL;
03454 priv->source_pixbuf_cache = NULL;
03455 priv->source_drawable = NULL;
03456 priv->pixmap = NULL;
03457 priv->cursor_backing_rect = rect;
03458 priv->cursor_backing_pixels = NULL;
03459 priv->gdk_interp_type = GDK_INTERP_NEAREST;
03460 priv->expose_handler_id = 0;
03461 priv->test = FALSE;
03462 priv->last_cursor_pos.x = 0;
03463 priv->last_cursor_pos.y = 0;
03464 priv->last_drawn_crosswire_pos.x = 0;
03465 priv->last_drawn_crosswire_pos.y = 0;
03466 priv->exposed_bounds = rectbounds;
03467 priv->source_area = rectbounds;
03468 priv->update_pointer_id = 0;
03469 priv->update_handler_id = 0;
03470 }
03471
03472 static void
03473 zoom_region_init (ZoomRegion *zoom_region)
03474 {
03475 DBG(g_message ("initializing region %p", zoom_region));
03476
03477 zoom_region_properties_init (zoom_region);
03478 zoom_region->smooth_scroll_policy =
03479 GNOME_Magnifier_ZoomRegion_SCROLL_SMOOTH;
03480 zoom_region->color_blind_filter =
03481 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER;
03482 zoom_region->contrast_r = 0.0;
03483 zoom_region->contrast_g = 0.0;
03484 zoom_region->contrast_b = 0.0;
03485 zoom_region->bright_r = 0.0;
03486 zoom_region->bright_g = 0.0;
03487 zoom_region->bright_b = 0.0;
03488 zoom_region->invert = FALSE;
03489 zoom_region->cache_source = FALSE;
03490 zoom_region->border_size = 0;
03491 zoom_region->border_color = 0;
03492 zoom_region->roi.x1 = 0;
03493 zoom_region->roi.x1 = 0;
03494 zoom_region->roi.x2 = 1;
03495 zoom_region->roi.x2 = 1;
03496 zoom_region->x_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER;
03497 zoom_region->y_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER;
03498 zoom_region->coalesce_func = _coalesce_update_rects;
03499 zoom_region->poll_mouse = TRUE;
03500 zoom_region->priv = g_malloc (sizeof (ZoomRegionPrivate));
03501 zoom_region_private_init (zoom_region->priv);
03502 bonobo_object_add_interface (BONOBO_OBJECT (zoom_region),
03503 BONOBO_OBJECT (zoom_region->properties));
03504 zoom_region->timing_output = FALSE;
03505 #ifdef ZOOM_REGION_DEBUG
03506 zoom_region->alive = TRUE;
03507 #endif
03508 zoom_region->priv->update_pointer_id =
03509 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
03510 200,
03511 zoom_region_update_pointer_timeout,
03512 zoom_region,
03513 NULL);
03514 }
03515
03516 ZoomRegion *
03517 zoom_region_new (void)
03518 {
03519 return g_object_new (zoom_region_get_type(), NULL);
03520 }
03521
03522
03523 static void
03524 zoom_region_finalize (GObject *region)
03525 {
03526 ZoomRegion *zoom_region = (ZoomRegion *) region;
03527
03528 DBG(g_message ("finalizing region %p", zoom_region));
03529
03530 if (zoom_region->priv && zoom_region->priv->q)
03531 {
03532 g_list_free (zoom_region->priv->q);
03533 zoom_region->priv->q = NULL;
03534 }
03535 if (GTK_IS_WIDGET (zoom_region->priv->w))
03536 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->w));
03537 if (GTK_IS_WIDGET (zoom_region->priv->border))
03538 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->border));
03539 if (zoom_region->priv->source_pixbuf_cache)
03540 g_object_unref (zoom_region->priv->source_pixbuf_cache);
03541 if (zoom_region->priv->scaled_pixbuf)
03542 g_object_unref (zoom_region->priv->scaled_pixbuf);
03543 if (zoom_region->priv->pixmap)
03544 g_object_unref (zoom_region->priv->pixmap);
03545 zoom_region->priv->pixmap = NULL;
03546 zoom_region->priv->parent = NULL;
03547 if (zoom_region->priv->cursor_backing_pixels)
03548 g_object_unref (zoom_region->priv->cursor_backing_pixels);
03549 g_free (zoom_region->priv);
03550 zoom_region->priv = NULL;
03551 #ifdef ZOOM_REGION_DEBUG
03552 zoom_region->alive = FALSE;
03553 #endif
03554 BONOBO_CALL_PARENT (G_OBJECT_CLASS, finalize, (region));
03555 }
03556
03557 BONOBO_TYPE_FUNC_FULL (ZoomRegion,
03558 GNOME_Magnifier_ZoomRegion,
03559 BONOBO_TYPE_OBJECT,
03560 zoom_region);