# zoom-region.c

Go to the documentation of this file.

    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 (zoom_region->priv->w->window)
    00624                 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
    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               zoom_region->priv->w->window &&
    00842               GDK_IS_DRAWABLE (zoom_region->priv->w->window) &&
    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 (zoom_region->priv->w->window);
    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 (zoom_region->priv->w->window,
    00938                                        zoom_region->priv->crosswire_gc,
    00939                                        rect.x, y_top_clip, rect.x,
    00940                                        y_bottom_clip);
    00941                         gdk_draw_line (zoom_region->priv->w->window,
    00942                                        zoom_region->priv->crosswire_gc,
    00943                                        x_left_clip, rect.y, x_right_clip,
    00944                                        rect.y);
    00945                 }
    00946                 gdk_draw_line (zoom_region->priv->w->window,
    00947                                zoom_region->priv->crosswire_gc,
    00948                                rect.x, y_start, rect.x, y_end);
    00949                 gdk_draw_line (zoom_region->priv->w->window,
    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                                 zoom_region->priv->w->window,
    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                                 zoom_region->priv->w->window,
    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                         zoom_region->priv->w->window,
    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                         zoom_region->priv->w->window,
    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 (zoom_region->priv->w->window,
    01038                                                 rect.width,
    01039                                                 rect.height,
    01040                                                 -1);
    01041                 }
    01042                 if (zoom_region->priv->w->window != NULL)
    01043                 {
    01044                         if (zoom_region->priv->default_gc == NULL)
    01045                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
    01046                         gdk_draw_drawable (zoom_region->priv->cursor_backing_pixels,
    01047                                      zoom_region->priv->default_gc,
    01048                                      zoom_region->priv->w->window,
    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 (zoom_region->priv->w->window))
    01057                 {
    01058                     if (zoom_region->priv->paint_cursor_gc == NULL)
    01059                                 zoom_region->priv->paint_cursor_gc = gdk_gc_new (zoom_region->priv->w->window);
    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 (zoom_region->priv->w->window,
    01069                                            zoom_region->priv->paint_cursor_gc,
    01070                                            TRUE,
    01071                                            rect.x, rect.y, rect.width, rect.height);
    01072
    01073                         gdk_draw_drawable (zoom_region->priv->w->window,
    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             (zoom_region->priv->border->window)) {
    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 (zoom_region->priv->w->window)) return;
    01169         if (zoom_region->priv->default_gc == NULL)
    01170                 zoom_region->priv->default_gc = gdk_gc_new (zoom_region->priv->w->window);
    01171
    01172         if (zoom_region->priv->pixmap && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
    01173         {
    01174                 gdk_draw_drawable (zoom_region->priv->w->window,
    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 (zoom_region->priv->w->window))
    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                                 zoom_region->priv->w->window,
    01220                                 width,
    01221                                 height,
    01222                                 gdk_drawable_get_depth (
    01223                                         zoom_region->priv->w->window));
    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 (zoom_region->priv->w->window))
    01289                 gdk_display_sync (gdk_drawable_get_display (
    01290                                           zoom_region->priv->w->window));
    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             zoom_region->priv->w->window)
    01311                 window = zoom_region->priv->w->window;
    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 && zoom_region->priv->w->window)
    01359                 window = zoom_region->priv->w->window;
    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 (zoom_region->priv->w->window))
    01389                 window = zoom_region->priv->w->window;
    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 (zoom_region->priv->w->window, width, height, -1);
    01777
    01778                         if (zoom_region->priv->default_gc == NULL)
    01779                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
    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(zoom_region->priv->w->window);
    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 && zoom_region->priv->w->window) {
    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                                 zoom_region->priv->w->window, &paint_rect);
    01952                         zoom_region_paint (zoom_region, &paint_rect);
    01953                         gdk_window_end_paint (zoom_region->priv->w->window);
    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                                                  &microseconds);
    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 (zoom_region->priv->w->window),
    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 (zoom_region->priv->w->window));
    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                                                 &microseconds);
    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                                                        &microseconds);
    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 (zoom_region->priv->w->window),
    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 (zoom_region->priv->w->window));
    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, &microseconds);
    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 (zoom_region->priv->w->window))
    03157         {
    03158             gdk_drawable_get_size (
    03159                 GDK_DRAWABLE (
    03160                     zoom_region->priv->w->window),
    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 (zoom_region->priv->w->window))
    03738         {
    03739             gdk_drawable_get_size (
    03740                 GDK_DRAWABLE (
    03741                     zoom_region->priv->w->window),
    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);