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