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 = zoom_region_view_rect_from_source_rect (zoom_region, source_rect);
01831                 if (p_rect) {
01832                         *p_rect = paint_rect;
01833                 }
01834                 /* paint_rect = zoom_region_clip_to_scaled_pixmap (zoom_region, paint_rect); */
01835                 DEBUG_RECT ("paint rect", paint_rect);
01836 
01837                 zoom_region_process_pixbuf (zoom_region, subimage);
01838 
01843                 gdk_pixbuf_scale (subimage,
01844                                   zoom_region->priv->scaled_pixbuf,
01845                                   0,
01846                                   0,
01847                                   paint_rect.width,
01848                                   paint_rect.height,
01849                                   0,
01850                                   0,
01851                                   zoom_region->xscale,
01852                                   zoom_region->yscale,
01853                                   zoom_region->priv->gdk_interp_type);
01854 
01855                 zoom_region_post_process_pixbuf (zoom_region, subimage,
01856                                                  zoom_region->priv->scaled_pixbuf);
01857                 if (zoom_region->priv->default_gc == NULL)
01858                         zoom_region->priv->default_gc = gdk_gc_new(zoom_region->priv->w->window);
01859 
01860 #ifndef USE_GDK_PIXBUF_RENDER_TO_DRAWABLE 
01861                 if (GDK_IS_DRAWABLE (zoom_region->priv->pixmap))
01862                     gdk_draw_pixbuf (zoom_region->priv->pixmap,
01863                                      zoom_region->priv->default_gc,
01864                                      zoom_region->priv->scaled_pixbuf,
01865                                      0,
01866                                      0,
01867                                      paint_rect.x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
01868                                      paint_rect.y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
01869                                      paint_rect.width,
01870                                      paint_rect.height,
01871                                      GDK_RGB_DITHER_NONE,
01872                                      0,
01873                                      0);
01874                 else
01875                     g_warning ("updating non-drawable pixmap: region %p", zoom_region);
01876 #else
01877                 gdk_pixbuf_render_to_drawable (zoom_region->priv->scaled_pixbuf,
01878                                                zoom_region->priv->pixmap,
01879                                                zoom_region->priv->default_gc,
01880                                                0,
01881                                                0,
01882                                                paint_rect.x + zoom_region->priv->exposed_bounds.x1,
01883                                                paint_rect.y + zoom_region->priv->exposed_bounds.y1,
01884                                                paint_rect.width,
01885                                                paint_rect.height,
01886                                                GDK_RGB_DITHER_NONE,
01887                                                0,
01888                                                0);
01889 #endif
01890                 if (gmag_gs_error_check ())
01891                         g_warning ("Could not render scaled image to drawable; out of memory!\n");
01892                 g_object_unref (subimage);
01893 
01894                 g_timer_stop (mag_timing.scale);
01895         }
01896         return source_rect;
01897 }
01898 
01905 static void
01906 zoom_region_update (ZoomRegion *zoom_region,
01907                     const GdkRectangle update_rect)
01908 {
01909         GdkRectangle paint_rect = {0, 0, 0, 0};
01910         if (zoom_region->priv->w && zoom_region->priv->w->window) {
01911                 GdkRectangle source_rect = zoom_region_update_pixmap (zoom_region, update_rect, &paint_rect);
01912                 if (paint_rect.x != 0 || paint_rect.y != 0 ||
01913                     paint_rect.width != 0 || paint_rect.height != 0) {
01914                         gdk_window_begin_paint_rect (
01915                                 zoom_region->priv->w->window, &paint_rect);
01916                         zoom_region_paint (zoom_region, &paint_rect);
01917                         gdk_window_end_paint (zoom_region->priv->w->window);
01918                 }
01919                 if (timing_test) {
01920                         mag_timing.num_scale_samples++;
01921                         
01922                         gulong microseconds;
01923 
01924                         mag_timing.scale_val =
01925                                 g_timer_elapsed (mag_timing.scale,
01926                                                  &microseconds);
01927                         mag_timing.scale_total += mag_timing.scale_val;
01928 
01929                         if (mag_timing.scale_val != 0 && (timing_scale_max == 0 ||
01930                            (1.0/(float)mag_timing.scale_val) > (1.0/(float)timing_scale_max)))
01931                                 timing_scale_max = mag_timing.scale_val;
01932                         if ((source_rect.height * source_rect.width / mag_timing.scale_val) > update_nrr_max)
01933                                 update_nrr_max = source_rect.height * source_rect.width / mag_timing.scale_val;
01934 
01935                         mag_timing.update_pixels_total += source_rect.height * source_rect.width;
01936 
01937                         if (zoom_region->timing_output) {
01938                                 fprintf(stderr, "  Update Duration          = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
01939                                         mag_timing.scale_val, (mag_timing.scale_total / 
01940                                         mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total);
01941                                 fprintf(stderr, "    Update Pixels          = %ld (avg. %ld) pixels/frame\n",
01942                                         (long) source_rect.height * source_rect.width,
01943                                         mag_timing.update_pixels_total / mag_timing.num_scale_samples);
01944                                 fprintf(stderr, "    Update Rate            = (avg. %f) (max. %f) updates/second\n",
01945                                         1.0/(mag_timing.scale_total / mag_timing.num_scale_samples), 1.0/(float)timing_scale_max);
01946                                 fprintf(stderr, "    Net Update Rate        = (avg. %f) (max. %f) Mpex/second\n",
01947                                         ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
01948                                         update_nrr_max / 1000000.0);
01949                         }
01950                 }
01951         } else {
01952                 fprintf (stderr, "update on uninitialized zoom region!\n");
01953         }
01954 }
01955 
01956 static void
01957 zoom_region_init_window (ZoomRegion *zoom_region)
01958 {
01959         GtkFixed *parent;
01960         GtkWidget *zoomer, *border;
01961         DBG(fprintf (stderr, "window not yet created...\n"));
01962         parent = GTK_FIXED (
01963                 ((Magnifier *)zoom_region->priv->parent)->priv->canvas);
01964         zoomer = gtk_drawing_area_new ();
01965         border = gtk_drawing_area_new ();
01966         zoom_region->priv->border = border;
01967         zoom_region->priv->w = zoomer;
01968 
01969 #ifdef ZOOM_REGION_DEBUG
01970         g_assert (zoom_region->alive);
01971 #endif
01972         gtk_widget_set_size_request (GTK_WIDGET (border),
01973                                      zoom_region->viewport.x2 -
01974                                      zoom_region->viewport.x1,
01975                                      zoom_region->viewport.y2 -
01976                                      zoom_region->viewport.y1);
01977         gtk_widget_set_size_request (GTK_WIDGET (zoomer),
01978                                      zoom_region->viewport.x2 -
01979                                      zoom_region->viewport.x1 -
01980                                      (zoom_region->border_size_right +
01981                                       zoom_region->border_size_left),
01982                                      zoom_region->viewport.y2 -
01983                                      zoom_region->viewport.y1 -
01984                                      (zoom_region->border_size_bottom +
01985                                       zoom_region->border_size_top));
01986         gtk_fixed_put (parent, border,
01987                        zoom_region->viewport.x1,
01988                        zoom_region->viewport.y1);
01989         gtk_fixed_put (parent, zoomer,
01990                        zoom_region->viewport.x1 +
01991                        zoom_region->border_size_left,
01992                        zoom_region->viewport.y1 +
01993                        zoom_region->border_size_top);
01994         gtk_widget_show (GTK_WIDGET (border));
01995         gtk_widget_show (GTK_WIDGET (zoomer));
01996         gtk_widget_show (GTK_WIDGET (parent));
01997         zoom_region->priv->expose_handler_id =
01998                 g_signal_connect (G_OBJECT (zoom_region->priv->w),
01999                                   "expose_event",
02000                                   G_CALLBACK (zoom_region_expose_handler),
02001                                   zoom_region);
02002         DBG(fprintf (stderr, "New window created\n"));
02003 }
02004 
02005 static int
02006 zoom_region_process_updates (gpointer data)
02007 {
02008         ZoomRegion *zoom_region = (ZoomRegion *) data;
02009 
02010         /* TODO: lock the queue when copying it? */
02011         zoom_region_coalesce_updates (zoom_region);
02012 
02013         if (zoom_region->priv->q != NULL) {
02014                 GList *last = g_list_last (zoom_region->priv->q);
02015 #ifdef ZOOM_REGION_DEBUG
02016                 fprintf (stderr, "qlen=%d\n", g_list_length (zoom_region->priv->q));
02017 #endif
02018                 if (last) {
02019                         zoom_region->priv->q = g_list_remove_link (zoom_region->priv->q,
02020                                                                    last);
02021                         zoom_region_update (zoom_region,
02022                                             * (GdkRectangle *) last->data);
02023                         g_list_free (last);
02024 #ifdef DEBUG
02025                         fputs (".\n", stderr); /* debug output, means we actually did something. */
02026 #endif
02027                 }
02028                 return TRUE;
02029         }
02030         else 
02031         {
02032                 if (zoom_region->priv) 
02033                         zoom_region->priv->update_handler_id = 0;
02034                 return FALSE;
02035         }
02036 }
02037 
02038 void
02039 timing_report(ZoomRegion *zoom_region)
02040 {
02041         float frame_avg;
02042         float x_scroll_incr, y_scroll_incr;
02043         int width, height, x, y;
02044 
02045         if (timing_test) {
02046                 width = (zoom_region->viewport.x2 -
02047                         zoom_region->viewport.x1) / zoom_region->xscale;
02048                 height = (zoom_region->viewport.y2 -
02049                         zoom_region->viewport.y1) / zoom_region->yscale;
02050 
02051                 frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples;
02052 
02053                 x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
02054                 y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
02055 
02056                 gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
02057                         &x, &y);
02058 
02059                 fprintf(stderr, "  Frames Processed         = %ld\n", 
02060                         mag_timing.num_frame_samples + 1);
02061                 fprintf(stderr, "  Width/Height/Depth       = %d/%d/%d\n", x, y,
02062                         gdk_drawable_get_depth (zoom_region->priv->w->window));
02063                 fprintf(stderr, "  Zoom Factor (x/y)        = %f/%f\n", zoom_region->xscale,
02064                         zoom_region->yscale);
02065                 if (mag_timing.num_scale_samples != 0) {
02066                         fprintf(stderr, "  Update Duration          = (avg. %f) (max. %f) (tot. %f) seconds\n",
02067                                 (mag_timing.scale_total / mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total);
02068                         fprintf(stderr, "    Update Pixels          = (avg. %ld) pixels/frame\n",
02069                                 mag_timing.update_pixels_total / mag_timing.num_scale_samples);
02070                         fprintf(stderr, "    Update Rate            = (avg. %f) (max. %f) updates/second\n",
02071                                 1.0/((float)mag_timing.scale_total / (float)mag_timing.num_scale_samples),
02072                                 1.0/(float)timing_scale_max);
02073                         fprintf(stderr, "    Net Update Rate        = (avg. %f) (max. %f) Mpex/second\n",
02074                                 ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
02075                                 update_nrr_max / 1000000.0);
02076                 }
02077                 fprintf(stderr, "  Pan Latency              = (avg. %f) (max. %f) seconds\n",
02078                         (mag_timing.idle_total / mag_timing.num_idle_samples), timing_idle_max);
02079                 fprintf(stderr, "  Total Frame Duration     = (avg. %f) (max. %f) (tot. %f) seconds\n",
02080                         frame_avg, timing_frame_max, mag_timing.frame_total);
02081                 fprintf(stderr, "  Frame Rate               = (avg. %f) (max. %f) frames/second\n",
02082                         1.0 / (mag_timing.frame_total / mag_timing.num_frame_samples), cps_max);
02083                 fprintf(stderr, "  Scroll Delta (x)         = (avg. %f) (tot. %d) lines\n",
02084                         x_scroll_incr, mag_timing.dx_total);
02085                 fprintf(stderr, "  Scroll Delta (y)         = (avg. %f) (tot. %d) lines\n",
02086                         y_scroll_incr, mag_timing.dy_total);
02087                 fprintf(stderr, "  Scroll Rate (x)          = (avg. %f) lines/second\n",
02088                         x_scroll_incr / frame_avg);
02089                 fprintf(stderr, "  Scroll Rate (y)          = (avg. %f) lines/second\n",
02090                         y_scroll_incr / frame_avg);
02091 
02092                 fprintf(stderr, "  Net Render Rate          = (avg. %f) (max. %f) Mpex/second\n\n",
02093                         (height * width *
02094                         ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
02095                         nrr_max / 1000000.0);
02096         }
02097 }
02098 
02099 static void
02100 zoom_region_time_frame(ZoomRegion *zoom_region, Magnifier *magnifier)
02101 {
02102         float frame_avg;
02103         float x_scroll_incr, y_scroll_incr;
02104         int width = magnifier->target_bounds.x2 - magnifier->target_bounds.x1;
02105         int height = magnifier->target_bounds.y2 - magnifier->target_bounds.y1;
02106 
02107         mag_timing.num_frame_samples++;
02108         g_timer_stop (mag_timing.frame);
02109 
02110         gulong microseconds;
02111 
02112         mag_timing.frame_val = g_timer_elapsed (mag_timing.frame,
02113                                                 &microseconds);
02114 
02115         mag_timing.frame_total += mag_timing.frame_val;
02116         if (mag_timing.frame_val > timing_frame_max)
02117                 timing_frame_max = mag_timing.frame_val;
02118         if (mag_timing.frame_val != 0 && 1.0/mag_timing.frame_val > cps_max)
02119                 cps_max = 1.0/mag_timing.frame_val;
02120 
02121         frame_avg = mag_timing.frame_total / mag_timing.num_frame_samples;
02122 
02123         x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
02124         y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
02125 
02126         if ((height * width / mag_timing.frame_val) > nrr_max)
02127                 nrr_max = height * width / mag_timing.frame_val;
02128 
02129         if (zoom_region->timing_output) {
02130                 fprintf(stderr, "  Total Frame Duration     = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
02131                         mag_timing.frame_val, frame_avg, timing_frame_max, mag_timing.frame_total);
02132                 fprintf(stderr, "  Frame Rate               = (avg. %f) (max. %f) frames/second\n",
02133                         1.0 /frame_avg, cps_max);
02134                 fprintf(stderr, "  Scroll Delta (x)         = (avg. %f) (tot. %d) lines\n",
02135                         x_scroll_incr, mag_timing.dx_total);
02136                 fprintf(stderr, "  Scroll Delta (y)         = (avg. %f) (tot. %d) lines\n",
02137                         y_scroll_incr, mag_timing.dy_total);
02138                 fprintf(stderr, "  Scroll Rate (x)          = (avg. %f) lines/second\n",
02139                         x_scroll_incr / frame_avg);
02140                 fprintf(stderr, "  Scroll Rate (y)          = (avg. %f) lines/second\n",
02141                         y_scroll_incr / frame_avg);
02142 
02143                 fprintf(stderr, "  Net Render Rate          = (avg. %f) (max. %f) Mpex/second\n",
02144                         (height * width *
02145                         ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
02146                         nrr_max / 1000000.0);
02147         }
02148 
02149         mag_timing.last_frame_val = mag_timing.frame_val;
02150         mag_timing.last_dy        = mag_timing.dy;
02151 
02152         if (reset_timing) {
02153                 fprintf(stderr, "\n### Updates summary:\n\n");
02154                 timing_report (zoom_region);
02155                 fprintf(stderr, "\n### Updates finished, starting panning test\n");
02156                 reset_timing_stats();
02157                 reset_timing = FALSE;
02158         }
02159 }
02160 
02161 static void
02162 zoom_region_sync (ZoomRegion *zoom_region)
02163 {
02164         while (zoom_region->priv->q)
02165                 zoom_region_process_updates (zoom_region);
02166 }
02167 
02168 static gboolean
02169 gdk_timing_idle (gpointer data)
02170 {
02171         ZoomRegion *zoom_region = data;
02172 
02173         /* Now update has finished, reset processing_updates */
02174         processing_updates = FALSE;
02175         g_timer_stop (mag_timing.idle);
02176 
02177         if (timing_test) {
02178                 mag_timing.num_idle_samples++;
02179 
02180                 gulong microseconds;
02181 
02182                 mag_timing.idle_val = g_timer_elapsed (mag_timing.idle,
02183                                                        &microseconds);
02184                 mag_timing.idle_total += mag_timing.idle_val;
02185 
02186                 if (mag_timing.idle_val > timing_idle_max)
02187                         timing_idle_max = mag_timing.idle_val;
02188 
02189                 if (zoom_region->timing_output) {
02190                         fprintf(stderr, "  Pan Latency              = %f (avg. %f) (max. %f) seconds\n",
02191                                 mag_timing.idle_val, (mag_timing.idle_total /
02192                                 mag_timing.num_idle_samples), timing_idle_max);
02193                 }
02194         }
02195 
02196         return FALSE;
02197 }
02198 
02199 static void
02200 zoom_region_get_move_x_y (ZoomRegion *zoom_region, long *x, long *y)
02201 {
02202         long width, height;
02203 
02204         width = (zoom_region->viewport.x2 - zoom_region->viewport.x1) /
02205                 zoom_region->xscale;
02206         height = (zoom_region->viewport.y2 - zoom_region->viewport.y1) /
02207                 zoom_region->yscale;
02208 
02209         switch (zoom_region->x_align_policy) {
02210         case GNOME_Magnifier_ZoomRegion_ALIGN_MAX:
02211                 *x = zoom_region->roi.x2 - width;
02212                 break;
02213         case GNOME_Magnifier_ZoomRegion_ALIGN_MIN:
02214                 *x = zoom_region->roi.x1;
02215                 break;
02216         case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER:
02217         default:
02218                 *x = ((zoom_region->roi.x1 + zoom_region->roi.x2) - width ) /
02219                         2;
02220         }
02221 
02222         switch (zoom_region->y_align_policy) {
02223         case GNOME_Magnifier_ZoomRegion_ALIGN_MAX:
02224                 *y = zoom_region->roi.y2 - height;
02225                 break;
02226         case GNOME_Magnifier_ZoomRegion_ALIGN_MIN:
02227                 *y = zoom_region->roi.y1;
02228                 break;
02229         case GNOME_Magnifier_ZoomRegion_ALIGN_CENTER:
02230         default:
02231                 *y = ((zoom_region->roi.y1 + zoom_region->roi.y2) - height ) /
02232                         2;
02233         }
02234 }
02235 
02236 static void
02237 zoom_region_align (ZoomRegion *zoom_region)
02238 {
02239         Magnifier *magnifier = zoom_region->priv->parent;
02240         long x = 0, y = 0;
02241 
02242         if (timing_start)
02243                 zoom_region_time_frame(zoom_region, magnifier);
02244 
02245         if (timing_test) {
02246                 g_timer_start (mag_timing.frame);
02247 
02248                 if (zoom_region->timing_output) {
02249                         gint x, y;
02250 
02251                         gdk_drawable_get_size (GDK_DRAWABLE (zoom_region->priv->w->window),
02252                                 &x, &y);
02253 
02254                         fprintf(stderr, "\nTiming Information - ROI   = (%d, %d) (%d, %d):\n",
02255                                 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
02256                                 zoom_region->roi.y2);
02257                         fprintf(stderr, "  Frame Number             = %ld\n", 
02258                                 mag_timing.num_frame_samples + 1);
02259                         fprintf(stderr, "  Width/Height/Depth       = %d/%d/%d\n", x, y,
02260                                 gdk_drawable_get_depth (zoom_region->priv->w->window));
02261                 }
02262 
02263                 /*
02264                  * The timing_start flag makes sure that we don't start displaying output
02265                  * until we have processed an entire frame.
02266                  */
02267                 if (!timing_start)
02268                         g_timer_start (mag_timing.process);
02269 
02270                 timing_start = TRUE;
02271         }
02272 
02273         g_timer_start (mag_timing.idle);
02274 
02275         /*
02276          * zoom_region_align calls
02277          *   zoom_region_moveto calls
02278          *     zoom_region_scroll calls
02279          *        zoom_region_scroll_fast or zoom_region_scroll_smooth calls
02280          *           gdk_window_scroll or gdk_window_invalidate_rect calls
02281          *              gdk_window_invalidate_region calls
02282          *                 gdk_window_invalidate_maybe_recurse
02283          * 
02284          * The last function in the stack will set up an idle handler of
02285          * priority GDK_PRIORITY_REDRAW (gdk_window_update_idle) to be called
02286          * to handle the work of updateing the screen.
02287          *
02288          * By setting up an idle handler of priority GDK_PRIORITY_REDRAW + 1,
02289          * it will be called immediately after and we can determine when GTK+
02290          * is finished with the update.
02291          */
02292         g_idle_add_full (GDK_PRIORITY_REDRAW + 1,
02293                 gdk_timing_idle, zoom_region, NULL);
02294 
02295         zoom_region_get_move_x_y (zoom_region, &x, &y);
02296 
02297         zoom_region_moveto (zoom_region, x, y);
02298 }
02299 
02300 static void
02301 zoom_region_set_viewport (ZoomRegion *zoom_region,
02302                           const GNOME_Magnifier_RectBounds *viewport)
02303 {
02304 #ifdef ZOOM_REGION_DEBUG
02305         g_assert (zoom_region->alive);
02306 #endif
02307         if (zoom_region->viewport.x1 == viewport->x1 &&
02308             zoom_region->viewport.y1 == viewport->y1 &&
02309             zoom_region->viewport.x2 == viewport->x2 &&
02310             zoom_region->viewport.y2 == viewport->y2) {
02311                 return;
02312         }
02313         zoom_region->viewport = *viewport;
02314 #ifdef DEBUG
02315         fprintf (stderr, "Setting viewport %d,%d - %d,%d\n",
02316                  (int) viewport->x1, (int) viewport->y1,
02317                  (int) viewport->x2, (int) viewport->y2);
02318 #endif
02319         zoom_region_align (zoom_region);
02320         if (!zoom_region->priv->w) {
02321                 zoom_region_init_window (zoom_region);
02322         } else {
02323                 CORBA_any *any;
02324                 CORBA_Environment ev;
02325                 Bonobo_PropertyBag properties;
02326                 Magnifier *magnifier = (Magnifier *) zoom_region->priv->parent;
02327                 GtkFixed *fixed = GTK_FIXED (magnifier->priv->canvas);
02328                 gtk_fixed_move (fixed,
02329                                 zoom_region->priv->border,
02330                                 zoom_region->viewport.x1,
02331                                 zoom_region->viewport.y1);
02332                 gtk_fixed_move (fixed,
02333                                 zoom_region->priv->w,
02334                                 zoom_region->viewport.x1 +
02335                                 zoom_region->border_size_left,
02336                                 zoom_region->viewport.y1 +
02337                                 zoom_region->border_size_top);
02338                 gtk_widget_set_size_request (
02339                         GTK_WIDGET (zoom_region->priv->border),
02340                         zoom_region->viewport.x2 - zoom_region->viewport.x1,
02341                         zoom_region->viewport.y2 - zoom_region->viewport.y1);
02342                 gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
02343                                              zoom_region->viewport.x2 -
02344                                              zoom_region->viewport.x1 -
02345                                              (zoom_region->border_size_right +
02346                                               zoom_region->border_size_left),
02347                                              zoom_region->viewport.y2 -
02348                                              zoom_region->viewport.y1 -
02349                                              (zoom_region->border_size_bottom +
02350                                               zoom_region->border_size_top));
02351                 CORBA_exception_init (&ev);
02352                 properties = 
02353                         GNOME_Magnifier_Magnifier_getProperties(
02354                                 BONOBO_OBJREF (
02355                                         (Magnifier *) zoom_region->priv->parent), &ev);
02356                 if (!BONOBO_EX (&ev))
02357                         any = Bonobo_PropertyBag_getValue (
02358                                 properties, "source-display-bounds", &ev);
02359                 if (!BONOBO_EX (&ev))
02360                         zoom_region->priv->source_area =
02361                                 *((GNOME_Magnifier_RectBounds *) any->_value);
02362                 if (zoom_region->priv->pixmap) 
02363                         g_object_unref (zoom_region->priv->pixmap);
02364                 zoom_region_create_pixmap (zoom_region);
02365                 if (zoom_region->priv->scaled_pixbuf)
02366                         g_object_unref (zoom_region->priv->scaled_pixbuf);
02367 
02368                 zoom_region->priv->scaled_pixbuf = 
02369                   gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
02370                                   (zoom_region->priv->source_area.x2 -
02371                                    zoom_region->priv->source_area.x1) * zoom_region->xscale + 1,
02372                                   (zoom_region->priv->source_area.y2 -
02373                                    zoom_region->priv->source_area.y1) * zoom_region->yscale + 1);
02374         }
02375         zoom_region_queue_update (zoom_region,
02376                                   zoom_region_source_rect_from_view_bounds (
02377                                           zoom_region, &zoom_region->viewport));
02378 }
02379 
02380 static void
02381 zoom_region_get_property (BonoboPropertyBag *bag,
02382                           BonoboArg *arg,
02383                           guint arg_id,
02384                           CORBA_Environment *ev,
02385                           gpointer user_data)
02386 {
02387         ZoomRegion *zoom_region = user_data;
02388 
02389 #ifdef ZOOM_REGION_DEBUG
02390         g_assert (zoom_region->alive);
02391 #endif
02392         DBG (fprintf (stderr, "Get zoom-region property: %s\n", prop_names[arg_id]));
02393 
02394         switch (arg_id) {
02395         case ZOOM_REGION_MANAGED_PROP:
02396                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->is_managed);
02397                 break;
02398         case ZOOM_REGION_POLL_MOUSE_PROP:
02399                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->poll_mouse);
02400                 break;
02401         case ZOOM_REGION_DRAW_CURSOR_PROP:
02402                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->draw_cursor);
02403                 break;
02404         case ZOOM_REGION_INVERT_PROP:
02405                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->invert);
02406                 break;
02407         case ZOOM_REGION_SMOOTHSCROLL_PROP:
02408                 BONOBO_ARG_SET_SHORT (arg, zoom_region->smooth_scroll_policy);
02409                 break;
02410         case ZOOM_REGION_COLORBLIND_PROP:
02411                 BONOBO_ARG_SET_SHORT (arg, zoom_region->color_blind_filter);
02412                 break;
02413         case ZOOM_REGION_TESTPATTERN_PROP:
02414                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->priv->test);
02415                 break;
02416         case ZOOM_REGION_SMOOTHING_PROP:
02417                 BONOBO_ARG_SET_STRING (arg, zoom_region->smoothing);
02418                 break;
02419         case ZOOM_REGION_CONTRASTR_PROP:
02420                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_r);
02421                 break;
02422         case ZOOM_REGION_CONTRASTG_PROP:
02423                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_g);
02424                 break;
02425         case ZOOM_REGION_CONTRASTB_PROP:
02426                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_b);
02427                 break;
02428         case ZOOM_REGION_BRIGHTR_PROP:
02429                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_r);
02430                 break;
02431         case ZOOM_REGION_BRIGHTG_PROP:
02432                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_g);
02433                 break;
02434         case ZOOM_REGION_BRIGHTB_PROP:
02435                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_b);
02436                 break;
02437         case ZOOM_REGION_XSCALE_PROP:
02438                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->xscale);
02439                 break;
02440         case ZOOM_REGION_YSCALE_PROP:
02441                 BONOBO_ARG_SET_FLOAT (arg, zoom_region->yscale);
02442                 break;
02443         case ZOOM_REGION_BORDERSIZE_PROP:
02444                 BONOBO_ARG_SET_LONG (
02445                         arg, (zoom_region->border_size_top +
02446                               zoom_region->border_size_left +
02447                               zoom_region->border_size_right +
02448                               zoom_region->border_size_bottom) / 4);
02449                 break;
02450         case ZOOM_REGION_BORDERSIZETOP_PROP:
02451                 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_top);
02452                 break;
02453         case ZOOM_REGION_BORDERSIZELEFT_PROP:
02454                 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_left);
02455                 break;
02456         case ZOOM_REGION_BORDERSIZERIGHT_PROP:
02457                 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_right);
02458                 break;
02459         case ZOOM_REGION_BORDERSIZEBOTTOM_PROP:
02460                 BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_bottom);
02461                 break;
02462         case ZOOM_REGION_XALIGN_PROP:
02463                 /* TODO: enums here */
02464                 BONOBO_ARG_SET_INT (arg, zoom_region->x_align_policy);
02465                 break;
02466         case ZOOM_REGION_YALIGN_PROP:
02467                 BONOBO_ARG_SET_INT (arg, zoom_region->y_align_policy);
02468                 break;
02469         case ZOOM_REGION_BORDERCOLOR_PROP:
02470                 BONOBO_ARG_SET_LONG (arg,
02471                                      zoom_region->border_color);
02472                 break;
02473         case ZOOM_REGION_VIEWPORT_PROP:
02474                 BONOBO_ARG_SET_GENERAL (arg, zoom_region->viewport,
02475                                         TC_GNOME_Magnifier_RectBounds,
02476                                         GNOME_Magnifier_RectBounds,
02477                                         NULL);
02478                 break;
02479         case ZOOM_REGION_TIMING_TEST_PROP:
02480                 BONOBO_ARG_SET_INT (arg, zoom_region->timing_iterations);
02481                 break;
02482         case ZOOM_REGION_TIMING_OUTPUT_PROP:
02483                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->timing_output);
02484                 break;
02485         case ZOOM_REGION_TIMING_PAN_RATE_PROP:
02486                 BONOBO_ARG_SET_INT (arg, zoom_region->timing_pan_rate);
02487                 break;
02488         case ZOOM_REGION_EXIT_MAGNIFIER:
02489                 BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->exit_magnifier);
02490                 break;
02491         default:
02492                 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
02493         };
02494 }
02495 
02496 static void
02497 zoom_region_update_borders (ZoomRegion *zoom_region)
02498 {
02499         gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->border),
02500                                      zoom_region->viewport.x2 -
02501                                      zoom_region->viewport.x1,
02502                                      zoom_region->viewport.y2 -
02503                                      zoom_region->viewport.y1);
02504         gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
02505                                      zoom_region->viewport.x2 -
02506                                      zoom_region->viewport.x1 -
02507                                      (zoom_region->border_size_right +
02508                                       zoom_region->border_size_left),
02509                                      zoom_region->viewport.y2 -
02510                                      zoom_region->viewport.y1 -
02511                                      (zoom_region->border_size_bottom +
02512                                       zoom_region->border_size_top));
02513         gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->border, zoom_region->viewport.x1, zoom_region->viewport.y1);
02514         gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->w, zoom_region->viewport.x1 + zoom_region->border_size_left, zoom_region->viewport.y1 + zoom_region->border_size_top);
02515 }
02516 
02517 gboolean
02518 impl_dbus_zoom_region_set_managed (ZoomRegion *zoom_region, gboolean managed)
02519 {
02520         zoom_region->is_managed = managed;
02521         
02522         return TRUE;
02523 }
02524 
02525 gboolean
02526 impl_dbus_zoom_region_get_managed (ZoomRegion *zoom_region)
02527 {
02528         return zoom_region->is_managed;
02529 }
02530 
02531 gboolean
02532 impl_dbus_zoom_region_set_poll_mouse (ZoomRegion *zoom_region, gboolean poll_mouse)
02533 {
02534         zoom_region->poll_mouse = poll_mouse;
02535         if (zoom_region->poll_mouse) {
02536                 g_message ("Adding polling timer");
02537                 zoom_region->priv->update_pointer_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
02538                                                                            200,
02539                                                                            zoom_region_update_pointer_timeout,
02540                                                                            zoom_region,
02541                                                                            NULL);
02542         } else if (zoom_region->priv->update_pointer_id) {
02543                 g_message ("Removing polling time");
02544                 g_source_remove (zoom_region->priv->update_pointer_id);
02545                 zoom_region->priv->update_pointer_id = 0;
02546         }
02547         
02548         return TRUE;
02549 }
02550 
02551 gboolean
02552 impl_dbus_zoom_region_get_poll_mouse (ZoomRegion *zoom_region)
02553 {
02554         return zoom_region->poll_mouse;
02555 }
02556 
02557 gboolean
02558 impl_dbus_zoom_region_set_draw_cursor (ZoomRegion *zoom_region, gboolean draw_cursor)
02559 {
02560         zoom_region->draw_cursor = draw_cursor;
02561         if (!zoom_region->draw_cursor) {
02562                 zoom_region_unpaint_cursor (zoom_region, NULL);
02563         }
02564         
02565         return TRUE;
02566 }
02567 
02568 gboolean
02569 impl_dbus_zoom_region_get_draw_cursor (ZoomRegion *zoom_region)
02570 {
02571         return zoom_region->draw_cursor;
02572 }
02573 
02574 gboolean
02575 impl_dbus_zoom_region_set_invert (ZoomRegion *zoom_region, gboolean invert)
02576 {
02577         zoom_region->invert = invert;
02578         zoom_region_update_current (zoom_region);
02579         
02580         return TRUE;
02581 }
02582 
02583 gboolean
02584 impl_dbus_zoom_region_get_invert (ZoomRegion *zoom_region)
02585 {
02586         return zoom_region->invert;
02587 }
02588 
02589 gboolean
02590 impl_dbus_zoom_region_set_smoothscroll (ZoomRegion *zoom_region, gshort smoothscroll)
02591 {
02592         zoom_region->smooth_scroll_policy = smoothscroll;
02593         
02594         return TRUE;
02595 }
02596 
02597 gshort
02598 impl_dbus_zoom_region_get_smoothscroll (ZoomRegion *zoom_region)
02599 {
02600         return zoom_region->smooth_scroll_policy;
02601 }
02602 
02603 gboolean
02604 impl_dbus_zoom_region_set_colorblind (ZoomRegion *zoom_region, gshort colorblind)
02605 {
02606         zoom_region->color_blind_filter = colorblind;
02607         zoom_region_update_current (zoom_region);
02608         
02609         return TRUE;
02610 }
02611 
02612 gshort
02613 impl_dbus_zoom_region_get_colorblind (ZoomRegion *zoom_region)
02614 {
02615         return zoom_region->color_blind_filter;
02616 }
02617 
02618 gboolean
02619 impl_dbus_zoom_region_set_smoothing (ZoomRegion *zoom_region, gchar *smoothing)
02620 {
02621         zoom_region->smoothing = g_strdup (smoothing);
02622         if (!strncmp (zoom_region->smoothing, "bilinear", 8)) {
02623                 zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR;
02624         } else {
02625                 zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST;
02626         }
02627         zoom_region_update_current (zoom_region);
02628         
02629         return TRUE;
02630 }
02631 
02632 gchar*
02633 impl_dbus_zoom_region_get_smoothing (ZoomRegion *zoom_region)
02634 {
02635         return g_strdup (zoom_region->smoothing);
02636 }
02637 
02638 gboolean
02639 impl_dbus_zoom_region_set_testpattern (ZoomRegion *zoom_region, gboolean test)
02640 {
02641         zoom_region->priv->test = test;
02642         if (zoom_region->priv->source_drawable) {
02643                 g_object_unref (zoom_region->priv->source_drawable);
02644                 zoom_region->priv->source_drawable = NULL;
02645         }
02646         zoom_region_update_current (zoom_region);
02647         
02648         return TRUE;
02649 }
02650 
02651 gboolean
02652 impl_dbus_zoom_region_get_testpattern (ZoomRegion *zoom_region)
02653 {
02654         return zoom_region->priv->test;
02655 }
02656 
02657 gboolean
02658 impl_dbus_zoom_region_set_bordersizes (ZoomRegion *zoom_region, gint32 **bordersizes)
02659 {
02660         zoom_region->border_size_left   = (*bordersizes)[0];
02661         zoom_region->border_size_top    = (*bordersizes)[1];
02662         zoom_region->border_size_right  = (*bordersizes)[2];
02663         zoom_region->border_size_bottom = (*bordersizes)[3];
02664         zoom_region_update_borders (zoom_region);
02665         
02666         return TRUE;
02667 }
02668 
02669 GArray*
02670 impl_dbus_zoom_region_get_bordersizes (ZoomRegion *zoom_region)
02671 {
02672         GArray *ret;
02673         
02674         ret = g_array_new (FALSE, FALSE, sizeof (gint32));
02675         
02676         g_array_append_val (ret, zoom_region->border_size_left);
02677         g_array_append_val (ret, zoom_region->border_size_top);
02678         g_array_append_val (ret, zoom_region->border_size_right);
02679         g_array_append_val (ret, zoom_region->border_size_bottom);
02680         
02681         return ret;
02682 }
02683 
02684 gboolean
02685 impl_dbus_zoom_region_set_bordercolor (ZoomRegion *zoom_region, guint32 bordercolor)
02686 {
02687         zoom_region->border_color = bordercolor;
02688         zoom_region_paint_border (zoom_region);
02689         
02690         return TRUE;
02691 }
02692 
02693 guint32
02694 impl_dbus_zoom_region_get_bordercolor (ZoomRegion *zoom_region)
02695 {
02696         return zoom_region->border_color;
02697 }
02698 
02699 gboolean
02700 impl_dbus_zoom_region_set_xalign (ZoomRegion *zoom_region, gint32 align)
02701 {
02702         zoom_region->x_align_policy = align;
02703         zoom_region_align (zoom_region);
02704         
02705         return TRUE;
02706 }
02707 
02708 gint32
02709 impl_dbus_zoom_region_get_xalign (ZoomRegion *zoom_region)
02710 {
02711         return zoom_region->x_align_policy;
02712 }
02713 
02714 gboolean
02715 impl_dbus_zoom_region_set_yalign (ZoomRegion *zoom_region, gint32 align)
02716 {
02717         zoom_region->y_align_policy = align;
02718         zoom_region_align (zoom_region);
02719         
02720         return TRUE;
02721 }
02722 
02723 gint32
02724 impl_dbus_zoom_region_get_yalign (ZoomRegion *zoom_region)
02725 {
02726         return zoom_region->y_align_policy;
02727 }
02728 
02729 gboolean
02730 impl_dbus_zoom_region_set_viewport (ZoomRegion *zoom_region, gint32 **viewport)
02731 {
02732         GNOME_Magnifier_RectBounds *bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds));
02733 
02734         bounds->x1 = (*viewport)[0];
02735         bounds->y1 = (*viewport)[1];
02736         bounds->x2 = (*viewport)[2];
02737         bounds->y2 = (*viewport)[3];
02738         
02739         zoom_region_set_viewport (zoom_region, bounds);
02740         
02741         g_free (bounds);
02742         
02743         return TRUE;
02744 }
02745 
02746 GArray*
02747 impl_dbus_zoom_region_get_viewport (ZoomRegion *zoom_region)
02748 {
02749         GArray *ret;
02750         
02751         ret = g_array_new (FALSE, FALSE, sizeof (gint32));
02752         
02753         g_array_append_val (ret, zoom_region->viewport.x1);
02754         g_array_append_val (ret, zoom_region->viewport.y1);
02755         g_array_append_val (ret, zoom_region->viewport.x2);
02756         g_array_append_val (ret, zoom_region->viewport.y2);
02757         
02758         return ret;
02759 }
02760 
02761 gboolean
02762 impl_dbus_zoom_region_set_timing_test (ZoomRegion *zoom_region, gint32 timing_iterations)
02763 {
02764         zoom_region->timing_iterations = timing_iterations;
02765         timing_test = TRUE;
02766         
02767         return TRUE;
02768 }
02769 
02770 gint32
02771 impl_dbus_zoom_region_get_timing_test (ZoomRegion *zoom_region)
02772 {
02773         return zoom_region->timing_iterations;
02774 }
02775 
02776 gboolean
02777 impl_dbus_zoom_region_set_timing_output (ZoomRegion *zoom_region, gboolean timing_output)
02778 {
02779         zoom_region->timing_output = timing_output;
02780         
02781         return TRUE;
02782 }
02783 
02784 gboolean
02785 impl_dbus_zoom_region_get_timing_output (ZoomRegion *zoom_region)
02786 {
02787         return zoom_region->timing_output;
02788 }
02789 
02790 gboolean
02791 impl_dbus_zoom_region_set_timing_pan_rate (ZoomRegion *zoom_region, gint32 timing_pan_rate)
02792 {
02793         zoom_region->timing_pan_rate = timing_pan_rate;
02794         timing_test = TRUE;
02795         
02796         return TRUE;
02797 }
02798 
02799 gint32
02800 impl_dbus_zoom_region_get_timing_pan_rate (ZoomRegion *zoom_region)
02801 {
02802         return zoom_region->timing_pan_rate;
02803 }
02804 
02805 gboolean
02806 impl_dbus_zoom_region_set_exit_magnifier (ZoomRegion *zoom_region, gboolean exit_magnifier)
02807 {
02808         zoom_region->exit_magnifier = exit_magnifier;
02809         
02810         return TRUE;
02811 }
02812 
02813 gboolean
02814 impl_dbus_zoom_region_get_exit_magnifier (ZoomRegion *zoom_region)
02815 {
02816         return zoom_region->exit_magnifier;
02817 }
02818 
02819 static void
02820 zoom_region_set_property (BonoboPropertyBag *bag,
02821                           BonoboArg *arg,
02822                           guint arg_id,
02823                           CORBA_Environment *ev,
02824                           gpointer user_data)
02825 {
02826         ZoomRegion *zoom_region = user_data;
02827         GNOME_Magnifier_RectBounds bounds;
02828         gfloat t;
02829 
02830 #ifdef ZOOM_REGION_DEBUG
02831         g_assert (zoom_region->alive);
02832 #endif
02833         DBG (fprintf (stderr, "Set zoom-region property: %s\n", prop_names[arg_id]));
02834 
02835         switch (arg_id) {
02836         case ZOOM_REGION_MANAGED_PROP:
02837                 zoom_region->is_managed = BONOBO_ARG_GET_BOOLEAN (arg);
02838                 break;
02839         case ZOOM_REGION_POLL_MOUSE_PROP:
02840                 zoom_region->poll_mouse = BONOBO_ARG_GET_BOOLEAN (arg);
02841                 if (zoom_region->poll_mouse)
02842                 {
02843                     g_message ("Adding polling timer");
02844                     zoom_region->priv->update_pointer_id =
02845                         g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
02846                                             200,
02847                                             zoom_region_update_pointer_timeout,
02848                                             zoom_region,
02849                                             NULL);
02850                 }
02851                 else if (zoom_region->priv->update_pointer_id)
02852                 {
02853                     g_message ("Removing polling timer");
02854                     g_source_remove (zoom_region->priv->update_pointer_id);
02855                     zoom_region->priv->update_pointer_id = 0;
02856                 }
02857                 break;
02858         case ZOOM_REGION_DRAW_CURSOR_PROP:
02859                 zoom_region->draw_cursor = BONOBO_ARG_GET_BOOLEAN (arg);
02860                 if (!zoom_region->draw_cursor)
02861                         zoom_region_unpaint_cursor (zoom_region, NULL);
02862                 break;
02863         case ZOOM_REGION_INVERT_PROP:
02864                 zoom_region->invert = BONOBO_ARG_GET_BOOLEAN (arg);
02865                 zoom_region_update_current (zoom_region);
02866                 break;
02867         case ZOOM_REGION_SMOOTHSCROLL_PROP:
02868                 zoom_region->smooth_scroll_policy = BONOBO_ARG_GET_SHORT (arg);
02869                 break;
02870         case ZOOM_REGION_COLORBLIND_PROP:
02871                 zoom_region->color_blind_filter = BONOBO_ARG_GET_SHORT (arg);
02872 
02873                 switch (zoom_region->color_blind_filter) {
02874                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER:
02875                         break; /* This entry is only to avoid a warning */
02876                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_RED:
02877                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_red);
02878                         break;
02879                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_GREEN:
02880                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_green);
02881                         break;
02882                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE_BLUE:
02883                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_blue);
02884                         break;
02885                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_RED:
02886                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_red);
02887                         break;
02888                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_GREEN:
02889                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_green);
02890                         break;
02891                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE_BLUE:
02892                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_blue);
02893                         break;
02894                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_POSITIVE:
02895                         colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_positive);
02896                         break;
02897                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_HUE_SHIFT_NEGATIVE:
02898                         colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_negative);
02899                         break;
02900                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_SATURATE:
02901                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate);
02902                         break;
02903                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_SELECTIVE_DESSATURATE:
02904                         colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate);
02905                         break;
02906                 case GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_MONOCHRONE_OTHERS:
02907                         colorblind_set_filter_type (cbr, colorblind_filter_t_monochrome_others);
02908                         break;
02909                 }
02910 
02911                 zoom_region_update_current (zoom_region);
02912                 break;
02913         case ZOOM_REGION_SMOOTHING_PROP:
02914                 zoom_region->smoothing = BONOBO_ARG_GET_STRING (arg);
02915                 if (!strncmp (zoom_region->smoothing, "bilinear", 8))
02916                         zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR;
02917                 else 
02918                         zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST;
02919                 zoom_region_update_current (zoom_region);
02920                 break;
02921         case ZOOM_REGION_TESTPATTERN_PROP:
02922                 zoom_region->priv->test = BONOBO_ARG_GET_BOOLEAN (arg);
02923                 if (zoom_region->priv->source_drawable) {
02924                         g_object_unref (zoom_region->priv->source_drawable);
02925                         zoom_region->priv->source_drawable = NULL;
02926                 }
02927                 zoom_region_update_current (zoom_region);
02928                 break;
02929         case ZOOM_REGION_CONTRASTR_PROP:
02930                 zoom_region->contrast_r =
02931                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02932                 zoom_region_update_current (zoom_region);
02933                 break;
02934         case ZOOM_REGION_CONTRASTG_PROP:
02935                 zoom_region->contrast_g =
02936                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02937                 zoom_region_update_current (zoom_region);
02938                 break;
02939         case ZOOM_REGION_CONTRASTB_PROP:
02940                 zoom_region->contrast_b =
02941                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02942                 zoom_region_update_current (zoom_region);
02943                 break;
02944         case ZOOM_REGION_BRIGHTR_PROP:
02945                 zoom_region->bright_r =
02946                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02947                 zoom_region_update_current (zoom_region);
02948                 break;
02949         case ZOOM_REGION_BRIGHTG_PROP:
02950                 zoom_region->bright_g =
02951                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02952                 zoom_region_update_current (zoom_region);
02953                 break;
02954         case ZOOM_REGION_BRIGHTB_PROP:
02955                 zoom_region->bright_b =
02956                         CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
02957                 zoom_region_update_current (zoom_region);
02958                 break;
02959         case ZOOM_REGION_XSCALE_PROP:
02960                 (void) zoom_region_update_scale (zoom_region,
02961                                                  BONOBO_ARG_GET_FLOAT (arg),
02962                                                  zoom_region->yscale);
02963                 break;
02964         case ZOOM_REGION_YSCALE_PROP:
02965                 (void) zoom_region_update_scale (zoom_region,
02966                                                  zoom_region->xscale,
02967                                                  BONOBO_ARG_GET_FLOAT (arg));
02968                 
02969                 break;
02970         case ZOOM_REGION_BORDERSIZE_PROP:
02971                 zoom_region->border_size_left =
02972                         zoom_region->border_size_top =
02973                         zoom_region->border_size_right =
02974                         zoom_region->border_size_bottom =
02975                         BONOBO_ARG_GET_LONG (arg);
02976                 zoom_region_update_borders (zoom_region);
02977                 break;
02978         case ZOOM_REGION_BORDERSIZELEFT_PROP:
02979                 zoom_region->border_size_left = BONOBO_ARG_GET_LONG (arg);
02980                 zoom_region_update_borders (zoom_region);
02981                 break;
02982         case ZOOM_REGION_BORDERSIZETOP_PROP:
02983                 zoom_region->border_size_top = BONOBO_ARG_GET_LONG (arg);
02984                 zoom_region_update_borders (zoom_region);
02985                 break;
02986         case ZOOM_REGION_BORDERSIZERIGHT_PROP:
02987                 zoom_region->border_size_right = BONOBO_ARG_GET_LONG (arg);
02988                 zoom_region_update_borders (zoom_region);
02989                 break;
02990         case ZOOM_REGION_BORDERSIZEBOTTOM_PROP:
02991                 zoom_region->border_size_bottom = BONOBO_ARG_GET_LONG (arg);
02992                 zoom_region_update_borders (zoom_region);
02993                 break;
02994         case ZOOM_REGION_BORDERCOLOR_PROP:
02995                 zoom_region->border_color =
02996                         BONOBO_ARG_GET_LONG (arg);
02997                 zoom_region_paint_border (zoom_region);
02998                 break;
02999         case ZOOM_REGION_XALIGN_PROP:
03000                 zoom_region->x_align_policy = BONOBO_ARG_GET_INT (arg);
03001                 zoom_region_align (zoom_region);
03002                 break;
03003         case ZOOM_REGION_YALIGN_PROP:
03004                 /* TODO: enums here */
03005                 zoom_region->y_align_policy = BONOBO_ARG_GET_INT (arg);
03006                 zoom_region_align (zoom_region);
03007                 break;
03008         case ZOOM_REGION_VIEWPORT_PROP:
03009                 bounds = BONOBO_ARG_GET_GENERAL (arg,
03010                                                  TC_GNOME_Magnifier_RectBounds,
03011                                                  GNOME_Magnifier_RectBounds,
03012                                                  NULL);
03013                 zoom_region_set_viewport (zoom_region, &bounds);
03014                 break;
03015         case ZOOM_REGION_TIMING_TEST_PROP:
03016                 zoom_region->timing_iterations = BONOBO_ARG_GET_INT (arg);
03017                 timing_test = TRUE;
03018                 break;
03019         case ZOOM_REGION_TIMING_OUTPUT_PROP:
03020                 zoom_region->timing_output = BONOBO_ARG_GET_BOOLEAN (arg);
03021                 break;
03022         case ZOOM_REGION_TIMING_PAN_RATE_PROP:
03023                 zoom_region->timing_pan_rate = BONOBO_ARG_GET_INT (arg);
03024                 timing_test = TRUE;
03025                 break;
03026         case ZOOM_REGION_EXIT_MAGNIFIER:
03027                 zoom_region->exit_magnifier = BONOBO_ARG_GET_BOOLEAN (arg);
03028                 break;
03029         default:
03030                 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
03031         };
03032 }
03033 
03034 static int
03035 zoom_region_process_pending (gpointer data)
03036 {
03037         ZoomRegion *zoom_region = (ZoomRegion *) data;
03038 
03039 #ifdef ZOOM_REGION_DEBUG
03040         g_assert (zoom_region->alive);
03041 #endif
03042         zoom_region_align (zoom_region);
03043         return FALSE;
03044 }
03045 
03046 static int
03047 zoom_region_pan_test (gpointer data)
03048 {
03049         ZoomRegion *zoom_region = (ZoomRegion *) data;
03050         Magnifier *magnifier = zoom_region->priv->parent; 
03051         GNOME_Magnifier_ZoomRegionList *zoom_regions;
03052         GNOME_Magnifier_RectBounds roi;
03053         CORBA_Environment ev;
03054         static int counter = 0;
03055         static gboolean finished_update = !TRUE;
03056         static float last_pixels_at_speed = -1;
03057         float pixels_at_speed;
03058         float total_time;
03059         int screen_height, height;
03060         int pixel_position;
03061         int pixel_direction;
03062 
03063         screen_height = gdk_screen_get_height (
03064                 gdk_display_get_screen (magnifier->source_display,
03065                  magnifier->source_screen_num));
03066 
03067         height = (zoom_region->viewport.y2 -
03068                 zoom_region->viewport.y1) / zoom_region->yscale;
03069 
03070         roi.x1 = zoom_region->roi.x1;
03071         roi.x2 = zoom_region->roi.x2;
03072 
03073         g_timer_stop (mag_timing.process);
03074 
03075         gulong microseconds;
03076 
03077         total_time = g_timer_elapsed (mag_timing.process, &microseconds);
03078 
03079         if (mag_timing.frame_total != 0.0)
03080                 pixels_at_speed = total_time * zoom_region->timing_pan_rate;
03081         else
03082                 pixels_at_speed = 0.0;
03083 
03084     /* Wait until it is actually necessary to update the screen */
03085     if ((int)(last_pixels_at_speed) == (int)(pixels_at_speed))
03086         return TRUE;
03087 
03088         pixel_position = (int)(pixels_at_speed) % (screen_height - height);
03089         counter = (int)(pixels_at_speed) / (screen_height - height);
03090         pixel_direction = counter % 2;
03091 
03092         if (!finished_update) {
03093                 if ((int)(pixels_at_speed) > (zoom_region->roi.y1 + height))
03094                         roi.y1 = zoom_region->roi.y1 + height;
03095                 else
03096                         roi.y1 = (int)(pixels_at_speed);
03097 
03098                 if (roi.y1 >= screen_height - height) {
03099                         roi.y1 = screen_height - height;
03100                 }
03101         } else {
03102                 if (pixel_direction == 0)
03103                         roi.y1 = screen_height - height - pixel_position;
03104                 else
03105                         roi.y1 = pixel_position;
03106         }
03107 
03108         roi.y2 = roi.y1 + height;
03109         magnifier->priv->cursor_x = (roi.x2 + roi.x1) / 2;
03110         magnifier->priv->cursor_y = (roi.y2 + roi.y1) / 2;
03111 
03112         /* Add one since in first loop we call zoom_region_process_updates */
03113         if (counter > zoom_region->timing_iterations - 1)
03114                 zoom_region->exit_magnifier = TRUE;
03115 
03116         zoom_regions = GNOME_Magnifier_Magnifier_getZoomRegions (
03117                 BONOBO_OBJREF (magnifier), &ev);
03118 
03119         if (zoom_regions && (zoom_regions->_length > 0)) {
03120                 GNOME_Magnifier_ZoomRegion_setROI (
03121                         zoom_regions->_buffer[0], &roi, &ev);
03122         }
03123 
03124         if (!finished_update) {
03125                 zoom_region_process_updates(zoom_region);
03126                 if (roi.y1 == screen_height - height) {
03127                         finished_update = TRUE;
03128                         reset_timing = TRUE;
03129                 }
03130         }
03131 
03132     last_pixels_at_speed = pixels_at_speed;
03133 
03134         return FALSE;
03135 }
03136 
03137 static void
03138 impl_zoom_region_set_pointer_pos (PortableServer_Servant servant,
03139                                   const CORBA_long mouse_x,
03140                                   const CORBA_long mouse_y,
03141                                   CORBA_Environment *ev)
03142 {
03143         ZoomRegion *zoom_region =
03144                 ZOOM_REGION (bonobo_object_from_servant (servant));
03145         GdkRectangle paint_area, *clip = NULL;
03146 
03147 #ifdef ZOOM_REGION_DEBUG
03148         g_assert (zoom_region->alive);
03149 #endif
03150         DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 
03151                       (long) mouse_x, (long) mouse_y));
03152 
03153         fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 
03154                       (long) mouse_x, (long) mouse_y);
03155 
03156         zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y);
03157 
03158         if (GTK_IS_WIDGET (zoom_region->priv->w) && 
03159             GDK_IS_DRAWABLE (zoom_region->priv->w->window))
03160         {
03161             gdk_drawable_get_size (
03162                 GDK_DRAWABLE (
03163                     zoom_region->priv->w->window),
03164                 &paint_area.width, &paint_area.height);
03165             paint_area.x = 0;
03166             paint_area.y = 0;
03167             clip = &paint_area;
03168             paint_area = zoom_region_clip_to_source (
03169                 zoom_region, paint_area);
03170         }
03171         /* 
03172          * if we update the cursor now, it causes flicker if the client 
03173          * subsequently calls setROI, so we wait for a redraw.
03174          * Perhaps we should cue a redraw on idle instead?
03175          */
03176 }
03177 
03178 static void
03179 impl_zoom_region_set_contrast (PortableServer_Servant servant,
03180                                const CORBA_float R,
03181                                const CORBA_float G,
03182                                const CORBA_float B,
03183                                CORBA_Environment *ev)
03184 {
03185         ZoomRegion *zoom_region =
03186                 ZOOM_REGION (bonobo_object_from_servant (servant));
03187         gfloat t;
03188 
03189 #ifdef ZOOM_REGION_DEBUG
03190         g_assert (zoom_region->alive);
03191 #endif
03192         DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B));
03193 
03194         /* if the contrast values are the same, this is a NOOP */
03195         if (zoom_region->contrast_r == R &&
03196             zoom_region->contrast_g == G &&
03197             zoom_region->contrast_b == B)
03198                 return;
03199 
03200         zoom_region->contrast_r = CLAMP_B_C (R);
03201         zoom_region->contrast_g = CLAMP_B_C (G);
03202         zoom_region->contrast_b = CLAMP_B_C (B);
03203 
03204         zoom_region_update_current (zoom_region);
03205 }
03206 
03207 static void
03208 impl_zoom_region_get_contrast (PortableServer_Servant servant,
03209                                CORBA_float *R,
03210                                CORBA_float *G,
03211                                CORBA_float *B,
03212                                CORBA_Environment *ev)
03213 {
03214         ZoomRegion *zoom_region =
03215                 ZOOM_REGION (bonobo_object_from_servant (servant));
03216 
03217 #ifdef ZOOM_REGION_DEBUG
03218         g_assert (zoom_region->alive);
03219 #endif
03220 
03221         *R = zoom_region->contrast_r;
03222         *G = zoom_region->contrast_g;
03223         *B = zoom_region->contrast_b;
03224 }
03225 
03226 static void
03227 impl_zoom_region_set_brightness (PortableServer_Servant servant,
03228                                  const CORBA_float R,
03229                                  const CORBA_float G,
03230                                  const CORBA_float B,
03231                                  CORBA_Environment *ev)
03232 {
03233         ZoomRegion *zoom_region =
03234                 ZOOM_REGION (bonobo_object_from_servant (servant));
03235         gfloat t;
03236 
03237 #ifdef ZOOM_REGION_DEBUG
03238         g_assert (zoom_region->alive);
03239 #endif
03240         DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B));
03241 
03242         /* if the contrast values are the same, this is a NOOP */
03243         if (zoom_region->bright_r == R &&
03244             zoom_region->bright_g == G &&
03245             zoom_region->bright_b == B)
03246                 return;
03247 
03248         zoom_region->bright_r = CLAMP_B_C (R);
03249         zoom_region->bright_g = CLAMP_B_C (G);
03250         zoom_region->bright_b = CLAMP_B_C (B);
03251 
03252         zoom_region_update_current (zoom_region);
03253 }
03254 
03255 static void
03256 impl_zoom_region_get_brightness (PortableServer_Servant servant,
03257                                  CORBA_float *R,
03258                                  CORBA_float *G,
03259                                  CORBA_float *B,
03260                                  CORBA_Environment *ev)
03261 {
03262         ZoomRegion *zoom_region =
03263                 ZOOM_REGION (bonobo_object_from_servant (servant));
03264 
03265 #ifdef ZOOM_REGION_DEBUG
03266         g_assert (zoom_region->alive);
03267 #endif
03268 
03269         *R = zoom_region->bright_r;
03270         *G = zoom_region->bright_g;
03271         *B = zoom_region->bright_b;
03272 }
03273 
03274 static void
03275 impl_zoom_region_set_roi (PortableServer_Servant servant,
03276                           const GNOME_Magnifier_RectBounds *bounds,
03277                           CORBA_Environment *ev)
03278 {
03279         ZoomRegion *zoom_region =
03280                 ZOOM_REGION (bonobo_object_from_servant (servant));
03281 
03282 #ifdef ZOOM_REGION_DEBUG
03283         g_assert (zoom_region->alive);
03284 #endif
03285         DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n", 
03286                       bounds->x1, bounds->y1, bounds->x2, bounds->y2));
03287 
03288         if ((zoom_region->roi.x1 == bounds->x1) &&
03289             (zoom_region->roi.x2 == bounds->x2) &&
03290             (zoom_region->roi.y1 == bounds->y1) &&
03291             (zoom_region->roi.y2 == bounds->y2)) {
03292             return;
03293         }
03294 
03295         /* if these bounds are clearly bogus, warn and ignore */
03296         if (!bounds || (bounds->x2 <= bounds->x1)
03297             || (bounds->y2 < bounds->y1) || 
03298             ((bounds->x1 + bounds->x2)/2 < 0) || 
03299             ((bounds->y1 + bounds->y2)/2 < 0))
03300         {
03301             g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n",
03302                        bounds->x1, bounds->y1, bounds->x2, bounds->y2);
03303             return;
03304         }
03305 
03306         zoom_region->roi = *bounds;
03307 
03308         if (zoom_region->timing_pan_rate > 0) {
03309                 /* Set idle handler to do panning test */
03310                 g_idle_add_full (GDK_PRIORITY_REDRAW + 3, 
03311                         zoom_region_pan_test, zoom_region, NULL);
03312         }
03313 
03314         if (zoom_region->exit_magnifier) {
03315                 if (timing_test) {
03316                         fprintf(stderr, "\n### Timing Summary:\n\n");
03317                         if (zoom_region->timing_pan_rate)
03318                                 fprintf(stderr, "  Pan Rate                 = %d\n", zoom_region->timing_pan_rate);
03319                         timing_report(zoom_region);
03320                 }
03321                 exit(0);
03322         }
03323 
03324         /*
03325          * Do not bother trying to update the screen if the last
03326          * screen update has not had time to complete.
03327          */
03328         if (processing_updates) {
03329                 /* Remove any previous idle handler */
03330                 if (pending_idle_handler != 0) {
03331                         g_source_remove(pending_idle_handler);
03332                         pending_idle_handler = 0;
03333                 }
03334 
03335                 /* Set idle handler to process this pending update when possible */
03336 
03337                 pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2,
03338                         zoom_region_process_pending, zoom_region, NULL);
03339 
03340                 if (zoom_region->timing_output) {
03341                         fprintf(stderr,
03342                                 "\n  [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n",
03343                                 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
03344                                 zoom_region->roi.y2);
03345                 }
03346         } else {
03347                 zoom_region_align (zoom_region);
03348         }
03349 }
03350 
03351 static CORBA_boolean
03352 impl_zoom_region_set_mag_factor (PortableServer_Servant servant,
03353                                  const CORBA_float mag_factor_x,
03354                                  const CORBA_float mag_factor_y,
03355                                  CORBA_Environment *ev)
03356 {
03357         ZoomRegion *zoom_region =
03358                 ZOOM_REGION (bonobo_object_from_servant (servant));
03359 
03360 #ifdef ZOOM_REGION_DEBUG
03361         g_assert (zoom_region->alive);
03362 #endif
03363         CORBA_any *any;
03364         CORBA_boolean retval = CORBA_TRUE;
03365 
03366         if ((zoom_region->xscale == mag_factor_x) &&
03367             (zoom_region->yscale == mag_factor_y)) {
03368                 return retval;
03369         }
03370 
03371         /* TODO: assert that parent is magnifier object */
03372         Bonobo_PropertyBag properties =
03373                 GNOME_Magnifier_Magnifier_getProperties(
03374                         BONOBO_OBJREF (
03375                                 (Magnifier *) zoom_region->priv->parent), ev);
03376         any = Bonobo_PropertyBag_getValue (
03377                 properties, "source-display-bounds", ev);
03378         if (!BONOBO_EX (ev))
03379                 zoom_region->priv->source_area =
03380                         *((GNOME_Magnifier_RectBounds *) any->_value);
03381         else
03382                 retval = CORBA_FALSE;
03383 
03384         retval = zoom_region_update_scale (zoom_region,
03385                                            mag_factor_x, mag_factor_y);
03386         zoom_region_sync (zoom_region);
03387 
03388         bonobo_object_release_unref (properties, NULL);
03389         return retval;
03390 }
03391 
03392 static void
03393 impl_zoom_region_get_mag_factor (PortableServer_Servant servant,
03394                                  CORBA_float *mag_factor_x,
03395                                  CORBA_float *mag_factor_y,
03396                                  CORBA_Environment *ev)
03397 {
03398         ZoomRegion *zoom_region =
03399                 ZOOM_REGION (bonobo_object_from_servant (servant));
03400 
03401 #ifdef ZOOM_REGION_DEBUG
03402         g_assert (zoom_region->alive);
03403 #endif
03404         *mag_factor_x = zoom_region->xscale;
03405         *mag_factor_y = zoom_region->yscale;
03406 }
03407 
03408 static Bonobo_PropertyBag
03409 impl_zoom_region_get_properties (PortableServer_Servant servant,
03410                                  CORBA_Environment *ev)
03411 {
03412         ZoomRegion *zoom_region =
03413                 ZOOM_REGION (bonobo_object_from_servant (servant));
03414 
03415 #ifdef ZOOM_REGION_DEBUG
03416         g_assert (zoom_region->alive);
03417 #endif
03418         return bonobo_object_dup_ref (
03419                 BONOBO_OBJREF (zoom_region->properties), ev);
03420 }
03421 
03422 static void
03423 impl_zoom_region_update_pointer (PortableServer_Servant servant,
03424                                  CORBA_Environment *ev)
03425 {
03426         ZoomRegion *zoom_region =
03427                 ZOOM_REGION (bonobo_object_from_servant (servant));
03428 
03429 #ifdef ZOOM_REGION_DEBUG
03430         g_assert (zoom_region->alive);
03431 #endif
03432 
03433         zoom_region_update_cursor (zoom_region, 0, 0, NULL);
03434 }
03435 
03436 static void
03437 impl_zoom_region_mark_dirty (PortableServer_Servant servant,
03438                              const GNOME_Magnifier_RectBounds *roi_dirty,
03439                              CORBA_Environment *ev)
03440 {
03441         ZoomRegion *zoom_region =
03442                 ZOOM_REGION (bonobo_object_from_servant (servant));
03443 
03444 #ifdef ZOOM_REGION_DEBUG
03445         g_assert (zoom_region->alive);
03446 #endif
03447         DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds (
03448                             zoom_region, roi_dirty) );
03449 
03450         zoom_region_update_pointer (zoom_region, TRUE);
03451         /* XXX ? should we clip here, or wait till process_updates? */
03452         zoom_region_queue_update (zoom_region, 
03453           zoom_region_clip_to_source (zoom_region, 
03454               zoom_region_rect_from_bounds (zoom_region, roi_dirty)));
03455 }
03456 
03457 static GNOME_Magnifier_RectBounds
03458 impl_zoom_region_get_roi (PortableServer_Servant servant,
03459                           CORBA_Environment     *ev)
03460 {
03461         ZoomRegion *zoom_region =
03462                 ZOOM_REGION (bonobo_object_from_servant (servant));
03463 
03464 #ifdef ZOOM_REGION_DEBUG
03465         g_assert (zoom_region->alive);
03466 #endif
03467         return zoom_region->roi;
03468 }
03469 
03470 static void
03471 impl_zoom_region_move_resize (PortableServer_Servant            servant,
03472                               const GNOME_Magnifier_RectBounds *viewport_bounds,
03473                               CORBA_Environment                *ev)
03474 {
03475         ZoomRegion *zoom_region =
03476                 ZOOM_REGION (bonobo_object_from_servant (servant));
03477 
03478 #ifdef ZOOM_REGION_DEBUG
03479         g_assert (zoom_region->alive);
03480 #endif
03481         zoom_region_set_viewport (zoom_region, viewport_bounds);
03482 }
03483 
03484 /* could be called multiple times... */
03485 static void
03486 zoom_region_do_dispose (ZoomRegion *zoom_region)
03487 {
03488         DBG(g_message ("disposing region %p", zoom_region));
03489         if (zoom_region->priv && zoom_region->priv->expose_handler_id && 
03490             GTK_IS_WIDGET (zoom_region->priv->w)) {
03491                 g_signal_handler_disconnect (
03492                         zoom_region->priv->w,
03493                         zoom_region->priv->expose_handler_id);
03494                 zoom_region->priv->expose_handler_id = 0;
03495         }
03496         if (zoom_region->priv && zoom_region->priv->update_pointer_id)
03497             g_source_remove (zoom_region->priv->update_pointer_id);
03498         if (zoom_region->priv && zoom_region->priv->update_handler_id)
03499             g_source_remove (zoom_region->priv->update_handler_id);
03500         g_idle_remove_by_data (zoom_region);
03501         
03502 #ifdef ZOOM_REGION_DEBUG
03503         zoom_region->alive = FALSE;
03504 #endif
03505 }
03506 
03507 static void
03508 impl_zoom_region_dispose (PortableServer_Servant servant,
03509                           CORBA_Environment     *ev)
03510 {
03511         ZoomRegion *zoom_region =
03512                 ZOOM_REGION (bonobo_object_from_servant (servant));
03513         zoom_region_do_dispose (zoom_region);
03514 }
03515 
03516 gboolean
03517 impl_dbus_zoom_region_dispose (ZoomRegion *zoom_region)
03518 {
03519         zoom_region_do_dispose (zoom_region);
03520         
03521         return TRUE;
03522 }
03523 
03524 gboolean
03525 impl_dbus_zoom_region_set_mag_factor (ZoomRegion *zoom_region, const gdouble mag_factor_x, const gdouble mag_factor_y)
03526 {
03527 #ifdef ZOOM_REGION_DEBUG
03528         g_assert (zoom_region->alive);
03529 #endif
03530         CORBA_Environment ev;
03531         CORBA_exception_init (&ev);
03532         CORBA_any *any;
03533         gboolean retval = TRUE;
03534 
03535         if ((zoom_region->xscale == mag_factor_x) &&
03536             (zoom_region->yscale == mag_factor_y)) {
03537                 return retval;
03538         }
03539         
03540         /* TODO: assert that parent is magnifier object */
03541         Bonobo_PropertyBag properties =
03542                 GNOME_Magnifier_Magnifier_getProperties(
03543                         BONOBO_OBJREF (
03544                                 (Magnifier *) zoom_region->priv->parent), &ev);
03545         any = Bonobo_PropertyBag_getValue (
03546                 properties, "source-display-bounds", &ev);
03547         if (!BONOBO_EX (&ev))
03548                 zoom_region->priv->source_area =
03549                         *((GNOME_Magnifier_RectBounds *) any->_value);
03550         else {
03551                 retval = FALSE;
03552                 return retval;
03553         }
03554 
03555         retval = zoom_region_update_scale (zoom_region, mag_factor_x, mag_factor_y);
03556         zoom_region_sync (zoom_region);
03557 
03558         return retval;
03559 }
03560 
03561 GArray*
03562 impl_dbus_zoom_region_get_mag_factor (ZoomRegion *zoom_region)
03563 {
03564         GArray *ret;
03565         
03566         ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
03567         
03568         g_array_append_val (ret, zoom_region->xscale);
03569         g_array_append_val (ret, zoom_region->yscale);
03570 
03571         return ret;
03572 }
03573 
03574 gboolean
03575 impl_dbus_zoom_region_set_roi (ZoomRegion *zoom_region, const gint32 **roi)
03576 {
03577         RectBounds *bounds = g_malloc(sizeof(RectBounds));
03578         _set_bounds (bounds, roi);
03579 
03580         #ifdef ZOOM_REGION_DEBUG
03581         g_assert (zoom_region->alive);
03582 #endif
03583         DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n", 
03584                       bounds->x1, bounds->y1, bounds->x2, bounds->y2));
03585 
03586         if ((zoom_region->roi.x1 == bounds->x1) &&
03587             (zoom_region->roi.x2 == bounds->x2) &&
03588             (zoom_region->roi.y1 == bounds->y1) &&
03589             (zoom_region->roi.y2 == bounds->y2)) {
03590             return TRUE;
03591         }
03592 
03593         /* if these bounds are clearly bogus, warn and ignore */
03594         if (!bounds || (bounds->x2 <= bounds->x1)
03595             || (bounds->y2 < bounds->y1) || 
03596             ((bounds->x1 + bounds->x2)/2 < 0) || 
03597             ((bounds->y1 + bounds->y2)/2 < 0))
03598         {
03599             g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n",
03600                        bounds->x1, bounds->y1, bounds->x2, bounds->y2);
03601             return FALSE;
03602         }
03603 
03604         zoom_region->roi.x1 = bounds->x1;
03605         zoom_region->roi.y1 = bounds->y1;
03606         zoom_region->roi.x2 = bounds->x2;
03607         zoom_region->roi.y2 = bounds->y2;
03608 
03609         if (zoom_region->timing_pan_rate > 0) {
03610                 /* Set idle handler to do panning test */
03611                 g_idle_add_full (GDK_PRIORITY_REDRAW + 3, 
03612                         zoom_region_pan_test, zoom_region, NULL);
03613         }
03614 
03615         if (zoom_region->exit_magnifier) {
03616                 if (timing_test) {
03617                         fprintf(stderr, "\n### Timing Summary:\n\n");
03618                         if (zoom_region->timing_pan_rate)
03619                                 fprintf(stderr, "  Pan Rate                 = %d\n", zoom_region->timing_pan_rate);
03620                         timing_report(zoom_region);
03621                 }
03622                 exit(0);
03623         }
03624 
03625         /*
03626          * Do not bother trying to update the screen if the last
03627          * screen update has not had time to complete.
03628          */
03629         if (processing_updates) {
03630                 /* Remove any previous idle handler */
03631                 if (pending_idle_handler != 0) {
03632                         g_source_remove(pending_idle_handler);
03633                         pending_idle_handler = 0;
03634                 }
03635 
03636                 /* Set idle handler to process this pending update when possible */
03637 
03638                 pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2,
03639                         zoom_region_process_pending, zoom_region, NULL);
03640 
03641                 if (zoom_region->timing_output) {
03642                         fprintf(stderr,
03643                                 "\n  [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n",
03644                                 zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
03645                                 zoom_region->roi.y2);
03646                 }
03647         } else {
03648                 zoom_region_align (zoom_region);
03649         }
03650         
03651         return TRUE;
03652 }
03653 
03654 /* TODO: Deprecate this RPC */
03655 gboolean
03656 impl_dbus_zoom_region_update_pointer (ZoomRegion *zoom_region)
03657 {
03658 #ifdef ZOOM_REGION_DEBUG
03659         g_assert (zoom_region->alive);
03660 #endif
03661 
03662         zoom_region_update_cursor (zoom_region, 0, 0, NULL);
03663         
03664         return TRUE;
03665 }
03666 
03667 gboolean
03668 impl_dbus_zoom_region_mark_dirty (ZoomRegion *zoom_region, gint32 **bounds)
03669 {
03670         GNOME_Magnifier_RectBounds *roi_dirty = g_malloc(sizeof(GNOME_Magnifier_RectBounds));
03671         roi_dirty->x1 = (*bounds)[0];
03672         roi_dirty->y1 = (*bounds)[1];
03673         roi_dirty->x2 = (*bounds)[2];
03674         roi_dirty->y2 = (*bounds)[3];
03675 
03676 #ifdef ZOOM_REGION_DEBUG
03677         g_assert (zoom_region->alive);
03678 #endif
03679         DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds (
03680                             zoom_region, roi_dirty) );
03681 
03682         zoom_region_update_pointer (zoom_region, TRUE);
03683         /* XXX ? should we clip here, or wait till process_updates? */
03684         zoom_region_queue_update (zoom_region, 
03685           zoom_region_clip_to_source (zoom_region, 
03686               zoom_region_rect_from_bounds (zoom_region, roi_dirty)));
03687 
03688         return TRUE;
03689 }
03690 
03691 GArray*
03692 impl_dbus_zoom_region_get_roi (ZoomRegion *zoom_region)
03693 {
03694         GArray *ret;
03695         
03696         ret = g_array_new (FALSE, FALSE, sizeof (gint32));
03697         
03698         g_array_append_val (ret, zoom_region->roi.x1);
03699         g_array_append_val (ret, zoom_region->roi.y1);
03700         g_array_append_val (ret, zoom_region->roi.x2);
03701         g_array_append_val (ret, zoom_region->roi.y2);
03702         
03703         return ret;
03704 }
03705 
03706 gboolean
03707 impl_dbus_zoom_region_move_resize (ZoomRegion *zoom_region, const gint32 **viewport)
03708 {
03709 #ifdef ZOOM_REGION_DEBUG
03710         g_assert (zoom_region->alive);
03711 #endif
03712         GNOME_Magnifier_RectBounds *viewport_bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds));
03713         viewport_bounds->x1 = (*viewport)[0];
03714         viewport_bounds->y1 = (*viewport)[1];
03715         viewport_bounds->x2 = (*viewport)[2];
03716         viewport_bounds->y2 = (*viewport)[3];
03717 
03718         zoom_region_set_viewport (zoom_region, viewport_bounds);
03719 
03720         return TRUE;
03721 }
03722 
03723 gboolean
03724 impl_dbus_zoom_region_set_pointer_pos (ZoomRegion *zoom_region, gint32 mouse_x, gint32 mouse_y)
03725 {
03726         GdkRectangle paint_area, *clip = NULL;
03727 
03728 #ifdef ZOOM_REGION_DEBUG
03729         g_assert (zoom_region->alive);
03730 #endif
03731         DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 
03732                       (long) mouse_x, (long) mouse_y));
03733 
03734         fprintf (stderr, "Set Pointer: \t%ld,%ld\n", 
03735                       (long) mouse_x, (long) mouse_y);
03736 
03737         zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y);
03738 
03739         if (GTK_IS_WIDGET (zoom_region->priv->w) && 
03740             GDK_IS_DRAWABLE (zoom_region->priv->w->window))
03741         {
03742             gdk_drawable_get_size (
03743                 GDK_DRAWABLE (
03744                     zoom_region->priv->w->window),
03745                 &paint_area.width, &paint_area.height);
03746             paint_area.x = 0;
03747             paint_area.y = 0;
03748             clip = &paint_area;
03749             paint_area = zoom_region_clip_to_source (
03750                 zoom_region, paint_area);
03751         }
03752         /* 
03753          * if we update the cursor now, it causes flicker if the client 
03754          * subsequently calls setROI, so we wait for a redraw.
03755          * Perhaps we should cue a redraw on idle instead?
03756          */
03757 
03758         return TRUE;
03759 }
03760 
03761 gboolean
03762 impl_dbus_zoom_region_set_contrast (ZoomRegion *zoom_region, gdouble R, gdouble G, gdouble B)
03763 {
03764         gfloat t;
03765 
03766 #ifdef ZOOM_REGION_DEBUG
03767         g_assert (zoom_region->alive);
03768 #endif
03769         DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B));
03770 
03771         /* if the contrast values are the same, this is a NOOP */
03772         if (zoom_region->contrast_r == R &&
03773             zoom_region->contrast_g == G &&
03774             zoom_region->contrast_b == B)
03775                 return TRUE;
03776 
03777         zoom_region->contrast_r = CLAMP_B_C (R);
03778         zoom_region->contrast_g = CLAMP_B_C (G);
03779         zoom_region->contrast_b = CLAMP_B_C (B);
03780 
03781         zoom_region_update_current (zoom_region);
03782 
03783         return TRUE;
03784 }
03785 
03786 GArray*
03787 impl_dbus_zoom_region_get_contrast (ZoomRegion *zoom_region)
03788 {
03789         GArray *ret;
03790         
03791         ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
03792         
03793         g_array_append_val (ret, zoom_region->contrast_r);
03794         g_array_append_val (ret, zoom_region->contrast_g);
03795         g_array_append_val (ret, zoom_region->contrast_b);
03796         
03797         return ret;
03798 }
03799 
03800 gboolean
03801 impl_dbus_zoom_region_set_brightness (ZoomRegion *zoom_region, gdouble R, gdouble G, gdouble B)
03802 {
03803         gfloat t;
03804 
03805 #ifdef ZOOM_REGION_DEBUG
03806         g_assert (zoom_region->alive);
03807 #endif
03808         DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B));
03809 
03810         /* if the contrast values are the same, this is a NOOP */
03811         if (zoom_region->bright_r == R &&
03812             zoom_region->bright_g == G &&
03813             zoom_region->bright_b == B)
03814                 return TRUE;
03815 
03816         zoom_region->bright_r = CLAMP_B_C (R);
03817         zoom_region->bright_g = CLAMP_B_C (G);
03818         zoom_region->bright_b = CLAMP_B_C (B);
03819 
03820         zoom_region_update_current (zoom_region);
03821         
03822         return TRUE;
03823 }
03824 
03825 GArray*
03826 impl_dbus_zoom_region_get_brightness (ZoomRegion *zoom_region)
03827 {
03828         GArray *ret;
03829         
03830         ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
03831         
03832         g_array_append_val (ret, zoom_region->bright_r);
03833         g_array_append_val (ret, zoom_region->bright_g);
03834         g_array_append_val (ret, zoom_region->bright_b);
03835         
03836         return ret;
03837 }
03838 
03839 /* could be called multiple times */
03840 static void
03841 zoom_region_dispose (GObject *object)
03842 {
03843         ZoomRegion *zoom_region = ZOOM_REGION (object);
03844 
03845         zoom_region_do_dispose (zoom_region);
03846 
03847         BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
03848 }
03849 
03850 static void
03851 zoom_region_class_init (ZoomRegionClass *klass)
03852 {
03853         GObjectClass * object_class = (GObjectClass *) klass;
03854         POA_GNOME_Magnifier_ZoomRegion__epv *epv = &klass->epv;
03855         parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT); /* needed by BONOBO_CALL_PARENT! */
03856 
03857         object_class->dispose = zoom_region_dispose;
03858         object_class->finalize = zoom_region_finalize;
03859         
03860         epv->setMagFactor = impl_zoom_region_set_mag_factor;
03861         epv->getMagFactor = impl_zoom_region_get_mag_factor;
03862         epv->getProperties = impl_zoom_region_get_properties;
03863         epv->setROI = impl_zoom_region_set_roi;
03864         epv->setPointerPos = impl_zoom_region_set_pointer_pos;
03865         epv->updatePointer = impl_zoom_region_update_pointer;
03866         epv->markDirty = impl_zoom_region_mark_dirty;
03867         epv->getROI = impl_zoom_region_get_roi;
03868         epv->moveResize = impl_zoom_region_move_resize;
03869         epv->dispose = impl_zoom_region_dispose;
03870         epv->setContrast = impl_zoom_region_set_contrast;
03871         epv->getContrast = impl_zoom_region_get_contrast;
03872         epv->setBrightness = impl_zoom_region_set_brightness;
03873         epv->getBrightness = impl_zoom_region_get_brightness;
03874 
03875         reset_timing_stats();
03876 #ifdef DEBUG_CLIENT_CALLS
03877         client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL);
03878 #endif
03879 }
03880 
03881 static void
03882 zoom_region_properties_init (ZoomRegion *zoom_region)
03883 {
03884         BonoboArg *def;
03885         
03886         zoom_region->properties =
03887                 bonobo_property_bag_new_closure (
03888                         g_cclosure_new_object (
03889                                 G_CALLBACK (zoom_region_get_property),
03890                                 G_OBJECT (zoom_region)),
03891                         g_cclosure_new_object (
03892                                 G_CALLBACK (zoom_region_set_property),
03893                                 G_OBJECT (zoom_region)));
03894 
03895         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03896         BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03897         
03898         bonobo_property_bag_add (zoom_region->properties,
03899                                  "is-managed",
03900                                  ZOOM_REGION_MANAGED_PROP,
03901                                  BONOBO_ARG_BOOLEAN,
03902                                  def,
03903                                  "If false, zoom region does not auto-update, but is drawn into directly by the client",
03904                                  Bonobo_PROPERTY_READABLE |
03905                                  Bonobo_PROPERTY_WRITEABLE);
03906 
03907         bonobo_arg_release (def);
03908         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03909         BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03910         
03911         bonobo_property_bag_add (zoom_region->properties,
03912                                  "poll-mouse",
03913                                  ZOOM_REGION_POLL_MOUSE_PROP,
03914                                  BONOBO_ARG_BOOLEAN,
03915                                  NULL,
03916                                  "If false, zoom region does not poll for pointer location, but is (exclusively) given it by the client",
03917                                  Bonobo_PROPERTY_READABLE |
03918                                  Bonobo_PROPERTY_WRITEABLE);
03919 
03920         bonobo_arg_release (def);
03921         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03922         BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03923         
03924         bonobo_property_bag_add (zoom_region->properties,
03925                                  "draw-cursor",
03926                                  ZOOM_REGION_DRAW_CURSOR_PROP,
03927                                  BONOBO_ARG_BOOLEAN,
03928                                  NULL,
03929                                  "If false, zoom region does not draw the cursor.",
03930                                  Bonobo_PROPERTY_READABLE |
03931                                  Bonobo_PROPERTY_WRITEABLE);
03932 
03933         bonobo_arg_release (def);
03934         def = bonobo_arg_new (BONOBO_ARG_SHORT);
03935         BONOBO_ARG_SET_SHORT (def, GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST);
03936         
03937         bonobo_property_bag_add (zoom_region->properties,
03938                                  "smooth-scroll-policy",
03939                                  ZOOM_REGION_SMOOTHSCROLL_PROP,
03940                                  BONOBO_ARG_SHORT,
03941                                  def,
03942                                  "scrolling policy, slower versus faster",
03943                                  Bonobo_PROPERTY_READABLE |
03944                                  Bonobo_PROPERTY_WRITEABLE);
03945 
03946         bonobo_arg_release (def);
03947         def = bonobo_arg_new (BONOBO_ARG_SHORT);
03948         BONOBO_ARG_SET_SHORT (
03949                 def,
03950                 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER);
03951         
03952         bonobo_property_bag_add (zoom_region->properties,
03953                                  "color-blind-filter",
03954                                  ZOOM_REGION_COLORBLIND_PROP,
03955                                  BONOBO_ARG_SHORT,
03956                                  def,
03957                                  "color blind filter to apply in an image",
03958                                  Bonobo_PROPERTY_READABLE |
03959                                  Bonobo_PROPERTY_WRITEABLE);
03960 
03961         bonobo_arg_release (def);
03962         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03963         BONOBO_ARG_SET_BOOLEAN (def, FALSE);
03964 
03965         bonobo_property_bag_add (zoom_region->properties,
03966                                  "use-test-pattern",
03967                                  ZOOM_REGION_TESTPATTERN_PROP,
03968                                  BONOBO_ARG_BOOLEAN,
03969                                  def,
03970                                  "use test pattern for source",
03971                                  Bonobo_PROPERTY_READABLE |
03972                                  Bonobo_PROPERTY_WRITEABLE);
03973 
03974         bonobo_arg_release (def);
03975         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
03976         BONOBO_ARG_SET_BOOLEAN (def, TRUE);
03977         
03978         bonobo_property_bag_add (zoom_region->properties,
03979                                  "inverse-video",
03980                                  ZOOM_REGION_INVERT_PROP,
03981                                  BONOBO_ARG_BOOLEAN,
03982                                  def,
03983                                  "inverse video display",
03984                                  Bonobo_PROPERTY_READABLE |
03985                                  Bonobo_PROPERTY_WRITEABLE);
03986 
03987         bonobo_arg_release (def);
03988 
03989         bonobo_property_bag_add (zoom_region->properties,
03990                                  "smoothing-type",
03991                                  ZOOM_REGION_SMOOTHING_PROP,
03992                                  BONOBO_ARG_STRING,
03993                                  NULL,
03994                                  "image smoothing algorithm used",
03995                                  Bonobo_PROPERTY_READABLE |
03996                                  Bonobo_PROPERTY_WRITEABLE);
03997 
03998         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
03999         BONOBO_ARG_SET_FLOAT (def, 0.0);
04000 
04001         bonobo_property_bag_add (zoom_region->properties,
04002                                  "red-contrast",
04003                                  ZOOM_REGION_CONTRASTR_PROP,
04004                                  BONOBO_ARG_FLOAT,
04005                                  def,
04006                                  "red image contrast ratio",
04007                                  Bonobo_PROPERTY_READABLE |
04008                                  Bonobo_PROPERTY_WRITEABLE);
04009         bonobo_arg_release (def);
04010 
04011         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04012         BONOBO_ARG_SET_FLOAT (def, 0.0);
04013 
04014         bonobo_property_bag_add (zoom_region->properties,
04015                                  "green-contrast",
04016                                  ZOOM_REGION_CONTRASTG_PROP,
04017                                  BONOBO_ARG_FLOAT,
04018                                  def,
04019                                  "green image contrast ratio",
04020                                  Bonobo_PROPERTY_READABLE |
04021                                  Bonobo_PROPERTY_WRITEABLE);
04022         bonobo_arg_release (def);
04023 
04024         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04025         BONOBO_ARG_SET_FLOAT (def, 0.0);
04026 
04027         bonobo_property_bag_add (zoom_region->properties,
04028                                  "blue-contrast",
04029                                  ZOOM_REGION_CONTRASTB_PROP,
04030                                  BONOBO_ARG_FLOAT,
04031                                  def,
04032                                  "blue image contrast ratio",
04033                                  Bonobo_PROPERTY_READABLE |
04034                                  Bonobo_PROPERTY_WRITEABLE);
04035         bonobo_arg_release (def);
04036 
04037         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04038         BONOBO_ARG_SET_FLOAT (def, 0.0);
04039 
04040         bonobo_property_bag_add (zoom_region->properties,
04041                                  "red-brightness",
04042                                  ZOOM_REGION_BRIGHTR_PROP,
04043                                  BONOBO_ARG_FLOAT,
04044                                  def,
04045                                  "red image brightness ratio",
04046                                  Bonobo_PROPERTY_READABLE |
04047                                  Bonobo_PROPERTY_WRITEABLE);
04048         bonobo_arg_release (def);
04049 
04050         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04051         BONOBO_ARG_SET_FLOAT (def, 0.0);
04052 
04053         bonobo_property_bag_add (zoom_region->properties,
04054                                  "green-brightness",
04055                                  ZOOM_REGION_BRIGHTG_PROP,
04056                                  BONOBO_ARG_FLOAT,
04057                                  def,
04058                                  "green image brightness ratio",
04059                                  Bonobo_PROPERTY_READABLE |
04060                                  Bonobo_PROPERTY_WRITEABLE);
04061         bonobo_arg_release (def);
04062 
04063         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04064         BONOBO_ARG_SET_FLOAT (def, 0.0);
04065 
04066         bonobo_property_bag_add (zoom_region->properties,
04067                                  "blue-brightness",
04068                                  ZOOM_REGION_BRIGHTB_PROP,
04069                                  BONOBO_ARG_FLOAT,
04070                                  def,
04071                                  "blue image brightness ratio",
04072                                  Bonobo_PROPERTY_READABLE |
04073                                  Bonobo_PROPERTY_WRITEABLE);
04074         bonobo_arg_release (def);
04075 
04076         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04077         BONOBO_ARG_SET_FLOAT (def, 2.0);
04078 
04079         bonobo_property_bag_add (zoom_region->properties,
04080                                  "mag-factor-x",
04081                                  ZOOM_REGION_XSCALE_PROP,
04082                                  BONOBO_ARG_FLOAT,
04083                                  def,
04084                                  "x scale factor",
04085                                  Bonobo_PROPERTY_READABLE |
04086                                  Bonobo_PROPERTY_WRITEABLE);
04087 
04088         bonobo_arg_release (def);
04089         def = bonobo_arg_new (BONOBO_ARG_FLOAT);
04090         BONOBO_ARG_SET_FLOAT (def, 2.0);
04091 
04092         bonobo_property_bag_add (zoom_region->properties,
04093                                  "mag-factor-y",
04094                                  ZOOM_REGION_YSCALE_PROP,
04095                                  BONOBO_ARG_FLOAT,
04096                                  def,
04097                                  "y scale factor",
04098                                  Bonobo_PROPERTY_READABLE |
04099                                  Bonobo_PROPERTY_WRITEABLE);
04100 
04101         bonobo_arg_release (def);
04102         def = bonobo_arg_new (BONOBO_ARG_LONG);
04103         BONOBO_ARG_SET_LONG (def, 0);
04104 
04105         bonobo_property_bag_add (zoom_region->properties,
04106                                  "border-size",
04107                                  ZOOM_REGION_BORDERSIZE_PROP,
04108                                  BONOBO_ARG_LONG,
04109                                  def,
04110                                  "size of zoom-region borders, in pixels",
04111                                  Bonobo_PROPERTY_READABLE |
04112                                  Bonobo_PROPERTY_WRITEABLE);
04113 
04114         bonobo_arg_release (def);
04115         def = bonobo_arg_new (BONOBO_ARG_LONG);
04116         BONOBO_ARG_SET_LONG (def, 0);
04117         
04118         bonobo_property_bag_add (zoom_region->properties,
04119                                  "border-size-left",
04120                                  ZOOM_REGION_BORDERSIZELEFT_PROP,
04121                                  BONOBO_ARG_LONG,
04122                                  def,
04123                                  "size of left zoom-region border, in pixels",
04124                                  Bonobo_PROPERTY_READABLE |
04125                                  Bonobo_PROPERTY_WRITEABLE);
04126 
04127         bonobo_arg_release (def);
04128         def = bonobo_arg_new (BONOBO_ARG_LONG);
04129         BONOBO_ARG_SET_LONG (def, 0);
04130         
04131         bonobo_property_bag_add (zoom_region->properties,
04132                                  "border-size-top",
04133                                  ZOOM_REGION_BORDERSIZETOP_PROP,
04134                                  BONOBO_ARG_LONG,
04135                                  def,
04136                                  "size of top zoom-region border, in pixels",
04137                                  Bonobo_PROPERTY_READABLE |
04138                                  Bonobo_PROPERTY_WRITEABLE);
04139 
04140         bonobo_arg_release (def);
04141         def = bonobo_arg_new (BONOBO_ARG_LONG);
04142         BONOBO_ARG_SET_LONG (def, 0);
04143         
04144         bonobo_property_bag_add (zoom_region->properties,
04145                                  "border-size-right",
04146                                  ZOOM_REGION_BORDERSIZERIGHT_PROP,
04147                                  BONOBO_ARG_LONG,
04148                                  def,
04149                                  "size of right zoom-region border, in pixels",
04150                                  Bonobo_PROPERTY_READABLE |
04151                                  Bonobo_PROPERTY_WRITEABLE);
04152 
04153         bonobo_arg_release (def);
04154         def = bonobo_arg_new (BONOBO_ARG_LONG);
04155         BONOBO_ARG_SET_LONG (def, 0);
04156         
04157         bonobo_property_bag_add (zoom_region->properties,
04158                                  "border-size-bottom",
04159                                  ZOOM_REGION_BORDERSIZEBOTTOM_PROP,
04160                                  BONOBO_ARG_LONG,
04161                                  def,
04162                                  "size of bottom zoom-region border, in "
04163                                  "pixels",
04164                                  Bonobo_PROPERTY_READABLE |
04165                                  Bonobo_PROPERTY_WRITEABLE);
04166 
04167         bonobo_arg_release (def);
04168         def = bonobo_arg_new (BONOBO_ARG_LONG);
04169         BONOBO_ARG_SET_LONG (def, 0x00000000);
04170         
04171         bonobo_property_bag_add (zoom_region->properties,
04172                                  "border-color",
04173                                  ZOOM_REGION_BORDERCOLOR_PROP,
04174                                  BONOBO_ARG_LONG,
04175                                  def,
04176                                  "border color, as RGBA32",
04177                                  Bonobo_PROPERTY_READABLE |
04178                                  Bonobo_PROPERTY_WRITEABLE);
04179 
04180         bonobo_arg_release (def);
04181         def = bonobo_arg_new (BONOBO_ARG_INT);
04182         BONOBO_ARG_SET_INT (def, 0);
04183 
04184         bonobo_property_bag_add (zoom_region->properties,
04185                                  "x-alignment",
04186                                  ZOOM_REGION_XALIGN_PROP,
04187                                  BONOBO_ARG_INT,
04188                                  def,
04189                                  "x-alignment policy for this region",
04190                                  Bonobo_PROPERTY_READABLE |
04191                                  Bonobo_PROPERTY_WRITEABLE);
04192 
04193         bonobo_arg_release (def);
04194         def = bonobo_arg_new (BONOBO_ARG_INT);
04195         BONOBO_ARG_SET_INT (def, 0);
04196 
04197         bonobo_property_bag_add (zoom_region->properties,
04198                                  "y-alignment",
04199                                  ZOOM_REGION_YALIGN_PROP,
04200                                  BONOBO_ARG_INT,
04201                                  def,
04202                                  "y-alignment policy for this region",
04203                                  Bonobo_PROPERTY_READABLE |
04204                                  Bonobo_PROPERTY_WRITEABLE);
04205         bonobo_arg_release (def);
04206 
04207         bonobo_property_bag_add (zoom_region->properties,
04208                                  "viewport",
04209                                  ZOOM_REGION_VIEWPORT_PROP,
04210                                  TC_GNOME_Magnifier_RectBounds,
04211                                  NULL,
04212                                  "viewport bounding box",
04213                                  Bonobo_PROPERTY_READABLE |
04214                                  Bonobo_PROPERTY_WRITEABLE);
04215 
04216         def = bonobo_arg_new (BONOBO_ARG_INT);
04217         BONOBO_ARG_SET_INT (def, 0);
04218 
04219         bonobo_property_bag_add (zoom_region->properties,
04220                                  "timing-iterations",
04221                                  ZOOM_REGION_TIMING_TEST_PROP,
04222                                  BONOBO_ARG_INT,
04223                                  def,
04224                                  "timing iterations",
04225                                  Bonobo_PROPERTY_READABLE |
04226                                  Bonobo_PROPERTY_WRITEABLE);
04227         bonobo_arg_release (def);
04228 
04229         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
04230         BONOBO_ARG_SET_BOOLEAN (def, FALSE);
04231         
04232         bonobo_property_bag_add (zoom_region->properties,
04233                                  "timing-output",
04234                                  ZOOM_REGION_TIMING_OUTPUT_PROP,
04235                                  BONOBO_ARG_BOOLEAN,
04236                                  def,
04237                                  "timing output",
04238                                  Bonobo_PROPERTY_READABLE |
04239                                  Bonobo_PROPERTY_WRITEABLE);
04240 
04241         bonobo_arg_release (def);
04242 
04243         def = bonobo_arg_new (BONOBO_ARG_INT);
04244         BONOBO_ARG_SET_INT (def, 0);
04245 
04246         bonobo_property_bag_add (zoom_region->properties,
04247                                  "timing-pan-rate",
04248                                  ZOOM_REGION_TIMING_PAN_RATE_PROP,
04249                                  BONOBO_ARG_INT,
04250                                  def,
04251                                  "timing pan rate",
04252                                  Bonobo_PROPERTY_READABLE |
04253                                  Bonobo_PROPERTY_WRITEABLE);
04254         bonobo_arg_release (def);
04255 
04256         def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
04257         BONOBO_ARG_SET_BOOLEAN (def, FALSE);
04258         
04259         bonobo_property_bag_add (zoom_region->properties,
04260                                  "exit-magnifier",
04261                                  ZOOM_REGION_EXIT_MAGNIFIER,
04262                                  BONOBO_ARG_BOOLEAN,
04263                                  def,
04264                                  "timing output",
04265                                  Bonobo_PROPERTY_READABLE |
04266                                  Bonobo_PROPERTY_WRITEABLE);
04267 
04268         bonobo_arg_release (def);
04269 
04270 }
04271 
04272 static void
04273 zoom_region_private_init (ZoomRegionPrivate *priv)
04274 {
04275         GdkRectangle rect = {0, 0, 0, 0};
04276         GNOME_Magnifier_RectBounds rectbounds = {0, 0, 0, 0};
04277         priv->parent = NULL;
04278         priv->w = NULL;
04279         priv->default_gc = NULL;
04280         priv->paint_cursor_gc = NULL;
04281         priv->crosswire_gc = NULL;
04282         priv->q = NULL;
04283         priv->scaled_pixbuf = NULL;
04284         priv->source_pixbuf_cache = NULL;
04285         priv->source_drawable = NULL;
04286         priv->pixmap = NULL;
04287         priv->cursor_backing_rect = rect;
04288         priv->cursor_backing_pixels = NULL;
04289         priv->gdk_interp_type = GDK_INTERP_NEAREST;
04290         priv->expose_handler_id = 0;
04291         priv->test = FALSE;
04292         priv->last_cursor_pos.x = 0;
04293         priv->last_cursor_pos.y = 0;
04294         priv->last_drawn_crosswire_pos.x = 0;
04295         priv->last_drawn_crosswire_pos.y = 0;
04296         priv->exposed_bounds = rectbounds;
04297         priv->source_area = rectbounds;
04298         priv->update_pointer_id = 0;
04299         priv->update_handler_id = 0;
04300 }
04301 
04302 
04303 
04304 static void
04305 zoom_region_init (ZoomRegion *zoom_region)
04306 {
04307         DBG(g_message ("initializing region %p", zoom_region));
04308 
04309 #ifdef HAVE_COLORBLIND
04310     cbr = colorblind_create();
04311     color = malloc (sizeof (COLORBLIND_XCOLOR));
04312 #endif /* HAVE_COLORBLIND */
04313 
04314         zoom_region_properties_init (zoom_region);
04315         zoom_region->draw_cursor = TRUE;
04316         zoom_region->smooth_scroll_policy =
04317                 GNOME_Magnifier_ZoomRegion_SCROLL_SMOOTH;
04318         zoom_region->color_blind_filter =
04319                 GNOME_Magnifier_ZoomRegion_COLORBLIND_FILTER_T_NO_FILTER;
04320         zoom_region->contrast_r = 0.0;
04321         zoom_region->contrast_g = 0.0;
04322         zoom_region->contrast_b = 0.0;
04323         zoom_region->bright_r = 0.0;
04324         zoom_region->bright_g = 0.0;
04325         zoom_region->bright_b = 0.0;
04326         zoom_region->invert = FALSE;
04327         zoom_region->cache_source = FALSE;
04328         zoom_region->border_size_left = 0;
04329         zoom_region->border_size_top = 0;
04330         zoom_region->border_size_right = 0;
04331         zoom_region->border_size_bottom = 0;
04332         zoom_region->border_color = 0;
04333         zoom_region->roi.x1 = 0;
04334         zoom_region->roi.x1 = 0;
04335         zoom_region->roi.x2 = 1;
04336         zoom_region->roi.x2 = 1;
04337         zoom_region->x_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER;
04338         zoom_region->y_align_policy = GNOME_Magnifier_ZoomRegion_ALIGN_CENTER;
04339         zoom_region->coalesce_func = _coalesce_update_rects;
04340         zoom_region->poll_mouse = TRUE; 
04341         zoom_region->priv = g_malloc (sizeof (ZoomRegionPrivate));
04342         zoom_region_private_init (zoom_region->priv);
04343         bonobo_object_add_interface (BONOBO_OBJECT (zoom_region),
04344                                      BONOBO_OBJECT (zoom_region->properties));
04345         zoom_region->timing_output = FALSE;
04346 #ifdef ZOOM_REGION_DEBUG
04347         zoom_region->alive = TRUE;
04348 #endif
04349         zoom_region->priv->update_pointer_id =
04350             g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
04351                                 200,
04352                                 zoom_region_update_pointer_timeout,
04353                                 zoom_region,
04354                                 NULL);
04355 }
04356 
04357 ZoomRegion *
04358 zoom_region_new (void)
04359 {
04360         ZoomRegionClass *klass = NULL;
04361         GError *error = NULL;
04362         ZoomRegion *_this_zoom_region = g_object_new (zoom_region_get_type(), NULL);
04363         _this_zoom_region->object_path = g_strdup_printf("/org/freedesktop/gnome/ZoomRegion/%i", zoom_region_number);
04364 
04365         klass = ZOOM_REGION_GET_CLASS (_this_zoom_region);
04366         
04367         klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
04368         if (klass->connection == NULL) {
04369                 g_warning ("Unable to connect to dbus: %s", error->message);
04370                 g_error_free (error);
04371                 return NULL;
04372         }
04373         
04374         dbus_g_object_type_install_info (ZOOM_REGION_TYPE, &dbus_glib_impl_dbus_zoom_region_object_info);
04375         
04376         dbus_g_connection_register_g_object (klass->connection, _this_zoom_region->object_path,
04377                                              G_OBJECT (_this_zoom_region));
04378                                                   
04379         zoom_region_number++;
04380                                                   
04381         return _this_zoom_region;
04382 }
04383 
04384 /* this one really shuts down the object - called once only */
04385 static void
04386 zoom_region_finalize (GObject *region)
04387 {
04388         ZoomRegion *zoom_region = (ZoomRegion *) region;
04389 
04390         DBG(g_message ("finalizing region %p", zoom_region));
04391 
04392         if (zoom_region->priv && zoom_region->priv->q) 
04393         {
04394                 g_list_free (zoom_region->priv->q);
04395                 zoom_region->priv->q = NULL;
04396         }
04397         if (GTK_IS_WIDGET (zoom_region->priv->w))
04398                 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->w));
04399         if (GTK_IS_WIDGET (zoom_region->priv->border))
04400                 gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->border));
04401         if (zoom_region->priv->source_pixbuf_cache) 
04402             g_object_unref (zoom_region->priv->source_pixbuf_cache);
04403         if (zoom_region->priv->scaled_pixbuf) 
04404             g_object_unref (zoom_region->priv->scaled_pixbuf);
04405         if (zoom_region->priv->pixmap) 
04406             g_object_unref (zoom_region->priv->pixmap);
04407         zoom_region->priv->pixmap = NULL;
04408         zoom_region->priv->parent = NULL;
04409         if (zoom_region->priv->cursor_backing_pixels) 
04410             g_object_unref (zoom_region->priv->cursor_backing_pixels);
04411         g_free (zoom_region->priv);
04412         zoom_region->priv = NULL;
04413 
04414 #ifdef HAVE_COLORBLIND
04415     free(cbr);
04416     free(color);
04417 #endif /* HAVE_COLORBLIND */
04418 
04419 #ifdef ZOOM_REGION_DEBUG
04420         zoom_region->alive = FALSE;
04421 #endif
04422         BONOBO_CALL_PARENT (G_OBJECT_CLASS, finalize, (region));
04423 }
04424 
04425 BONOBO_TYPE_FUNC_FULL (ZoomRegion, 
04426                        GNOME_Magnifier_ZoomRegion,
04427                        BONOBO_TYPE_OBJECT,
04428                        zoom_region);
Generated on Sun Jun 20 06:55:11 2010 for gnome-mag by  doxygen 1.6.3