gnome-mag
|
00001 /* 00002 * AT-SPI - Assistive Technology Service Provider Interface 00003 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) 00004 * 00005 * Copyright 2001 Sun Microsystems Inc. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public 00018 * License along with this library; if not, write to the 00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00020 * Boston, MA 02111-1307, USA. 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 00030 #ifdef HAVE_COLORBLIND 00031 #include <colorblind.h> 00032 #endif /* HAVE_COLORBLIND */ 00033 00034 #include <gdk/gdk.h> 00035 #include <gtk/gtk.h> 00036 00037 #ifdef USE_GDKPIXBUF_RENDER_TO_DRAWABLE 00038 #include <gdk/gdkpixbuf.h> 00039 #endif 00040 00041 #include <gdk/gdkx.h> 00042 #include <libbonobo.h> 00043 #include <math.h> 00044 00045 #undef ZOOM_REGION_DEBUG 00046 00047 #include "zoom-region.h" 00048 #include "zoom-region-private.h" 00049 #include "magnifier.h" /* needed to access parent data */ 00050 #include "magnifier-private.h" /* needed to access parent data */ 00051 #include "zoom-region-server.h" 00052 00053 #define DEBUG_CLIENT_CALLS 00054 00055 #ifdef DEBUG_CLIENT_CALLS 00056 static gboolean client_debug = FALSE; 00057 #define DBG(a) if (client_debug) { (a); } 00058 #else 00059 #define DBG(a) 00060 #endif 00061 00062 static GObjectClass *parent_class = NULL; 00063 00064 enum { 00065 ZOOM_REGION_MANAGED_PROP, 00066 ZOOM_REGION_POLL_MOUSE_PROP, 00067 ZOOM_REGION_DRAW_CURSOR_PROP, 00068 ZOOM_REGION_SMOOTHSCROLL_PROP, 00069 ZOOM_REGION_COLORBLIND_PROP, 00070 ZOOM_REGION_INVERT_PROP, 00071 ZOOM_REGION_SMOOTHING_PROP, 00072 ZOOM_REGION_CONTRASTR_PROP, 00073 ZOOM_REGION_CONTRASTG_PROP, 00074 ZOOM_REGION_CONTRASTB_PROP, 00075 ZOOM_REGION_BRIGHTR_PROP, 00076 ZOOM_REGION_BRIGHTG_PROP, 00077 ZOOM_REGION_BRIGHTB_PROP, 00078 ZOOM_REGION_XSCALE_PROP, 00079 ZOOM_REGION_YSCALE_PROP, 00080 ZOOM_REGION_BORDERSIZE_PROP, 00081 ZOOM_REGION_BORDERSIZETOP_PROP, 00082 ZOOM_REGION_BORDERSIZELEFT_PROP, 00083 ZOOM_REGION_BORDERSIZERIGHT_PROP, 00084 ZOOM_REGION_BORDERSIZEBOTTOM_PROP, 00085 ZOOM_REGION_BORDERCOLOR_PROP, 00086 ZOOM_REGION_XALIGN_PROP, 00087 ZOOM_REGION_YALIGN_PROP, 00088 ZOOM_REGION_VIEWPORT_PROP, 00089 ZOOM_REGION_TESTPATTERN_PROP, 00090 ZOOM_REGION_TIMING_TEST_PROP, 00091 ZOOM_REGION_TIMING_OUTPUT_PROP, 00092 ZOOM_REGION_TIMING_PAN_RATE_PROP, 00093 ZOOM_REGION_EXIT_MAGNIFIER 00094 } PropIdx; 00095 00096 #ifdef DEBUG_CLIENT_CALLS 00097 gchar* prop_names[ZOOM_REGION_EXIT_MAGNIFIER + 1] = 00098 { 00099 "MANAGED", 00100 "POLLMOUSE", 00101 "DRAWCURSOR", 00102 "SMOOTHSCROLL", 00103 "COLORBLIND", 00104 "INVERT", 00105 "SMOOTHING", 00106 "CONTRASTR", 00107 "CONTRASTG", 00108 "CONTRASTB", 00109 "BRIGHTR", 00110 "BRIGHTG", 00111 "BRIGHTB", 00112 "XSCALE", 00113 "YSCALE", 00114 "BORDERSIZE", 00115 "BORDERSIZETOP", 00116 "BORDERSIZELEFT", 00117 "BORDERSIZERIGHT", 00118 "BORDERSIZEBOTTOM", 00119 "BORDERCOLOR", 00120 "XALIGN", 00121 "YALIGN", 00122 "VIEWPORT", 00123 "TESTPATTERN", 00124 "TIMING_TEST", 00125 "TIMING_OUTPUT", 00126 "TIMING_PAN_RATE", 00127 "EXIT_MAGNIFIER" 00128 }; 00129 #endif 00130 00131 typedef enum { 00132 ZOOM_REGION_ERROR_NONE, 00133 ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE, 00134 ZOOM_REGION_ERROR_TOO_BIG 00135 } ZoomRegionPixmapCreationError; 00136 00137 static float timing_scale_max = 0; 00138 static float timing_idle_max = 0; 00139 static float timing_frame_max = 0; 00140 static float cps_max = 0; 00141 static float nrr_max = 0; 00142 static float update_nrr_max = 0; 00143 static gboolean reset_timing = FALSE; 00144 static gboolean timing_test = FALSE; 00145 00146 static guint pending_idle_handler = 0; 00147 static gboolean processing_updates = FALSE; 00148 static gboolean timing_start = FALSE; 00149 00150 static gboolean can_coalesce = TRUE ; /* change this when event coalescing is working */ 00151 00152 static int zoom_region_number = 0; 00153 00154 #define CLAMP_B_C(v) (t = (v), CLAMP (t, -1, 1)); 00155 00156 static void zoom_region_sync (ZoomRegion *region); 00157 static void zoom_region_finalize (GObject *object); 00158 static void zoom_region_update (ZoomRegion *zoom_region, 00159 const GdkRectangle rect); 00160 static void zoom_region_queue_update (ZoomRegion *zoom_region, 00161 const GdkRectangle rect); 00162 00163 static int zoom_region_process_updates (gpointer data); 00164 static void zoom_region_paint (ZoomRegion *zoom_region, GdkRectangle *rect); 00165 static void zoom_region_paint_pixmap (ZoomRegion *zoom_region, GdkRectangle *rect); 00166 static int zoom_region_update_pointer_timeout (gpointer data); 00167 static GdkRectangle zoom_region_rect_from_bounds (ZoomRegion *zoom_region, 00168 const GNOME_Magnifier_RectBounds *bounds); 00169 static ZoomRegionPixmapCreationError zoom_region_create_pixmap (ZoomRegion *zoom_region); 00170 static GdkRectangle zoom_region_update_pixmap (ZoomRegion *zoom_region, const GdkRectangle update_rect, GdkRectangle *paint_rect); 00171 static void zoom_region_get_move_x_y (ZoomRegion *zoom_region, long *x, long *y); 00172 static void zoom_region_recompute_exposed_bounds (ZoomRegion *zoom_region); 00173 static void zoom_region_update_current (ZoomRegion *zoom_region); 00174 00175 void 00176 reset_timing_stats() 00177 { 00178 timing_scale_max = 0; 00179 timing_idle_max = 0; 00180 timing_frame_max = 0; 00181 cps_max = 0; 00182 nrr_max = 0; 00183 update_nrr_max = 0; 00184 mag_timing.num_scale_samples = 0; 00185 mag_timing.num_idle_samples = 0; 00186 mag_timing.num_frame_samples = 0; 00187 mag_timing.num_line_samples = 0; 00188 mag_timing.scale_total = 0; 00189 mag_timing.idle_total = 0; 00190 mag_timing.frame_total = 0; 00191 mag_timing.update_pixels_total = 0; 00192 mag_timing.update_pixels_total = 0; 00193 mag_timing.dx_total = 0; 00194 mag_timing.dy_total = 0; 00195 mag_timing.last_frame_val = 0; 00196 mag_timing.last_dy = 0; 00197 g_timer_start (mag_timing.process); 00198 } 00199 00202 #undef DEBUG 00203 #ifdef DEBUG 00204 #define DEBUG_RECT(a, b) _debug_announce_rect (a, b) 00205 #else 00206 #define DEBUG_RECT(a, b) 00207 #endif 00208 static void 00209 _debug_announce_rect (char *msg, GdkRectangle rect) 00210 { 00211 fprintf (stderr, "%s: (%d,%d - %d,%d)\n", 00212 msg, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); 00213 } 00214 00215 static void 00216 _set_bounds (RectBounds *struct_bounds, const gint32 **vector_bounds) 00217 { 00218 struct_bounds->x1 = (*vector_bounds)[0]; 00219 struct_bounds->y1 = (*vector_bounds)[1]; 00220 struct_bounds->x2 = (*vector_bounds)[2]; 00221 struct_bounds->y2 = (*vector_bounds)[3]; 00222 } 00223 00224 static gboolean 00225 _diff_pixbufs (const GdkPixbuf *a, const GdkPixbuf *b) 00226 { 00227 long i, j; 00228 int bits_per_byte = 8; /* always true? */ 00229 guchar *pa = gdk_pixbuf_get_pixels (a); 00230 guchar *pb = gdk_pixbuf_get_pixels (b); 00231 guchar *cpa, *cpb; 00232 long rsa = gdk_pixbuf_get_rowstride (a); 00233 long rsb = gdk_pixbuf_get_rowstride (b); 00234 long rowbytes = gdk_pixbuf_get_width (a) * 00235 gdk_pixbuf_get_bits_per_sample (a) * 00236 gdk_pixbuf_get_n_channels (a)/ bits_per_byte; 00237 long n_rows = gdk_pixbuf_get_height (a); 00238 00239 if (gdk_pixbuf_get_height (b) != n_rows) 00240 return TRUE; 00241 if (gdk_pixbuf_get_width (b) != gdk_pixbuf_get_width (a)) 00242 return TRUE; 00243 for (j = 0; j < n_rows; ++j) 00244 { 00245 cpa = pa + j * rsa; 00246 cpb = pb + j * rsb; 00247 for (i = 0; i < rowbytes; ++i) 00248 { 00249 if (*cpa != *cpb) 00250 { 00251 return TRUE; 00252 } 00253 cpa++; 00254 cpb++; 00255 } 00256 } 00257 return FALSE; 00258 } 00259 00262 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED 00263 00272 static gboolean 00273 _combine_rects (GdkRectangle *a, GdkRectangle *b) 00274 { 00275 gboolean can_combine = FALSE; 00276 if ((a->x == b->x) && (a->x + a->width == b->x + b->width)) 00277 { 00278 can_combine = TRUE; 00279 } 00280 else if ((a->y == b->y) && (a->y + a->height == b->y + b->height)) 00281 { 00282 can_combine = TRUE; 00283 } 00284 if (can_combine) 00285 { 00286 GdkRectangle c; 00287 /* TODO: check and fix this */ 00288 if (gdk_rectangle_intersect (a, b, &c)) 00289 { 00290 gdk_rectangle_union (a, b, &c); 00291 *a = c; 00292 can_combine = TRUE; 00293 } 00294 else 00295 { 00296 can_combine = FALSE; 00297 } 00298 } 00299 return can_combine; 00300 } 00301 00315 static gboolean 00316 _refactor_rects (GdkRectangle *p, GdkRectangle *n) 00317 { 00318 gboolean refactored = FALSE; 00319 GdkRectangle *a, *b; 00320 if (p->x == n->x) 00321 { 00322 if (p->width < n->width) 00323 { 00324 a = p; 00325 b = n; 00326 } 00327 else 00328 { 00329 a = n; 00330 b = p; 00331 } 00332 if (a->y == b->y + b->height) 00333 { 00334 a->y -= b->height; 00335 a->height += b->height; 00336 b->x += a->width; 00337 b->width -= a->width; 00338 refactored = TRUE; 00339 } 00340 else if (a->y + a->height == b->y) 00341 { 00342 a->height += b->height; 00343 b->x += a->width; 00344 b->width -= a->width; 00345 refactored = TRUE; 00346 } 00347 if (refactored) fprintf (stderr, "REFACTOR 1\n"); 00348 } 00349 else if (p->y == n->y) 00350 { 00351 if (p->height < n->height) 00352 { 00353 a = p; 00354 b = n; 00355 } 00356 else 00357 { 00358 a = n; 00359 b = p; 00360 } 00361 if (a->x == b->x + b->width) 00362 { 00363 a->x -= b->width; 00364 a->width += b->width; 00365 b->y += a->height; 00366 b->height -= a->height; 00367 refactored = TRUE; 00368 } 00369 else if (a->x + a->width == b->x) 00370 { 00371 a->width += b->width; 00372 b->y += a->height; 00373 b->height -= a->height; 00374 refactored = TRUE; 00375 } 00376 if (refactored) fprintf (stderr, "REFACTOR 2\n"); 00377 } 00378 else if (p->x + p->width == n->x + n->width) 00379 { 00380 if (p->width < n->width) 00381 { 00382 a = p; 00383 b = n; 00384 } 00385 else 00386 { 00387 a = n; 00388 b = p; 00389 } 00390 if (a->y == b->y + b->height) 00391 { 00392 a->y -= b->height; 00393 a->height += b->height; 00394 b->width -= a->width; 00395 refactored = TRUE; 00396 } 00397 else if (a->y + a->height == b->y) 00398 { 00399 a->height += b->height; 00400 b->width -= a->width; 00401 refactored = TRUE; 00402 } 00403 if (refactored) fprintf (stderr, "REFACTOR 3\n"); 00404 } 00405 else if (p->y + p->height == n->y + n->height) 00406 { 00407 if (p->height < n->height) 00408 { 00409 a = p; 00410 b = n; 00411 } 00412 else 00413 { 00414 a = n; 00415 b = p; 00416 } 00417 if (a->x == b->x + b->width) 00418 { 00419 a->x -= b->width; 00420 a->width += b->width; 00421 b->height -= a->height; 00422 refactored = TRUE; 00423 } 00424 else if (a->x + a->width == b->x) 00425 { 00426 a->width += b->width; 00427 b->height -= a->height; 00428 refactored = TRUE; 00429 } 00430 if (refactored) fprintf (stderr, "REFACTOR 4\n"); 00431 } 00432 return refactored; 00433 } 00434 00435 static GList* 00436 _combine_update_rects (GList *q, int lookahead_n) 00437 { 00438 int i = 0; 00439 GdkRectangle *a = q->data; 00440 GList *p = q; 00441 while (i < lookahead_n && p && p->next) 00442 { 00443 if (_combine_rects (a, q->next->data)) 00444 { 00445 q = g_list_delete_link (q, p->next); 00446 } 00447 else 00448 { 00449 p = p->next; 00450 ++i; 00451 } 00452 } 00453 return q; 00454 } 00455 #endif 00456 00457 /*#define _is_horizontal_rect(r) (((2 * (r)->width / 3 * (r)->height)) > 1)*/ 00458 /*#define _is_vertical_rect(r) (((2 * (r)->height / 3 * (r)->width)) > 1)*/ 00459 #define _is_horizontal_rect(r) ((r)->width > (r)->height) 00460 #define _is_vertical_rect(r) ((r)->height > (r)->width) 00461 00468 static GList * 00469 _coalesce_update_rects (GList *q, int min_coalesce_length) 00470 { 00471 GdkRectangle *v = NULL, *h = NULL; 00472 GList *compact_queue = NULL; 00473 /* fprintf (stderr, "starting queue length = %d\n", g_list_length (q)); */ 00474 if (g_list_length (q) < min_coalesce_length) 00475 return g_list_copy (q); 00476 while (q) 00477 { 00478 if (_is_vertical_rect ((GdkRectangle *) (q->data))) 00479 { 00480 if (v) gdk_rectangle_union (v, q->data, v); 00481 else 00482 { 00483 v = g_new0 (GdkRectangle, 1); 00484 *v = *(GdkRectangle *)q->data; 00485 } 00486 } 00487 else if (_is_horizontal_rect ((GdkRectangle *) (q->data))) 00488 { 00489 if (h) gdk_rectangle_union (h, q->data, h); 00490 else 00491 { 00492 h = g_new0 (GdkRectangle, 1); 00493 *h = *(GdkRectangle *)q->data; 00494 } 00495 } 00496 else 00497 compact_queue = g_list_prepend (compact_queue, q->data); 00498 q = q->next; 00499 }; 00500 if (v) 00501 compact_queue = g_list_prepend (compact_queue, v); 00502 if (h) 00503 compact_queue = g_list_prepend (compact_queue, h); 00504 /* fprintf (stderr, "ending queue length = %d\n", g_list_length (compact_queue));*/ 00505 /* don't free the original queue, that's the caller's responsibility */ 00506 return compact_queue; 00507 } 00508 00509 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED 00510 static GList * 00511 _smartbutbroken_coalesce_update_rects (GList *q, int lookahead_n) 00512 { 00513 int i = 0, len; 00514 fprintf (stderr, "starting queue length = %d\n", g_list_length (q)); 00515 do { 00516 GdkRectangle *a; 00517 len = g_list_length (q); 00518 q = _combine_update_rects (q, lookahead_n); 00519 a = q->data; 00520 while (i < lookahead_n && q && q->next) 00521 { 00522 if (_refactor_rects (a, q->next->data)) 00523 break; 00524 else 00525 ++i; 00526 } 00527 q = _combine_update_rects (q, lookahead_n); 00528 } while (g_list_length (q) < len); 00529 fprintf (stderr, "ending queue length = %d\n", g_list_length (q)); 00530 return q; 00531 } 00532 #endif 00533 00537 static GdkRectangle 00538 _rectangle_clip_to_rectangle (GdkRectangle area, 00539 GdkRectangle clip_rect) 00540 { 00541 GdkRectangle clipped; 00542 clipped.x = MAX (area.x, clip_rect.x); 00543 clipped.y = MAX (area.y, clip_rect.y); 00544 clipped.width = MIN ((area.x + area.width), (clip_rect.x + clip_rect.width)) - clipped.x; 00545 clipped.height = MIN ((area.y + area.height), (clip_rect.y + clip_rect.height)) - clipped.y; 00546 return clipped; 00547 } 00548 00549 static GdkRectangle 00550 _rectangle_clip_to_bounds (GdkRectangle area, 00551 GNOME_Magnifier_RectBounds *clip_bounds) 00552 { 00553 area.x = MAX (area.x, clip_bounds->x1); 00554 area.x = MIN (area.x, clip_bounds->x2); 00555 area.width = MIN (area.width, clip_bounds->x2 - area.x); 00556 area.y = MAX (area.y, clip_bounds->y1); 00557 area.y = MIN (area.y, clip_bounds->y2); 00558 area.height = MIN (area.height, clip_bounds->y2 - area.y); 00559 return area; 00560 } 00561 00562 static GdkRectangle 00563 zoom_region_clip_to_source (ZoomRegion *zoom_region, 00564 GdkRectangle area) 00565 { 00566 GNOME_Magnifier_RectBounds *source_rect_ptr; 00567 if (zoom_region && zoom_region->priv && zoom_region->priv->parent) 00568 { 00569 source_rect_ptr = &((Magnifier *)zoom_region->priv->parent)->source_bounds; 00570 DEBUG_RECT ("clipping to source bounds", zoom_region_rect_from_bounds (zoom_region, source_rect_ptr)); 00571 return _rectangle_clip_to_bounds (area, source_rect_ptr); 00572 } 00573 return area; 00574 } 00575 00576 static GdkRectangle 00577 zoom_region_clip_to_exposed_target (ZoomRegion *zoom_region, 00578 GdkRectangle area) 00579 { 00580 GNOME_Magnifier_RectBounds onscreen_target, *source_area; 00581 source_area = &zoom_region->priv->source_area; 00582 00583 onscreen_target.x1 = MAX (floor (zoom_region->priv->exposed_bounds.x1 00584 / zoom_region->xscale), 00585 source_area->x1); 00586 onscreen_target.y1 = MAX (floor (zoom_region->priv->exposed_bounds.y1 00587 / zoom_region->yscale), 00588 source_area->y1); 00589 onscreen_target.x2 = MIN (ceil (zoom_region->priv->exposed_bounds.x2 00590 / zoom_region->xscale), 00591 source_area->x2); 00592 onscreen_target.y2 = MIN (ceil (zoom_region->priv->exposed_bounds.y2 00593 / zoom_region->yscale), 00594 source_area->y2); 00595 00596 return _rectangle_clip_to_bounds (area, &onscreen_target); 00597 } 00598 00599 static GdkRectangle 00600 zoom_region_clip_to_scaled_pixmap (ZoomRegion *zoom_region, 00601 GdkRectangle area) 00602 { 00603 GdkRectangle pixmap_area = {0, 0, 0, 0}; 00604 if (zoom_region->priv && zoom_region->priv->pixmap) 00605 { 00606 gdk_drawable_get_size (zoom_region->priv->pixmap, &pixmap_area.width, &pixmap_area.height); 00607 return _rectangle_clip_to_rectangle (area, pixmap_area); 00608 } 00609 else 00610 return area; 00611 } 00612 00613 static GdkRectangle 00614 zoom_region_clip_to_window (ZoomRegion *zoom_region, 00615 GdkRectangle area) 00616 { 00617 GdkRectangle window_rect; 00618 00619 /* we can just return ATM because _rectangle_clip_to_rectangle is unimplemented now */ 00620 00621 return area; 00622 00623 if (gtk_widget_get_window (zoom_region->priv->w)) 00624 gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)), 00625 &window_rect.x, 00626 &window_rect.y); 00627 else 00628 { 00629 window_rect.x = 0; 00630 window_rect.y = 0; 00631 } 00632 return _rectangle_clip_to_rectangle (area, window_rect); 00633 } 00634 00635 static GdkRectangle 00636 zoom_region_source_rect_from_view_bounds (ZoomRegion *zoom_region, 00637 const GNOME_Magnifier_RectBounds *view_bounds) 00638 { 00639 GdkRectangle source_rect; 00640 source_rect.x = floor ((view_bounds->x1 + zoom_region->priv->exposed_bounds.x1) 00641 / zoom_region->xscale); 00642 source_rect.y = floor ((view_bounds->y1 + zoom_region->priv->exposed_bounds.y1) 00643 / zoom_region->yscale); 00644 source_rect.width = ceil ((view_bounds->x2 - view_bounds->x1) / zoom_region->xscale) + 1; 00645 source_rect.height = ceil ((view_bounds->y2 - view_bounds->y1) / zoom_region->yscale) + 1; 00646 return source_rect; 00647 } 00648 00649 static GdkRectangle 00650 zoom_region_view_rect_from_source_rect (ZoomRegion *zoom_region, 00651 const GdkRectangle source_rect) 00652 { 00653 GdkRectangle view_rect; 00654 view_rect.x = source_rect.x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1; 00655 view_rect.y = source_rect.y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1; 00656 view_rect.width = source_rect.width * zoom_region->xscale; 00657 view_rect.height = source_rect.height * zoom_region->yscale; 00658 DEBUG_RECT ("source", source_rect); 00659 DEBUG_RECT ("converted to view-rect", view_rect); 00660 return view_rect; 00661 } 00662 00663 static GdkRectangle 00664 zoom_region_source_rect_from_view_rect (ZoomRegion *zoom_region, 00665 const GdkRectangle view_rect) 00666 { 00667 GdkRectangle source_rect; 00668 source_rect.x = floor ((view_rect.x + zoom_region->priv->exposed_bounds.x1) 00669 / zoom_region->xscale); 00670 source_rect.y = floor ((view_rect.y + zoom_region->priv->exposed_bounds.y1) 00671 / zoom_region->yscale); 00672 source_rect.width = ceil (view_rect.width / zoom_region->xscale) + 1; 00673 source_rect.height = ceil (view_rect.height / zoom_region->yscale) + 1; 00674 return source_rect; 00675 } 00676 00677 static GdkRectangle 00678 zoom_region_rect_from_bounds (ZoomRegion *zoom_region, 00679 const GNOME_Magnifier_RectBounds *bounds) 00680 { 00681 GdkRectangle rect; 00682 rect.x = bounds->x1; 00683 rect.y = bounds->y1; 00684 rect.width = bounds->x2 - bounds->x1; 00685 rect.height = bounds->y2 - bounds->y1; 00686 return rect; 00687 } 00688 00691 static CORBA_boolean 00692 zoom_region_update_scale (ZoomRegion *zoom_region, gdouble x, gdouble y) 00693 { 00694 gdouble x_old = zoom_region->xscale; 00695 gdouble y_old = zoom_region->yscale; 00696 long x_move, y_move; 00697 00698 zoom_region->xscale = x; 00699 zoom_region->yscale = y; 00700 00701 if (zoom_region->priv->scaled_pixbuf) 00702 g_object_unref (zoom_region->priv->scaled_pixbuf); 00703 zoom_region->priv->scaled_pixbuf = 00704 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); 00705 00706 if (zoom_region->priv->pixmap) 00707 g_object_unref (zoom_region->priv->pixmap); 00708 00709 if (zoom_region_create_pixmap (zoom_region) == 00710 ZOOM_REGION_ERROR_TOO_BIG) { 00711 zoom_region->xscale = x_old; 00712 zoom_region->yscale = y_old; 00713 zoom_region_create_pixmap (zoom_region); 00714 g_object_unref (zoom_region->priv->scaled_pixbuf); 00715 00716 /* only create a scaled image big enough for the target 00717 * display, for now */ 00718 zoom_region->priv->scaled_pixbuf = gdk_pixbuf_new ( 00719 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); 00720 00721 return FALSE; 00722 } 00723 00724 zoom_region_get_move_x_y (zoom_region, &x_move, &y_move); 00725 zoom_region->priv->exposed_bounds.x1 = x_move * zoom_region->xscale; 00726 zoom_region->priv->exposed_bounds.y1 = y_move * zoom_region->yscale; 00727 zoom_region_recompute_exposed_bounds (zoom_region); 00728 zoom_region_update_current (zoom_region); 00729 00730 return TRUE; 00731 } 00732 00733 static void 00734 zoom_region_queue_update (ZoomRegion *zoom_region, 00735 const GdkRectangle update_rect) 00736 { 00737 GdkRectangle *rect = 00738 g_new0 (GdkRectangle, 1); 00739 *rect = update_rect; 00740 00741 #ifdef ZOOM_REGION_DEBUG 00742 g_assert (zoom_region->alive); 00743 #endif 00744 DEBUG_RECT ("queueing update", *rect); 00745 00746 zoom_region->priv->q = 00747 g_list_prepend (zoom_region->priv->q, rect); 00748 if (zoom_region->priv && zoom_region->priv->update_handler_id == 0) 00749 zoom_region->priv->update_handler_id = 00750 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, 00751 zoom_region_process_updates, 00752 zoom_region, 00753 NULL); 00754 } 00755 00756 static void 00757 zoom_region_update_current (ZoomRegion *zoom_region) 00758 { 00759 #ifdef ZOOM_REGION_DEBUG 00760 g_assert (zoom_region->alive); 00761 #endif 00762 if (zoom_region->priv) 00763 { 00764 gboolean pixmap_valid = GDK_IS_DRAWABLE (zoom_region->priv->pixmap); 00765 if (!pixmap_valid) 00766 pixmap_valid = (zoom_region_create_pixmap (zoom_region) == ZOOM_REGION_ERROR_NONE); 00767 if (pixmap_valid) 00768 zoom_region_update (zoom_region, 00769 zoom_region_source_rect_from_view_bounds ( 00770 zoom_region, 00771 &zoom_region->viewport)); 00772 } 00773 } 00774 00775 static GdkRectangle 00776 zoom_region_cursor_rect (ZoomRegion *zoom_region) 00777 { 00778 GdkRectangle rect = {0, 0, 0, 0}; 00779 Magnifier *magnifier = zoom_region->priv->parent; 00780 GdkDrawable *cursor = NULL; 00781 if (magnifier) 00782 cursor = magnifier_get_cursor (magnifier); 00783 if (cursor) 00784 { 00785 rect.x = zoom_region->priv->last_cursor_pos.x; 00786 rect.y = zoom_region->priv->last_cursor_pos.y; 00787 rect = zoom_region_view_rect_from_source_rect (zoom_region, rect); 00788 rect.x -= magnifier->cursor_hotspot.x; 00789 rect.y -= magnifier->cursor_hotspot.y; 00790 gdk_drawable_get_size (cursor, &rect.width, &rect.height); 00791 } 00792 return rect; 00793 } 00794 00795 static void 00796 zoom_region_unpaint_crosswire_cursor (ZoomRegion *zoom_region, 00797 GdkRectangle *clip_rect) 00798 { 00799 Magnifier *magnifier = zoom_region->priv->parent; 00800 GdkRectangle vline_rect, hline_rect; 00801 GdkPoint cursor_pos; 00802 00803 #ifdef ZOOM_REGION_DEBUG 00804 g_assert (zoom_region->alive); 00805 #endif 00806 if (!magnifier || magnifier->crosswire_size <= 0) return; 00807 00808 cursor_pos = zoom_region->priv->last_drawn_crosswire_pos; 00809 vline_rect.x = cursor_pos.x - magnifier->crosswire_size/2; 00810 vline_rect.y = clip_rect ? clip_rect->y : 0; 00811 vline_rect.width = MAX (magnifier->crosswire_size, 1); 00812 vline_rect.height = clip_rect ? clip_rect->height : 4096; 00813 hline_rect.x = clip_rect ? clip_rect->x : 0; 00814 hline_rect.y = cursor_pos.y - magnifier->crosswire_size/2; 00815 hline_rect.width = clip_rect ? clip_rect->width : 4096; 00816 hline_rect.height = MAX (magnifier->crosswire_size, 1); 00817 00818 zoom_region_paint_pixmap (zoom_region, &vline_rect); 00819 zoom_region_paint_pixmap (zoom_region, &hline_rect); 00820 } 00821 00822 static void 00823 zoom_region_paint_crosswire_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect) 00824 { 00825 Magnifier *magnifier = zoom_region->priv->parent; 00826 static GdkColormap *cmap; 00827 static GdkColor last_color; 00828 static gboolean last_color_init = FALSE; 00829 GdkGCValues values; 00830 GdkRectangle rect; 00831 GdkDrawable *cursor; 00832 GdkColor color = {0, 0, 0, 0}; 00833 int x_start = 0, y_start = 0, x_end = 4096, y_end = 4096; 00834 int x_left_clip = 0, x_right_clip = 0, y_top_clip = 0, y_bottom_clip = 0; 00835 int csize = 0; 00836 00837 #ifdef ZOOM_REGION_DEBUG 00838 g_assert (zoom_region->alive); 00839 #endif 00840 if (!(magnifier && 00841 gtk_widget_get_window (zoom_region->priv->w) && 00842 GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)) && 00843 magnifier->crosswire_size > 0)) return; 00844 00845 if (zoom_region->priv->crosswire_gc == NULL) 00846 { 00847 zoom_region->priv->crosswire_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w)); 00848 cmap = gdk_gc_get_colormap(zoom_region->priv->crosswire_gc); 00849 last_color_init = FALSE; 00850 } 00851 00852 if (magnifier->crosswire_color == 0) 00853 { 00854 color.red = 0xFFFF; 00855 color.blue = 0xFFFF; 00856 color.green = 0xFFFF; 00857 values.function = GDK_INVERT; 00858 } 00859 else 00860 { 00861 color.red = (magnifier->crosswire_color & 0xFF0000) >> 8; 00862 color.green = (magnifier->crosswire_color & 0xFF00); 00863 color.blue = (magnifier->crosswire_color & 0xFF) << 8; 00864 values.function = GDK_COPY; 00865 } 00866 00867 values.foreground = color; 00868 00869 /* Only reset colors if they have changed */ 00870 if (!last_color_init || color.red != last_color.red || 00871 color.blue != last_color.blue || color.green != last_color.green) 00872 { 00873 if (cmap) 00874 { 00875 gdk_rgb_find_color (cmap, &(values.foreground)); 00876 gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION | GDK_GC_FOREGROUND); 00877 } 00878 else 00879 { 00880 gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION); 00881 } 00882 00883 last_color.red = color.red; 00884 last_color.blue = color.blue; 00885 last_color.green = color.green; 00886 last_color_init = TRUE; 00887 } 00888 00889 rect.x = zoom_region->priv->last_cursor_pos.x; 00890 rect.y = zoom_region->priv->last_cursor_pos.y; 00891 rect.width = 0; 00892 rect.height = 0; 00893 rect = zoom_region_view_rect_from_source_rect (zoom_region, rect); 00894 if (clip_rect) gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, clip_rect); 00895 else gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, NULL); 00896 00897 if ((cursor = magnifier_get_cursor (magnifier))) { 00898 gdk_drawable_get_size (cursor, &csize, &csize); 00899 } 00900 00901 if (magnifier->crosswire_length) { 00902 if (magnifier->crosswire_clip) { 00903 x_start = rect.x - magnifier->cursor_hotspot.x - 00904 magnifier->crosswire_length; 00905 x_end = rect.x + 00906 (csize - magnifier->cursor_hotspot.x) + 00907 magnifier->crosswire_length; 00908 y_start = rect.y - magnifier->cursor_hotspot.y - 00909 magnifier->crosswire_length; 00910 y_end = rect.y + 00911 (csize - magnifier->cursor_hotspot.y) + 00912 magnifier->crosswire_length; 00913 } else { 00914 x_start = rect.x - magnifier->crosswire_length; 00915 x_end = rect.x + magnifier->crosswire_length; 00916 y_start = rect.y - magnifier->crosswire_length; 00917 y_end = rect.y + magnifier->crosswire_length; 00918 } 00919 } 00920 00921 if (magnifier->crosswire_clip) 00922 { 00923 y_top_clip = rect.y - magnifier->cursor_hotspot.y - 00924 magnifier->crosswire_size; 00925 y_bottom_clip = rect.y + 00926 (csize - magnifier->cursor_hotspot.y) + 00927 magnifier->crosswire_size; 00928 x_left_clip = rect.x - magnifier->cursor_hotspot.x - 00929 magnifier->crosswire_size; 00930 x_right_clip = rect.x + 00931 (csize - magnifier->cursor_hotspot.x) + 00932 magnifier->crosswire_size; 00933 00934 } 00935 if (magnifier->crosswire_size == 1) { 00936 if (magnifier->crosswire_clip) { 00937 gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w), 00938 zoom_region->priv->crosswire_gc, 00939 rect.x, y_top_clip, rect.x, 00940 y_bottom_clip); 00941 gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w), 00942 zoom_region->priv->crosswire_gc, 00943 x_left_clip, rect.y, x_right_clip, 00944 rect.y); 00945 } 00946 gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w), 00947 zoom_region->priv->crosswire_gc, 00948 rect.x, y_start, rect.x, y_end); 00949 gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w), 00950 zoom_region->priv->crosswire_gc, 00951 x_start, rect.y, x_end, rect.y); 00952 } 00953 else { 00954 if (magnifier->crosswire_clip ) { 00955 gdk_draw_rectangle ( 00956 gtk_widget_get_window (zoom_region->priv->w), 00957 zoom_region->priv->crosswire_gc, TRUE, 00958 rect.x - magnifier->crosswire_size / 2, 00959 y_top_clip, magnifier->crosswire_size, 00960 y_bottom_clip - y_top_clip); 00961 gdk_draw_rectangle ( 00962 gtk_widget_get_window (zoom_region->priv->w), 00963 zoom_region->priv->crosswire_gc, TRUE, 00964 x_left_clip, 00965 rect.y - magnifier->crosswire_size / 2, 00966 x_right_clip - x_left_clip, 00967 magnifier->crosswire_size); 00968 } 00969 gdk_draw_rectangle ( 00970 gtk_widget_get_window (zoom_region->priv->w), 00971 zoom_region->priv->crosswire_gc, TRUE, 00972 rect.x - magnifier->crosswire_size / 2, y_start, 00973 magnifier->crosswire_size, y_end - y_start); 00974 gdk_draw_rectangle ( 00975 gtk_widget_get_window (zoom_region->priv->w), 00976 zoom_region->priv->crosswire_gc, TRUE, 00977 x_start, rect.y - magnifier->crosswire_size / 2, 00978 x_end - x_start, magnifier->crosswire_size); 00979 } 00980 } 00981 00982 static void 00983 zoom_region_unpaint_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect) 00984 { 00985 #ifdef ZOOM_REGION_DEBUG 00986 g_assert (zoom_region->alive); 00987 #endif 00988 zoom_region_paint_pixmap (zoom_region, 00989 &zoom_region->priv->cursor_backing_rect); 00990 } 00991 00992 00993 static void 00994 zoom_region_paint_cursor (ZoomRegion *zoom_region, 00995 GdkRectangle *clip_rect) 00996 { 00997 GdkGCValues values; 00998 GdkRectangle rect, intersct; 00999 GdkRectangle fullscreen; 01000 Magnifier *magnifier = zoom_region->priv->parent; 01001 rect = zoom_region_cursor_rect (zoom_region); 01002 #ifdef ZOOM_REGION_DEBUG 01003 g_assert (zoom_region->alive); 01004 #endif 01005 if (!zoom_region->draw_cursor) 01006 return; 01007 01008 if (clip_rect == NULL) 01009 { 01010 fullscreen = zoom_region_rect_from_bounds (zoom_region, 01011 &zoom_region->viewport); 01012 clip_rect = &fullscreen; 01013 } 01014 /* save the unclipped cursor pos for 'undrawing' the crosswire, the clipped one is no good */ 01015 zoom_region->priv->last_drawn_crosswire_pos.x = rect.x + magnifier->cursor_hotspot.x; 01016 zoom_region->priv->last_drawn_crosswire_pos.y = rect.y + magnifier->cursor_hotspot.y; 01017 01018 if (gdk_rectangle_intersect (clip_rect, &rect, &intersct)) 01019 { 01020 int width = 0, height = 0; 01021 01022 GdkDrawable *cursor = magnifier_get_cursor (magnifier); 01023 if (!cursor) 01024 return; 01025 else if (!GDK_IS_DRAWABLE (cursor)) g_message ("cursor isn't DRAWABLE!"); 01026 zoom_region->priv->cursor_backing_rect = rect; 01027 if (zoom_region->priv->cursor_backing_pixels) { 01028 gdk_drawable_get_size (zoom_region->priv->cursor_backing_pixels, 01029 &width, &height); 01030 } 01031 if (rect.width != width || rect.height != height) 01032 { 01033 if (zoom_region->priv->cursor_backing_pixels) { 01034 g_object_unref (zoom_region->priv->cursor_backing_pixels); 01035 } 01036 zoom_region->priv->cursor_backing_pixels = 01037 gdk_pixmap_new (gtk_widget_get_window (zoom_region->priv->w), 01038 rect.width, 01039 rect.height, 01040 -1); 01041 } 01042 if (gtk_widget_get_window (zoom_region->priv->w) != NULL) 01043 { 01044 if (zoom_region->priv->default_gc == NULL) 01045 zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w)); 01046 gdk_draw_drawable (zoom_region->priv->cursor_backing_pixels, 01047 zoom_region->priv->default_gc, 01048 gtk_widget_get_window (zoom_region->priv->w), 01049 rect.x, 01050 rect.y, 01051 0, 0, 01052 rect.width, 01053 rect.height); 01054 } 01055 DEBUG_RECT ("painting", rect); 01056 if (cursor && zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 01057 { 01058 if (zoom_region->priv->paint_cursor_gc == NULL) 01059 zoom_region->priv->paint_cursor_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w)); 01060 01061 gdk_gc_set_clip_rectangle (zoom_region->priv->paint_cursor_gc, clip_rect); 01062 values.clip_x_origin = rect.x; 01063 values.clip_y_origin = rect.y; 01064 values.clip_mask = magnifier->priv->cursor_mask; 01065 gdk_gc_set_values(zoom_region->priv->paint_cursor_gc, &values, GDK_GC_CLIP_X_ORIGIN | 01066 GDK_GC_CLIP_Y_ORIGIN | GDK_GC_CLIP_MASK); 01067 01068 gdk_draw_rectangle (gtk_widget_get_window (zoom_region->priv->w), 01069 zoom_region->priv->paint_cursor_gc, 01070 TRUE, 01071 rect.x, rect.y, rect.width, rect.height); 01072 01073 gdk_draw_drawable (gtk_widget_get_window (zoom_region->priv->w), 01074 zoom_region->priv->paint_cursor_gc, 01075 cursor, 01076 0, 0, 01077 rect.x, 01078 rect.y, 01079 rect.width, 01080 rect.height); 01081 } 01082 } 01083 } 01084 01089 static void 01090 zoom_region_coalesce_updates (ZoomRegion *zoom_region) 01091 { 01092 /* TODO: lock the queue ? */ 01093 GList *q; 01094 int lookahead_n = 4; /* 'distance' to look ahead in queue */ 01095 int max_qlen = 50; 01096 01097 if (zoom_region->priv && zoom_region->priv->q && g_list_length (zoom_region->priv->q) > max_qlen) 01098 { 01099 g_list_free (zoom_region->priv->q); 01100 zoom_region->priv->q = NULL; /* just discard and update everything */ 01101 /* CAUTION: this can be an expensive operation! */ 01102 zoom_region_queue_update (zoom_region, zoom_region_rect_from_bounds 01103 (zoom_region, &zoom_region->priv->source_area)); 01104 } 01105 else 01106 01107 if (zoom_region->priv && zoom_region->priv->q && 01108 (g_list_length (zoom_region->priv->q) > 1) && can_coalesce) 01109 { 01110 q = g_list_reverse (g_list_copy (zoom_region->priv->q)); 01111 if (q) 01112 { 01113 GList *coalesce_copy; 01114 if (zoom_region->coalesce_func) 01115 { 01116 GList *new; 01117 coalesce_copy = (*zoom_region->coalesce_func) (q, lookahead_n); 01118 new = g_list_reverse (coalesce_copy); 01119 g_list_free (zoom_region->priv->q); 01120 zoom_region->priv->q = new; 01121 } 01122 g_list_free (q); 01123 } 01124 } 01125 } 01126 01127 01128 static void 01129 zoom_region_paint_border (ZoomRegion *zoom_region) 01130 { 01131 GdkColor color; 01132 01133 #ifdef ZOOM_REGION_DEBUG 01134 g_assert (zoom_region->alive); 01135 #endif 01136 if ((zoom_region->border_size_left > 0 || 01137 zoom_region->border_size_top > 0 || 01138 zoom_region->border_size_right > 0 || 01139 zoom_region->border_size_bottom > 0) && 01140 (gtk_widget_get_window (zoom_region->priv->border))) { 01141 color.red = (((zoom_region->border_color & 0xFF0000) >> 16) * 01142 65535) / 255; 01143 color.green = (((zoom_region->border_color & 0xFF00) >> 8) * 01144 65535) / 255; 01145 color.blue = ((zoom_region->border_color & 0xFF) * 65535) / 01146 255; 01147 01148 #ifdef DEBUG_BORDER 01149 fprintf (stderr, "border color triple RGB=%d|%d|%d\n", 01150 color.red, color.green, color.blue); 01151 #endif 01152 01153 gtk_widget_modify_bg (zoom_region->priv->border, 01154 GTK_STATE_NORMAL, &color); 01155 } 01156 } 01157 01158 static void 01159 zoom_region_paint_pixmap (ZoomRegion *zoom_region, 01160 GdkRectangle *area) 01161 { 01162 #ifdef ZOOM_REGION_DEBUG 01163 g_assert (zoom_region->alive); 01164 #endif 01165 g_assert (zoom_region->priv); 01166 g_assert (zoom_region->priv->w); 01167 01168 if (!GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) return; 01169 if (zoom_region->priv->default_gc == NULL) 01170 zoom_region->priv->default_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w)); 01171 01172 if (zoom_region->priv->pixmap && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 01173 { 01174 gdk_draw_drawable (gtk_widget_get_window (zoom_region->priv->w), 01175 zoom_region->priv->default_gc, 01176 zoom_region->priv->pixmap, 01177 area->x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale, 01178 area->y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale, 01179 area->x, 01180 area->y, 01181 area->width, 01182 area->height); 01183 } 01184 } 01185 01189 static void 01190 zoom_region_paint (ZoomRegion *zoom_region, 01191 GdkRectangle *area) 01192 { 01193 GdkRectangle paint_area; 01194 01195 #ifdef ZOOM_REGION_DEBUG 01196 g_assert (zoom_region->alive); 01197 #endif 01198 DEBUG_RECT ("painting (clipped)", *area); 01199 paint_area = zoom_region_clip_to_window (zoom_region, *area); 01200 zoom_region_paint_pixmap (zoom_region, &paint_area); 01201 zoom_region_paint_cursor (zoom_region, &paint_area); 01202 zoom_region_paint_crosswire_cursor (zoom_region, &paint_area); 01203 } 01204 01205 static ZoomRegionPixmapCreationError 01206 zoom_region_create_pixmap (ZoomRegion *zoom_region) 01207 { 01208 #ifdef ZOOM_REGION_DEBUG 01209 g_assert (zoom_region->alive); 01210 #endif 01211 if (zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 01212 { 01213 long width = (zoom_region->priv->source_area.x2 - 01214 zoom_region->priv->source_area.x1) * zoom_region->xscale; 01215 long height = (zoom_region->priv->source_area.y2 - 01216 zoom_region->priv->source_area.y1) * zoom_region->yscale; 01217 zoom_region->priv->pixmap = 01218 gdk_pixmap_new ( 01219 gtk_widget_get_window (zoom_region->priv->w), 01220 width, 01221 height, 01222 gdk_drawable_get_depth ( 01223 gtk_widget_get_window (zoom_region->priv->w))); 01224 01225 if (gmag_gs_error_check ()) { 01226 zoom_region->priv->pixmap = NULL; 01227 return ZOOM_REGION_ERROR_TOO_BIG; 01228 } 01229 01230 DEBUG_RECT("viewport", zoom_region_source_rect_from_view_bounds 01231 (zoom_region, &zoom_region->viewport)); 01232 DEBUG_RECT("source", zoom_region_rect_from_bounds 01233 (zoom_region, &((Magnifier*)zoom_region->priv->parent)->source_bounds)); 01234 01235 return ZOOM_REGION_ERROR_NONE; 01236 } 01237 01238 return ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE; 01239 } 01240 01241 static void 01242 zoom_region_expose_handler (GtkWindow * w, 01243 GdkEventExpose *event, 01244 gpointer data) 01245 { 01246 ZoomRegion *zoom_region = data; 01247 DEBUG_RECT ("expose", event->area); 01248 01249 #ifdef ZOOM_REGION_DEBUG 01250 g_assert (zoom_region->alive); 01251 #endif 01252 if (zoom_region->priv->pixmap == NULL) 01253 { 01254 ZoomRegionPixmapCreationError ret; 01255 /* TODO: scale down if this fails here */ 01256 while ((ret = zoom_region_create_pixmap (zoom_region)) == 01257 ZOOM_REGION_ERROR_TOO_BIG) { 01258 zoom_region->xscale -= 1.0; 01259 zoom_region->yscale -= 1.0; 01260 zoom_region->priv->pixmap = NULL; 01261 g_warning ("Scale factor too big to fit in memory; shrinking."); 01262 } 01263 if (ret == ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE) 01264 g_warning ("create-pixmap: no target drawable"); 01265 else 01266 zoom_region_update_pixmap (zoom_region, event->area, 01267 NULL); 01268 } 01269 zoom_region_paint (zoom_region, &event->area); 01270 } 01271 01272 static void 01273 zoom_region_update_cursor (ZoomRegion *zoom_region, int dx, int dy, 01274 GdkRectangle *clip_rect) 01275 { 01276 #ifdef ZOOM_REGION_DEBUG 01277 g_assert (zoom_region->alive); 01278 #endif 01279 zoom_region_unpaint_crosswire_cursor (zoom_region, clip_rect); 01280 zoom_region_unpaint_cursor (zoom_region, clip_rect); 01281 zoom_region->priv->cursor_backing_rect.x += dx; 01282 zoom_region->priv->cursor_backing_rect.y += dy; 01283 zoom_region->priv->last_drawn_crosswire_pos.x += dx; 01284 zoom_region->priv->last_drawn_crosswire_pos.y += dy; 01285 zoom_region_paint_cursor (zoom_region, clip_rect); 01286 zoom_region_paint_crosswire_cursor (zoom_region, clip_rect); 01287 if (GTK_IS_WIDGET (zoom_region->priv->w) && 01288 GDK_IS_WINDOW (gtk_widget_get_window (zoom_region->priv->w))) 01289 gdk_display_sync (gdk_drawable_get_display ( 01290 gtk_widget_get_window (zoom_region->priv->w))); 01291 } 01292 01293 static gboolean 01294 zoom_region_calculate_scroll_rects (ZoomRegion *zoom_region, 01295 int dx, int dy, 01296 GdkRectangle *scroll_rect, 01297 GdkRectangle *expose_rect_h, 01298 GdkRectangle *expose_rect_v) 01299 { 01300 GdkWindow *window = NULL; 01301 GdkRectangle rect = {0, 0, 0, 0}; 01302 gboolean retval = TRUE; 01303 01304 #ifdef ZOOM_REGION_DEBUG 01305 g_assert (zoom_region->alive); 01306 #endif 01307 rect.x = 0; 01308 rect.y = 0; 01309 if (zoom_region && zoom_region->priv->w && 01310 gtk_widget_get_window (zoom_region->priv->w)) 01311 window = gtk_widget_get_window (zoom_region->priv->w); 01312 else 01313 retval = FALSE; 01314 if (!window) 01315 retval = FALSE; 01316 01317 if (window != NULL) 01318 gdk_drawable_get_size (GDK_DRAWABLE (window), 01319 &rect.width, 01320 &rect.height); 01321 01322 if ((ABS (dx) >= rect.width) || (ABS (dy) >= rect.height)) { 01323 *scroll_rect = rect; 01324 DBG(fprintf (stderr, "deltas too big to scroll\n")); 01325 retval = FALSE; 01326 } 01327 else { 01328 scroll_rect->x = MAX (0, dx); 01329 scroll_rect->y = MAX (0, dy); 01330 scroll_rect->width = MIN (rect.width + dx, rect.width - dx); 01331 scroll_rect->height = MIN (rect.height + dy, rect.height - dy); 01332 } 01333 01334 expose_rect_h->x = 0; 01335 expose_rect_h->y = (scroll_rect->y == 0) ? scroll_rect->height : 0; 01336 expose_rect_h->width = rect.width; 01337 expose_rect_h->height = rect.height - scroll_rect->height; 01338 01339 expose_rect_v->x = (scroll_rect->x == 0) ? scroll_rect->width : 0; 01340 expose_rect_v->y = scroll_rect->y; 01341 expose_rect_v->width = rect.width - scroll_rect->width; 01342 expose_rect_v->height = scroll_rect->height; 01343 01344 return retval; 01345 } 01346 01347 static void 01348 zoom_region_scroll_fast (ZoomRegion *zoom_region, int dx, int dy, 01349 GdkRectangle *scroll_rect, 01350 GdkRectangle *expose_rect_h, 01351 GdkRectangle *expose_rect_v) 01352 { 01353 GdkWindow *window; 01354 01355 #ifdef ZOOM_REGION_DEBUG 01356 g_assert (zoom_region->alive); 01357 #endif 01358 if (zoom_region->priv->w && gtk_widget_get_window (zoom_region->priv->w)) 01359 window = gtk_widget_get_window (zoom_region->priv->w); 01360 else { 01361 processing_updates = FALSE; 01362 return; 01363 } 01364 zoom_region_unpaint_crosswire_cursor (zoom_region, scroll_rect); 01365 zoom_region_unpaint_cursor (zoom_region, scroll_rect); 01366 gdk_window_scroll (window, dx, dy); 01367 zoom_region_paint_cursor (zoom_region, scroll_rect); 01368 zoom_region_paint_crosswire_cursor (zoom_region, scroll_rect); 01369 gdk_window_process_updates (window, FALSE); 01370 /* sync reduces cursor flicker, but slows things down */ 01371 if (zoom_region->smooth_scroll_policy > 01372 GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST) 01373 gdk_display_sync (gdk_drawable_get_display (window)); 01374 } 01375 01376 static void 01377 zoom_region_scroll_smooth (ZoomRegion *zoom_region, int dx, int dy, 01378 GdkRectangle *scroll_rect, 01379 GdkRectangle *expose_rect_h, 01380 GdkRectangle *expose_rect_v) 01381 { 01382 GdkWindow *window = NULL; 01383 GdkRectangle window_rect; 01384 01385 #ifdef ZOOM_REGION_DEBUG 01386 g_assert (zoom_region->alive); 01387 #endif 01388 if (zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 01389 window = gtk_widget_get_window (zoom_region->priv->w); 01390 else 01391 return; 01392 window_rect.x = 0; 01393 window_rect.y = 0; 01394 gdk_drawable_get_size (GDK_DRAWABLE (window), 01395 &window_rect.width, &window_rect.height); 01396 gdk_window_begin_paint_rect (window, &window_rect); 01397 gdk_window_invalidate_rect (window, &window_rect, FALSE); 01398 gdk_window_process_updates (window, FALSE); 01399 gdk_window_end_paint (window); 01400 } 01401 01402 static void 01403 zoom_region_scroll (ZoomRegion *zoom_region, int dx, int dy) 01404 { 01405 GdkRectangle scroll_rect, expose_rect_h, expose_rect_v; 01406 gboolean can_scroll; 01407 01408 #ifdef ZOOM_REGION_DEBUG 01409 g_assert (zoom_region->alive); 01410 #endif 01411 if (timing_test) { 01412 mag_timing.num_line_samples++; 01413 mag_timing.dx = abs(dx); 01414 mag_timing.dy = abs(dy); 01415 mag_timing.dx_total += mag_timing.dx; 01416 mag_timing.dy_total += mag_timing.dy; 01417 if (zoom_region->timing_output) { 01418 fprintf(stderr, " Panning Increment (x) = %d (avg. %f) lines/frame\n", 01419 mag_timing.dx, (float)mag_timing.dx_total / (float)mag_timing.num_line_samples); 01420 fprintf(stderr, " Panning Increment (y) = %d (avg. %f) lines/frame\n", 01421 mag_timing.dy, (float)mag_timing.dy_total / (float)mag_timing.num_line_samples); 01422 } 01423 } 01424 01425 /* 01426 * Currently processing a screen update. This flag used to disallow 01427 * other updates to occur until this one finishes 01428 */ 01429 processing_updates = TRUE; 01430 01431 can_scroll = zoom_region_calculate_scroll_rects (zoom_region, dx, dy, 01432 &scroll_rect, 01433 &expose_rect_h, 01434 &expose_rect_v); 01435 01436 if (can_scroll) { 01437 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_h), NULL); 01438 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_v), NULL); 01439 01440 if (zoom_region->smooth_scroll_policy > GNOME_Magnifier_ZoomRegion_SCROLL_FAST) { 01441 zoom_region_scroll_smooth (zoom_region, dx, dy, 01442 &scroll_rect, 01443 &expose_rect_h, 01444 &expose_rect_v); 01445 } else { 01446 zoom_region_scroll_fast (zoom_region, dx, dy, 01447 &scroll_rect, 01448 &expose_rect_h, 01449 &expose_rect_v); 01450 } 01451 } else { 01452 zoom_region_queue_update (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, scroll_rect)); 01453 } 01454 } 01455 01456 static void 01457 zoom_region_recompute_exposed_bounds (ZoomRegion *zoom_region) 01458 { 01459 zoom_region->priv->exposed_bounds.x2 = zoom_region->priv->exposed_bounds.x1 01460 + (zoom_region->viewport.x2 - zoom_region->viewport.x1); 01461 zoom_region->priv->exposed_bounds.y2 = zoom_region->priv->exposed_bounds.y1 01462 + (zoom_region->viewport.y2 - zoom_region->viewport.y1); 01463 } 01464 01465 static void 01466 zoom_region_set_cursor_pos (ZoomRegion *zoom_region, int x, int y) 01467 { 01468 if (zoom_region->priv) 01469 { 01470 zoom_region->priv->last_cursor_pos.x = x; 01471 zoom_region->priv->last_cursor_pos.y = y; 01472 } 01473 } 01474 01475 static gboolean 01476 zoom_region_update_pointer (ZoomRegion *zoom_region, gboolean draw_cursor) 01477 { 01478 Magnifier *magnifier; 01479 gint mouse_x_return, mouse_y_return; 01480 guint mask_return; 01481 01482 #ifdef ZOOM_REGION_DEBUG 01483 g_assert (zoom_region->alive); 01484 #endif 01485 if (!zoom_region->priv || !zoom_region->priv->parent 01486 || !zoom_region->poll_mouse) 01487 return FALSE; 01488 01489 magnifier = zoom_region->priv->parent; 01490 01491 /* TODO: there's really no reason we should be using magnifier->priv->root here */ 01492 if (magnifier && magnifier->priv && magnifier_get_root (magnifier)) 01493 { 01494 gdk_window_get_pointer ( 01495 magnifier_get_root (magnifier), 01496 &mouse_x_return, 01497 &mouse_y_return, 01498 &mask_return); 01499 01500 if (zoom_region->priv->last_cursor_pos.x != mouse_x_return 01501 || zoom_region->priv->last_cursor_pos.y != mouse_y_return) 01502 { 01503 zoom_region_set_cursor_pos (zoom_region, 01504 mouse_x_return, 01505 mouse_y_return); 01506 if (draw_cursor) 01507 zoom_region_update_cursor (zoom_region, 0, 0, 01508 NULL); 01509 01510 return TRUE; 01511 } 01512 } 01513 return FALSE; 01514 } 01515 01516 static int 01517 zoom_region_update_pointer_idle (gpointer data) 01518 { 01519 ZoomRegion *zoom_region = (ZoomRegion *) data; 01520 01521 if (zoom_region_update_pointer (zoom_region, TRUE)) 01522 return TRUE; 01523 else { 01524 if (zoom_region->priv) 01525 zoom_region->priv->update_pointer_id = 01526 g_timeout_add_full (G_PRIORITY_DEFAULT, 01527 100, 01528 zoom_region_update_pointer_timeout, 01529 zoom_region, 01530 NULL); 01531 return FALSE; 01532 } 01533 } 01534 01535 static int 01536 zoom_region_update_pointer_timeout (gpointer data) 01537 { 01538 ZoomRegion *zoom_region = data; 01539 01540 if (zoom_region->priv && zoom_region_update_pointer (zoom_region, 01541 TRUE)) { 01542 zoom_region->priv->update_pointer_id = 01543 g_idle_add_full (G_PRIORITY_HIGH_IDLE, 01544 zoom_region_update_pointer_idle, 01545 data, 01546 NULL); 01547 return FALSE; 01548 } else 01549 return TRUE; 01550 } 01551 01552 static void 01553 zoom_region_moveto (ZoomRegion *zoom_region, 01554 const long x, const long y) 01555 { 01556 long dx = x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1; 01557 long dy = y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1; 01558 #ifdef ZOOM_REGION_DEBUG 01559 g_assert (zoom_region->alive); 01560 #endif 01561 /* fprintf (stderr, "moveto %ld %ld\n", x, y); */ 01562 01563 mag_timing.dx = 0; 01564 mag_timing.dy = 0; 01565 01566 if ((dx != 0) || (dy != 0)) { 01567 zoom_region_update_pointer (zoom_region, FALSE); 01568 zoom_region->priv->exposed_bounds.x1 = x * zoom_region->xscale; 01569 zoom_region->priv->exposed_bounds.y1 = y * zoom_region->yscale; 01570 zoom_region_recompute_exposed_bounds (zoom_region); 01571 zoom_region_scroll (zoom_region, 01572 -dx, -dy); 01573 } 01574 } 01575 01576 /* 01577 * Process that must be made in-line in the current pixbuf. 01578 */ 01579 static void 01580 zoom_region_process_pixbuf (ZoomRegion *zoom_region, GdkPixbuf *pixbuf) 01581 { 01582 int rowstride = gdk_pixbuf_get_rowstride (pixbuf); 01583 int i, j, t; 01584 int w = gdk_pixbuf_get_width (pixbuf); 01585 int h = gdk_pixbuf_get_height (pixbuf); 01586 int n_channels = gdk_pixbuf_get_n_channels (pixbuf); 01587 guchar *pixels = gdk_pixbuf_get_pixels (pixbuf); 01588 guchar *pixels_row; 01589 #ifdef HAVE_COLORBLIND 01590 COLORBLIND_RUNTIME *cbr; 01591 COLORBLIND_XCOLOR *color; 01592 #endif /* HAVE_COLORBLIND */ 01593 01594 gboolean manipulate_contrast = FALSE; 01595 gboolean manipulate_brightness = FALSE; 01596 gboolean color_blind_filter = FALSE; 01597 01598 if (zoom_region->contrast_r != 0 || zoom_region->contrast_g != 0 || 01599 zoom_region->contrast_b != 0) { 01600 manipulate_contrast = TRUE; 01601 } 01602 01603 if (zoom_region->bright_r != 0 || zoom_region->bright_g != 0 || 01604 zoom_region->bright_b != 0) { 01605 manipulate_brightness = TRUE; 01606 } 01607 01608 #ifdef HAVE_COLORBLIND 01609 if (zoom_region->color_blind_filter != 01610 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER) { 01611 color_blind_filter = TRUE; 01612 cbr = colorblind_create (); 01613 color = malloc (sizeof (COLORBLIND_XCOLOR)); 01614 switch (zoom_region->color_blind_filter) { 01615 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER: 01616 break; /* This entry is only to avoid a warning */ 01617 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_RED: 01618 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_red); 01619 break; 01620 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_GREEN: 01621 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_green); 01622 break; 01623 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_BLUE: 01624 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_blue); 01625 break; 01626 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_RED: 01627 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_red); 01628 break; 01629 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_GREEN: 01630 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_green); 01631 break; 01632 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_BLUE: 01633 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_blue); 01634 break; 01635 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_POSITIVE: 01636 colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_positive); 01637 break; 01638 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_NEGATIVE: 01639 colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_negative); 01640 break; 01641 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE: 01642 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate); 01643 break; 01644 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE: 01645 colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate); 01646 break; 01647 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_MONOCHRONE_OTHERS: 01648 colorblind_set_filter_type (cbr, colorblind_filter_t_monochrome_others); 01649 break; 01650 } 01651 } 01652 #endif /* HAVE_COLORBLIND */ 01653 01654 if (!manipulate_contrast && !zoom_region->invert && 01655 !manipulate_brightness && !color_blind_filter) 01656 return; 01657 01658 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255)) 01659 #define CLAMP_LOW_MID(v) (t = (v), CLAMP (t, 0, 127)) 01660 #define CLAMP_MID_HIGH(v) (t = (v), CLAMP (t, 127, 255)) 01661 01662 for (j = 0; j < h; ++j) { 01663 pixels_row = pixels; 01664 for (i = 0; i < w; ++i) { 01665 if (manipulate_contrast) { 01666 /* Set the RED contrast */ 01667 if (pixels_row[0] <= 127) 01668 pixels_row[0] = CLAMP_LOW_MID (pixels_row[0] - zoom_region->contrast_r * 127); 01669 else 01670 pixels_row[0] = CLAMP_MID_HIGH (pixels_row[0] + zoom_region->contrast_r * 127); 01671 01672 /* Set the GREEN contrast */ 01673 if (pixels_row[1] <= 127) 01674 pixels_row[1] = CLAMP_LOW_MID (pixels_row[1] - zoom_region->contrast_g * 127); 01675 else 01676 pixels_row[1] = CLAMP_MID_HIGH (pixels_row[1] + zoom_region->contrast_g * 127); 01677 01678 /* Set the BLUE contrast */ 01679 if (pixels_row[2] <= 127) 01680 pixels_row[2] = CLAMP_LOW_MID (pixels_row[2] - zoom_region->contrast_b * 127); 01681 else 01682 pixels_row[2] = CLAMP_MID_HIGH (pixels_row[2] + zoom_region->contrast_b * 127); 01683 } 01684 01685 if (manipulate_brightness) { 01686 /* Set the RED brightness */ 01687 pixels_row[0] = CLAMP_UCHAR (pixels_row[0] + zoom_region->bright_r * 255); 01688 01689 /* Set the GREEN brightness */ 01690 pixels_row[1] = CLAMP_UCHAR (pixels_row[1] + zoom_region->bright_g * 255); 01691 01692 /* Set the BLUE brightness */ 01693 pixels_row[2] = CLAMP_UCHAR (pixels_row[2] + zoom_region->bright_b * 255); 01694 } 01695 01696 if (zoom_region->invert) { 01697 pixels_row[0] = ~(pixels_row[0]); 01698 pixels_row[1] = ~(pixels_row[1]); 01699 pixels_row[2] = ~(pixels_row[2]); 01700 } 01701 01702 #ifdef HAVE_COLORBLIND 01703 if (color_blind_filter) { 01704 color->red = pixels_row[0]; 01705 color->green = pixels_row[1]; 01706 color->blue = pixels_row[2]; 01707 if (colorblind_filter (cbr, color)) { 01708 pixels_row[0] = color->red; 01709 pixels_row[1] = color->green; 01710 pixels_row[2] = color->blue; 01711 } 01712 } 01713 #endif /* HAVE_COLORBLIND */ 01714 01715 pixels_row += n_channels; 01716 } 01717 pixels += rowstride; 01718 } 01719 } 01720 01721 static void 01722 zoom_region_post_process_pixbuf (ZoomRegion *zoom_region, 01723 GdkPixbuf *subimage, 01724 GdkPixbuf *scaled_image) 01725 { 01726 /* nothing yet */ 01736 } 01737 01738 static GdkPixbuf * 01739 zoom_region_get_source_subwindow (ZoomRegion *zoom_region, 01740 const GdkRectangle bounds) 01741 { 01742 int i, j, width, height; 01743 Magnifier *magnifier = zoom_region->priv->parent; 01744 GdkPixbuf *subimage = NULL; 01745 01746 #ifdef ZOOM_REGION_DEBUG 01747 g_assert (zoom_region->alive); 01748 #endif 01749 width = gdk_screen_get_width ( 01750 gdk_display_get_screen (magnifier->source_display, 01751 magnifier->source_screen_num)); 01752 height = gdk_screen_get_height ( 01753 gdk_display_get_screen (magnifier->source_display, 01754 magnifier->source_screen_num)); 01755 01756 if ((bounds.width <= 0) || (bounds.height <= 0)) 01757 { 01758 return NULL; 01759 } 01760 01761 if (!zoom_region->priv->source_drawable) 01762 { 01763 /* TESTING ONLY */ 01764 if (zoom_region->priv->test) { 01765 GdkImage *test_image = NULL; 01766 01767 test_image = gdk_image_new (GDK_IMAGE_FASTEST, 01768 gdk_visual_get_system (), 01769 width, 01770 height); 01771 01772 for (i = 0; i < width; ++i) 01773 for (j = 0; j < height; ++j) 01774 gdk_image_put_pixel (test_image, i, j, i*j); 01775 01776 zoom_region->priv->source_drawable = gdk_pixmap_new (gtk_widget_get_window (zoom_region->priv->w), width, height, -1); 01777 01778 if (zoom_region->priv->default_gc == NULL) 01779 zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w)); 01780 01781 gdk_draw_image (zoom_region->priv->source_drawable, 01782 zoom_region->priv->default_gc, 01783 test_image, 01784 0, 0, 01785 0, 0, 01786 width, height); 01787 } 01788 else 01789 { 01790 if (magnifier->priv->source_drawable) { 01791 zoom_region->priv->source_drawable = 01792 magnifier->priv->source_drawable; 01793 } else 01794 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num)); 01795 } 01796 if (zoom_region->cache_source) 01797 { 01798 zoom_region->priv->source_pixbuf_cache = 01799 gdk_pixbuf_new (GDK_COLORSPACE_RGB, 01800 FALSE, 01801 8, /* FIXME: not always 8? */ 01802 width, height); 01803 } 01804 } 01805 DEBUG_RECT ("getting subimage from ", bounds); 01806 01807 subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable, 01808 gdk_colormap_get_system (), 01809 bounds.x, 01810 bounds.y, 01811 0, 01812 0, 01813 bounds.width, 01814 bounds.height); 01815 01816 /* TODO: blank the region overlapped by the target display if source == target */ 01817 01818 if (!subimage) 01819 _debug_announce_rect ("update of invalid subregion!\n", bounds); 01820 01821 /* if this zoom-region keeps a cache, do a diff to see if update is necessary */ 01822 if (zoom_region->cache_source && subimage) { 01823 GdkPixbuf *cache_subpixbuf = 01824 gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache, 01825 bounds.x, bounds.y, bounds.width, bounds.height); 01826 if (_diff_pixbufs (subimage, cache_subpixbuf)) { 01827 gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height, 01828 zoom_region->priv->source_pixbuf_cache, 01829 bounds.x, bounds.y); 01830 } 01831 else 01832 { 01833 if (subimage) 01834 g_object_unref (subimage); 01835 subimage = NULL; 01836 } 01837 g_object_unref (cache_subpixbuf); 01838 } 01839 return subimage; 01840 } 01841 01842 static GdkRectangle 01843 zoom_region_update_pixmap (ZoomRegion *zoom_region, 01844 const GdkRectangle update_rect, 01845 GdkRectangle *p_rect) 01846 { 01847 GdkPixbuf *subimage; 01848 GdkRectangle source_rect; 01849 01850 #ifdef ZOOM_REGION_DEBUG 01851 g_assert (zoom_region->alive); 01852 #endif 01853 DEBUG_RECT ("unclipped update rect", update_rect); 01854 source_rect = zoom_region_clip_to_source (zoom_region, update_rect); 01855 DEBUG_RECT ("clipped to source", source_rect); 01856 source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect); 01857 DEBUG_RECT ("update rect clipped to exposed target", source_rect); 01858 01859 subimage = zoom_region_get_source_subwindow (zoom_region, source_rect); 01860 01861 if (subimage) 01862 { 01863 GdkRectangle paint_rect; 01864 g_timer_start (mag_timing.scale); 01865 DEBUG_RECT ("source rect", source_rect); 01866 paint_rect = zoom_region_view_rect_from_source_rect (zoom_region, source_rect); 01867 if (p_rect) { 01868 *p_rect = paint_rect; 01869 } 01870 /* paint_rect = zoom_region_clip_to_scaled_pixmap (zoom_region, paint_rect); */ 01871 DEBUG_RECT ("paint rect", paint_rect); 01872 01873 zoom_region_process_pixbuf (zoom_region, subimage); 01874 01879 gdk_pixbuf_scale (subimage, 01880 zoom_region->priv->scaled_pixbuf, 01881 0, 01882 0, 01883 paint_rect.width, 01884 paint_rect.height, 01885 0, 01886 0, 01887 zoom_region->xscale, 01888 zoom_region->yscale, 01889 zoom_region->priv->gdk_interp_type); 01890 01891 zoom_region_post_process_pixbuf (zoom_region, subimage, 01892 zoom_region->priv->scaled_pixbuf); 01893 if (zoom_region->priv->default_gc == NULL) 01894 zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w)); 01895 01896 #ifndef USE_GDK_PIXBUF_RENDER_TO_DRAWABLE 01897 if (GDK_IS_DRAWABLE (zoom_region->priv->pixmap)) 01898 gdk_draw_pixbuf (zoom_region->priv->pixmap, 01899 zoom_region->priv->default_gc, 01900 zoom_region->priv->scaled_pixbuf, 01901 0, 01902 0, 01903 paint_rect.x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale, 01904 paint_rect.y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale, 01905 paint_rect.width, 01906 paint_rect.height, 01907 GDK_RGB_DITHER_NONE, 01908 0, 01909 0); 01910 else 01911 g_warning ("updating non-drawable pixmap: region %p", zoom_region); 01912 #else 01913 gdk_pixbuf_render_to_drawable (zoom_region->priv->scaled_pixbuf, 01914 zoom_region->priv->pixmap, 01915 zoom_region->priv->default_gc, 01916 0, 01917 0, 01918 paint_rect.x + zoom_region->priv->exposed_bounds.x1, 01919 paint_rect.y + zoom_region->priv->exposed_bounds.y1, 01920 paint_rect.width, 01921 paint_rect.height, 01922 GDK_RGB_DITHER_NONE, 01923 0, 01924 0); 01925 #endif 01926 if (gmag_gs_error_check ()) 01927 g_warning ("Could not render scaled image to drawable; out of memory!\n"); 01928 g_object_unref (subimage); 01929 01930 g_timer_stop (mag_timing.scale); 01931 } 01932 return source_rect; 01933 } 01934 01941 static void 01942 zoom_region_update (ZoomRegion *zoom_region, 01943 const GdkRectangle update_rect) 01944 { 01945 GdkRectangle paint_rect = {0, 0, 0, 0}; 01946 if (zoom_region->priv->w && gtk_widget_get_window (zoom_region->priv->w)) { 01947 GdkRectangle source_rect = zoom_region_update_pixmap (zoom_region, update_rect, &paint_rect); 01948 if (paint_rect.x != 0 || paint_rect.y != 0 || 01949 paint_rect.width != 0 || paint_rect.height != 0) { 01950 gdk_window_begin_paint_rect ( 01951 gtk_widget_get_window (zoom_region->priv->w), &paint_rect); 01952 zoom_region_paint (zoom_region, &paint_rect); 01953 gdk_window_end_paint (gtk_widget_get_window (zoom_region->priv->w)); 01954 } 01955 if (timing_test) { 01956 mag_timing.num_scale_samples++; 01957 01958 gulong microseconds; 01959 01960 mag_timing.scale_val = 01961 g_timer_elapsed (mag_timing.scale, 01962 µseconds); 01963 mag_timing.scale_total += mag_timing.scale_val; 01964 01965 if (mag_timing.scale_val != 0 && (timing_scale_max == 0 || 01966 (1.0/(float)mag_timing.scale_val) > (1.0/(float)timing_scale_max))) 01967 timing_scale_max = mag_timing.scale_val; 01968 if ((source_rect.height * source_rect.width / mag_timing.scale_val) > update_nrr_max) 01969 update_nrr_max = source_rect.height * source_rect.width / mag_timing.scale_val; 01970 01971 mag_timing.update_pixels_total += source_rect.height * source_rect.width; 01972 01973 if (zoom_region->timing_output) { 01974 fprintf(stderr, " Update Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n", 01975 mag_timing.scale_val, (mag_timing.scale_total / 01976 mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total); 01977 fprintf(stderr, " Update Pixels = %ld (avg. %ld) pixels/frame\n", 01978 (long) source_rect.height * source_rect.width, 01979 mag_timing.update_pixels_total / mag_timing.num_scale_samples); 01980 fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n", 01981 1.0/(mag_timing.scale_total / mag_timing.num_scale_samples), 1.0/(float)timing_scale_max); 01982 fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n", 01983 ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0, 01984 update_nrr_max / 1000000.0); 01985 } 01986 } 01987 } else { 01988 fprintf (stderr, "update on uninitialized zoom region!\n"); 01989 } 01990 } 01991 01992 static void 01993 zoom_region_init_window (ZoomRegion *zoom_region) 01994 { 01995 GtkFixed *parent; 01996 GtkWidget *zoomer, *border; 01997 DBG(fprintf (stderr, "window not yet created...\n")); 01998 parent = GTK_FIXED ( 01999 ((Magnifier *)zoom_region->priv->parent)->priv->canvas); 02000 zoomer = gtk_drawing_area_new (); 02001 border = gtk_drawing_area_new (); 02002 zoom_region->priv->border = border; 02003 zoom_region->priv->w = zoomer; 02004 02005 #ifdef ZOOM_REGION_DEBUG 02006 g_assert (zoom_region->alive); 02007 #endif 02008 gtk_widget_set_size_request (GTK_WIDGET (border), 02009 zoom_region->viewport.x2 - 02010 zoom_region->viewport.x1, 02011 zoom_region->viewport.y2 - 02012 zoom_region->viewport.y1); 02013 gtk_widget_set_size_request (GTK_WIDGET (zoomer), 02014 zoom_region->viewport.x2 - 02015 zoom_region->viewport.x1 - 02016 (zoom_region->border_size_right + 02017 zoom_region->border_size_left), 02018 zoom_region->viewport.y2 - 02019 zoom_region->viewport.y1 - 02020 (zoom_region->border_size_bottom + 02021 zoom_region->border_size_top)); 02022 gtk_fixed_put (parent, border, 02023 zoom_region->viewport.x1, 02024 zoom_region->viewport.y1); 02025 gtk_fixed_put (parent, zoomer, 02026 zoom_region->viewport.x1 + 02027 zoom_region->border_size_left, 02028 zoom_region->viewport.y1 + 02029 zoom_region->border_size_top); 02030 gtk_widget_show (GTK_WIDGET (border)); 02031 gtk_widget_show (GTK_WIDGET (zoomer)); 02032 gtk_widget_show (GTK_WIDGET (parent)); 02033 zoom_region->priv->expose_handler_id = 02034 g_signal_connect (G_OBJECT (zoom_region->priv->w), 02035 "expose_event", 02036 G_CALLBACK (zoom_region_expose_handler), 02037 zoom_region); 02038 DBG(fprintf (stderr, "New window created\n")); 02039 } 02040 02041 static int 02042 zoom_region_process_updates (gpointer data) 02043 { 02044 ZoomRegion *zoom_region = (ZoomRegion *) data; 02045 02046 /* TODO: lock the queue when copying it? */ 02047 zoom_region_coalesce_updates (zoom_region); 02048 02049 if (zoom_region->priv->q != NULL) { 02050 GList *last = g_list_last (zoom_region->priv->q); 02051 #ifdef ZOOM_REGION_DEBUG 02052 fprintf (stderr, "qlen=%d\n", g_list_length (zoom_region->priv->q)); 02053 #endif 02054 if (last) { 02055 zoom_region->priv->q = g_list_remove_link (zoom_region->priv->q, 02056 last); 02057 zoom_region_update (zoom_region, 02058 * (GdkRectangle *) last->data); 02059 g_list_free (last); 02060 #ifdef DEBUG 02061 fputs (".\n", stderr); /* debug output, means we actually did something. */ 02062 #endif 02063 } 02064 return TRUE; 02065 } 02066 else 02067 { 02068 if (zoom_region->priv) 02069 zoom_region->priv->update_handler_id = 0; 02070 return FALSE; 02071 } 02072 } 02073 02074 void 02075 timing_report(ZoomRegion *zoom_region) 02076 { 02077 float frame_avg; 02078 float x_scroll_incr, y_scroll_incr; 02079 int width, height, x, y; 02080 02081 if (timing_test) { 02082 width = (zoom_region->viewport.x2 - 02083 zoom_region->viewport.x1) / zoom_region->xscale; 02084 height = (zoom_region->viewport.y2 - 02085 zoom_region->viewport.y1) / zoom_region->yscale; 02086 02087 frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples; 02088 02089 x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples; 02090 y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples; 02091 02092 gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)), 02093 &x, &y); 02094 02095 fprintf(stderr, " Frames Processed = %ld\n", 02096 mag_timing.num_frame_samples + 1); 02097 fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y, 02098 gdk_drawable_get_depth (gtk_widget_get_window (zoom_region->priv->w))); 02099 fprintf(stderr, " Zoom Factor (x/y) = %f/%f\n", zoom_region->xscale, 02100 zoom_region->yscale); 02101 if (mag_timing.num_scale_samples != 0) { 02102 fprintf(stderr, " Update Duration = (avg. %f) (max. %f) (tot. %f) seconds\n", 02103 (mag_timing.scale_total / mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total); 02104 fprintf(stderr, " Update Pixels = (avg. %ld) pixels/frame\n", 02105 mag_timing.update_pixels_total / mag_timing.num_scale_samples); 02106 fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n", 02107 1.0/((float)mag_timing.scale_total / (float)mag_timing.num_scale_samples), 02108 1.0/(float)timing_scale_max); 02109 fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n", 02110 ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0, 02111 update_nrr_max / 1000000.0); 02112 } 02113 fprintf(stderr, " Pan Latency = (avg. %f) (max. %f) seconds\n", 02114 (mag_timing.idle_total / mag_timing.num_idle_samples), timing_idle_max); 02115 fprintf(stderr, " Total Frame Duration = (avg. %f) (max. %f) (tot. %f) seconds\n", 02116 frame_avg, timing_frame_max, mag_timing.frame_total); 02117 fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n", 02118 1.0 / (mag_timing.frame_total / mag_timing.num_frame_samples), cps_max); 02119 fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n", 02120 x_scroll_incr, mag_timing.dx_total); 02121 fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n", 02122 y_scroll_incr, mag_timing.dy_total); 02123 fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n", 02124 x_scroll_incr / frame_avg); 02125 fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n", 02126 y_scroll_incr / frame_avg); 02127 02128 fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n\n", 02129 (height * width * 02130 ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0, 02131 nrr_max / 1000000.0); 02132 } 02133 } 02134 02135 static void 02136 zoom_region_time_frame(ZoomRegion *zoom_region, Magnifier *magnifier) 02137 { 02138 float frame_avg; 02139 float x_scroll_incr, y_scroll_incr; 02140 int width = magnifier->target_bounds.x2 - magnifier->target_bounds.x1; 02141 int height = magnifier->target_bounds.y2 - magnifier->target_bounds.y1; 02142 02143 mag_timing.num_frame_samples++; 02144 g_timer_stop (mag_timing.frame); 02145 02146 gulong microseconds; 02147 02148 mag_timing.frame_val = g_timer_elapsed (mag_timing.frame, 02149 µseconds); 02150 02151 mag_timing.frame_total += mag_timing.frame_val; 02152 if (mag_timing.frame_val > timing_frame_max) 02153 timing_frame_max = mag_timing.frame_val; 02154 if (mag_timing.frame_val != 0 && 1.0/mag_timing.frame_val > cps_max) 02155 cps_max = 1.0/mag_timing.frame_val; 02156 02157 frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples; 02158 02159 x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples; 02160 y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples; 02161 02162 if ((height * width / mag_timing.frame_val) > nrr_max) 02163 nrr_max = height * width / mag_timing.frame_val; 02164 02165 if (zoom_region->timing_output) { 02166 fprintf(stderr, " Total Frame Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n", 02167 mag_timing.frame_val, frame_avg, timing_frame_max, mag_timing.frame_total); 02168 fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n", 02169 1.0 /frame_avg, cps_max); 02170 fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n", 02171 x_scroll_incr, mag_timing.dx_total); 02172 fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n", 02173 y_scroll_incr, mag_timing.dy_total); 02174 fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n", 02175 x_scroll_incr / frame_avg); 02176 fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n", 02177 y_scroll_incr / frame_avg); 02178 02179 fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n", 02180 (height * width * 02181 ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0, 02182 nrr_max / 1000000.0); 02183 } 02184 02185 mag_timing.last_frame_val = mag_timing.frame_val; 02186 mag_timing.last_dy = mag_timing.dy; 02187 02188 if (reset_timing) { 02189 fprintf(stderr, "\n### Updates summary:\n\n"); 02190 timing_report (zoom_region); 02191 fprintf(stderr, "\n### Updates finished, starting panning test\n"); 02192 reset_timing_stats(); 02193 reset_timing = FALSE; 02194 } 02195 } 02196 02197 static void 02198 zoom_region_sync (ZoomRegion *zoom_region) 02199 { 02200 while (zoom_region->priv->q) 02201 zoom_region_process_updates (zoom_region); 02202 } 02203 02204 static gboolean 02205 gdk_timing_idle (gpointer data) 02206 { 02207 ZoomRegion *zoom_region = data; 02208 02209 /* Now update has finished, reset processing_updates */ 02210 processing_updates = FALSE; 02211 g_timer_stop (mag_timing.idle); 02212 02213 if (timing_test) { 02214 mag_timing.num_idle_samples++; 02215 02216 gulong microseconds; 02217 02218 mag_timing.idle_val = g_timer_elapsed (mag_timing.idle, 02219 µseconds); 02220 mag_timing.idle_total += mag_timing.idle_val; 02221 02222 if (mag_timing.idle_val > timing_idle_max) 02223 timing_idle_max = mag_timing.idle_val; 02224 02225 if (zoom_region->timing_output) { 02226 fprintf(stderr, " Pan Latency = %f (avg. %f) (max. %f) seconds\n", 02227 mag_timing.idle_val, (mag_timing.idle_total / 02228 mag_timing.num_idle_samples), timing_idle_max); 02229 } 02230 } 02231 02232 return FALSE; 02233 } 02234 02235 static void 02236 zoom_region_get_move_x_y (ZoomRegion *zoom_region, long *x, long *y) 02237 { 02238 long width, height; 02239 02240 width = (zoom_region->viewport.x2 - zoom_region->viewport.x1) / 02241 zoom_region->xscale; 02242 height = (zoom_region->viewport.y2 - zoom_region->viewport.y1) / 02243 zoom_region->yscale; 02244 02245 switch (zoom_region->x_align_policy) { 02246 case GNOME_Magnifier_ZoomRegion_ALIGN_MAX: 02247 *x = zoom_region->roi.x2 - width; 02248 break; 02249 case GNOME_Magnifier_ZoomRegion_ALIGN_MIN: 02250 *x = zoom_region->roi.x1; 02251 break; 02252 case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER: 02253 default: 02254 *x = ((zoom_region->roi.x1 + zoom_region->roi.x2) - width ) / 02255 2; 02256 } 02257 02258 switch (zoom_region->y_align_policy) { 02259 case GNOME_Magnifier_ZoomRegion_ALIGN_MAX: 02260 *y = zoom_region->roi.y2 - height; 02261 break; 02262 case GNOME_Magnifier_ZoomRegion_ALIGN_MIN: 02263 *y = zoom_region->roi.y1; 02264 break; 02265 case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER: 02266 default: 02267 *y = ((zoom_region->roi.y1 + zoom_region->roi.y2) - height ) / 02268 2; 02269 } 02270 } 02271 02272 static void 02273 zoom_region_align (ZoomRegion *zoom_region) 02274 { 02275 Magnifier *magnifier = zoom_region->priv->parent; 02276 long x = 0, y = 0; 02277 02278 if (timing_start) 02279 zoom_region_time_frame(zoom_region, magnifier); 02280 02281 if (timing_test) { 02282 g_timer_start (mag_timing.frame); 02283 02284 if (zoom_region->timing_output) { 02285 gint x, y; 02286 02287 gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)), 02288 &x, &y); 02289 02290 fprintf(stderr, "\nTiming Information - ROI = (%d, %d) (%d, %d):\n", 02291 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2, 02292 zoom_region->roi.y2); 02293 fprintf(stderr, " Frame Number = %ld\n", 02294 mag_timing.num_frame_samples + 1); 02295 fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y, 02296 gdk_drawable_get_depth (gtk_widget_get_window (zoom_region->priv->w))); 02297 } 02298 02299 /* 02300 * The timing_start flag makes sure that we don't start displaying output 02301 * until we have processed an entire frame. 02302 */ 02303 if (!timing_start) 02304 g_timer_start (mag_timing.process); 02305 02306 timing_start = TRUE; 02307 } 02308 02309 g_timer_start (mag_timing.idle); 02310 02311 /* 02312 * zoom_region_align calls 02313 * zoom_region_moveto calls 02314 * zoom_region_scroll calls 02315 * zoom_region_scroll_fast or zoom_region_scroll_smooth calls 02316 * gdk_window_scroll or gdk_window_invalidate_rect calls 02317 * gdk_window_invalidate_region calls 02318 * gdk_window_invalidate_maybe_recurse 02319 * 02320 * The last function in the stack will set up an idle handler of 02321 * priority GDK_PRIORITY_REDRAW (gdk_window_update_idle) to be called 02322 * to handle the work of updateing the screen. 02323 * 02324 * By setting up an idle handler of priority GDK_PRIORITY_REDRAW + 1, 02325 * it will be called immediately after and we can determine when GTK+ 02326 * is finished with the update. 02327 */ 02328 g_idle_add_full (GDK_PRIORITY_REDRAW + 1, 02329 gdk_timing_idle, zoom_region, NULL); 02330 02331 zoom_region_get_move_x_y (zoom_region, &x, &y); 02332 02333 zoom_region_moveto (zoom_region, x, y); 02334 } 02335 02336 static void 02337 zoom_region_set_viewport (ZoomRegion *zoom_region, 02338 const GNOME_Magnifier_RectBounds *viewport) 02339 { 02340 #ifdef ZOOM_REGION_DEBUG 02341 g_assert (zoom_region->alive); 02342 #endif 02343 if (zoom_region->viewport.x1 == viewport->x1 && 02344 zoom_region->viewport.y1 == viewport->y1 && 02345 zoom_region->viewport.x2 == viewport->x2 && 02346 zoom_region->viewport.y2 == viewport->y2) { 02347 return; 02348 } 02349 zoom_region->viewport = *viewport; 02350 #ifdef DEBUG 02351 fprintf (stderr, "Setting viewport %d,%d - %d,%d\n", 02352 (int) viewport->x1, (int) viewport->y1, 02353 (int) viewport->x2, (int) viewport->y2); 02354 #endif 02355 zoom_region_align (zoom_region); 02356 if (!zoom_region->priv->w) { 02357 zoom_region_init_window (zoom_region); 02358 } else { 02359 CORBA_any *any; 02360 CORBA_Environment ev; 02361 Bonobo_PropertyBag properties; 02362 Magnifier *magnifier = (Magnifier *) zoom_region->priv->parent; 02363 GtkFixed *fixed = GTK_FIXED (magnifier->priv->canvas); 02364 gtk_fixed_move (fixed, 02365 zoom_region->priv->border, 02366 zoom_region->viewport.x1, 02367 zoom_region->viewport.y1); 02368 gtk_fixed_move (fixed, 02369 zoom_region->priv->w, 02370 zoom_region->viewport.x1 + 02371 zoom_region->border_size_left, 02372 zoom_region->viewport.y1 + 02373 zoom_region->border_size_top); 02374 gtk_widget_set_size_request ( 02375 GTK_WIDGET (zoom_region->priv->border), 02376 zoom_region->viewport.x2 - zoom_region->viewport.x1, 02377 zoom_region->viewport.y2 - zoom_region->viewport.y1); 02378 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w), 02379 zoom_region->viewport.x2 - 02380 zoom_region->viewport.x1 - 02381 (zoom_region->border_size_right + 02382 zoom_region->border_size_left), 02383 zoom_region->viewport.y2 - 02384 zoom_region->viewport.y1 - 02385 (zoom_region->border_size_bottom + 02386 zoom_region->border_size_top)); 02387 CORBA_exception_init (&ev); 02388 properties = 02389 GNOME_Magnifier_Magnifier_getProperties( 02390 BONOBO_OBJREF ( 02391 (Magnifier *) zoom_region->priv->parent), &ev); 02392 if (!BONOBO_EX (&ev)) 02393 any = Bonobo_PropertyBag_getValue ( 02394 properties, "source-display-bounds", &ev); 02395 if (!BONOBO_EX (&ev)) 02396 zoom_region->priv->source_area = 02397 *((GNOME_Magnifier_RectBounds *) any->_value); 02398 if (zoom_region->priv->pixmap) 02399 g_object_unref (zoom_region->priv->pixmap); 02400 zoom_region_create_pixmap (zoom_region); 02401 if (zoom_region->priv->scaled_pixbuf) 02402 g_object_unref (zoom_region->priv->scaled_pixbuf); 02403 02404 zoom_region->priv->scaled_pixbuf = 02405 gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 02406 (zoom_region->priv->source_area.x2 - 02407 zoom_region->priv->source_area.x1) * zoom_region->xscale + 1, 02408 (zoom_region->priv->source_area.y2 - 02409 zoom_region->priv->source_area.y1) * zoom_region->yscale + 1); 02410 } 02411 zoom_region_queue_update (zoom_region, 02412 zoom_region_source_rect_from_view_bounds ( 02413 zoom_region, &zoom_region->viewport)); 02414 } 02415 02416 static void 02417 zoom_region_get_property (BonoboPropertyBag *bag, 02418 BonoboArg *arg, 02419 guint arg_id, 02420 CORBA_Environment *ev, 02421 gpointer user_data) 02422 { 02423 ZoomRegion *zoom_region = user_data; 02424 02425 #ifdef ZOOM_REGION_DEBUG 02426 g_assert (zoom_region->alive); 02427 #endif 02428 DBG (fprintf (stderr, "Get zoom-region property: %s\n", prop_names[arg_id])); 02429 02430 switch (arg_id) { 02431 case ZOOM_REGION_MANAGED_PROP: 02432 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->is_managed); 02433 break; 02434 case ZOOM_REGION_POLL_MOUSE_PROP: 02435 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->poll_mouse); 02436 break; 02437 case ZOOM_REGION_DRAW_CURSOR_PROP: 02438 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->draw_cursor); 02439 break; 02440 case ZOOM_REGION_INVERT_PROP: 02441 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->invert); 02442 break; 02443 case ZOOM_REGION_SMOOTHSCROLL_PROP: 02444 BONOBO_ARG_SET_SHORT (arg, zoom_region->smooth_scroll_policy); 02445 break; 02446 case ZOOM_REGION_COLORBLIND_PROP: 02447 BONOBO_ARG_SET_SHORT (arg, zoom_region->color_blind_filter); 02448 break; 02449 case ZOOM_REGION_TESTPATTERN_PROP: 02450 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->priv->test); 02451 break; 02452 case ZOOM_REGION_SMOOTHING_PROP: 02453 BONOBO_ARG_SET_STRING (arg, zoom_region->smoothing); 02454 break; 02455 case ZOOM_REGION_CONTRASTR_PROP: 02456 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_r); 02457 break; 02458 case ZOOM_REGION_CONTRASTG_PROP: 02459 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_g); 02460 break; 02461 case ZOOM_REGION_CONTRASTB_PROP: 02462 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_b); 02463 break; 02464 case ZOOM_REGION_BRIGHTR_PROP: 02465 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_r); 02466 break; 02467 case ZOOM_REGION_BRIGHTG_PROP: 02468 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_g); 02469 break; 02470 case ZOOM_REGION_BRIGHTB_PROP: 02471 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_b); 02472 break; 02473 case ZOOM_REGION_XSCALE_PROP: 02474 BONOBO_ARG_SET_FLOAT (arg, zoom_region->xscale); 02475 break; 02476 case ZOOM_REGION_YSCALE_PROP: 02477 BONOBO_ARG_SET_FLOAT (arg, zoom_region->yscale); 02478 break; 02479 case ZOOM_REGION_BORDERSIZE_PROP: 02480 BONOBO_ARG_SET_LONG ( 02481 arg, (zoom_region->border_size_top + 02482 zoom_region->border_size_left + 02483 zoom_region->border_size_right + 02484 zoom_region->border_size_bottom) / 4); 02485 break; 02486 case ZOOM_REGION_BORDERSIZETOP_PROP: 02487 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_top); 02488 break; 02489 case ZOOM_REGION_BORDERSIZELEFT_PROP: 02490 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_left); 02491 break; 02492 case ZOOM_REGION_BORDERSIZERIGHT_PROP: 02493 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_right); 02494 break; 02495 case ZOOM_REGION_BORDERSIZEBOTTOM_PROP: 02496 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_bottom); 02497 break; 02498 case ZOOM_REGION_XALIGN_PROP: 02499 /* TODO: enums here */ 02500 BONOBO_ARG_SET_INT (arg, zoom_region->x_align_policy); 02501 break; 02502 case ZOOM_REGION_YALIGN_PROP: 02503 BONOBO_ARG_SET_INT (arg, zoom_region->y_align_policy); 02504 break; 02505 case ZOOM_REGION_BORDERCOLOR_PROP: 02506 BONOBO_ARG_SET_LONG (arg, 02507 zoom_region->border_color); 02508 break; 02509 case ZOOM_REGION_VIEWPORT_PROP: 02510 BONOBO_ARG_SET_GENERAL (arg, zoom_region->viewport, 02511 TC_GNOME_Magnifier_RectBounds, 02512 GNOME_Magnifier_RectBounds, 02513 NULL); 02514 break; 02515 case ZOOM_REGION_TIMING_TEST_PROP: 02516 BONOBO_ARG_SET_INT (arg, zoom_region->timing_iterations); 02517 break; 02518 case ZOOM_REGION_TIMING_OUTPUT_PROP: 02519 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->timing_output); 02520 break; 02521 case ZOOM_REGION_TIMING_PAN_RATE_PROP: 02522 BONOBO_ARG_SET_INT (arg, zoom_region->timing_pan_rate); 02523 break; 02524 case ZOOM_REGION_EXIT_MAGNIFIER: 02525 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->exit_magnifier); 02526 break; 02527 default: 02528 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound); 02529 }; 02530 } 02531 02532 static void 02533 zoom_region_update_borders (ZoomRegion *zoom_region) 02534 { 02535 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->border), 02536 zoom_region->viewport.x2 - 02537 zoom_region->viewport.x1, 02538 zoom_region->viewport.y2 - 02539 zoom_region->viewport.y1); 02540 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w), 02541 zoom_region->viewport.x2 - 02542 zoom_region->viewport.x1 - 02543 (zoom_region->border_size_right + 02544 zoom_region->border_size_left), 02545 zoom_region->viewport.y2 - 02546 zoom_region->viewport.y1 - 02547 (zoom_region->border_size_bottom + 02548 zoom_region->border_size_top)); 02549 gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->border, zoom_region->viewport.x1, zoom_region->viewport.y1); 02550 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); 02551 } 02552 02553 gboolean 02554 impl_dbus_zoom_region_set_managed (ZoomRegion *zoom_region, gboolean managed) 02555 { 02556 zoom_region->is_managed = managed; 02557 02558 return TRUE; 02559 } 02560 02561 gboolean 02562 impl_dbus_zoom_region_get_managed (ZoomRegion *zoom_region) 02563 { 02564 return zoom_region->is_managed; 02565 } 02566 02567 gboolean 02568 impl_dbus_zoom_region_set_poll_mouse (ZoomRegion *zoom_region, gboolean poll_mouse) 02569 { 02570 zoom_region->poll_mouse = poll_mouse; 02571 if (zoom_region->poll_mouse) { 02572 g_message ("Adding polling timer"); 02573 zoom_region->priv->update_pointer_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 02574 200, 02575 zoom_region_update_pointer_timeout, 02576 zoom_region, 02577 NULL); 02578 } else if (zoom_region->priv->update_pointer_id) { 02579 g_message ("Removing polling time"); 02580 g_source_remove (zoom_region->priv->update_pointer_id); 02581 zoom_region->priv->update_pointer_id = 0; 02582 } 02583 02584 return TRUE; 02585 } 02586 02587 gboolean 02588 impl_dbus_zoom_region_get_poll_mouse (ZoomRegion *zoom_region) 02589 { 02590 return zoom_region->poll_mouse; 02591 } 02592 02593 gboolean 02594 impl_dbus_zoom_region_set_draw_cursor (ZoomRegion *zoom_region, gboolean draw_cursor) 02595 { 02596 zoom_region->draw_cursor = draw_cursor; 02597 if (!zoom_region->draw_cursor) { 02598 zoom_region_unpaint_cursor (zoom_region, NULL); 02599 } 02600 02601 return TRUE; 02602 } 02603 02604 gboolean 02605 impl_dbus_zoom_region_get_draw_cursor (ZoomRegion *zoom_region) 02606 { 02607 return zoom_region->draw_cursor; 02608 } 02609 02610 gboolean 02611 impl_dbus_zoom_region_set_invert (ZoomRegion *zoom_region, gboolean invert) 02612 { 02613 zoom_region->invert = invert; 02614 zoom_region_update_current (zoom_region); 02615 02616 return TRUE; 02617 } 02618 02619 gboolean 02620 impl_dbus_zoom_region_get_invert (ZoomRegion *zoom_region) 02621 { 02622 return zoom_region->invert; 02623 } 02624 02625 gboolean 02626 impl_dbus_zoom_region_set_smoothscroll (ZoomRegion *zoom_region, gshort smoothscroll) 02627 { 02628 zoom_region->smooth_scroll_policy = smoothscroll; 02629 02630 return TRUE; 02631 } 02632 02633 gshort 02634 impl_dbus_zoom_region_get_smoothscroll (ZoomRegion *zoom_region) 02635 { 02636 return zoom_region->smooth_scroll_policy; 02637 } 02638 02639 gboolean 02640 impl_dbus_zoom_region_set_colorblind (ZoomRegion *zoom_region, gshort colorblind) 02641 { 02642 zoom_region->color_blind_filter = colorblind; 02643 zoom_region_update_current (zoom_region); 02644 02645 return TRUE; 02646 } 02647 02648 gshort 02649 impl_dbus_zoom_region_get_colorblind (ZoomRegion *zoom_region) 02650 { 02651 return zoom_region->color_blind_filter; 02652 } 02653 02654 gboolean 02655 impl_dbus_zoom_region_set_smoothing (ZoomRegion *zoom_region, gchar *smoothing) 02656 { 02657 zoom_region->smoothing = g_strdup (smoothing); 02658 if (!strncmp (zoom_region->smoothing, "bilinear", 8)) { 02659 zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR; 02660 } else { 02661 zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST; 02662 } 02663 zoom_region_update_current (zoom_region); 02664 02665 return TRUE; 02666 } 02667 02668 gchar* 02669 impl_dbus_zoom_region_get_smoothing (ZoomRegion *zoom_region) 02670 { 02671 return g_strdup (zoom_region->smoothing); 02672 } 02673 02674 gboolean 02675 impl_dbus_zoom_region_set_testpattern (ZoomRegion *zoom_region, gboolean test) 02676 { 02677 zoom_region->priv->test = test; 02678 if (zoom_region->priv->source_drawable) { 02679 g_object_unref (zoom_region->priv->source_drawable); 02680 zoom_region->priv->source_drawable = NULL; 02681 } 02682 zoom_region_update_current (zoom_region); 02683 02684 return TRUE; 02685 } 02686 02687 gboolean 02688 impl_dbus_zoom_region_get_testpattern (ZoomRegion *zoom_region) 02689 { 02690 return zoom_region->priv->test; 02691 } 02692 02693 gboolean 02694 impl_dbus_zoom_region_set_bordersizes (ZoomRegion *zoom_region, gint32 **bordersizes) 02695 { 02696 zoom_region->border_size_left = (*bordersizes)[0]; 02697 zoom_region->border_size_top = (*bordersizes)[1]; 02698 zoom_region->border_size_right = (*bordersizes)[2]; 02699 zoom_region->border_size_bottom = (*bordersizes)[3]; 02700 zoom_region_update_borders (zoom_region); 02701 02702 return TRUE; 02703 } 02704 02705 GArray* 02706 impl_dbus_zoom_region_get_bordersizes (ZoomRegion *zoom_region) 02707 { 02708 GArray *ret; 02709 02710 ret = g_array_new (FALSE, FALSE, sizeof (gint32)); 02711 02712 g_array_append_val (ret, zoom_region->border_size_left); 02713 g_array_append_val (ret, zoom_region->border_size_top); 02714 g_array_append_val (ret, zoom_region->border_size_right); 02715 g_array_append_val (ret, zoom_region->border_size_bottom); 02716 02717 return ret; 02718 } 02719 02720 gboolean 02721 impl_dbus_zoom_region_set_bordercolor (ZoomRegion *zoom_region, guint32 bordercolor) 02722 { 02723 zoom_region->border_color = bordercolor; 02724 zoom_region_paint_border (zoom_region); 02725 02726 return TRUE; 02727 } 02728 02729 guint32 02730 impl_dbus_zoom_region_get_bordercolor (ZoomRegion *zoom_region) 02731 { 02732 return zoom_region->border_color; 02733 } 02734 02735 gboolean 02736 impl_dbus_zoom_region_set_xalign (ZoomRegion *zoom_region, gint32 align) 02737 { 02738 zoom_region->x_align_policy = align; 02739 zoom_region_align (zoom_region); 02740 02741 return TRUE; 02742 } 02743 02744 gint32 02745 impl_dbus_zoom_region_get_xalign (ZoomRegion *zoom_region) 02746 { 02747 return zoom_region->x_align_policy; 02748 } 02749 02750 gboolean 02751 impl_dbus_zoom_region_set_yalign (ZoomRegion *zoom_region, gint32 align) 02752 { 02753 zoom_region->y_align_policy = align; 02754 zoom_region_align (zoom_region); 02755 02756 return TRUE; 02757 } 02758 02759 gint32 02760 impl_dbus_zoom_region_get_yalign (ZoomRegion *zoom_region) 02761 { 02762 return zoom_region->y_align_policy; 02763 } 02764 02765 gboolean 02766 impl_dbus_zoom_region_set_viewport (ZoomRegion *zoom_region, gint32 **viewport) 02767 { 02768 GNOME_Magnifier_RectBounds *bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds)); 02769 02770 bounds->x1 = (*viewport)[0]; 02771 bounds->y1 = (*viewport)[1]; 02772 bounds->x2 = (*viewport)[2]; 02773 bounds->y2 = (*viewport)[3]; 02774 02775 zoom_region_set_viewport (zoom_region, bounds); 02776 02777 g_free (bounds); 02778 02779 return TRUE; 02780 } 02781 02782 GArray* 02783 impl_dbus_zoom_region_get_viewport (ZoomRegion *zoom_region) 02784 { 02785 GArray *ret; 02786 02787 ret = g_array_new (FALSE, FALSE, sizeof (gint32)); 02788 02789 g_array_append_val (ret, zoom_region->viewport.x1); 02790 g_array_append_val (ret, zoom_region->viewport.y1); 02791 g_array_append_val (ret, zoom_region->viewport.x2); 02792 g_array_append_val (ret, zoom_region->viewport.y2); 02793 02794 return ret; 02795 } 02796 02797 gboolean 02798 impl_dbus_zoom_region_set_timing_test (ZoomRegion *zoom_region, gint32 timing_iterations) 02799 { 02800 zoom_region->timing_iterations = timing_iterations; 02801 timing_test = TRUE; 02802 02803 return TRUE; 02804 } 02805 02806 gint32 02807 impl_dbus_zoom_region_get_timing_test (ZoomRegion *zoom_region) 02808 { 02809 return zoom_region->timing_iterations; 02810 } 02811 02812 gboolean 02813 impl_dbus_zoom_region_set_timing_output (ZoomRegion *zoom_region, gboolean timing_output) 02814 { 02815 zoom_region->timing_output = timing_output; 02816 02817 return TRUE; 02818 } 02819 02820 gboolean 02821 impl_dbus_zoom_region_get_timing_output (ZoomRegion *zoom_region) 02822 { 02823 return zoom_region->timing_output; 02824 } 02825 02826 gboolean 02827 impl_dbus_zoom_region_set_timing_pan_rate (ZoomRegion *zoom_region, gint32 timing_pan_rate) 02828 { 02829 zoom_region->timing_pan_rate = timing_pan_rate; 02830 timing_test = TRUE; 02831 02832 return TRUE; 02833 } 02834 02835 gint32 02836 impl_dbus_zoom_region_get_timing_pan_rate (ZoomRegion *zoom_region) 02837 { 02838 return zoom_region->timing_pan_rate; 02839 } 02840 02841 gboolean 02842 impl_dbus_zoom_region_set_exit_magnifier (ZoomRegion *zoom_region, gboolean exit_magnifier) 02843 { 02844 zoom_region->exit_magnifier = exit_magnifier; 02845 02846 return TRUE; 02847 } 02848 02849 gboolean 02850 impl_dbus_zoom_region_get_exit_magnifier (ZoomRegion *zoom_region) 02851 { 02852 return zoom_region->exit_magnifier; 02853 } 02854 02855 static void 02856 zoom_region_set_property (BonoboPropertyBag *bag, 02857 BonoboArg *arg, 02858 guint arg_id, 02859 CORBA_Environment *ev, 02860 gpointer user_data) 02861 { 02862 ZoomRegion *zoom_region = user_data; 02863 GNOME_Magnifier_RectBounds bounds; 02864 gfloat t; 02865 02866 #ifdef ZOOM_REGION_DEBUG 02867 g_assert (zoom_region->alive); 02868 #endif 02869 DBG (fprintf (stderr, "Set zoom-region property: %s\n", prop_names[arg_id])); 02870 02871 switch (arg_id) { 02872 case ZOOM_REGION_MANAGED_PROP: 02873 zoom_region->is_managed = BONOBO_ARG_GET_BOOLEAN (arg); 02874 break; 02875 case ZOOM_REGION_POLL_MOUSE_PROP: 02876 zoom_region->poll_mouse = BONOBO_ARG_GET_BOOLEAN (arg); 02877 if (zoom_region->poll_mouse) 02878 { 02879 g_message ("Adding polling timer"); 02880 zoom_region->priv->update_pointer_id = 02881 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 02882 200, 02883 zoom_region_update_pointer_timeout, 02884 zoom_region, 02885 NULL); 02886 } 02887 else if (zoom_region->priv->update_pointer_id) 02888 { 02889 g_message ("Removing polling timer"); 02890 g_source_remove (zoom_region->priv->update_pointer_id); 02891 zoom_region->priv->update_pointer_id = 0; 02892 } 02893 break; 02894 case ZOOM_REGION_DRAW_CURSOR_PROP: 02895 zoom_region->draw_cursor = BONOBO_ARG_GET_BOOLEAN (arg); 02896 if (!zoom_region->draw_cursor) 02897 zoom_region_unpaint_cursor (zoom_region, NULL); 02898 break; 02899 case ZOOM_REGION_INVERT_PROP: 02900 zoom_region->invert = BONOBO_ARG_GET_BOOLEAN (arg); 02901 zoom_region_update_current (zoom_region); 02902 break; 02903 case ZOOM_REGION_SMOOTHSCROLL_PROP: 02904 zoom_region->smooth_scroll_policy = BONOBO_ARG_GET_SHORT (arg); 02905 break; 02906 case ZOOM_REGION_COLORBLIND_PROP: 02907 zoom_region->color_blind_filter = BONOBO_ARG_GET_SHORT (arg); 02908 zoom_region_update_current (zoom_region); 02909 break; 02910 case ZOOM_REGION_SMOOTHING_PROP: 02911 zoom_region->smoothing = BONOBO_ARG_GET_STRING (arg); 02912 if (!strncmp (zoom_region->smoothing, "bilinear", 8)) 02913 zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR; 02914 else 02915 zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST; 02916 zoom_region_update_current (zoom_region); 02917 break; 02918 case ZOOM_REGION_TESTPATTERN_PROP: 02919 zoom_region->priv->test = BONOBO_ARG_GET_BOOLEAN (arg); 02920 if (zoom_region->priv->source_drawable) { 02921 g_object_unref (zoom_region->priv->source_drawable); 02922 zoom_region->priv->source_drawable = NULL; 02923 } 02924 zoom_region_update_current (zoom_region); 02925 break; 02926 case ZOOM_REGION_CONTRASTR_PROP: 02927 zoom_region->contrast_r = 02928 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02929 zoom_region_update_current (zoom_region); 02930 break; 02931 case ZOOM_REGION_CONTRASTG_PROP: 02932 zoom_region->contrast_g = 02933 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02934 zoom_region_update_current (zoom_region); 02935 break; 02936 case ZOOM_REGION_CONTRASTB_PROP: 02937 zoom_region->contrast_b = 02938 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02939 zoom_region_update_current (zoom_region); 02940 break; 02941 case ZOOM_REGION_BRIGHTR_PROP: 02942 zoom_region->bright_r = 02943 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02944 zoom_region_update_current (zoom_region); 02945 break; 02946 case ZOOM_REGION_BRIGHTG_PROP: 02947 zoom_region->bright_g = 02948 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02949 zoom_region_update_current (zoom_region); 02950 break; 02951 case ZOOM_REGION_BRIGHTB_PROP: 02952 zoom_region->bright_b = 02953 CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg)); 02954 zoom_region_update_current (zoom_region); 02955 break; 02956 case ZOOM_REGION_XSCALE_PROP: 02957 (void) zoom_region_update_scale (zoom_region, 02958 BONOBO_ARG_GET_FLOAT (arg), 02959 zoom_region->yscale); 02960 break; 02961 case ZOOM_REGION_YSCALE_PROP: 02962 (void) zoom_region_update_scale (zoom_region, 02963 zoom_region->xscale, 02964 BONOBO_ARG_GET_FLOAT (arg)); 02965 02966 break; 02967 case ZOOM_REGION_BORDERSIZE_PROP: 02968 zoom_region->border_size_left = 02969 zoom_region->border_size_top = 02970 zoom_region->border_size_right = 02971 zoom_region->border_size_bottom = 02972 BONOBO_ARG_GET_LONG (arg); 02973 zoom_region_update_borders (zoom_region); 02974 break; 02975 case ZOOM_REGION_BORDERSIZELEFT_PROP: 02976 zoom_region->border_size_left = BONOBO_ARG_GET_LONG (arg); 02977 zoom_region_update_borders (zoom_region); 02978 break; 02979 case ZOOM_REGION_BORDERSIZETOP_PROP: 02980 zoom_region->border_size_top = BONOBO_ARG_GET_LONG (arg); 02981 zoom_region_update_borders (zoom_region); 02982 break; 02983 case ZOOM_REGION_BORDERSIZERIGHT_PROP: 02984 zoom_region->border_size_right = BONOBO_ARG_GET_LONG (arg); 02985 zoom_region_update_borders (zoom_region); 02986 break; 02987 case ZOOM_REGION_BORDERSIZEBOTTOM_PROP: 02988 zoom_region->border_size_bottom = BONOBO_ARG_GET_LONG (arg); 02989 zoom_region_update_borders (zoom_region); 02990 break; 02991 case ZOOM_REGION_BORDERCOLOR_PROP: 02992 zoom_region->border_color = 02993 BONOBO_ARG_GET_LONG (arg); 02994 zoom_region_paint_border (zoom_region); 02995 break; 02996 case ZOOM_REGION_XALIGN_PROP: 02997 zoom_region->x_align_policy = BONOBO_ARG_GET_INT (arg); 02998 zoom_region_align (zoom_region); 02999 break; 03000 case ZOOM_REGION_YALIGN_PROP: 03001 /* TODO: enums here */ 03002 zoom_region->y_align_policy = BONOBO_ARG_GET_INT (arg); 03003 zoom_region_align (zoom_region); 03004 break; 03005 case ZOOM_REGION_VIEWPORT_PROP: 03006 bounds = BONOBO_ARG_GET_GENERAL (arg, 03007 TC_GNOME_Magnifier_RectBounds, 03008 GNOME_Magnifier_RectBounds, 03009 NULL); 03010 zoom_region_set_viewport (zoom_region, &bounds); 03011 break; 03012 case ZOOM_REGION_TIMING_TEST_PROP: 03013 zoom_region->timing_iterations = BONOBO_ARG_GET_INT (arg); 03014 timing_test = TRUE; 03015 break; 03016 case ZOOM_REGION_TIMING_OUTPUT_PROP: 03017 zoom_region->timing_output = BONOBO_ARG_GET_BOOLEAN (arg); 03018 break; 03019 case ZOOM_REGION_TIMING_PAN_RATE_PROP: 03020 zoom_region->timing_pan_rate = BONOBO_ARG_GET_INT (arg); 03021 timing_test = TRUE; 03022 break; 03023 case ZOOM_REGION_EXIT_MAGNIFIER: 03024 zoom_region->exit_magnifier = BONOBO_ARG_GET_BOOLEAN (arg); 03025 break; 03026 default: 03027 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound); 03028 }; 03029 } 03030 03031 static int 03032 zoom_region_process_pending (gpointer data) 03033 { 03034 ZoomRegion *zoom_region = (ZoomRegion *) data; 03035 03036 #ifdef ZOOM_REGION_DEBUG 03037 g_assert (zoom_region->alive); 03038 #endif 03039 zoom_region_align (zoom_region); 03040 return FALSE; 03041 } 03042 03043 static int 03044 zoom_region_pan_test (gpointer data) 03045 { 03046 ZoomRegion *zoom_region = (ZoomRegion *) data; 03047 Magnifier *magnifier = zoom_region->priv->parent; 03048 GNOME_Magnifier_ZoomRegionList *zoom_regions; 03049 GNOME_Magnifier_RectBounds roi; 03050 CORBA_Environment ev; 03051 static int counter = 0; 03052 static gboolean finished_update = !TRUE; 03053 static float last_pixels_at_speed = -1; 03054 float pixels_at_speed; 03055 float total_time; 03056 int screen_height, height; 03057 int pixel_position; 03058 int pixel_direction; 03059 03060 screen_height = gdk_screen_get_height ( 03061 gdk_display_get_screen (magnifier->source_display, 03062 magnifier->source_screen_num)); 03063 03064 height = (zoom_region->viewport.y2 - 03065 zoom_region->viewport.y1) / zoom_region->yscale; 03066 03067 roi.x1 = zoom_region->roi.x1; 03068 roi.x2 = zoom_region->roi.x2; 03069 03070 g_timer_stop (mag_timing.process); 03071 03072 gulong microseconds; 03073 03074 total_time = g_timer_elapsed (mag_timing.process, µseconds); 03075 03076 if (mag_timing.frame_total != 0.0) 03077 pixels_at_speed = total_time * zoom_region->timing_pan_rate; 03078 else 03079 pixels_at_speed = 0.0; 03080 03081 /* Wait until it is actually necessary to update the screen */ 03082 if ((int)(last_pixels_at_speed) == (int)(pixels_at_speed)) 03083 return TRUE; 03084 03085 pixel_position = (int)(pixels_at_speed) % (screen_height - height); 03086 counter = (int)(pixels_at_speed) / (screen_height - height); 03087 pixel_direction = counter % 2; 03088 03089 if (!finished_update) { 03090 if ((int)(pixels_at_speed) > (zoom_region->roi.y1 + height)) 03091 roi.y1 = zoom_region->roi.y1 + height; 03092 else 03093 roi.y1 = (int)(pixels_at_speed); 03094 03095 if (roi.y1 >= screen_height - height) { 03096 roi.y1 = screen_height - height; 03097 } 03098 } else { 03099 if (pixel_direction == 0) 03100 roi.y1 = screen_height - height - pixel_position; 03101 else 03102 roi.y1 = pixel_position; 03103 } 03104 03105 roi.y2 = roi.y1 + height; 03106 magnifier->priv->cursor_x = (roi.x2 + roi.x1) / 2; 03107 magnifier->priv->cursor_y = (roi.y2 + roi.y1) / 2; 03108 03109 /* Add one since in first loop we call zoom_region_process_updates */ 03110 if (counter > zoom_region->timing_iterations - 1) 03111 zoom_region->exit_magnifier = TRUE; 03112 03113 zoom_regions = GNOME_Magnifier_Magnifier_getZoomRegions ( 03114 BONOBO_OBJREF (magnifier), &ev); 03115 03116 if (zoom_regions && (zoom_regions->_length > 0)) { 03117 GNOME_Magnifier_ZoomRegion_setROI ( 03118 zoom_regions->_buffer[0], &roi, &ev); 03119 } 03120 03121 if (!finished_update) { 03122 zoom_region_process_updates(zoom_region); 03123 if (roi.y1 == screen_height - height) { 03124 finished_update = TRUE; 03125 reset_timing = TRUE; 03126 } 03127 } 03128 03129 last_pixels_at_speed = pixels_at_speed; 03130 03131 return FALSE; 03132 } 03133 03134 static void 03135 impl_zoom_region_set_pointer_pos (PortableServer_Servant servant, 03136 const CORBA_long mouse_x, 03137 const CORBA_long mouse_y, 03138 CORBA_Environment *ev) 03139 { 03140 ZoomRegion *zoom_region = 03141 ZOOM_REGION (bonobo_object_from_servant (servant)); 03142 GdkRectangle paint_area, *clip = NULL; 03143 03144 #ifdef ZOOM_REGION_DEBUG 03145 g_assert (zoom_region->alive); 03146 #endif 03147 DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 03148 (long) mouse_x, (long) mouse_y)); 03149 03150 fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 03151 (long) mouse_x, (long) mouse_y); 03152 03153 zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y); 03154 03155 if (GTK_IS_WIDGET (zoom_region->priv->w) && 03156 GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 03157 { 03158 gdk_drawable_get_size ( 03159 GDK_DRAWABLE ( 03160 gtk_widget_get_window (zoom_region->priv->w)), 03161 &paint_area.width, &paint_area.height); 03162 paint_area.x = 0; 03163 paint_area.y = 0; 03164 clip = &paint_area; 03165 paint_area = zoom_region_clip_to_source ( 03166 zoom_region, paint_area); 03167 } 03168 /* 03169 * if we update the cursor now, it causes flicker if the client 03170 * subsequently calls setROI, so we wait for a redraw. 03171 * Perhaps we should cue a redraw on idle instead? 03172 */ 03173 } 03174 03175 static void 03176 impl_zoom_region_set_contrast (PortableServer_Servant servant, 03177 const CORBA_float R, 03178 const CORBA_float G, 03179 const CORBA_float B, 03180 CORBA_Environment *ev) 03181 { 03182 ZoomRegion *zoom_region = 03183 ZOOM_REGION (bonobo_object_from_servant (servant)); 03184 gfloat t; 03185 03186 #ifdef ZOOM_REGION_DEBUG 03187 g_assert (zoom_region->alive); 03188 #endif 03189 DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B)); 03190 03191 /* if the contrast values are the same, this is a NOOP */ 03192 if (zoom_region->contrast_r == R && 03193 zoom_region->contrast_g == G && 03194 zoom_region->contrast_b == B) 03195 return; 03196 03197 zoom_region->contrast_r = CLAMP_B_C (R); 03198 zoom_region->contrast_g = CLAMP_B_C (G); 03199 zoom_region->contrast_b = CLAMP_B_C (B); 03200 03201 zoom_region_update_current (zoom_region); 03202 } 03203 03204 static void 03205 impl_zoom_region_get_contrast (PortableServer_Servant servant, 03206 CORBA_float *R, 03207 CORBA_float *G, 03208 CORBA_float *B, 03209 CORBA_Environment *ev) 03210 { 03211 ZoomRegion *zoom_region = 03212 ZOOM_REGION (bonobo_object_from_servant (servant)); 03213 03214 #ifdef ZOOM_REGION_DEBUG 03215 g_assert (zoom_region->alive); 03216 #endif 03217 03218 *R = zoom_region->contrast_r; 03219 *G = zoom_region->contrast_g; 03220 *B = zoom_region->contrast_b; 03221 } 03222 03223 static void 03224 impl_zoom_region_set_brightness (PortableServer_Servant servant, 03225 const CORBA_float R, 03226 const CORBA_float G, 03227 const CORBA_float B, 03228 CORBA_Environment *ev) 03229 { 03230 ZoomRegion *zoom_region = 03231 ZOOM_REGION (bonobo_object_from_servant (servant)); 03232 gfloat t; 03233 03234 #ifdef ZOOM_REGION_DEBUG 03235 g_assert (zoom_region->alive); 03236 #endif 03237 DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B)); 03238 03239 /* if the contrast values are the same, this is a NOOP */ 03240 if (zoom_region->bright_r == R && 03241 zoom_region->bright_g == G && 03242 zoom_region->bright_b == B) 03243 return; 03244 03245 zoom_region->bright_r = CLAMP_B_C (R); 03246 zoom_region->bright_g = CLAMP_B_C (G); 03247 zoom_region->bright_b = CLAMP_B_C (B); 03248 03249 zoom_region_update_current (zoom_region); 03250 } 03251 03252 static void 03253 impl_zoom_region_get_brightness (PortableServer_Servant servant, 03254 CORBA_float *R, 03255 CORBA_float *G, 03256 CORBA_float *B, 03257 CORBA_Environment *ev) 03258 { 03259 ZoomRegion *zoom_region = 03260 ZOOM_REGION (bonobo_object_from_servant (servant)); 03261 03262 #ifdef ZOOM_REGION_DEBUG 03263 g_assert (zoom_region->alive); 03264 #endif 03265 03266 *R = zoom_region->bright_r; 03267 *G = zoom_region->bright_g; 03268 *B = zoom_region->bright_b; 03269 } 03270 03271 static void 03272 impl_zoom_region_set_roi (PortableServer_Servant servant, 03273 const GNOME_Magnifier_RectBounds *bounds, 03274 CORBA_Environment *ev) 03275 { 03276 ZoomRegion *zoom_region = 03277 ZOOM_REGION (bonobo_object_from_servant (servant)); 03278 03279 #ifdef ZOOM_REGION_DEBUG 03280 g_assert (zoom_region->alive); 03281 #endif 03282 DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n", 03283 bounds->x1, bounds->y1, bounds->x2, bounds->y2)); 03284 03285 if ((zoom_region->roi.x1 == bounds->x1) && 03286 (zoom_region->roi.x2 == bounds->x2) && 03287 (zoom_region->roi.y1 == bounds->y1) && 03288 (zoom_region->roi.y2 == bounds->y2)) { 03289 return; 03290 } 03291 03292 /* if these bounds are clearly bogus, warn and ignore */ 03293 if (!bounds || (bounds->x2 <= bounds->x1) 03294 || (bounds->y2 < bounds->y1) || 03295 ((bounds->x1 + bounds->x2)/2 < 0) || 03296 ((bounds->y1 + bounds->y2)/2 < 0)) 03297 { 03298 g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n", 03299 bounds->x1, bounds->y1, bounds->x2, bounds->y2); 03300 return; 03301 } 03302 03303 zoom_region->roi = *bounds; 03304 03305 if (zoom_region->timing_pan_rate > 0) { 03306 /* Set idle handler to do panning test */ 03307 g_idle_add_full (GDK_PRIORITY_REDRAW + 3, 03308 zoom_region_pan_test, zoom_region, NULL); 03309 } 03310 03311 if (zoom_region->exit_magnifier) { 03312 if (timing_test) { 03313 fprintf(stderr, "\n### Timing Summary:\n\n"); 03314 if (zoom_region->timing_pan_rate) 03315 fprintf(stderr, " Pan Rate = %d\n", zoom_region->timing_pan_rate); 03316 timing_report(zoom_region); 03317 } 03318 exit(0); 03319 } 03320 03321 /* 03322 * Do not bother trying to update the screen if the last 03323 * screen update has not had time to complete. 03324 */ 03325 if (processing_updates) { 03326 /* Remove any previous idle handler */ 03327 if (pending_idle_handler != 0) { 03328 g_source_remove(pending_idle_handler); 03329 pending_idle_handler = 0; 03330 } 03331 03332 /* Set idle handler to process this pending update when possible */ 03333 03334 pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2, 03335 zoom_region_process_pending, zoom_region, NULL); 03336 03337 if (zoom_region->timing_output) { 03338 fprintf(stderr, 03339 "\n [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n", 03340 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2, 03341 zoom_region->roi.y2); 03342 } 03343 } else { 03344 zoom_region_align (zoom_region); 03345 } 03346 } 03347 03348 static CORBA_boolean 03349 impl_zoom_region_set_mag_factor (PortableServer_Servant servant, 03350 const CORBA_float mag_factor_x, 03351 const CORBA_float mag_factor_y, 03352 CORBA_Environment *ev) 03353 { 03354 ZoomRegion *zoom_region = 03355 ZOOM_REGION (bonobo_object_from_servant (servant)); 03356 03357 #ifdef ZOOM_REGION_DEBUG 03358 g_assert (zoom_region->alive); 03359 #endif 03360 CORBA_any *any; 03361 CORBA_boolean retval = CORBA_TRUE; 03362 03363 if ((zoom_region->xscale == mag_factor_x) && 03364 (zoom_region->yscale == mag_factor_y)) { 03365 return retval; 03366 } 03367 03368 /* TODO: assert that parent is magnifier object */ 03369 Bonobo_PropertyBag properties = 03370 GNOME_Magnifier_Magnifier_getProperties( 03371 BONOBO_OBJREF ( 03372 (Magnifier *) zoom_region->priv->parent), ev); 03373 any = Bonobo_PropertyBag_getValue ( 03374 properties, "source-display-bounds", ev); 03375 if (!BONOBO_EX (ev)) 03376 zoom_region->priv->source_area = 03377 *((GNOME_Magnifier_RectBounds *) any->_value); 03378 else 03379 retval = CORBA_FALSE; 03380 03381 retval = zoom_region_update_scale (zoom_region, 03382 mag_factor_x, mag_factor_y); 03383 zoom_region_sync (zoom_region); 03384 03385 bonobo_object_release_unref (properties, NULL); 03386 return retval; 03387 } 03388 03389 static void 03390 impl_zoom_region_get_mag_factor (PortableServer_Servant servant, 03391 CORBA_float *mag_factor_x, 03392 CORBA_float *mag_factor_y, 03393 CORBA_Environment *ev) 03394 { 03395 ZoomRegion *zoom_region = 03396 ZOOM_REGION (bonobo_object_from_servant (servant)); 03397 03398 #ifdef ZOOM_REGION_DEBUG 03399 g_assert (zoom_region->alive); 03400 #endif 03401 *mag_factor_x = zoom_region->xscale; 03402 *mag_factor_y = zoom_region->yscale; 03403 } 03404 03405 static Bonobo_PropertyBag 03406 impl_zoom_region_get_properties (PortableServer_Servant servant, 03407 CORBA_Environment *ev) 03408 { 03409 ZoomRegion *zoom_region = 03410 ZOOM_REGION (bonobo_object_from_servant (servant)); 03411 03412 #ifdef ZOOM_REGION_DEBUG 03413 g_assert (zoom_region->alive); 03414 #endif 03415 return bonobo_object_dup_ref ( 03416 BONOBO_OBJREF (zoom_region->properties), ev); 03417 } 03418 03419 static void 03420 impl_zoom_region_update_pointer (PortableServer_Servant servant, 03421 CORBA_Environment *ev) 03422 { 03423 ZoomRegion *zoom_region = 03424 ZOOM_REGION (bonobo_object_from_servant (servant)); 03425 03426 #ifdef ZOOM_REGION_DEBUG 03427 g_assert (zoom_region->alive); 03428 #endif 03429 03430 zoom_region_update_cursor (zoom_region, 0, 0, NULL); 03431 } 03432 03433 static void 03434 impl_zoom_region_mark_dirty (PortableServer_Servant servant, 03435 const GNOME_Magnifier_RectBounds *roi_dirty, 03436 CORBA_Environment *ev) 03437 { 03438 ZoomRegion *zoom_region = 03439 ZOOM_REGION (bonobo_object_from_servant (servant)); 03440 03441 #ifdef ZOOM_REGION_DEBUG 03442 g_assert (zoom_region->alive); 03443 #endif 03444 DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds ( 03445 zoom_region, roi_dirty) ); 03446 03447 zoom_region_update_pointer (zoom_region, TRUE); 03448 /* XXX ? should we clip here, or wait till process_updates? */ 03449 zoom_region_queue_update (zoom_region, 03450 zoom_region_clip_to_source (zoom_region, 03451 zoom_region_rect_from_bounds (zoom_region, roi_dirty))); 03452 } 03453 03454 static GNOME_Magnifier_RectBounds 03455 impl_zoom_region_get_roi (PortableServer_Servant servant, 03456 CORBA_Environment *ev) 03457 { 03458 ZoomRegion *zoom_region = 03459 ZOOM_REGION (bonobo_object_from_servant (servant)); 03460 03461 #ifdef ZOOM_REGION_DEBUG 03462 g_assert (zoom_region->alive); 03463 #endif 03464 return zoom_region->roi; 03465 } 03466 03467 static void 03468 impl_zoom_region_move_resize (PortableServer_Servant servant, 03469 const GNOME_Magnifier_RectBounds *viewport_bounds, 03470 CORBA_Environment *ev) 03471 { 03472 ZoomRegion *zoom_region = 03473 ZOOM_REGION (bonobo_object_from_servant (servant)); 03474 03475 #ifdef ZOOM_REGION_DEBUG 03476 g_assert (zoom_region->alive); 03477 #endif 03478 zoom_region_set_viewport (zoom_region, viewport_bounds); 03479 } 03480 03481 /* could be called multiple times... */ 03482 static void 03483 zoom_region_do_dispose (ZoomRegion *zoom_region) 03484 { 03485 DBG(g_message ("disposing region %p", zoom_region)); 03486 if (zoom_region->priv && zoom_region->priv->expose_handler_id && 03487 GTK_IS_WIDGET (zoom_region->priv->w)) { 03488 g_signal_handler_disconnect ( 03489 zoom_region->priv->w, 03490 zoom_region->priv->expose_handler_id); 03491 zoom_region->priv->expose_handler_id = 0; 03492 } 03493 if (zoom_region->priv && zoom_region->priv->update_pointer_id) 03494 g_source_remove (zoom_region->priv->update_pointer_id); 03495 if (zoom_region->priv && zoom_region->priv->update_handler_id) 03496 g_source_remove (zoom_region->priv->update_handler_id); 03497 g_idle_remove_by_data (zoom_region); 03498 03499 #ifdef ZOOM_REGION_DEBUG 03500 zoom_region->alive = FALSE; 03501 #endif 03502 } 03503 03504 static void 03505 impl_zoom_region_dispose (PortableServer_Servant servant, 03506 CORBA_Environment *ev) 03507 { 03508 ZoomRegion *zoom_region = 03509 ZOOM_REGION (bonobo_object_from_servant (servant)); 03510 zoom_region_do_dispose (zoom_region); 03511 } 03512 03513 gboolean 03514 impl_dbus_zoom_region_dispose (ZoomRegion *zoom_region) 03515 { 03516 zoom_region_do_dispose (zoom_region); 03517 03518 return TRUE; 03519 } 03520 03521 gboolean 03522 impl_dbus_zoom_region_set_mag_factor (ZoomRegion *zoom_region, const gdouble mag_factor_x, const gdouble mag_factor_y) 03523 { 03524 #ifdef ZOOM_REGION_DEBUG 03525 g_assert (zoom_region->alive); 03526 #endif 03527 CORBA_Environment ev; 03528 CORBA_exception_init (&ev); 03529 CORBA_any *any; 03530 gboolean retval = TRUE; 03531 03532 if ((zoom_region->xscale == mag_factor_x) && 03533 (zoom_region->yscale == mag_factor_y)) { 03534 return retval; 03535 } 03536 03537 /* TODO: assert that parent is magnifier object */ 03538 Bonobo_PropertyBag properties = 03539 GNOME_Magnifier_Magnifier_getProperties( 03540 BONOBO_OBJREF ( 03541 (Magnifier *) zoom_region->priv->parent), &ev); 03542 any = Bonobo_PropertyBag_getValue ( 03543 properties, "source-display-bounds", &ev); 03544 if (!BONOBO_EX (&ev)) 03545 zoom_region->priv->source_area = 03546 *((GNOME_Magnifier_RectBounds *) any->_value); 03547 else { 03548 retval = FALSE; 03549 return retval; 03550 } 03551 03552 retval = zoom_region_update_scale (zoom_region, mag_factor_x, mag_factor_y); 03553 zoom_region_sync (zoom_region); 03554 03555 return retval; 03556 } 03557 03558 GArray* 03559 impl_dbus_zoom_region_get_mag_factor (ZoomRegion *zoom_region) 03560 { 03561 GArray *ret; 03562 03563 ret = g_array_new (FALSE, FALSE, sizeof (gdouble)); 03564 03565 g_array_append_val (ret, zoom_region->xscale); 03566 g_array_append_val (ret, zoom_region->yscale); 03567 03568 return ret; 03569 } 03570 03571 gboolean 03572 impl_dbus_zoom_region_set_roi (ZoomRegion *zoom_region, const gint32 **roi) 03573 { 03574 RectBounds *bounds = g_malloc(sizeof(RectBounds)); 03575 _set_bounds (bounds, roi); 03576 03577 #ifdef ZOOM_REGION_DEBUG 03578 g_assert (zoom_region->alive); 03579 #endif 03580 DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n", 03581 bounds->x1, bounds->y1, bounds->x2, bounds->y2)); 03582 03583 if ((zoom_region->roi.x1 == bounds->x1) && 03584 (zoom_region->roi.x2 == bounds->x2) && 03585 (zoom_region->roi.y1 == bounds->y1) && 03586 (zoom_region->roi.y2 == bounds->y2)) { 03587 return TRUE; 03588 } 03589 03590 /* if these bounds are clearly bogus, warn and ignore */ 03591 if (!bounds || (bounds->x2 <= bounds->x1) 03592 || (bounds->y2 < bounds->y1) || 03593 ((bounds->x1 + bounds->x2)/2 < 0) || 03594 ((bounds->y1 + bounds->y2)/2 < 0)) 03595 { 03596 g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n", 03597 bounds->x1, bounds->y1, bounds->x2, bounds->y2); 03598 return FALSE; 03599 } 03600 03601 zoom_region->roi.x1 = bounds->x1; 03602 zoom_region->roi.y1 = bounds->y1; 03603 zoom_region->roi.x2 = bounds->x2; 03604 zoom_region->roi.y2 = bounds->y2; 03605 03606 if (zoom_region->timing_pan_rate > 0) { 03607 /* Set idle handler to do panning test */ 03608 g_idle_add_full (GDK_PRIORITY_REDRAW + 3, 03609 zoom_region_pan_test, zoom_region, NULL); 03610 } 03611 03612 if (zoom_region->exit_magnifier) { 03613 if (timing_test) { 03614 fprintf(stderr, "\n### Timing Summary:\n\n"); 03615 if (zoom_region->timing_pan_rate) 03616 fprintf(stderr, " Pan Rate = %d\n", zoom_region->timing_pan_rate); 03617 timing_report(zoom_region); 03618 } 03619 exit(0); 03620 } 03621 03622 /* 03623 * Do not bother trying to update the screen if the last 03624 * screen update has not had time to complete. 03625 */ 03626 if (processing_updates) { 03627 /* Remove any previous idle handler */ 03628 if (pending_idle_handler != 0) { 03629 g_source_remove(pending_idle_handler); 03630 pending_idle_handler = 0; 03631 } 03632 03633 /* Set idle handler to process this pending update when possible */ 03634 03635 pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2, 03636 zoom_region_process_pending, zoom_region, NULL); 03637 03638 if (zoom_region->timing_output) { 03639 fprintf(stderr, 03640 "\n [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n", 03641 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2, 03642 zoom_region->roi.y2); 03643 } 03644 } else { 03645 zoom_region_align (zoom_region); 03646 } 03647 03648 return TRUE; 03649 } 03650 03651 /* TODO: Deprecate this RPC */ 03652 gboolean 03653 impl_dbus_zoom_region_update_pointer (ZoomRegion *zoom_region) 03654 { 03655 #ifdef ZOOM_REGION_DEBUG 03656 g_assert (zoom_region->alive); 03657 #endif 03658 03659 zoom_region_update_cursor (zoom_region, 0, 0, NULL); 03660 03661 return TRUE; 03662 } 03663 03664 gboolean 03665 impl_dbus_zoom_region_mark_dirty (ZoomRegion *zoom_region, gint32 **bounds) 03666 { 03667 GNOME_Magnifier_RectBounds *roi_dirty = g_malloc(sizeof(GNOME_Magnifier_RectBounds)); 03668 roi_dirty->x1 = (*bounds)[0]; 03669 roi_dirty->y1 = (*bounds)[1]; 03670 roi_dirty->x2 = (*bounds)[2]; 03671 roi_dirty->y2 = (*bounds)[3]; 03672 03673 #ifdef ZOOM_REGION_DEBUG 03674 g_assert (zoom_region->alive); 03675 #endif 03676 DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds ( 03677 zoom_region, roi_dirty) ); 03678 03679 zoom_region_update_pointer (zoom_region, TRUE); 03680 /* XXX ? should we clip here, or wait till process_updates? */ 03681 zoom_region_queue_update (zoom_region, 03682 zoom_region_clip_to_source (zoom_region, 03683 zoom_region_rect_from_bounds (zoom_region, roi_dirty))); 03684 03685 return TRUE; 03686 } 03687 03688 GArray* 03689 impl_dbus_zoom_region_get_roi (ZoomRegion *zoom_region) 03690 { 03691 GArray *ret; 03692 03693 ret = g_array_new (FALSE, FALSE, sizeof (gint32)); 03694 03695 g_array_append_val (ret, zoom_region->roi.x1); 03696 g_array_append_val (ret, zoom_region->roi.y1); 03697 g_array_append_val (ret, zoom_region->roi.x2); 03698 g_array_append_val (ret, zoom_region->roi.y2); 03699 03700 return ret; 03701 } 03702 03703 gboolean 03704 impl_dbus_zoom_region_move_resize (ZoomRegion *zoom_region, const gint32 **viewport) 03705 { 03706 #ifdef ZOOM_REGION_DEBUG 03707 g_assert (zoom_region->alive); 03708 #endif 03709 GNOME_Magnifier_RectBounds *viewport_bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds)); 03710 viewport_bounds->x1 = (*viewport)[0]; 03711 viewport_bounds->y1 = (*viewport)[1]; 03712 viewport_bounds->x2 = (*viewport)[2]; 03713 viewport_bounds->y2 = (*viewport)[3]; 03714 03715 zoom_region_set_viewport (zoom_region, viewport_bounds); 03716 03717 return TRUE; 03718 } 03719 03720 gboolean 03721 impl_dbus_zoom_region_set_pointer_pos (ZoomRegion *zoom_region, gint32 mouse_x, gint32 mouse_y) 03722 { 03723 GdkRectangle paint_area, *clip = NULL; 03724 03725 #ifdef ZOOM_REGION_DEBUG 03726 g_assert (zoom_region->alive); 03727 #endif 03728 DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 03729 (long) mouse_x, (long) mouse_y)); 03730 03731 fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 03732 (long) mouse_x, (long) mouse_y); 03733 03734 zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y); 03735 03736 if (GTK_IS_WIDGET (zoom_region->priv->w) && 03737 GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) 03738 { 03739 gdk_drawable_get_size ( 03740 GDK_DRAWABLE ( 03741 gtk_widget_get_window (zoom_region->priv->w)), 03742 &paint_area.width, &paint_area.height); 03743 paint_area.x = 0; 03744 paint_area.y = 0; 03745 clip = &paint_area; 03746 paint_area = zoom_region_clip_to_source ( 03747 zoom_region, paint_area); 03748 } 03749 /* 03750 * if we update the cursor now, it causes flicker if the client 03751 * subsequently calls setROI, so we wait for a redraw. 03752 * Perhaps we should cue a redraw on idle instead? 03753 */ 03754 03755 return TRUE; 03756 } 03757 03758 gboolean 03759 impl_dbus_zoom_region_set_contrast (ZoomRegion *zoom_region, gdouble R, gdouble G, gdouble B) 03760 { 03761 gfloat t; 03762 03763 #ifdef ZOOM_REGION_DEBUG 03764 g_assert (zoom_region->alive); 03765 #endif 03766 DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B)); 03767 03768 /* if the contrast values are the same, this is a NOOP */ 03769 if (zoom_region->contrast_r == R && 03770 zoom_region->contrast_g == G && 03771 zoom_region->contrast_b == B) 03772 return TRUE; 03773 03774 zoom_region->contrast_r = CLAMP_B_C (R); 03775 zoom_region->contrast_g = CLAMP_B_C (G); 03776 zoom_region->contrast_b = CLAMP_B_C (B); 03777 03778 zoom_region_update_current (zoom_region); 03779 03780 return TRUE; 03781 } 03782 03783 GArray* 03784 impl_dbus_zoom_region_get_contrast (ZoomRegion *zoom_region) 03785 { 03786 GArray *ret; 03787 03788 ret = g_array_new (FALSE, FALSE, sizeof (gdouble)); 03789 03790 g_array_append_val (ret, zoom_region->contrast_r); 03791 g_array_append_val (ret, zoom_region->contrast_g); 03792 g_array_append_val (ret, zoom_region->contrast_b); 03793 03794 return ret; 03795 } 03796 03797 gboolean 03798 impl_dbus_zoom_region_set_brightness (ZoomRegion *zoom_region, gdouble R, gdouble G, gdouble B) 03799 { 03800 gfloat t; 03801 03802 #ifdef ZOOM_REGION_DEBUG 03803 g_assert (zoom_region->alive); 03804 #endif 03805 DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B)); 03806 03807 /* if the contrast values are the same, this is a NOOP */ 03808 if (zoom_region->bright_r == R && 03809 zoom_region->bright_g == G && 03810 zoom_region->bright_b == B) 03811 return TRUE; 03812 03813 zoom_region->bright_r = CLAMP_B_C (R); 03814 zoom_region->bright_g = CLAMP_B_C (G); 03815 zoom_region->bright_b = CLAMP_B_C (B); 03816 03817 zoom_region_update_current (zoom_region); 03818 03819 return TRUE; 03820 } 03821 03822 GArray* 03823 impl_dbus_zoom_region_get_brightness (ZoomRegion *zoom_region) 03824 { 03825 GArray *ret; 03826 03827 ret = g_array_new (FALSE, FALSE, sizeof (gdouble)); 03828 03829 g_array_append_val (ret, zoom_region->bright_r); 03830 g_array_append_val (ret, zoom_region->bright_g); 03831 g_array_append_val (ret, zoom_region->bright_b); 03832 03833 return ret; 03834 } 03835 03836 /* could be called multiple times */ 03837 static void 03838 zoom_region_dispose (GObject *object) 03839 { 03840 ZoomRegion *zoom_region = ZOOM_REGION (object); 03841 03842 zoom_region_do_dispose (zoom_region); 03843 03844 BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); 03845 } 03846 03847 static void 03848 zoom_region_class_init (ZoomRegionClass *klass) 03849 { 03850 GObjectClass * object_class = (GObjectClass *) klass; 03851 POA_GNOME_Magnifier_ZoomRegion__epv *epv = &klass->epv; 03852 parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT); /* needed by BONOBO_CALL_PARENT! */ 03853 03854 object_class->dispose = zoom_region_dispose; 03855 object_class->finalize = zoom_region_finalize; 03856 03857 epv->setMagFactor = impl_zoom_region_set_mag_factor; 03858 epv->getMagFactor = impl_zoom_region_get_mag_factor; 03859 epv->getProperties = impl_zoom_region_get_properties; 03860 epv->setROI = impl_zoom_region_set_roi; 03861 epv->setPointerPos = impl_zoom_region_set_pointer_pos; 03862 epv->updatePointer = impl_zoom_region_update_pointer; 03863 epv->markDirty = impl_zoom_region_mark_dirty; 03864 epv->getROI = impl_zoom_region_get_roi; 03865 epv->moveResize = impl_zoom_region_move_resize; 03866 epv->dispose = impl_zoom_region_dispose; 03867 epv->setContrast = impl_zoom_region_set_contrast; 03868 epv->getContrast = impl_zoom_region_get_contrast; 03869 epv->setBrightness = impl_zoom_region_set_brightness; 03870 epv->getBrightness = impl_zoom_region_get_brightness; 03871 03872 reset_timing_stats(); 03873 #ifdef DEBUG_CLIENT_CALLS 03874 client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL); 03875 #endif 03876 } 03877 03878 static void 03879 zoom_region_properties_init (ZoomRegion *zoom_region) 03880 { 03881 BonoboArg *def; 03882 03883 zoom_region->properties = 03884 bonobo_property_bag_new_closure ( 03885 g_cclosure_new_object ( 03886 G_CALLBACK (zoom_region_get_property), 03887 G_OBJECT (zoom_region)), 03888 g_cclosure_new_object ( 03889 G_CALLBACK (zoom_region_set_property), 03890 G_OBJECT (zoom_region))); 03891 03892 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 03893 BONOBO_ARG_SET_BOOLEAN (def, TRUE); 03894 03895 bonobo_property_bag_add (zoom_region->properties, 03896 "is-managed", 03897 ZOOM_REGION_MANAGED_PROP, 03898 BONOBO_ARG_BOOLEAN, 03899 def, 03900 "If false, zoom region does not auto-update, but is drawn into directly by the client", 03901 Bonobo_PROPERTY_READABLE | 03902 Bonobo_PROPERTY_WRITEABLE); 03903 03904 bonobo_arg_release (def); 03905 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 03906 BONOBO_ARG_SET_BOOLEAN (def, TRUE); 03907 03908 bonobo_property_bag_add (zoom_region->properties, 03909 "poll-mouse", 03910 ZOOM_REGION_POLL_MOUSE_PROP, 03911 BONOBO_ARG_BOOLEAN, 03912 NULL, 03913 "If false, zoom region does not poll for pointer location, but is (exclusively) given it by the client", 03914 Bonobo_PROPERTY_READABLE | 03915 Bonobo_PROPERTY_WRITEABLE); 03916 03917 bonobo_arg_release (def); 03918 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 03919 BONOBO_ARG_SET_BOOLEAN (def, TRUE); 03920 03921 bonobo_property_bag_add (zoom_region->properties, 03922 "draw-cursor", 03923 ZOOM_REGION_DRAW_CURSOR_PROP, 03924 BONOBO_ARG_BOOLEAN, 03925 NULL, 03926 "If false, zoom region does not draw the cursor.", 03927 Bonobo_PROPERTY_READABLE | 03928 Bonobo_PROPERTY_WRITEABLE); 03929 03930 bonobo_arg_release (def); 03931 def = bonobo_arg_new (BONOBO_ARG_SHORT); 03932 BONOBO_ARG_SET_SHORT (def, GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST); 03933 03934 bonobo_property_bag_add (zoom_region->properties, 03935 "smooth-scroll-policy", 03936 ZOOM_REGION_SMOOTHSCROLL_PROP, 03937 BONOBO_ARG_SHORT, 03938 def, 03939 "scrolling policy, slower versus faster", 03940 Bonobo_PROPERTY_READABLE | 03941 Bonobo_PROPERTY_WRITEABLE); 03942 03943 bonobo_arg_release (def); 03944 def = bonobo_arg_new (BONOBO_ARG_SHORT); 03945 BONOBO_ARG_SET_SHORT ( 03946 def, 03947 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER); 03948 03949 bonobo_property_bag_add (zoom_region->properties, 03950 "color-blind-filter", 03951 ZOOM_REGION_COLORBLIND_PROP, 03952 BONOBO_ARG_SHORT, 03953 def, 03954 "color blind filter to apply in an image", 03955 Bonobo_PROPERTY_READABLE | 03956 Bonobo_PROPERTY_WRITEABLE); 03957 03958 bonobo_arg_release (def); 03959 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 03960 BONOBO_ARG_SET_BOOLEAN (def, FALSE); 03961 03962 bonobo_property_bag_add (zoom_region->properties, 03963 "use-test-pattern", 03964 ZOOM_REGION_TESTPATTERN_PROP, 03965 BONOBO_ARG_BOOLEAN, 03966 def, 03967 "use test pattern for source", 03968 Bonobo_PROPERTY_READABLE | 03969 Bonobo_PROPERTY_WRITEABLE); 03970 03971 bonobo_arg_release (def); 03972 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 03973 BONOBO_ARG_SET_BOOLEAN (def, TRUE); 03974 03975 bonobo_property_bag_add (zoom_region->properties, 03976 "inverse-video", 03977 ZOOM_REGION_INVERT_PROP, 03978 BONOBO_ARG_BOOLEAN, 03979 def, 03980 "inverse video display", 03981 Bonobo_PROPERTY_READABLE | 03982 Bonobo_PROPERTY_WRITEABLE); 03983 03984 bonobo_arg_release (def); 03985 03986 bonobo_property_bag_add (zoom_region->properties, 03987 "smoothing-type", 03988 ZOOM_REGION_SMOOTHING_PROP, 03989 BONOBO_ARG_STRING, 03990 NULL, 03991 "image smoothing algorithm used", 03992 Bonobo_PROPERTY_READABLE | 03993 Bonobo_PROPERTY_WRITEABLE); 03994 03995 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 03996 BONOBO_ARG_SET_FLOAT (def, 0.0); 03997 03998 bonobo_property_bag_add (zoom_region->properties, 03999 "red-contrast", 04000 ZOOM_REGION_CONTRASTR_PROP, 04001 BONOBO_ARG_FLOAT, 04002 def, 04003 "red image contrast ratio", 04004 Bonobo_PROPERTY_READABLE | 04005 Bonobo_PROPERTY_WRITEABLE); 04006 bonobo_arg_release (def); 04007 04008 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04009 BONOBO_ARG_SET_FLOAT (def, 0.0); 04010 04011 bonobo_property_bag_add (zoom_region->properties, 04012 "green-contrast", 04013 ZOOM_REGION_CONTRASTG_PROP, 04014 BONOBO_ARG_FLOAT, 04015 def, 04016 "green image contrast ratio", 04017 Bonobo_PROPERTY_READABLE | 04018 Bonobo_PROPERTY_WRITEABLE); 04019 bonobo_arg_release (def); 04020 04021 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04022 BONOBO_ARG_SET_FLOAT (def, 0.0); 04023 04024 bonobo_property_bag_add (zoom_region->properties, 04025 "blue-contrast", 04026 ZOOM_REGION_CONTRASTB_PROP, 04027 BONOBO_ARG_FLOAT, 04028 def, 04029 "blue image contrast ratio", 04030 Bonobo_PROPERTY_READABLE | 04031 Bonobo_PROPERTY_WRITEABLE); 04032 bonobo_arg_release (def); 04033 04034 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04035 BONOBO_ARG_SET_FLOAT (def, 0.0); 04036 04037 bonobo_property_bag_add (zoom_region->properties, 04038 "red-brightness", 04039 ZOOM_REGION_BRIGHTR_PROP, 04040 BONOBO_ARG_FLOAT, 04041 def, 04042 "red image brightness ratio", 04043 Bonobo_PROPERTY_READABLE | 04044 Bonobo_PROPERTY_WRITEABLE); 04045 bonobo_arg_release (def); 04046 04047 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04048 BONOBO_ARG_SET_FLOAT (def, 0.0); 04049 04050 bonobo_property_bag_add (zoom_region->properties, 04051 "green-brightness", 04052 ZOOM_REGION_BRIGHTG_PROP, 04053 BONOBO_ARG_FLOAT, 04054 def, 04055 "green image brightness ratio", 04056 Bonobo_PROPERTY_READABLE | 04057 Bonobo_PROPERTY_WRITEABLE); 04058 bonobo_arg_release (def); 04059 04060 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04061 BONOBO_ARG_SET_FLOAT (def, 0.0); 04062 04063 bonobo_property_bag_add (zoom_region->properties, 04064 "blue-brightness", 04065 ZOOM_REGION_BRIGHTB_PROP, 04066 BONOBO_ARG_FLOAT, 04067 def, 04068 "blue image brightness ratio", 04069 Bonobo_PROPERTY_READABLE | 04070 Bonobo_PROPERTY_WRITEABLE); 04071 bonobo_arg_release (def); 04072 04073 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04074 BONOBO_ARG_SET_FLOAT (def, 2.0); 04075 04076 bonobo_property_bag_add (zoom_region->properties, 04077 "mag-factor-x", 04078 ZOOM_REGION_XSCALE_PROP, 04079 BONOBO_ARG_FLOAT, 04080 def, 04081 "x scale factor", 04082 Bonobo_PROPERTY_READABLE | 04083 Bonobo_PROPERTY_WRITEABLE); 04084 04085 bonobo_arg_release (def); 04086 def = bonobo_arg_new (BONOBO_ARG_FLOAT); 04087 BONOBO_ARG_SET_FLOAT (def, 2.0); 04088 04089 bonobo_property_bag_add (zoom_region->properties, 04090 "mag-factor-y", 04091 ZOOM_REGION_YSCALE_PROP, 04092 BONOBO_ARG_FLOAT, 04093 def, 04094 "y scale factor", 04095 Bonobo_PROPERTY_READABLE | 04096 Bonobo_PROPERTY_WRITEABLE); 04097 04098 bonobo_arg_release (def); 04099 def = bonobo_arg_new (BONOBO_ARG_LONG); 04100 BONOBO_ARG_SET_LONG (def, 0); 04101 04102 bonobo_property_bag_add (zoom_region->properties, 04103 "border-size", 04104 ZOOM_REGION_BORDERSIZE_PROP, 04105 BONOBO_ARG_LONG, 04106 def, 04107 "size of zoom-region borders, in pixels", 04108 Bonobo_PROPERTY_READABLE | 04109 Bonobo_PROPERTY_WRITEABLE); 04110 04111 bonobo_arg_release (def); 04112 def = bonobo_arg_new (BONOBO_ARG_LONG); 04113 BONOBO_ARG_SET_LONG (def, 0); 04114 04115 bonobo_property_bag_add (zoom_region->properties, 04116 "border-size-left", 04117 ZOOM_REGION_BORDERSIZELEFT_PROP, 04118 BONOBO_ARG_LONG, 04119 def, 04120 "size of left zoom-region border, in pixels", 04121 Bonobo_PROPERTY_READABLE | 04122 Bonobo_PROPERTY_WRITEABLE); 04123 04124 bonobo_arg_release (def); 04125 def = bonobo_arg_new (BONOBO_ARG_LONG); 04126 BONOBO_ARG_SET_LONG (def, 0); 04127 04128 bonobo_property_bag_add (zoom_region->properties, 04129 "border-size-top", 04130 ZOOM_REGION_BORDERSIZETOP_PROP, 04131 BONOBO_ARG_LONG, 04132 def, 04133 "size of top zoom-region border, in pixels", 04134 Bonobo_PROPERTY_READABLE | 04135 Bonobo_PROPERTY_WRITEABLE); 04136 04137 bonobo_arg_release (def); 04138 def = bonobo_arg_new (BONOBO_ARG_LONG); 04139 BONOBO_ARG_SET_LONG (def, 0); 04140 04141 bonobo_property_bag_add (zoom_region->properties, 04142 "border-size-right", 04143 ZOOM_REGION_BORDERSIZERIGHT_PROP, 04144 BONOBO_ARG_LONG, 04145 def, 04146 "size of right zoom-region border, in pixels", 04147 Bonobo_PROPERTY_READABLE | 04148 Bonobo_PROPERTY_WRITEABLE); 04149 04150 bonobo_arg_release (def); 04151 def = bonobo_arg_new (BONOBO_ARG_LONG); 04152 BONOBO_ARG_SET_LONG (def, 0); 04153 04154 bonobo_property_bag_add (zoom_region->properties, 04155 "border-size-bottom", 04156 ZOOM_REGION_BORDERSIZEBOTTOM_PROP, 04157 BONOBO_ARG_LONG, 04158 def, 04159 "size of bottom zoom-region border, in " 04160 "pixels", 04161 Bonobo_PROPERTY_READABLE | 04162 Bonobo_PROPERTY_WRITEABLE); 04163 04164 bonobo_arg_release (def); 04165 def = bonobo_arg_new (BONOBO_ARG_LONG); 04166 BONOBO_ARG_SET_LONG (def, 0x00000000); 04167 04168 bonobo_property_bag_add (zoom_region->properties, 04169 "border-color", 04170 ZOOM_REGION_BORDERCOLOR_PROP, 04171 BONOBO_ARG_LONG, 04172 def, 04173 "border color, as RGBA32", 04174 Bonobo_PROPERTY_READABLE | 04175 Bonobo_PROPERTY_WRITEABLE); 04176 04177 bonobo_arg_release (def); 04178 def = bonobo_arg_new (BONOBO_ARG_INT); 04179 BONOBO_ARG_SET_INT (def, 0); 04180 04181 bonobo_property_bag_add (zoom_region->properties, 04182 "x-alignment", 04183 ZOOM_REGION_XALIGN_PROP, 04184 BONOBO_ARG_INT, 04185 def, 04186 "x-alignment policy for this region", 04187 Bonobo_PROPERTY_READABLE | 04188 Bonobo_PROPERTY_WRITEABLE); 04189 04190 bonobo_arg_release (def); 04191 def = bonobo_arg_new (BONOBO_ARG_INT); 04192 BONOBO_ARG_SET_INT (def, 0); 04193 04194 bonobo_property_bag_add (zoom_region->properties, 04195 "y-alignment", 04196 ZOOM_REGION_YALIGN_PROP, 04197 BONOBO_ARG_INT, 04198 def, 04199 "y-alignment policy for this region", 04200 Bonobo_PROPERTY_READABLE | 04201 Bonobo_PROPERTY_WRITEABLE); 04202 bonobo_arg_release (def); 04203 04204 bonobo_property_bag_add (zoom_region->properties, 04205 "viewport", 04206 ZOOM_REGION_VIEWPORT_PROP, 04207 TC_GNOME_Magnifier_RectBounds, 04208 NULL, 04209 "viewport bounding box", 04210 Bonobo_PROPERTY_READABLE | 04211 Bonobo_PROPERTY_WRITEABLE); 04212 04213 def = bonobo_arg_new (BONOBO_ARG_INT); 04214 BONOBO_ARG_SET_INT (def, 0); 04215 04216 bonobo_property_bag_add (zoom_region->properties, 04217 "timing-iterations", 04218 ZOOM_REGION_TIMING_TEST_PROP, 04219 BONOBO_ARG_INT, 04220 def, 04221 "timing iterations", 04222 Bonobo_PROPERTY_READABLE | 04223 Bonobo_PROPERTY_WRITEABLE); 04224 bonobo_arg_release (def); 04225 04226 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 04227 BONOBO_ARG_SET_BOOLEAN (def, FALSE); 04228 04229 bonobo_property_bag_add (zoom_region->properties, 04230 "timing-output", 04231 ZOOM_REGION_TIMING_OUTPUT_PROP, 04232 BONOBO_ARG_BOOLEAN, 04233 def, 04234 "timing output", 04235 Bonobo_PROPERTY_READABLE | 04236 Bonobo_PROPERTY_WRITEABLE); 04237 04238 bonobo_arg_release (def); 04239 04240 def = bonobo_arg_new (BONOBO_ARG_INT); 04241 BONOBO_ARG_SET_INT (def, 0); 04242 04243 bonobo_property_bag_add (zoom_region->properties, 04244 "timing-pan-rate", 04245 ZOOM_REGION_TIMING_PAN_RATE_PROP, 04246 BONOBO_ARG_INT, 04247 def, 04248 "timing pan rate", 04249 Bonobo_PROPERTY_READABLE | 04250 Bonobo_PROPERTY_WRITEABLE); 04251 bonobo_arg_release (def); 04252 04253 def = bonobo_arg_new (BONOBO_ARG_BOOLEAN); 04254 BONOBO_ARG_SET_BOOLEAN (def, FALSE); 04255 04256 bonobo_property_bag_add (zoom_region->properties, 04257 "exit-magnifier", 04258 ZOOM_REGION_EXIT_MAGNIFIER, 04259 BONOBO_ARG_BOOLEAN, 04260 def, 04261 "timing output", 04262 Bonobo_PROPERTY_READABLE | 04263 Bonobo_PROPERTY_WRITEABLE); 04264 04265 bonobo_arg_release (def); 04266 04267 } 04268 04269 static void 04270 zoom_region_private_init (ZoomRegionPrivate *priv) 04271 { 04272 GdkRectangle rect = {0, 0, 0, 0}; 04273 GNOME_Magnifier_RectBounds rectbounds = {0, 0, 0, 0}; 04274 priv->parent = NULL; 04275 priv->w = NULL; 04276 priv->default_gc = NULL; 04277 priv->paint_cursor_gc = NULL; 04278 priv->crosswire_gc = NULL; 04279 priv->q = NULL; 04280 priv->scaled_pixbuf = NULL; 04281 priv->source_pixbuf_cache = NULL; 04282 priv->source_drawable = NULL; 04283 priv->pixmap = NULL; 04284 priv->cursor_backing_rect = rect; 04285 priv->cursor_backing_pixels = NULL; 04286 priv->gdk_interp_type = GDK_INTERP_NEAREST; 04287 priv->expose_handler_id = 0; 04288 priv->test = FALSE; 04289 priv->last_cursor_pos.x = 0; 04290 priv->last_cursor_pos.y = 0; 04291 priv->last_drawn_crosswire_pos.x = 0; 04292 priv->last_drawn_crosswire_pos.y = 0; 04293 priv->exposed_bounds = rectbounds; 04294 priv->source_area = rectbounds; 04295 priv->update_pointer_id = 0; 04296 priv->update_handler_id = 0; 04297 } 04298 04299 static void 04300 zoom_region_init (ZoomRegion *zoom_region) 04301 { 04302 DBG(g_message ("initializing region %p", zoom_region)); 04303 04304 zoom_region_properties_init (zoom_region); 04305 zoom_region->draw_cursor = TRUE; 04306 zoom_region->smooth_scroll_policy = 04307 GNOME_Magnifier_ZoomRegion_SCROLL_SMOOTH; 04308 zoom_region->color_blind_filter = 04309 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER; 04310 zoom_region->contrast_r = 0.0; 04311 zoom_region->contrast_g = 0.0; 04312 zoom_region->contrast_b = 0.0; 04313 zoom_region->bright_r = 0.0; 04314 zoom_region->bright_g = 0.0; 04315 zoom_region->bright_b = 0.0; 04316 zoom_region->invert = FALSE; 04317 zoom_region->cache_source = FALSE; 04318 zoom_region->border_size_left = 0; 04319 zoom_region->border_size_top = 0; 04320 zoom_region->border_size_right = 0; 04321 zoom_region->border_size_bottom = 0; 04322 zoom_region->border_color = 0; 04323 zoom_region->roi.x1 = 0; 04324 zoom_region->roi.x1 = 0; 04325 zoom_region->roi.x2 = 1; 04326 zoom_region->roi.x2 = 1; 04327 zoom_region->x_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER; 04328 zoom_region->y_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER; 04329 zoom_region->coalesce_func = _coalesce_update_rects; 04330 zoom_region->poll_mouse = TRUE; 04331 zoom_region->priv = g_malloc (sizeof (ZoomRegionPrivate)); 04332 zoom_region_private_init (zoom_region->priv); 04333 bonobo_object_add_interface (BONOBO_OBJECT (zoom_region), 04334 BONOBO_OBJECT (zoom_region->properties)); 04335 zoom_region->timing_output = FALSE; 04336 #ifdef ZOOM_REGION_DEBUG 04337 zoom_region->alive = TRUE; 04338 #endif 04339 zoom_region->priv->update_pointer_id = 04340 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 04341 200, 04342 zoom_region_update_pointer_timeout, 04343 zoom_region, 04344 NULL); 04345 } 04346 04347 ZoomRegion * 04348 zoom_region_new (void) 04349 { 04350 ZoomRegionClass *klass = NULL; 04351 GError *error = NULL; 04352 ZoomRegion *_this_zoom_region = g_object_new (zoom_region_get_type(), NULL); 04353 _this_zoom_region->object_path = g_strdup_printf("/org/freedesktop/gnome/ZoomRegion/%i", zoom_region_number); 04354 04355 klass = ZOOM_REGION_GET_CLASS (_this_zoom_region); 04356 04357 klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); 04358 if (klass->connection == NULL) { 04359 g_warning ("Unable to connect to dbus: %s", error->message); 04360 g_error_free (error); 04361 return NULL; 04362 } 04363 04364 dbus_g_object_type_install_info (ZOOM_REGION_TYPE, &dbus_glib_impl_dbus_zoom_region_object_info); 04365 04366 dbus_g_connection_register_g_object (klass->connection, _this_zoom_region->object_path, 04367 G_OBJECT (_this_zoom_region)); 04368 04369 zoom_region_number++; 04370 04371 return _this_zoom_region; 04372 } 04373 04374 /* this one really shuts down the object - called once only */ 04375 static void 04376 zoom_region_finalize (GObject *region) 04377 { 04378 ZoomRegion *zoom_region = (ZoomRegion *) region; 04379 04380 DBG(g_message ("finalizing region %p", zoom_region)); 04381 04382 if (zoom_region->priv && zoom_region->priv->q) 04383 { 04384 g_list_free (zoom_region->priv->q); 04385 zoom_region->priv->q = NULL; 04386 } 04387 if (GTK_IS_WIDGET (zoom_region->priv->w)) 04388 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->w)); 04389 if (GTK_IS_WIDGET (zoom_region->priv->border)) 04390 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->border)); 04391 if (zoom_region->priv->source_pixbuf_cache) 04392 g_object_unref (zoom_region->priv->source_pixbuf_cache); 04393 if (zoom_region->priv->scaled_pixbuf) 04394 g_object_unref (zoom_region->priv->scaled_pixbuf); 04395 if (zoom_region->priv->pixmap) 04396 g_object_unref (zoom_region->priv->pixmap); 04397 zoom_region->priv->pixmap = NULL; 04398 zoom_region->priv->parent = NULL; 04399 if (zoom_region->priv->cursor_backing_pixels) 04400 g_object_unref (zoom_region->priv->cursor_backing_pixels); 04401 g_free (zoom_region->priv); 04402 zoom_region->priv = NULL; 04403 #ifdef ZOOM_REGION_DEBUG 04404 zoom_region->alive = FALSE; 04405 #endif 04406 BONOBO_CALL_PARENT (G_OBJECT_CLASS, finalize, (region)); 04407 } 04408 04409 BONOBO_TYPE_FUNC_FULL (ZoomRegion, 04410 GNOME_Magnifier_ZoomRegion, 04411 BONOBO_TYPE_OBJECT, 04412 zoom_region);