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