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 #ifdef HAVE_COLORBLIND
00138 static COLORBLIND_RUNTIME *cbr = NULL;
00139 static COLORBLIND_XCOLOR *color = NULL;
00140 #endif /* HAVE_COLORBLIND */
00141 
00142 
00143 static float timing_scale_max  = 0;
00144 static float timing_idle_max   = 0;
00145 static float timing_frame_max  = 0;
00146 static float cps_max           = 0;
00147 static float nrr_max           = 0;
00148 static float update_nrr_max    = 0;
00149 static gboolean reset_timing   = FALSE;
00150 static gboolean timing_test    = FALSE;
00151 
00152 static guint pending_idle_handler = 0;
00153 static gboolean processing_updates = FALSE;
00154 static gboolean timing_start = FALSE;
00155 
00156 static gboolean can_coalesce = TRUE ; /* change this when event coalescing is working */
00157 
00158 static int zoom_region_number = 0;
00159 
00160 #define CLAMP_B_C(v) (t = (v), CLAMP (t, -1, 1));
00161 
00162 static void zoom_region_sync (ZoomRegion *region);
00163 static void zoom_region_finalize (GObject *object);
00164 static void zoom_region_update (ZoomRegion *zoom_region,
00165                                 const GdkRectangle rect);
00166 static void zoom_region_queue_update (ZoomRegion *zoom_region,
00167                                       const GdkRectangle rect);
00168 
00169 static int  zoom_region_process_updates (gpointer data);
00170 static void zoom_region_paint (ZoomRegion *zoom_region, GdkRectangle *rect);
00171 static void zoom_region_paint_pixmap (ZoomRegion *zoom_region, GdkRectangle *rect);
00172 static int  zoom_region_update_pointer_timeout (gpointer data);
00173 static GdkRectangle zoom_region_rect_from_bounds (ZoomRegion *zoom_region,
00174                                                   const GNOME_Magnifier_RectBounds *bounds);
00175 static ZoomRegionPixmapCreationError zoom_region_create_pixmap (ZoomRegion *zoom_region);
00176 static GdkRectangle zoom_region_update_pixmap (ZoomRegion *zoom_region, const GdkRectangle update_rect, GdkRectangle *paint_rect);
00177 static void zoom_region_get_move_x_y (ZoomRegion *zoom_region, long *x, long *y);
00178 static void zoom_region_recompute_exposed_bounds (ZoomRegion *zoom_region);
00179 static void zoom_region_update_current (ZoomRegion *zoom_region);
00180 
00181 void
00182 reset_timing_stats()
00183 {
00184         timing_scale_max               = 0;
00185         timing_idle_max                = 0;
00186         timing_frame_max               = 0;
00187         cps_max                        = 0;
00188         nrr_max                        = 0;
00189         update_nrr_max                 = 0;
00190         mag_timing.num_scale_samples   = 0;
00191         mag_timing.num_idle_samples    = 0;
00192         mag_timing.num_frame_samples   = 0;
00193         mag_timing.num_line_samples    = 0;
00194         mag_timing.scale_total         = 0;
00195         mag_timing.idle_total          = 0;
00196         mag_timing.frame_total         = 0;
00197         mag_timing.update_pixels_total = 0;
00198         mag_timing.update_pixels_total = 0;
00199         mag_timing.dx_total            = 0;
00200         mag_timing.dy_total            = 0;
00201         mag_timing.last_frame_val      = 0;
00202         mag_timing.last_dy             = 0;
00203         g_timer_start (mag_timing.process);
00204 }
00205 
00208 #undef DEBUG
00209 #ifdef DEBUG
00210 #define DEBUG_RECT(a, b) _debug_announce_rect (a, b)
00211 #else
00212 #define DEBUG_RECT(a, b) 
00213 #endif
00214 static void
00215 _debug_announce_rect (char *msg, GdkRectangle rect)
00216 {
00217         fprintf (stderr, "%s: (%d,%d - %d,%d)\n",
00218                  msg, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
00219 }
00220 
00221 static void
00222 _set_bounds (RectBounds *struct_bounds, const gint32 **vector_bounds)
00223 {
00224         struct_bounds->x1 = (*vector_bounds)[0];
00225         struct_bounds->y1 = (*vector_bounds)[1];
00226         struct_bounds->x2 = (*vector_bounds)[2];
00227         struct_bounds->y2 = (*vector_bounds)[3];
00228 }
00229 
00230 static gboolean
00231 _diff_pixbufs (const GdkPixbuf *a, const GdkPixbuf *b)
00232 {
00233         long i, j;
00234         int bits_per_byte = 8; /* always true? */
00235         guchar *pa = gdk_pixbuf_get_pixels (a);
00236         guchar *pb = gdk_pixbuf_get_pixels (b);
00237         guchar *cpa, *cpb;
00238         long rsa = gdk_pixbuf_get_rowstride (a);
00239         long rsb = gdk_pixbuf_get_rowstride (b);
00240         long rowbytes = gdk_pixbuf_get_width (a) *
00241                 gdk_pixbuf_get_bits_per_sample (a) *
00242                 gdk_pixbuf_get_n_channels (a)/ bits_per_byte;
00243         long n_rows = gdk_pixbuf_get_height (a);
00244 
00245         if (gdk_pixbuf_get_height (b) != n_rows)
00246                 return TRUE;
00247         if (gdk_pixbuf_get_width (b) != gdk_pixbuf_get_width (a))
00248                 return TRUE;
00249         for (j = 0; j < n_rows; ++j)
00250         {
00251                 cpa = pa + j * rsa;
00252                 cpb = pb + j * rsb;
00253                 for (i = 0; i < rowbytes; ++i)
00254                 {
00255                         if (*cpa != *cpb)
00256                         {
00257                                 return TRUE;
00258                         }
00259                         cpa++;
00260                         cpb++;
00261                 }               
00262         }
00263         return FALSE;
00264 }
00265 
00268 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
00269 
00278 static gboolean
00279 _combine_rects (GdkRectangle *a, GdkRectangle *b)
00280 {
00281         gboolean can_combine = FALSE;
00282         if ((a->x == b->x) && (a->x + a->width == b->x + b->width))
00283         {
00284                 can_combine = TRUE;
00285         }
00286         else if ((a->y == b->y) && (a->y + a->height == b->y + b->height))
00287         {
00288                 can_combine = TRUE;
00289         }
00290         if (can_combine)
00291         {
00292                 GdkRectangle c;
00293                 /* TODO: check and fix this */
00294                 if (gdk_rectangle_intersect (a, b, &c))
00295                 {
00296                         gdk_rectangle_union (a, b, &c);
00297                         *a = c;
00298                         can_combine = TRUE;
00299                 }
00300                 else
00301                 {
00302                         can_combine = FALSE;
00303                 }
00304         }
00305         return can_combine;
00306 }
00307 
00321 static gboolean
00322 _refactor_rects (GdkRectangle *p, GdkRectangle *n)
00323 {
00324         gboolean refactored = FALSE;
00325         GdkRectangle *a, *b;
00326         if (p->x == n->x)
00327         {
00328                 if (p->width < n->width)
00329                 {
00330                         a = p;
00331                         b = n;
00332                 }
00333                 else
00334                 {
00335                         a = n;
00336                         b = p;
00337                 }
00338                 if (a->y == b->y + b->height)
00339                 {
00340                         a->y -= b->height;
00341                         a->height += b->height;
00342                         b->x += a->width;
00343                         b->width -= a->width;
00344                         refactored = TRUE;
00345                 }
00346                 else if (a->y + a->height == b->y)
00347                 {
00348                         a->height += b->height;
00349                         b->x += a->width;
00350                         b->width -= a->width;
00351                         refactored = TRUE;
00352                 }
00353                 if (refactored) fprintf (stderr, "REFACTOR 1\n");
00354         }               
00355         else if (p->y == n->y)
00356         {
00357                 if (p->height < n->height)
00358                 {
00359                         a = p;
00360                         b = n;
00361                 }
00362                 else
00363                 {
00364                         a = n;
00365                         b = p;
00366                 }
00367                 if (a->x == b->x + b->width)
00368                 {
00369                         a->x -= b->width;
00370                         a->width += b->width;
00371                         b->y += a->height;
00372                         b->height -= a->height;
00373                         refactored = TRUE;
00374                 }
00375                 else if (a->x + a->width == b->x)
00376                 {
00377                         a->width += b->width;
00378                         b->y += a->height;
00379                         b->height -= a->height;
00380                         refactored = TRUE;
00381                 }
00382                 if (refactored) fprintf (stderr, "REFACTOR 2\n");
00383         }
00384         else if (p->x + p->width == n->x + n->width)
00385         {
00386                 if (p->width < n->width)
00387                 {
00388                         a = p;
00389                         b = n;
00390                 }
00391                 else
00392                 {
00393                         a = n;
00394                         b = p;
00395                 }
00396                 if (a->y == b->y + b->height)
00397                 {
00398                         a->y -= b->height;
00399                         a->height += b->height;
00400                         b->width -= a->width;
00401                         refactored = TRUE;
00402                 }
00403                 else if (a->y + a->height == b->y)
00404                 {
00405                         a->height += b->height;
00406                         b->width -= a->width;
00407                         refactored = TRUE;
00408                 }
00409                 if (refactored) fprintf (stderr, "REFACTOR 3\n");
00410         }
00411         else if (p->y + p->height == n->y + n->height)
00412         {
00413                 if (p->height < n->height)
00414                 {
00415                         a = p;
00416                         b = n;
00417                 }
00418                 else
00419                 {
00420                         a = n;
00421                         b = p;
00422                 }
00423                 if (a->x == b->x + b->width)
00424                 {
00425                         a->x -= b->width;
00426                         a->width += b->width;
00427                         b->height -= a->height;
00428                         refactored = TRUE;
00429                 }
00430                 else if (a->x + a->width == b->x)
00431                 {
00432                         a->width += b->width;
00433                         b->height -= a->height;
00434                         refactored = TRUE;
00435                 }
00436                 if (refactored) fprintf (stderr, "REFACTOR 4\n");
00437         }
00438         return refactored;
00439 }
00440 
00441 static GList*
00442 _combine_update_rects (GList *q, int lookahead_n)
00443 {
00444         int i = 0;
00445         GdkRectangle *a = q->data;
00446         GList *p = q;
00447         while (i < lookahead_n && p && p->next)
00448         {
00449                 if (_combine_rects (a, q->next->data))
00450                 {
00451                         q = g_list_delete_link (q, p->next);
00452                 }
00453                 else
00454                 {
00455                         p = p->next;
00456                         ++i;
00457                 }
00458         }
00459         return q;
00460 }
00461 #endif
00462 
00463 /*#define _is_horizontal_rect(r)   (((2 * (r)->width / 3 * (r)->height)) > 1)*/
00464 /*#define _is_vertical_rect(r)   (((2 * (r)->height / 3 * (r)->width)) > 1)*/
00465 #define _is_horizontal_rect(r) ((r)->width > (r)->height) 
00466 #define _is_vertical_rect(r)   ((r)->height > (r)->width)
00467 
00474 static GList *
00475 _coalesce_update_rects (GList *q, int min_coalesce_length)
00476 {
00477         GdkRectangle *v = NULL, *h = NULL;
00478         GList *compact_queue = NULL;
00479 /*      fprintf (stderr, "starting queue length = %d\n", g_list_length (q)); */
00480         if (g_list_length (q) < min_coalesce_length) 
00481                 return g_list_copy (q);
00482         while (q)
00483         {
00484                 if (_is_vertical_rect ((GdkRectangle *) (q->data)))
00485                 {
00486                         if (v) gdk_rectangle_union (v, q->data, v);
00487                         else
00488                         {
00489                                 v = g_new0 (GdkRectangle, 1);
00490                                 *v = *(GdkRectangle *)q->data;
00491                         }
00492                 }
00493                 else if (_is_horizontal_rect ((GdkRectangle *) (q->data)))
00494                 {
00495                         if (h) gdk_rectangle_union (h, q->data, h);
00496                         else
00497                         {
00498                                 h = g_new0 (GdkRectangle, 1);
00499                                 *h = *(GdkRectangle *)q->data;
00500                         }
00501                 }
00502                 else
00503                         compact_queue = g_list_prepend (compact_queue, q->data);
00504                 q = q->next;
00505         };
00506         if (v)
00507                 compact_queue = g_list_prepend (compact_queue, v);
00508         if (h)
00509                 compact_queue = g_list_prepend (compact_queue, h);
00510 /*      fprintf (stderr, "ending queue length = %d\n", g_list_length (compact_queue));*/
00511         /* don't free the original queue, that's the caller's responsibility */
00512         return compact_queue;
00513 }
00514 
00515 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
00516 static GList *
00517 _smartbutbroken_coalesce_update_rects (GList *q, int lookahead_n)
00518 {
00519         int i = 0, len;
00520         fprintf (stderr, "starting queue length = %d\n", g_list_length (q));
00521         do {
00522                 GdkRectangle *a;
00523                 len = g_list_length (q);
00524                 q = _combine_update_rects (q, lookahead_n);
00525                 a = q->data;
00526                 while (i < lookahead_n && q && q->next)
00527                 {
00528                         if (_refactor_rects (a, q->next->data))
00529                                 break;
00530                         else
00531                                 ++i;
00532                 }
00533                 q = _combine_update_rects (q, lookahead_n);
00534         } while (g_list_length (q) < len);
00535         fprintf (stderr, "ending queue length = %d\n", g_list_length (q));
00536         return q;
00537 }
00538 #endif
00539 
00543 static GdkRectangle
00544 _rectangle_clip_to_rectangle (GdkRectangle area,
00545                               GdkRectangle clip_rect)
00546 {
00547         GdkRectangle clipped;
00548         clipped.x = MAX (area.x, clip_rect.x);
00549         clipped.y = MAX (area.y, clip_rect.y);
00550         clipped.width = MIN ((area.x + area.width), (clip_rect.x + clip_rect.width)) - clipped.x;
00551         clipped.height = MIN ((area.y + area.height), (clip_rect.y + clip_rect.height)) - clipped.y;
00552         return clipped;
00553 }
00554 
00555 static GdkRectangle
00556 _rectangle_clip_to_bounds (GdkRectangle area,
00557                            GNOME_Magnifier_RectBounds *clip_bounds)
00558 {
00559         area.x = MAX (area.x, clip_bounds->x1);
00560         area.x = MIN (area.x, clip_bounds->x2);
00561         area.width = MIN (area.width, clip_bounds->x2 - area.x);
00562         area.y = MAX (area.y, clip_bounds->y1);
00563         area.y = MIN (area.y, clip_bounds->y2);
00564         area.height = MIN (area.height, clip_bounds->y2 - area.y);
00565         return area;
00566 }
00567 
00568 static GdkRectangle
00569 zoom_region_clip_to_source (ZoomRegion *zoom_region,
00570                             GdkRectangle area)
00571 {
00572     GNOME_Magnifier_RectBounds *source_rect_ptr;
00573     if (zoom_region && zoom_region->priv && zoom_region->priv->parent)
00574     {
00575         source_rect_ptr = &((Magnifier *)zoom_region->priv->parent)->source_bounds;
00576         DEBUG_RECT ("clipping to source bounds", zoom_region_rect_from_bounds (zoom_region, source_rect_ptr)); 
00577         return _rectangle_clip_to_bounds (area, source_rect_ptr);
00578     }
00579     return area;
00580 }
00581 
00582 static GdkRectangle
00583 zoom_region_clip_to_exposed_target (ZoomRegion *zoom_region,
00584                                     GdkRectangle area)
00585 {
00586         GNOME_Magnifier_RectBounds onscreen_target, *source_area;
00587         source_area = &zoom_region->priv->source_area;
00588 
00589         onscreen_target.x1 = MAX (floor (zoom_region->priv->exposed_bounds.x1
00590                                          / zoom_region->xscale),
00591                                          source_area->x1);
00592         onscreen_target.y1 = MAX (floor (zoom_region->priv->exposed_bounds.y1
00593                                          / zoom_region->yscale),
00594                                          source_area->y1);
00595         onscreen_target.x2 = MIN (ceil (zoom_region->priv->exposed_bounds.x2
00596                                         / zoom_region->xscale),
00597                                         source_area->x2);
00598         onscreen_target.y2 = MIN (ceil (zoom_region->priv->exposed_bounds.y2
00599                                         / zoom_region->yscale),
00600                                         source_area->y2);
00601 
00602         return _rectangle_clip_to_bounds (area, &onscreen_target);
00603 }
00604 
00605 static GdkRectangle
00606 zoom_region_clip_to_scaled_pixmap (ZoomRegion *zoom_region,
00607                                    GdkRectangle area)
00608 {
00609         GdkRectangle pixmap_area = {0, 0, 0, 0};
00610         if (zoom_region->priv && zoom_region->priv->pixmap)
00611         {
00612             gdk_drawable_get_size (zoom_region->priv->pixmap, &pixmap_area.width, &pixmap_area.height);
00613             return _rectangle_clip_to_rectangle (area, pixmap_area);
00614         }
00615         else
00616             return area;
00617 }
00618 
00619 static GdkRectangle
00620 zoom_region_clip_to_window (ZoomRegion *zoom_region,
00621                             GdkRectangle area)
00622 {
00623         GdkRectangle window_rect;
00624 
00625         /* we can just return ATM because _rectangle_clip_to_rectangle is unimplemented now */
00626 
00627         return area;
00628 
00629         if (zoom_region->priv->w->window)
00630                 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
00631                                        &window_rect.x,
00632                                        &window_rect.y);
00633         else 
00634         {
00635                 window_rect.x = 0;
00636                 window_rect.y = 0;
00637         }
00638         return _rectangle_clip_to_rectangle (area, window_rect);
00639 }
00640 
00641 static GdkRectangle
00642 zoom_region_source_rect_from_view_bounds (ZoomRegion *zoom_region,
00643                                           const GNOME_Magnifier_RectBounds *view_bounds)
00644 {
00645         GdkRectangle source_rect;
00646         source_rect.x = floor ((view_bounds->x1 + zoom_region->priv->exposed_bounds.x1)
00647                                / zoom_region->xscale);
00648         source_rect.y = floor ((view_bounds->y1 + zoom_region->priv->exposed_bounds.y1)
00649                                 / zoom_region->yscale);
00650         source_rect.width = ceil ((view_bounds->x2 - view_bounds->x1) / zoom_region->xscale) + 1;
00651         source_rect.height = ceil ((view_bounds->y2 - view_bounds->y1) / zoom_region->yscale) + 1;
00652         return source_rect;
00653 }
00654 
00655 static GdkRectangle
00656 zoom_region_view_rect_from_source_rect (ZoomRegion *zoom_region,
00657                                         const GdkRectangle source_rect)
00658 {
00659         GdkRectangle view_rect;
00660         view_rect.x = source_rect.x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
00661         view_rect.y = source_rect.y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
00662         view_rect.width = source_rect.width * zoom_region->xscale;
00663         view_rect.height = source_rect.height * zoom_region->yscale;
00664         DEBUG_RECT ("source", source_rect);
00665         DEBUG_RECT ("converted to view-rect", view_rect);
00666         return view_rect;
00667 }
00668 
00669 static GdkRectangle
00670 zoom_region_source_rect_from_view_rect (ZoomRegion *zoom_region,
00671                                         const GdkRectangle view_rect)
00672 {
00673         GdkRectangle source_rect;
00674         source_rect.x = floor ((view_rect.x + zoom_region->priv->exposed_bounds.x1)
00675                                / zoom_region->xscale);
00676         source_rect.y = floor ((view_rect.y + zoom_region->priv->exposed_bounds.y1)
00677                                 / zoom_region->yscale);
00678         source_rect.width = ceil (view_rect.width / zoom_region->xscale) + 1;
00679         source_rect.height = ceil (view_rect.height / zoom_region->yscale) + 1;
00680         return source_rect;
00681 }
00682 
00683 static GdkRectangle
00684 zoom_region_rect_from_bounds (ZoomRegion *zoom_region,
00685                               const GNOME_Magnifier_RectBounds *bounds)
00686 {
00687         GdkRectangle rect;
00688         rect.x = bounds->x1;
00689         rect.y = bounds->y1;
00690         rect.width = bounds->x2 - bounds->x1;
00691         rect.height = bounds->y2 - bounds->y1;
00692         return rect;
00693 }
00694 
00697 static CORBA_boolean
00698 zoom_region_update_scale (ZoomRegion *zoom_region, gdouble x, gdouble y)
00699 {
00700         gdouble x_old = zoom_region->xscale;
00701         gdouble y_old = zoom_region->yscale;
00702         long x_move, y_move;
00703 
00704         zoom_region->xscale = x;
00705         zoom_region->yscale = y;
00706 
00707         if (zoom_region->priv->scaled_pixbuf)
00708                 g_object_unref (zoom_region->priv->scaled_pixbuf);
00709         zoom_region->priv->scaled_pixbuf =
00710                 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);
00711 
00712         if (zoom_region->priv->pixmap)
00713                 g_object_unref (zoom_region->priv->pixmap);
00714 
00715         if (zoom_region_create_pixmap (zoom_region) ==
00716             ZOOM_REGION_ERROR_TOO_BIG) {
00717                 zoom_region->xscale = x_old;
00718                 zoom_region->yscale = y_old;
00719                 zoom_region_create_pixmap (zoom_region);
00720                 g_object_unref (zoom_region->priv->scaled_pixbuf);
00721 
00722                 /* only create a scaled image big enough for the target
00723                  * display, for now */
00724                 zoom_region->priv->scaled_pixbuf = gdk_pixbuf_new (
00725                         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);
00726 
00727                 return FALSE;
00728         }
00729 
00730         zoom_region_get_move_x_y (zoom_region, &x_move, &y_move);
00731         zoom_region->priv->exposed_bounds.x1 = x_move * zoom_region->xscale;
00732         zoom_region->priv->exposed_bounds.y1 = y_move * zoom_region->yscale;
00733         zoom_region_recompute_exposed_bounds (zoom_region);
00734         zoom_region_update_current (zoom_region);
00735 
00736         return TRUE;
00737 }
00738 
00739 static void
00740 zoom_region_queue_update (ZoomRegion *zoom_region,
00741                           const GdkRectangle update_rect)
00742 {
00743         GdkRectangle *rect =
00744                 g_new0 (GdkRectangle, 1);
00745         *rect = update_rect;
00746 
00747 #ifdef ZOOM_REGION_DEBUG
00748         g_assert (zoom_region->alive);
00749 #endif
00750         DEBUG_RECT ("queueing update", *rect);
00751 
00752         zoom_region->priv->q =
00753                 g_list_prepend (zoom_region->priv->q, rect);
00754         if (zoom_region->priv && zoom_region->priv->update_handler_id == 0)
00755                 zoom_region->priv->update_handler_id = 
00756                         g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
00757                                          zoom_region_process_updates,
00758                                          zoom_region,
00759                                          NULL);
00760 }
00761 
00762 static void
00763 zoom_region_update_current (ZoomRegion *zoom_region)
00764 {
00765 #ifdef ZOOM_REGION_DEBUG
00766         g_assert (zoom_region->alive);
00767 #endif
00768         if (zoom_region->priv)
00769         {
00770                 gboolean pixmap_valid = GDK_IS_DRAWABLE (zoom_region->priv->pixmap);
00771                 if (!pixmap_valid)
00772                         pixmap_valid = (zoom_region_create_pixmap (zoom_region) == ZOOM_REGION_ERROR_NONE);
00773                 if (pixmap_valid)
00774                         zoom_region_update (zoom_region,
00775                                             zoom_region_source_rect_from_view_bounds (
00776                                                     zoom_region,
00777                                                     &zoom_region->viewport));
00778         }
00779 }
00780 
00781 static GdkRectangle
00782 zoom_region_cursor_rect (ZoomRegion *zoom_region)
00783 {
00784         GdkRectangle rect = {0, 0, 0, 0};
00785         Magnifier *magnifier = zoom_region->priv->parent;
00786         GdkDrawable *cursor = NULL;
00787         if (magnifier)
00788                 cursor = magnifier_get_cursor (magnifier);
00789         if (cursor)
00790         {
00791                 rect.x = zoom_region->priv->last_cursor_pos.x;
00792                 rect.y = zoom_region->priv->last_cursor_pos.y;
00793                 rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
00794                 rect.x -= magnifier->cursor_hotspot.x;
00795                 rect.y -= magnifier->cursor_hotspot.y;
00796                 gdk_drawable_get_size (cursor, &rect.width, &rect.height);
00797         }
00798         return rect;
00799 }
00800 
00801 static void
00802 zoom_region_unpaint_crosswire_cursor (ZoomRegion *zoom_region,
00803                                       GdkRectangle *clip_rect)
00804 {
00805         Magnifier *magnifier = zoom_region->priv->parent;
00806         GdkRectangle vline_rect, hline_rect;
00807         GdkPoint cursor_pos;
00808 
00809 #ifdef ZOOM_REGION_DEBUG
00810         g_assert (zoom_region->alive);
00811 #endif
00812         if (!magnifier || magnifier->crosswire_size <= 0) return;
00813 
00814         cursor_pos = zoom_region->priv->last_drawn_crosswire_pos;
00815         vline_rect.x = cursor_pos.x - magnifier->crosswire_size/2;
00816         vline_rect.y = clip_rect ? clip_rect->y : 0; 
00817         vline_rect.width = MAX (magnifier->crosswire_size, 1);
00818         vline_rect.height = clip_rect ? clip_rect->height : 4096; 
00819         hline_rect.x = clip_rect ? clip_rect->x : 0; 
00820         hline_rect.y = cursor_pos.y - magnifier->crosswire_size/2;
00821         hline_rect.width = clip_rect ? clip_rect->width : 4096;
00822         hline_rect.height = MAX (magnifier->crosswire_size, 1);
00823 
00824         zoom_region_paint_pixmap (zoom_region, &vline_rect);
00825         zoom_region_paint_pixmap (zoom_region, &hline_rect);
00826 }
00827 
00828 static void
00829 zoom_region_paint_crosswire_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect)
00830 {
00831         Magnifier *magnifier = zoom_region->priv->parent;
00832         static GdkColormap *cmap;
00833         static GdkColor last_color;
00834         static gboolean last_color_init = FALSE;
00835         GdkGCValues values;
00836         GdkRectangle rect;
00837         GdkDrawable *cursor;
00838         GdkColor color = {0, 0, 0, 0};
00839         int x_start = 0, y_start = 0, x_end = 4096, y_end = 4096;
00840         int x_left_clip = 0, x_right_clip = 0, y_top_clip = 0, y_bottom_clip = 0;
00841         int csize = 0;
00842         
00843 #ifdef ZOOM_REGION_DEBUG
00844         g_assert (zoom_region->alive);
00845 #endif
00846         if (!(magnifier &&
00847               zoom_region->priv->w->window &&
00848               GDK_IS_DRAWABLE (zoom_region->priv->w->window) &&
00849               magnifier->crosswire_size > 0)) return;
00850 
00851         if (zoom_region->priv->crosswire_gc == NULL) 
00852         {
00853                 zoom_region->priv->crosswire_gc = gdk_gc_new (zoom_region->priv->w->window);
00854                 cmap = gdk_gc_get_colormap(zoom_region->priv->crosswire_gc);
00855                 last_color_init = FALSE;
00856         }
00857 
00858         if (magnifier->crosswire_color == 0)
00859         {
00860                 color.red = 0xFFFF;
00861                 color.blue = 0xFFFF;
00862                 color.green = 0xFFFF;
00863                 values.function = GDK_INVERT;
00864         }
00865         else
00866         {
00867                 color.red = (magnifier->crosswire_color & 0xFF0000) >> 8;
00868                 color.green = (magnifier->crosswire_color & 0xFF00);
00869                 color.blue = (magnifier->crosswire_color & 0xFF) << 8;
00870                 values.function = GDK_COPY;
00871         }
00872 
00873         values.foreground = color;
00874 
00875         /* Only reset colors if they have changed */
00876     if (!last_color_init || color.red != last_color.red ||
00877             color.blue != last_color.blue || color.green != last_color.green)
00878         {
00879                 if (cmap)
00880                 {
00881                         gdk_rgb_find_color (cmap, &(values.foreground));
00882                         gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
00883                 }
00884                 else
00885                 {
00886                         gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION);
00887                 }
00888 
00889                 last_color.red   = color.red;
00890                 last_color.blue  = color.blue;
00891                 last_color.green = color.green;
00892                 last_color_init  = TRUE;
00893         }
00894 
00895         rect.x = zoom_region->priv->last_cursor_pos.x;
00896         rect.y = zoom_region->priv->last_cursor_pos.y;
00897         rect.width = 0;
00898         rect.height = 0;
00899         rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
00900         if (clip_rect) gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, clip_rect);
00901         else gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, NULL);
00902 
00903         if ((cursor = magnifier_get_cursor (magnifier))) {
00904                 gdk_drawable_get_size (cursor, &csize, &csize);
00905         }
00906 
00907         if (magnifier->crosswire_length) {
00908                 if (magnifier->crosswire_clip) {
00909                         x_start = rect.x - magnifier->cursor_hotspot.x -
00910                                 magnifier->crosswire_length;
00911                         x_end = rect.x +
00912                                 (csize - magnifier->cursor_hotspot.x) +
00913                                 magnifier->crosswire_length;
00914                         y_start = rect.y - magnifier->cursor_hotspot.y -
00915                                 magnifier->crosswire_length;
00916                         y_end = rect.y +
00917                                 (csize - magnifier->cursor_hotspot.y) +
00918                                 magnifier->crosswire_length;
00919                 } else {
00920                         x_start = rect.x - magnifier->crosswire_length;
00921                         x_end = rect.x + magnifier->crosswire_length;
00922                         y_start = rect.y - magnifier->crosswire_length;
00923                         y_end = rect.y + magnifier->crosswire_length;
00924                 }
00925         }
00926 
00927         if (magnifier->crosswire_clip)
00928         {
00929                 y_top_clip = rect.y - magnifier->cursor_hotspot.y -
00930                         magnifier->crosswire_size;
00931                 y_bottom_clip = rect.y +
00932                         (csize - magnifier->cursor_hotspot.y) +
00933                         magnifier->crosswire_size;
00934                 x_left_clip = rect.x - magnifier->cursor_hotspot.x -
00935                         magnifier->crosswire_size;
00936                 x_right_clip = rect.x +
00937                         (csize - magnifier->cursor_hotspot.x) +
00938                         magnifier->crosswire_size;
00939 
00940         }
00941         if (magnifier->crosswire_size == 1) {
00942                 if (magnifier->crosswire_clip) {
00943                         gdk_draw_line (zoom_region->priv->w->window,
00944                                        zoom_region->priv->crosswire_gc,
00945                                        rect.x, y_top_clip, rect.x,
00946                                        y_bottom_clip);
00947                         gdk_draw_line (zoom_region->priv->w->window,
00948                                        zoom_region->priv->crosswire_gc,
00949                                        x_left_clip, rect.y, x_right_clip,
00950                                        rect.y);
00951                 }
00952                 gdk_draw_line (zoom_region->priv->w->window,
00953                                zoom_region->priv->crosswire_gc,
00954                                rect.x, y_start, rect.x, y_end);
00955                 gdk_draw_line (zoom_region->priv->w->window,
00956                                zoom_region->priv->crosswire_gc,
00957                                x_start, rect.y, x_end, rect.y);
00958         }
00959         else {
00960                 if (magnifier->crosswire_clip ) {
00961                         gdk_draw_rectangle (
00962                                 zoom_region->priv->w->window,
00963                                 zoom_region->priv->crosswire_gc, TRUE,
00964                                 rect.x - magnifier->crosswire_size / 2,
00965                                 y_top_clip, magnifier->crosswire_size,
00966                                 y_bottom_clip - y_top_clip);
00967                         gdk_draw_rectangle (
00968                                 zoom_region->priv->w->window,
00969                                 zoom_region->priv->crosswire_gc, TRUE,
00970                                 x_left_clip,
00971                                 rect.y - magnifier->crosswire_size / 2,
00972                                 x_right_clip - x_left_clip,
00973                                 magnifier->crosswire_size);
00974                 }
00975                 gdk_draw_rectangle (
00976                         zoom_region->priv->w->window,
00977                         zoom_region->priv->crosswire_gc, TRUE,
00978                         rect.x - magnifier->crosswire_size / 2, y_start,
00979                         magnifier->crosswire_size, y_end - y_start);
00980                 gdk_draw_rectangle (
00981                         zoom_region->priv->w->window,
00982                         zoom_region->priv->crosswire_gc, TRUE,
00983                         x_start, rect.y - magnifier->crosswire_size / 2,
00984                         x_end - x_start, magnifier->crosswire_size);
00985         }
00986 }
00987 
00988 static void
00989 zoom_region_unpaint_cursor (ZoomRegion *zoom_region, GdkRectangle *clip_rect)
00990 {
00991 #ifdef ZOOM_REGION_DEBUG
00992         g_assert (zoom_region->alive);
00993 #endif
00994         zoom_region_paint_pixmap (zoom_region,
00995                                   &zoom_region->priv->cursor_backing_rect);
00996 }
00997 
00998 
00999 static void
01000 zoom_region_paint_cursor (ZoomRegion *zoom_region,
01001                           GdkRectangle *clip_rect)
01002 {
01003         GdkGCValues values;
01004         GdkRectangle rect, intersct;
01005         GdkRectangle fullscreen;
01006         Magnifier *magnifier = zoom_region->priv->parent;
01007         rect = zoom_region_cursor_rect (zoom_region);
01008 #ifdef ZOOM_REGION_DEBUG
01009         g_assert (zoom_region->alive);
01010 #endif
01011         if (!zoom_region->draw_cursor)
01012                 return;
01013 
01014         if (clip_rect == NULL)
01015         {
01016                 fullscreen = zoom_region_rect_from_bounds (zoom_region,
01017                                                            &zoom_region->viewport);
01018                 clip_rect = &fullscreen;
01019         }
01020         /* save the unclipped cursor pos for 'undrawing' the crosswire, the clipped one is no good */
01021         zoom_region->priv->last_drawn_crosswire_pos.x = rect.x + magnifier->cursor_hotspot.x;
01022         zoom_region->priv->last_drawn_crosswire_pos.y = rect.y + magnifier->cursor_hotspot.y;
01023 
01024         if (gdk_rectangle_intersect (clip_rect, &rect, &intersct))
01025         {
01026                 int width = 0, height = 0;
01027                 
01028                 GdkDrawable *cursor = magnifier_get_cursor (magnifier);
01029                 if (!cursor)
01030                         return;
01031                 else if (!GDK_IS_DRAWABLE (cursor)) g_message ("cursor isn't DRAWABLE!");
01032                 zoom_region->priv->cursor_backing_rect = rect;
01033                 if (zoom_region->priv->cursor_backing_pixels) {
01034                         gdk_drawable_get_size (zoom_region->priv->cursor_backing_pixels,
01035                                                &width, &height);
01036                 }
01037                 if (rect.width != width || rect.height != height)
01038                 {
01039                         if (zoom_region->priv->cursor_backing_pixels) {
01040                                 g_object_unref (zoom_region->priv->cursor_backing_pixels);
01041                         }
01042                         zoom_region->priv->cursor_backing_pixels =
01043                                 gdk_pixmap_new (zoom_region->priv->w->window,
01044                                                 rect.width,
01045                                                 rect.height,
01046                                                 -1);
01047                 }
01048                 if (zoom_region->priv->w->window != NULL)
01049                 {
01050                         if (zoom_region->priv->default_gc == NULL) 
01051                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01052                         gdk_draw_drawable (zoom_region->priv->cursor_backing_pixels,
01053                                      zoom_region->priv->default_gc,
01054                                      zoom_region->priv->w->window,
01055                                      rect.x,
01056                                      rect.y,
01057                                      0, 0,
01058                                      rect.width,
01059                                      rect.height);
01060                 }
01061                 DEBUG_RECT ("painting", rect);
01062                 if (cursor && zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01063                 {
01064                     if (zoom_region->priv->paint_cursor_gc == NULL)
01065                                 zoom_region->priv->paint_cursor_gc = gdk_gc_new (zoom_region->priv->w->window);
01066 
01067                         gdk_gc_set_clip_rectangle (zoom_region->priv->paint_cursor_gc, clip_rect);
01068                         values.clip_x_origin = rect.x;
01069                         values.clip_y_origin = rect.y;
01070                         values.clip_mask = magnifier->priv->cursor_mask;
01071                         gdk_gc_set_values(zoom_region->priv->paint_cursor_gc, &values, GDK_GC_CLIP_X_ORIGIN |
01072                                           GDK_GC_CLIP_Y_ORIGIN  | GDK_GC_CLIP_MASK);
01073 
01074                         gdk_draw_rectangle (zoom_region->priv->w->window,
01075                                            zoom_region->priv->paint_cursor_gc,
01076                                            TRUE,
01077                                            rect.x, rect.y, rect.width, rect.height);
01078 
01079                         gdk_draw_drawable (zoom_region->priv->w->window,
01080                                            zoom_region->priv->paint_cursor_gc,
01081                                            cursor,
01082                                            0, 0,
01083                                            rect.x,
01084                                            rect.y,
01085                                            rect.width,
01086                                            rect.height);
01087                 }
01088         }
01089 }
01090 
01095 static void
01096 zoom_region_coalesce_updates (ZoomRegion *zoom_region)
01097 {
01098         /* TODO: lock the queue ? */
01099         GList *q;
01100         int lookahead_n = 4; /* 'distance' to look ahead in queue */
01101         int max_qlen = 50;
01102 
01103         if (zoom_region->priv && zoom_region->priv->q && g_list_length (zoom_region->priv->q) > max_qlen)
01104         {
01105                 g_list_free (zoom_region->priv->q);
01106                 zoom_region->priv->q = NULL; /* just discard and update everything */
01107                 /* CAUTION: this can be an expensive operation! */
01108                 zoom_region_queue_update (zoom_region, zoom_region_rect_from_bounds
01109                                           (zoom_region, &zoom_region->priv->source_area));
01110         }
01111         else 
01112 
01113         if (zoom_region->priv && zoom_region->priv->q && 
01114             (g_list_length (zoom_region->priv->q) > 1) && can_coalesce)
01115         {               
01116                 q = g_list_reverse (g_list_copy (zoom_region->priv->q));
01117                 if (q)
01118                 {
01119                         GList *coalesce_copy;
01120                         if (zoom_region->coalesce_func)
01121                         {
01122                                 GList *new;
01123                                 coalesce_copy = (*zoom_region->coalesce_func) (q, lookahead_n);
01124                                 new = g_list_reverse (coalesce_copy);
01125                                 g_list_free (zoom_region->priv->q);
01126                                 zoom_region->priv->q = new;
01127                         }
01128                         g_list_free (q);
01129                 }
01130         }
01131 }
01132 
01133 
01134 static void
01135 zoom_region_paint_border (ZoomRegion *zoom_region)
01136 {
01137         GdkColor color;
01138 
01139 #ifdef ZOOM_REGION_DEBUG
01140         g_assert (zoom_region->alive);
01141 #endif
01142         if ((zoom_region->border_size_left > 0 ||
01143              zoom_region->border_size_top > 0 ||
01144              zoom_region->border_size_right > 0 ||
01145              zoom_region->border_size_bottom > 0) &&
01146             (zoom_region->priv->border->window)) {
01147                 color.red = (((zoom_region->border_color & 0xFF0000) >> 16) *
01148                              65535) / 255;
01149                 color.green = (((zoom_region->border_color & 0xFF00) >> 8) *
01150                                65535) / 255;
01151                 color.blue = ((zoom_region->border_color & 0xFF) * 65535) /
01152                         255;
01153 
01154 #ifdef DEBUG_BORDER
01155                 fprintf (stderr, "border color triple RGB=%d|%d|%d\n",
01156                          color.red, color.green, color.blue);
01157 #endif
01158 
01159                 gtk_widget_modify_bg (zoom_region->priv->border,
01160                                       GTK_STATE_NORMAL, &color);
01161         }
01162 }
01163 
01164 static void
01165 zoom_region_paint_pixmap (ZoomRegion *zoom_region,
01166                           GdkRectangle *area)
01167 {
01168 #ifdef ZOOM_REGION_DEBUG
01169         g_assert (zoom_region->alive);
01170 #endif
01171         g_assert (zoom_region->priv);
01172         g_assert (zoom_region->priv->w);
01173 
01174         if (!GDK_IS_DRAWABLE (zoom_region->priv->w->window)) return;
01175         if (zoom_region->priv->default_gc == NULL) 
01176                 zoom_region->priv->default_gc = gdk_gc_new (zoom_region->priv->w->window);
01177 
01178         if (zoom_region->priv->pixmap && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01179         {
01180                 gdk_draw_drawable (zoom_region->priv->w->window,
01181                                    zoom_region->priv->default_gc,
01182                                    zoom_region->priv->pixmap,
01183                                    area->x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
01184                                    area->y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
01185                                    area->x,
01186                                    area->y,
01187                                    area->width,
01188                                    area->height);
01189         }
01190 }
01191 
01195 static void
01196 zoom_region_paint (ZoomRegion *zoom_region,
01197                    GdkRectangle *area)
01198 {
01199         GdkRectangle paint_area;
01200 
01201 #ifdef ZOOM_REGION_DEBUG
01202         g_assert (zoom_region->alive);
01203 #endif
01204         DEBUG_RECT ("painting (clipped)", *area);
01205         paint_area = zoom_region_clip_to_window (zoom_region, *area);
01206         zoom_region_paint_pixmap (zoom_region, &paint_area);
01207         zoom_region_paint_cursor (zoom_region, &paint_area);
01208         zoom_region_paint_crosswire_cursor (zoom_region, &paint_area);
01209 }
01210 
01211 static ZoomRegionPixmapCreationError
01212 zoom_region_create_pixmap (ZoomRegion *zoom_region)
01213 {
01214 #ifdef ZOOM_REGION_DEBUG
01215         g_assert (zoom_region->alive);
01216 #endif
01217         if (zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01218         {
01219                 long width = (zoom_region->priv->source_area.x2 -
01220                               zoom_region->priv->source_area.x1) * zoom_region->xscale;
01221                 long height = (zoom_region->priv->source_area.y2 -
01222                                zoom_region->priv->source_area.y1) * zoom_region->yscale;
01223                 zoom_region->priv->pixmap =
01224                         gdk_pixmap_new (
01225                                 zoom_region->priv->w->window,
01226                                 width,
01227                                 height,
01228                                 gdk_drawable_get_depth (
01229                                         zoom_region->priv->w->window));
01230 
01231                 if (gmag_gs_error_check ()) {
01232                         zoom_region->priv->pixmap = NULL;
01233                         return ZOOM_REGION_ERROR_TOO_BIG;
01234                 }
01235 
01236                 DEBUG_RECT("viewport", zoom_region_source_rect_from_view_bounds
01237                            (zoom_region, &zoom_region->viewport));
01238                 DEBUG_RECT("source", zoom_region_rect_from_bounds
01239                            (zoom_region, &((Magnifier*)zoom_region->priv->parent)->source_bounds));
01240 
01241                 return ZOOM_REGION_ERROR_NONE;
01242         }
01243         
01244         return ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE;
01245 }
01246 
01247 static void
01248 zoom_region_expose_handler (GtkWindow * w,
01249                             GdkEventExpose *event,
01250                             gpointer data)
01251 {
01252         ZoomRegion *zoom_region = data;
01253         DEBUG_RECT ("expose", event->area);
01254 
01255 #ifdef ZOOM_REGION_DEBUG
01256         g_assert (zoom_region->alive);
01257 #endif
01258         if (zoom_region->priv->pixmap == NULL)
01259         {
01260                 ZoomRegionPixmapCreationError ret; 
01261                 /* TODO: scale down if this fails here */
01262                 while ((ret = zoom_region_create_pixmap (zoom_region)) ==
01263                     ZOOM_REGION_ERROR_TOO_BIG) {
01264                         zoom_region->xscale -= 1.0;
01265                         zoom_region->yscale -= 1.0;
01266                         zoom_region->priv->pixmap = NULL;
01267                         g_warning ("Scale factor too big to fit in memory; shrinking.");
01268                 }
01269                 if (ret == ZOOM_REGION_ERROR_NO_TARGET_DRAWABLE) 
01270                         g_warning ("create-pixmap: no target drawable");
01271                 else
01272                         zoom_region_update_pixmap (zoom_region, event->area,
01273                                                    NULL);
01274         }
01275         zoom_region_paint (zoom_region, &event->area);
01276 }
01277 
01278 static void
01279 zoom_region_update_cursor (ZoomRegion *zoom_region, int dx, int dy,
01280                            GdkRectangle *clip_rect)
01281 {
01282 #ifdef ZOOM_REGION_DEBUG
01283         g_assert (zoom_region->alive);
01284 #endif
01285         zoom_region_unpaint_crosswire_cursor (zoom_region, clip_rect);
01286         zoom_region_unpaint_cursor (zoom_region, clip_rect);
01287         zoom_region->priv->cursor_backing_rect.x += dx;
01288         zoom_region->priv->cursor_backing_rect.y += dy;
01289         zoom_region->priv->last_drawn_crosswire_pos.x += dx;
01290         zoom_region->priv->last_drawn_crosswire_pos.y += dy;
01291         zoom_region_paint_cursor (zoom_region, clip_rect);
01292         zoom_region_paint_crosswire_cursor (zoom_region, clip_rect);
01293         if (GTK_IS_WIDGET (zoom_region->priv->w) &&
01294             GDK_IS_WINDOW (zoom_region->priv->w->window))
01295                 gdk_display_sync (gdk_drawable_get_display (
01296                                           zoom_region->priv->w->window));
01297 }
01298 
01299 static gboolean
01300 zoom_region_calculate_scroll_rects (ZoomRegion *zoom_region,
01301                                     int dx, int dy,
01302                                     GdkRectangle *scroll_rect,
01303                                     GdkRectangle *expose_rect_h,
01304                                     GdkRectangle *expose_rect_v)
01305 {
01306         GdkWindow *window = NULL;
01307         GdkRectangle rect = {0, 0, 0, 0};
01308         gboolean retval = TRUE;
01309 
01310 #ifdef ZOOM_REGION_DEBUG
01311         g_assert (zoom_region->alive);
01312 #endif
01313         rect.x = 0;
01314         rect.y = 0;
01315         if (zoom_region && zoom_region->priv->w &&
01316             zoom_region->priv->w->window)
01317                 window = zoom_region->priv->w->window;
01318         else
01319                 retval = FALSE;
01320         if (!window)
01321                 retval = FALSE;
01322 
01323         if (window != NULL)
01324           gdk_drawable_get_size (GDK_DRAWABLE (window),
01325                                  &rect.width,
01326                                  &rect.height);
01327 
01328         if ((ABS (dx) >= rect.width) || (ABS (dy) >= rect.height)) {
01329                 *scroll_rect = rect;
01330                 DBG(fprintf (stderr, "deltas too big to scroll\n"));
01331                 retval = FALSE;
01332         }
01333         else {
01334             scroll_rect->x = MAX (0, dx);
01335             scroll_rect->y = MAX (0, dy);
01336             scroll_rect->width = MIN (rect.width + dx, rect.width - dx);
01337             scroll_rect->height = MIN (rect.height + dy, rect.height - dy);
01338         }
01339 
01340         expose_rect_h->x = 0;
01341         expose_rect_h->y = (scroll_rect->y == 0) ? scroll_rect->height : 0;
01342         expose_rect_h->width = rect.width;
01343         expose_rect_h->height = rect.height - scroll_rect->height;
01344 
01345         expose_rect_v->x = (scroll_rect->x == 0) ? scroll_rect->width : 0;
01346         expose_rect_v->y = scroll_rect->y;
01347         expose_rect_v->width = rect.width - scroll_rect->width;
01348         expose_rect_v->height = scroll_rect->height;
01349 
01350         return retval;
01351 }
01352 
01353 static void
01354 zoom_region_scroll_fast (ZoomRegion *zoom_region, int dx, int dy,
01355                          GdkRectangle *scroll_rect,
01356                          GdkRectangle *expose_rect_h,
01357                          GdkRectangle *expose_rect_v)
01358 {
01359         GdkWindow *window;
01360 
01361 #ifdef ZOOM_REGION_DEBUG
01362         g_assert (zoom_region->alive);
01363 #endif
01364         if (zoom_region->priv->w && zoom_region->priv->w->window)
01365                 window = zoom_region->priv->w->window;
01366         else {
01367                 processing_updates = FALSE;
01368                 return;
01369         }
01370         zoom_region_unpaint_crosswire_cursor (zoom_region, scroll_rect);
01371         zoom_region_unpaint_cursor (zoom_region, scroll_rect);
01372         gdk_window_scroll (window, dx, dy);
01373         zoom_region_paint_cursor (zoom_region, scroll_rect);
01374         zoom_region_paint_crosswire_cursor (zoom_region, scroll_rect);
01375         gdk_window_process_updates (window, FALSE);
01376         /* sync reduces cursor flicker, but slows things down */
01377         if (zoom_region->smooth_scroll_policy >
01378             GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST)
01379                 gdk_display_sync (gdk_drawable_get_display (window)); 
01380 }
01381 
01382 static void
01383 zoom_region_scroll_smooth (ZoomRegion *zoom_region, int dx, int dy,
01384                            GdkRectangle *scroll_rect,
01385                            GdkRectangle *expose_rect_h,
01386                            GdkRectangle *expose_rect_v)
01387 {
01388         GdkWindow *window = NULL;
01389         GdkRectangle window_rect;
01390 
01391 #ifdef ZOOM_REGION_DEBUG
01392         g_assert (zoom_region->alive);
01393 #endif
01394         if (zoom_region->priv->w && GDK_IS_DRAWABLE (zoom_region->priv->w->window))
01395                 window = zoom_region->priv->w->window;
01396         else
01397                 return;
01398         window_rect.x = 0;
01399         window_rect.y = 0;
01400         gdk_drawable_get_size (GDK_DRAWABLE (window),
01401                                &window_rect.width, &window_rect.height);
01402         gdk_window_begin_paint_rect (window, &window_rect);
01403         gdk_window_invalidate_rect (window, &window_rect, FALSE);
01404         gdk_window_process_updates (window, FALSE); 
01405         gdk_window_end_paint (window);
01406 }
01407 
01408 static void
01409 zoom_region_scroll (ZoomRegion *zoom_region, int dx, int dy)
01410 {
01411         GdkRectangle scroll_rect, expose_rect_h, expose_rect_v;
01412         gboolean can_scroll;
01413 
01414 #ifdef ZOOM_REGION_DEBUG
01415         g_assert (zoom_region->alive);
01416 #endif
01417         if (timing_test) {
01418                 mag_timing.num_line_samples++;
01419                 mag_timing.dx = abs(dx);
01420                 mag_timing.dy = abs(dy);
01421                 mag_timing.dx_total += mag_timing.dx;
01422                 mag_timing.dy_total += mag_timing.dy;
01423                 if (zoom_region->timing_output) {
01424                         fprintf(stderr, "  Panning Increment (x)    = %d (avg. %f) lines/frame\n",
01425                                 mag_timing.dx, (float)mag_timing.dx_total / (float)mag_timing.num_line_samples);
01426                         fprintf(stderr, "  Panning Increment (y)    = %d (avg. %f) lines/frame\n",
01427                                 mag_timing.dy, (float)mag_timing.dy_total / (float)mag_timing.num_line_samples);
01428                 }
01429         }
01430 
01431     /*
01432      * Currently processing a screen update.  This flag used to disallow
01433      * other updates to occur until this one finishes
01434      */
01435     processing_updates = TRUE;
01436 
01437         can_scroll = zoom_region_calculate_scroll_rects (zoom_region, dx, dy,
01438                                                          &scroll_rect,
01439                                                          &expose_rect_h,
01440                                                          &expose_rect_v);
01441         
01442         if (can_scroll) {
01443                 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_h), NULL);
01444                 zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_v), NULL);
01445 
01446                 if (zoom_region->smooth_scroll_policy > GNOME_Magnifier_ZoomRegion_SCROLL_FAST) {
01447                         zoom_region_scroll_smooth (zoom_region, dx, dy,
01448                                                    &scroll_rect,
01449                                                    &expose_rect_h,
01450                                                    &expose_rect_v);
01451                 } else {
01452                         zoom_region_scroll_fast (zoom_region, dx, dy,
01453                                                  &scroll_rect,
01454                                                  &expose_rect_h,
01455                                                  &expose_rect_v);
01456                 }
01457         } else {
01458                 zoom_region_queue_update (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, scroll_rect));
01459         }
01460 }
01461 
01462 static void
01463 zoom_region_recompute_exposed_bounds (ZoomRegion *zoom_region)
01464 {
01465         zoom_region->priv->exposed_bounds.x2 = zoom_region->priv->exposed_bounds.x1
01466                 + (zoom_region->viewport.x2 - zoom_region->viewport.x1);
01467         zoom_region->priv->exposed_bounds.y2 = zoom_region->priv->exposed_bounds.y1
01468                 + (zoom_region->viewport.y2 - zoom_region->viewport.y1);
01469 }
01470 
01471 static void
01472 zoom_region_set_cursor_pos (ZoomRegion *zoom_region, int x, int y)
01473 {
01474         if (zoom_region->priv)
01475         {
01476                 zoom_region->priv->last_cursor_pos.x = x;
01477                 zoom_region->priv->last_cursor_pos.y = y;
01478         }
01479 }
01480 
01481 static gboolean
01482 zoom_region_update_pointer (ZoomRegion *zoom_region, gboolean draw_cursor)
01483 {
01484         Magnifier *magnifier;
01485         gint mouse_x_return, mouse_y_return;
01486         guint mask_return;
01487 
01488 #ifdef ZOOM_REGION_DEBUG
01489         g_assert (zoom_region->alive);
01490 #endif
01491         if (!zoom_region->priv || !zoom_region->priv->parent 
01492             || !zoom_region->poll_mouse)
01493               return FALSE; 
01494 
01495         magnifier = zoom_region->priv->parent;
01496 
01497         /* TODO: there's really no reason we should be using magnifier->priv->root here */
01498         if (magnifier && magnifier->priv && magnifier_get_root (magnifier))
01499         {
01500                 gdk_window_get_pointer (
01501                         magnifier_get_root (magnifier),
01502                         &mouse_x_return,
01503                         &mouse_y_return,
01504                         &mask_return);
01505                 
01506                 if (zoom_region->priv->last_cursor_pos.x != mouse_x_return
01507                     || zoom_region->priv->last_cursor_pos.y != mouse_y_return)
01508                 {
01509                         zoom_region_set_cursor_pos (zoom_region,
01510                                                     mouse_x_return,
01511                                                     mouse_y_return);
01512                         if (draw_cursor)
01513                                 zoom_region_update_cursor (zoom_region, 0, 0,
01514                                                            NULL);
01515                         
01516                         return TRUE;
01517                 }
01518         }       
01519         return FALSE;
01520 }
01521 
01522 static int
01523 zoom_region_update_pointer_idle (gpointer data)
01524 {
01525         ZoomRegion *zoom_region = (ZoomRegion *) data;
01526 
01527         if (zoom_region_update_pointer (zoom_region, TRUE))
01528                 return TRUE;
01529         else {
01530                 if (zoom_region->priv)
01531                         zoom_region->priv->update_pointer_id =
01532                             g_timeout_add_full (G_PRIORITY_DEFAULT,
01533                                                 100,
01534                                                 zoom_region_update_pointer_timeout,
01535                                                 zoom_region,
01536                                                 NULL);
01537                 return FALSE;
01538         }
01539 }
01540 
01541 static int
01542 zoom_region_update_pointer_timeout (gpointer data)
01543 {
01544         ZoomRegion *zoom_region = data;
01545 
01546         if (zoom_region->priv && zoom_region_update_pointer (zoom_region,
01547                                                              TRUE)) {
01548             zoom_region->priv->update_pointer_id =
01549                 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
01550                                  zoom_region_update_pointer_idle,
01551                                  data,
01552                                  NULL);
01553                 return FALSE;
01554         } else 
01555                 return TRUE;
01556 }
01557 
01558 static void
01559 zoom_region_moveto (ZoomRegion *zoom_region,
01560                     const long x, const long y)
01561 {
01562         long dx = x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
01563         long dy = y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
01564 #ifdef ZOOM_REGION_DEBUG
01565         g_assert (zoom_region->alive);
01566 #endif
01567 /* fprintf (stderr, "moveto %ld %ld\n", x, y); */
01568 
01569         mag_timing.dx = 0;
01570         mag_timing.dy = 0;
01571 
01572         if ((dx != 0) || (dy != 0)) {
01573                 zoom_region_update_pointer (zoom_region, FALSE);
01574                 zoom_region->priv->exposed_bounds.x1 = x * zoom_region->xscale;
01575                 zoom_region->priv->exposed_bounds.y1 = y * zoom_region->yscale;
01576                 zoom_region_recompute_exposed_bounds (zoom_region);
01577                 zoom_region_scroll (zoom_region,
01578                                     -dx, -dy);
01579         }
01580 }
01581 
01582 /*
01583  * Process that must be made in-line in the current pixbuf.
01584  */
01585 static void
01586 zoom_region_process_pixbuf (ZoomRegion *zoom_region, GdkPixbuf *pixbuf)
01587 {
01588         int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
01589         int i, j, t;
01590         int w = gdk_pixbuf_get_width (pixbuf);
01591         int h = gdk_pixbuf_get_height (pixbuf);
01592         int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
01593         guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
01594         guchar *pixels_row;
01595 
01596         gboolean manipulate_contrast = FALSE;
01597         gboolean manipulate_brightness = FALSE;
01598         gboolean color_blind_filter = FALSE;
01599 
01600         if (zoom_region->contrast_r != 0 || zoom_region->contrast_g != 0 ||
01601             zoom_region->contrast_b != 0) {
01602                 manipulate_contrast = TRUE;
01603         }
01604 
01605         if (zoom_region->bright_r != 0 || zoom_region->bright_g != 0 ||
01606             zoom_region->bright_b != 0) {
01607                 manipulate_brightness = TRUE;
01608         }
01609 
01610 #ifdef HAVE_COLORBLIND
01611         if (zoom_region->color_blind_filter !=
01612             GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER) {
01613                 color_blind_filter = TRUE;
01614         }
01615 #endif /* HAVE_COLORBLIND */
01616 
01617         if (!manipulate_contrast && !zoom_region->invert &&
01618             !manipulate_brightness && !color_blind_filter)
01619                 return;
01620 
01621 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
01622 #define CLAMP_LOW_MID(v) (t = (v), CLAMP (t, 0, 127))
01623 #define CLAMP_MID_HIGH(v) (t = (v), CLAMP (t, 127, 255))
01624 
01625         for (j = 0; j < h; ++j) {
01626                 pixels_row = pixels;
01627                 for (i = 0; i < w; ++i) {
01628                         if (manipulate_contrast) {
01629                                 /* Set the RED contrast */
01630                                 if (pixels_row[0] <= 127)
01631                                         pixels_row[0] = CLAMP_LOW_MID (pixels_row[0] - zoom_region->contrast_r * 127);
01632                                 else
01633                                         pixels_row[0] = CLAMP_MID_HIGH (pixels_row[0] + zoom_region->contrast_r * 127);
01634 
01635                                 /* Set the GREEN contrast */
01636                                 if (pixels_row[1] <= 127)
01637                                         pixels_row[1] = CLAMP_LOW_MID (pixels_row[1] - zoom_region->contrast_g * 127);
01638                                 else
01639                                         pixels_row[1] = CLAMP_MID_HIGH (pixels_row[1] + zoom_region->contrast_g * 127);
01640 
01641                                 /* Set the BLUE contrast */
01642                                 if (pixels_row[2] <= 127)
01643                                         pixels_row[2] = CLAMP_LOW_MID (pixels_row[2] - zoom_region->contrast_b * 127);
01644                                 else
01645                                         pixels_row[2] = CLAMP_MID_HIGH (pixels_row[2] + zoom_region->contrast_b * 127);
01646                         }
01647 
01648                         if (manipulate_brightness) {
01649                                 /* Set the RED brightness */
01650                                 pixels_row[0] = CLAMP_UCHAR (pixels_row[0] + zoom_region->bright_r * 255);
01651                                 
01652                                 /* Set the GREEN brightness */
01653                                 pixels_row[1] = CLAMP_UCHAR (pixels_row[1] + zoom_region->bright_g * 255);
01654 
01655                                 /* Set the BLUE brightness */
01656                                 pixels_row[2] = CLAMP_UCHAR (pixels_row[2] + zoom_region->bright_b * 255);
01657                         }
01658 
01659                         if (zoom_region->invert) {
01660                                 pixels_row[0] = ~(pixels_row[0]);
01661                                 pixels_row[1] = ~(pixels_row[1]);
01662                                 pixels_row[2] = ~(pixels_row[2]);
01663                         }
01664 
01665 #ifdef HAVE_COLORBLIND
01666                         if (color_blind_filter) {
01667                                 color->red   = pixels_row[0];
01668                                 color->green = pixels_row[1];
01669                                 color->blue  = pixels_row[2];
01670                                 if (colorblind_filter (cbr, color)) {
01671                                         pixels_row[0] = color->red;
01672                                         pixels_row[1] = color->green;
01673                                         pixels_row[2] = color->blue;
01674                                 }
01675                         }
01676 #endif /* HAVE_COLORBLIND */
01677                         
01678                         pixels_row += n_channels;
01679                 }
01680                 pixels += rowstride;
01681         }
01682 
01683 }
01684 
01685 static void
01686 zoom_region_post_process_pixbuf (ZoomRegion *zoom_region,
01687                                  GdkPixbuf *subimage,
01688                                  GdkPixbuf *scaled_image)
01689 {
01690         /* nothing yet */
01700 }
01701 
01702 static GdkPixbuf *
01703 zoom_region_get_source_subwindow (ZoomRegion *zoom_region,
01704                                   const GdkRectangle bounds)
01705 {
01706         int i, j, width, height;
01707         Magnifier *magnifier = zoom_region->priv->parent;
01708         GdkPixbuf *subimage = NULL;
01709 
01710 #ifdef ZOOM_REGION_DEBUG
01711         g_assert (zoom_region->alive);
01712 #endif
01713         width = gdk_screen_get_width (
01714                 gdk_display_get_screen (magnifier->source_display,
01715                                         magnifier->source_screen_num));
01716         height = gdk_screen_get_height (
01717                 gdk_display_get_screen (magnifier->source_display,
01718                                         magnifier->source_screen_num));
01719 
01720         if ((bounds.width <= 0) || (bounds.height <= 0))
01721         {
01722                 return NULL;
01723         }
01724         
01725         if (!zoom_region->priv->source_drawable)
01726         {
01727                 /* TESTING ONLY */
01728                 if (zoom_region->priv->test) {
01729                         GdkImage *test_image = NULL;
01730 
01731                         test_image = gdk_image_new (GDK_IMAGE_FASTEST,
01732                                                     gdk_visual_get_system (),
01733                                                     width,
01734                                                     height);
01735 
01736                         for (i = 0; i < width; ++i)
01737                                 for (j = 0; j < height; ++j)
01738                                         gdk_image_put_pixel (test_image, i, j, i*j);
01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
01784 
01785         /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
01786         if (zoom_region->cache_source && subimage) {
01787                 GdkPixbuf *cache_subpixbuf =
01788                         gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
01789                                                   bounds.x, bounds.y, bounds.width, bounds.height);
01790                 if (_diff_pixbufs (subimage, cache_subpixbuf)) {
01791                         gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
01792                                               zoom_region->priv->source_pixbuf_cache,
01793                                               bounds.x, bounds.y);
01794                 }
01795                 else
01796                 {
01797                         if (subimage)
01798                                 g_object_unref (subimage);
01799                         subimage = NULL;
01800                 }
01801                 g_object_unref (cache_subpixbuf);
01802         }
01803         return subimage;
01804 }
01805 
01806 static GdkRectangle
01807 zoom_region_update_pixmap (ZoomRegion *zoom_region,
01808                            const GdkRectangle update_rect,
01809                            GdkRectangle *p_rect)
01810 {
01811         GdkPixbuf *subimage;
01812         GdkRectangle source_rect;
01813 
01814 #ifdef ZOOM_REGION_DEBUG
01815         g_assert (zoom_region->alive);
01816 #endif
01817         DEBUG_RECT ("unclipped update rect", update_rect);
01818         source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
01819         DEBUG_RECT ("clipped to source", source_rect);
01820         source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
01821         DEBUG_RECT ("update rect clipped to exposed target", source_rect); 
01822 
01823         subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
01824 
01825         if (subimage)
01826         {
01827                 GdkRectangle paint_rect;
01828                 g_timer_start (mag_timing.scale);
01829                 DEBUG_RECT ("source rect", source_rect);
01830                 paint_rect = 01739 
01740                         zoom_region->priv->source_drawable = gdk_pixmap_new (zoom_region->priv->w->window, width, height, -1);
01741 
01742                         if (zoom_region->priv->default_gc == NULL)
01743                                 zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01744 
01745                         gdk_draw_image (zoom_region->priv->source_drawable,
01746                                         zoom_region->priv->default_gc,
01747                                         test_image,
01748                                         0, 0,
01749                                         0, 0,
01750                                         width, height);
01751                 }
01752                 else
01753                 {
01754                         if (magnifier->priv->source_drawable) {
01755                                 zoom_region->priv->source_drawable =
01756                                         magnifier->priv->source_drawable;
01757                         } else
01758                                 zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
01759                 }
01760                 if (zoom_region->cache_source)
01761                 {
01762                         zoom_region->priv->source_pixbuf_cache =
01763                                 gdk_pixbuf_new (GDK_COLORSPACE_RGB,
01764                                                 FALSE,
01765                                                 8, /* FIXME: not always 8? */
01766                                                 width, height);
01767                 }
01768         }
01769         DEBUG_RECT ("getting subimage from ", bounds);
01770 
01771         subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
01772                                                  gdk_colormap_get_system (),
01773                                                  bounds.x,
01774                                                  bounds.y,
01775                                                  0,
01776                                                  0,
01777                                                  bounds.width,
01778                                                  bounds.height);
01779 
01780         /* TODO: blank the region overlapped by the target display if source == target */
01781         
01782         if (!subimage)
01783                 _debug_announce_rect ("update of invalid subregion!\n", bounds);
<