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