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