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