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