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