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);
Generated on Tue Jul 20 11:14:56 2010 for gnome-mag by  doxygen 1.6.3