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