gnome-mag
zoom-region.c
Go to the documentation of this file.
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 #include "config.h"
24 #include "gmag-graphical-server.h"
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <popt.h>
29 
30 #ifdef HAVE_COLORBLIND
31 #include <colorblind.h>
32 #endif /* HAVE_COLORBLIND */
33 
34 #include <gdk/gdk.h>
35 #include <gtk/gtk.h>
36 
37 #ifdef USE_GDKPIXBUF_RENDER_TO_DRAWABLE
38 #include <gdk/gdkpixbuf.h>
39 #endif
40 
41 #include <gdk/gdkx.h>
42 #include <libbonobo.h>
43 #include <math.h>
44 
45 #undef ZOOM_REGION_DEBUG
46 
47 #include "zoom-region.h"
48 #include "zoom-region-private.h"
49 #include "magnifier.h" /* needed to access parent data */
50 #include "magnifier-private.h" /* needed to access parent data */
51 #include "zoom-region-server.h"
52 
53 #define DEBUG_CLIENT_CALLS
54 
55 #ifdef DEBUG_CLIENT_CALLS
56 static gboolean client_debug = FALSE;
57 #define DBG(a) if (client_debug) { (a); }
58 #else
59 #define DBG(a)
60 #endif
61 
62 static GObjectClass *parent_class = NULL;
63 
64 enum {
94 } PropIdx;
95 
96 #ifdef DEBUG_CLIENT_CALLS
98 {
99  "MANAGED",
100  "POLLMOUSE",
101  "DRAWCURSOR",
102  "SMOOTHSCROLL",
103  "COLORBLIND",
104  "INVERT",
105  "SMOOTHING",
106  "CONTRASTR",
107  "CONTRASTG",
108  "CONTRASTB",
109  "BRIGHTR",
110  "BRIGHTG",
111  "BRIGHTB",
112  "XSCALE",
113  "YSCALE",
114  "BORDERSIZE",
115  "BORDERSIZETOP",
116  "BORDERSIZELEFT",
117  "BORDERSIZERIGHT",
118  "BORDERSIZEBOTTOM",
119  "BORDERCOLOR",
120  "XALIGN",
121  "YALIGN",
122  "VIEWPORT",
123  "TESTPATTERN",
124  "TIMING_TEST",
125  "TIMING_OUTPUT",
126  "TIMING_PAN_RATE",
127  "EXIT_MAGNIFIER"
128 };
129 #endif
130 
131 typedef enum {
136 
137 #ifdef HAVE_COLORBLIND
138 static COLORBLIND_RUNTIME *cbr = NULL;
139 static COLORBLIND_XCOLOR *color = NULL;
140 #endif /* HAVE_COLORBLIND */
141 
142 
143 static float timing_scale_max = 0;
144 static float timing_idle_max = 0;
145 static float timing_frame_max = 0;
146 static float cps_max = 0;
147 static float nrr_max = 0;
148 static float update_nrr_max = 0;
149 static gboolean reset_timing = FALSE;
150 static gboolean timing_test = FALSE;
151 
152 static guint pending_idle_handler = 0;
153 static gboolean processing_updates = FALSE;
154 static gboolean timing_start = FALSE;
155 
156 static gboolean can_coalesce = TRUE ; /* change this when event coalescing is working */
157 
158 static int zoom_region_number = 0;
159 
160 #define CLAMP_B_C(v) (t = (v), CLAMP (t, -1, 1));
161 
162 static void zoom_region_sync (ZoomRegion *region);
163 static void zoom_region_finalize (GObject *object);
165  const GdkRectangle rect);
167  const GdkRectangle rect);
168 
169 static int zoom_region_process_updates (gpointer data);
170 static void zoom_region_paint (ZoomRegion *zoom_region, GdkRectangle *rect);
171 static void zoom_region_paint_pixmap (ZoomRegion *zoom_region, GdkRectangle *rect);
172 static int zoom_region_update_pointer_timeout (gpointer data);
174  const GNOME_Magnifier_RectBounds *bounds);
176 static GdkRectangle zoom_region_update_pixmap (ZoomRegion *zoom_region, const GdkRectangle update_rect, GdkRectangle *paint_rect);
177 static void zoom_region_get_move_x_y (ZoomRegion *zoom_region, long *x, long *y);
180 
181 void
183 {
184  timing_scale_max = 0;
185  timing_idle_max = 0;
186  timing_frame_max = 0;
187  cps_max = 0;
188  nrr_max = 0;
189  update_nrr_max = 0;
199  mag_timing.dx_total = 0;
200  mag_timing.dy_total = 0;
202  mag_timing.last_dy = 0;
203  g_timer_start (mag_timing.process);
204 }
205 
208 #undef DEBUG
209 #ifdef DEBUG
210 #define DEBUG_RECT(a, b) _debug_announce_rect (a, b)
211 #else
212 #define DEBUG_RECT(a, b)
213 #endif
214 static void
215 _debug_announce_rect (char *msg, GdkRectangle rect)
216 {
217  fprintf (stderr, "%s: (%d,%d - %d,%d)\n",
218  msg, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
219 }
220 
221 static void
222 _set_bounds (RectBounds *struct_bounds, const gint32 **vector_bounds)
223 {
224  struct_bounds->x1 = (*vector_bounds)[0];
225  struct_bounds->y1 = (*vector_bounds)[1];
226  struct_bounds->x2 = (*vector_bounds)[2];
227  struct_bounds->y2 = (*vector_bounds)[3];
228 }
229 
230 static gboolean
231 _diff_pixbufs (const GdkPixbuf *a, const GdkPixbuf *b)
232 {
233  long i, j;
234  int bits_per_byte = 8; /* always true? */
235  guchar *pa = gdk_pixbuf_get_pixels (a);
236  guchar *pb = gdk_pixbuf_get_pixels (b);
237  guchar *cpa, *cpb;
238  long rsa = gdk_pixbuf_get_rowstride (a);
239  long rsb = gdk_pixbuf_get_rowstride (b);
240  long rowbytes = gdk_pixbuf_get_width (a) *
241  gdk_pixbuf_get_bits_per_sample (a) *
242  gdk_pixbuf_get_n_channels (a)/ bits_per_byte;
243  long n_rows = gdk_pixbuf_get_height (a);
244 
245  if (gdk_pixbuf_get_height (b) != n_rows)
246  return TRUE;
247  if (gdk_pixbuf_get_width (b) != gdk_pixbuf_get_width (a))
248  return TRUE;
249  for (j = 0; j < n_rows; ++j)
250  {
251  cpa = pa + j * rsa;
252  cpb = pb + j * rsb;
253  for (i = 0; i < rowbytes; ++i)
254  {
255  if (*cpa != *cpb)
256  {
257  return TRUE;
258  }
259  cpa++;
260  cpb++;
261  }
262  }
263  return FALSE;
264 }
265 
268 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
269 
278 static gboolean
279 _combine_rects (GdkRectangle *a, GdkRectangle *b)
280 {
281  gboolean can_combine = FALSE;
282  if ((a->x == b->x) && (a->x + a->width == b->x + b->width))
283  {
284  can_combine = TRUE;
285  }
286  else if ((a->y == b->y) && (a->y + a->height == b->y + b->height))
287  {
288  can_combine = TRUE;
289  }
290  if (can_combine)
291  {
292  GdkRectangle c;
293  /* TODO: check and fix this */
294  if (gdk_rectangle_intersect (a, b, &c))
295  {
296  gdk_rectangle_union (a, b, &c);
297  *a = c;
298  can_combine = TRUE;
299  }
300  else
301  {
302  can_combine = FALSE;
303  }
304  }
305  return can_combine;
306 }
307 
321 static gboolean
322 _refactor_rects (GdkRectangle *p, GdkRectangle *n)
323 {
324  gboolean refactored = FALSE;
325  GdkRectangle *a, *b;
326  if (p->x == n->x)
327  {
328  if (p->width < n->width)
329  {
330  a = p;
331  b = n;
332  }
333  else
334  {
335  a = n;
336  b = p;
337  }
338  if (a->y == b->y + b->height)
339  {
340  a->y -= b->height;
341  a->height += b->height;
342  b->x += a->width;
343  b->width -= a->width;
344  refactored = TRUE;
345  }
346  else if (a->y + a->height == b->y)
347  {
348  a->height += b->height;
349  b->x += a->width;
350  b->width -= a->width;
351  refactored = TRUE;
352  }
353  if (refactored) fprintf (stderr, "REFACTOR 1\n");
354  }
355  else if (p->y == n->y)
356  {
357  if (p->height < n->height)
358  {
359  a = p;
360  b = n;
361  }
362  else
363  {
364  a = n;
365  b = p;
366  }
367  if (a->x == b->x + b->width)
368  {
369  a->x -= b->width;
370  a->width += b->width;
371  b->y += a->height;
372  b->height -= a->height;
373  refactored = TRUE;
374  }
375  else if (a->x + a->width == b->x)
376  {
377  a->width += b->width;
378  b->y += a->height;
379  b->height -= a->height;
380  refactored = TRUE;
381  }
382  if (refactored) fprintf (stderr, "REFACTOR 2\n");
383  }
384  else if (p->x + p->width == n->x + n->width)
385  {
386  if (p->width < n->width)
387  {
388  a = p;
389  b = n;
390  }
391  else
392  {
393  a = n;
394  b = p;
395  }
396  if (a->y == b->y + b->height)
397  {
398  a->y -= b->height;
399  a->height += b->height;
400  b->width -= a->width;
401  refactored = TRUE;
402  }
403  else if (a->y + a->height == b->y)
404  {
405  a->height += b->height;
406  b->width -= a->width;
407  refactored = TRUE;
408  }
409  if (refactored) fprintf (stderr, "REFACTOR 3\n");
410  }
411  else if (p->y + p->height == n->y + n->height)
412  {
413  if (p->height < n->height)
414  {
415  a = p;
416  b = n;
417  }
418  else
419  {
420  a = n;
421  b = p;
422  }
423  if (a->x == b->x + b->width)
424  {
425  a->x -= b->width;
426  a->width += b->width;
427  b->height -= a->height;
428  refactored = TRUE;
429  }
430  else if (a->x + a->width == b->x)
431  {
432  a->width += b->width;
433  b->height -= a->height;
434  refactored = TRUE;
435  }
436  if (refactored) fprintf (stderr, "REFACTOR 4\n");
437  }
438  return refactored;
439 }
440 
441 static GList*
442 _combine_update_rects (GList *q, int lookahead_n)
443 {
444  int i = 0;
445  GdkRectangle *a = q->data;
446  GList *p = q;
447  while (i < lookahead_n && p && p->next)
448  {
449  if (_combine_rects (a, q->next->data))
450  {
451  q = g_list_delete_link (q, p->next);
452  }
453  else
454  {
455  p = p->next;
456  ++i;
457  }
458  }
459  return q;
460 }
461 #endif
462 
463 /*#define _is_horizontal_rect(r) (((2 * (r)->width / 3 * (r)->height)) > 1)*/
464 /*#define _is_vertical_rect(r) (((2 * (r)->height / 3 * (r)->width)) > 1)*/
465 #define _is_horizontal_rect(r) ((r)->width > (r)->height)
466 #define _is_vertical_rect(r) ((r)->height > (r)->width)
467 
474 static GList *
475 _coalesce_update_rects (GList *q, int min_coalesce_length)
476 {
477  GdkRectangle *v = NULL, *h = NULL;
478  GList *compact_queue = NULL;
479 /* fprintf (stderr, "starting queue length = %d\n", g_list_length (q)); */
480  if (g_list_length (q) < min_coalesce_length)
481  return g_list_copy (q);
482  while (q)
483  {
484  if (_is_vertical_rect ((GdkRectangle *) (q->data)))
485  {
486  if (v) gdk_rectangle_union (v, q->data, v);
487  else
488  {
489  v = g_new0 (GdkRectangle, 1);
490  *v = *(GdkRectangle *)q->data;
491  }
492  }
493  else if (_is_horizontal_rect ((GdkRectangle *) (q->data)))
494  {
495  if (h) gdk_rectangle_union (h, q->data, h);
496  else
497  {
498  h = g_new0 (GdkRectangle, 1);
499  *h = *(GdkRectangle *)q->data;
500  }
501  }
502  else
503  compact_queue = g_list_prepend (compact_queue, q->data);
504  q = q->next;
505  };
506  if (v)
507  compact_queue = g_list_prepend (compact_queue, v);
508  if (h)
509  compact_queue = g_list_prepend (compact_queue, h);
510 /* fprintf (stderr, "ending queue length = %d\n", g_list_length (compact_queue));*/
511  /* don't free the original queue, that's the caller's responsibility */
512  return compact_queue;
513 }
514 
515 #ifdef BROKEN_COALESCE_STUFF_GETS_FIXED
516 static GList *
517 _smartbutbroken_coalesce_update_rects (GList *q, int lookahead_n)
518 {
519  int i = 0, len;
520  fprintf (stderr, "starting queue length = %d\n", g_list_length (q));
521  do {
522  GdkRectangle *a;
523  len = g_list_length (q);
524  q = _combine_update_rects (q, lookahead_n);
525  a = q->data;
526  while (i < lookahead_n && q && q->next)
527  {
528  if (_refactor_rects (a, q->next->data))
529  break;
530  else
531  ++i;
532  }
533  q = _combine_update_rects (q, lookahead_n);
534  } while (g_list_length (q) < len);
535  fprintf (stderr, "ending queue length = %d\n", g_list_length (q));
536  return q;
537 }
538 #endif
539 
543 static GdkRectangle
544 _rectangle_clip_to_rectangle (GdkRectangle area,
545  GdkRectangle clip_rect)
546 {
547  GdkRectangle clipped;
548  clipped.x = MAX (area.x, clip_rect.x);
549  clipped.y = MAX (area.y, clip_rect.y);
550  clipped.width = MIN ((area.x + area.width), (clip_rect.x + clip_rect.width)) - clipped.x;
551  clipped.height = MIN ((area.y + area.height), (clip_rect.y + clip_rect.height)) - clipped.y;
552  return clipped;
553 }
554 
555 static GdkRectangle
556 _rectangle_clip_to_bounds (GdkRectangle area,
557  GNOME_Magnifier_RectBounds *clip_bounds)
558 {
559  area.x = MAX (area.x, clip_bounds->x1);
560  area.x = MIN (area.x, clip_bounds->x2);
561  area.width = MIN (area.width, clip_bounds->x2 - area.x);
562  area.y = MAX (area.y, clip_bounds->y1);
563  area.y = MIN (area.y, clip_bounds->y2);
564  area.height = MIN (area.height, clip_bounds->y2 - area.y);
565  return area;
566 }
567 
568 static GdkRectangle
570  GdkRectangle area)
571 {
572  GNOME_Magnifier_RectBounds *source_rect_ptr;
573  if (zoom_region && zoom_region->priv && zoom_region->priv->parent)
574  {
575  source_rect_ptr = &((Magnifier *)zoom_region->priv->parent)->source_bounds;
576  DEBUG_RECT ("clipping to source bounds", zoom_region_rect_from_bounds (zoom_region, source_rect_ptr));
577  return _rectangle_clip_to_bounds (area, source_rect_ptr);
578  }
579  return area;
580 }
581 
582 static GdkRectangle
584  GdkRectangle area)
585 {
586  GNOME_Magnifier_RectBounds onscreen_target, *source_area;
587  source_area = &zoom_region->priv->source_area;
588 
589  onscreen_target.x1 = MAX (floor (zoom_region->priv->exposed_bounds.x1
590  / zoom_region->xscale),
591  source_area->x1);
592  onscreen_target.y1 = MAX (floor (zoom_region->priv->exposed_bounds.y1
593  / zoom_region->yscale),
594  source_area->y1);
595  onscreen_target.x2 = MIN (ceil (zoom_region->priv->exposed_bounds.x2
596  / zoom_region->xscale),
597  source_area->x2);
598  onscreen_target.y2 = MIN (ceil (zoom_region->priv->exposed_bounds.y2
599  / zoom_region->yscale),
600  source_area->y2);
601 
602  return _rectangle_clip_to_bounds (area, &onscreen_target);
603 }
604 
605 static GdkRectangle
607  GdkRectangle area)
608 {
609  GdkRectangle pixmap_area = {0, 0, 0, 0};
610  if (zoom_region->priv && zoom_region->priv->pixmap)
611  {
612  gdk_drawable_get_size (zoom_region->priv->pixmap, &pixmap_area.width, &pixmap_area.height);
613  return _rectangle_clip_to_rectangle (area, pixmap_area);
614  }
615  else
616  return area;
617 }
618 
619 static GdkRectangle
621  GdkRectangle area)
622 {
623  GdkRectangle window_rect;
624 
625  /* we can just return ATM because _rectangle_clip_to_rectangle is unimplemented now */
626 
627  return area;
628 
629  if (gtk_widget_get_window (zoom_region->priv->w))
630  gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)),
631  &window_rect.x,
632  &window_rect.y);
633  else
634  {
635  window_rect.x = 0;
636  window_rect.y = 0;
637  }
638  return _rectangle_clip_to_rectangle (area, window_rect);
639 }
640 
641 static GdkRectangle
643  const GNOME_Magnifier_RectBounds *view_bounds)
644 {
645  GdkRectangle source_rect;
646  source_rect.x = floor ((view_bounds->x1 + zoom_region->priv->exposed_bounds.x1)
647  / zoom_region->xscale);
648  source_rect.y = floor ((view_bounds->y1 + zoom_region->priv->exposed_bounds.y1)
649  / zoom_region->yscale);
650  source_rect.width = ceil ((view_bounds->x2 - view_bounds->x1) / zoom_region->xscale) + 1;
651  source_rect.height = ceil ((view_bounds->y2 - view_bounds->y1) / zoom_region->yscale) + 1;
652  return source_rect;
653 }
654 
655 static GdkRectangle
657  const GdkRectangle source_rect)
658 {
659  GdkRectangle view_rect;
660  view_rect.x = source_rect.x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
661  view_rect.y = source_rect.y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
662  view_rect.width = source_rect.width * zoom_region->xscale;
663  view_rect.height = source_rect.height * zoom_region->yscale;
664  DEBUG_RECT ("source", source_rect);
665  DEBUG_RECT ("converted to view-rect", view_rect);
666  return view_rect;
667 }
668 
669 static GdkRectangle
671  const GdkRectangle view_rect)
672 {
673  GdkRectangle source_rect;
674  source_rect.x = floor ((view_rect.x + zoom_region->priv->exposed_bounds.x1)
675  / zoom_region->xscale);
676  source_rect.y = floor ((view_rect.y + zoom_region->priv->exposed_bounds.y1)
677  / zoom_region->yscale);
678  source_rect.width = ceil (view_rect.width / zoom_region->xscale) + 1;
679  source_rect.height = ceil (view_rect.height / zoom_region->yscale) + 1;
680  return source_rect;
681 }
682 
683 static GdkRectangle
685  const GNOME_Magnifier_RectBounds *bounds)
686 {
687  GdkRectangle rect;
688  rect.x = bounds->x1;
689  rect.y = bounds->y1;
690  rect.width = bounds->x2 - bounds->x1;
691  rect.height = bounds->y2 - bounds->y1;
692  return rect;
693 }
694 
697 static CORBA_boolean
699 {
700  gdouble x_old = zoom_region->xscale;
701  gdouble y_old = zoom_region->yscale;
702  long x_move, y_move;
703 
704  zoom_region->xscale = x;
705  zoom_region->yscale = y;
706 
707  if (zoom_region->priv->scaled_pixbuf)
708  g_object_unref (zoom_region->priv->scaled_pixbuf);
709  zoom_region->priv->scaled_pixbuf =
710  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);
711 
712  if (zoom_region->priv->pixmap)
713  g_object_unref (zoom_region->priv->pixmap);
714 
715  if (zoom_region_create_pixmap (zoom_region) ==
717  zoom_region->xscale = x_old;
718  zoom_region->yscale = y_old;
719  zoom_region_create_pixmap (zoom_region);
720  g_object_unref (zoom_region->priv->scaled_pixbuf);
721 
722  /* only create a scaled image big enough for the target
723  * display, for now */
724  zoom_region->priv->scaled_pixbuf = gdk_pixbuf_new (
725  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);
726 
727  return FALSE;
728  }
729 
730  zoom_region_get_move_x_y (zoom_region, &x_move, &y_move);
731  zoom_region->priv->exposed_bounds.x1 = x_move * zoom_region->xscale;
732  zoom_region->priv->exposed_bounds.y1 = y_move * zoom_region->yscale;
734  zoom_region_update_current (zoom_region);
735 
736  return TRUE;
737 }
738 
739 static void
741  const GdkRectangle update_rect)
742 {
743  GdkRectangle *rect =
744  g_new0 (GdkRectangle, 1);
745  *rect = update_rect;
746 
747 #ifdef ZOOM_REGION_DEBUG
748  g_assert (zoom_region->alive);
749 #endif
750  DEBUG_RECT ("queueing update", *rect);
751 
752  zoom_region->priv->q =
753  g_list_prepend (zoom_region->priv->q, rect);
754  if (zoom_region->priv && zoom_region->priv->update_handler_id == 0)
755  zoom_region->priv->update_handler_id =
756  g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
758  zoom_region,
759  NULL);
760 }
761 
762 static void
764 {
765 #ifdef ZOOM_REGION_DEBUG
766  g_assert (zoom_region->alive);
767 #endif
768  if (zoom_region->priv)
769  {
770  gboolean pixmap_valid = GDK_IS_DRAWABLE (zoom_region->priv->pixmap);
771  if (!pixmap_valid)
772  pixmap_valid = (zoom_region_create_pixmap (zoom_region) == ZOOM_REGION_ERROR_NONE);
773  if (pixmap_valid)
774  zoom_region_update (zoom_region,
776  zoom_region,
777  &zoom_region->viewport));
778  }
779 }
780 
781 static GdkRectangle
783 {
784  GdkRectangle rect = {0, 0, 0, 0};
785  Magnifier *magnifier = zoom_region->priv->parent;
786  GdkDrawable *cursor = NULL;
787  if (magnifier)
788  cursor = magnifier_get_cursor (magnifier);
789  if (cursor)
790  {
791  rect.x = zoom_region->priv->last_cursor_pos.x;
792  rect.y = zoom_region->priv->last_cursor_pos.y;
793  rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
794  rect.x -= magnifier->cursor_hotspot.x;
795  rect.y -= magnifier->cursor_hotspot.y;
796  gdk_drawable_get_size (cursor, &rect.width, &rect.height);
797  }
798  return rect;
799 }
800 
801 static void
803  GdkRectangle *clip_rect)
804 {
805  Magnifier *magnifier = zoom_region->priv->parent;
806  GdkRectangle vline_rect, hline_rect;
807  GdkPoint cursor_pos;
808 
809 #ifdef ZOOM_REGION_DEBUG
810  g_assert (zoom_region->alive);
811 #endif
812  if (!magnifier || magnifier->crosswire_size <= 0) return;
813 
814  cursor_pos = zoom_region->priv->last_drawn_crosswire_pos;
815  vline_rect.x = cursor_pos.x - magnifier->crosswire_size/2;
816  vline_rect.y = clip_rect ? clip_rect->y : 0;
817  vline_rect.width = MAX (magnifier->crosswire_size, 1);
818  vline_rect.height = clip_rect ? clip_rect->height : 4096;
819  hline_rect.x = clip_rect ? clip_rect->x : 0;
820  hline_rect.y = cursor_pos.y - magnifier->crosswire_size/2;
821  hline_rect.width = clip_rect ? clip_rect->width : 4096;
822  hline_rect.height = MAX (magnifier->crosswire_size, 1);
823 
824  zoom_region_paint_pixmap (zoom_region, &vline_rect);
825  zoom_region_paint_pixmap (zoom_region, &hline_rect);
826 }
827 
828 static void
830 {
831  Magnifier *magnifier = zoom_region->priv->parent;
832  static GdkColormap *cmap;
833  static GdkColor last_color;
834  static gboolean last_color_init = FALSE;
835  GdkGCValues values;
836  GdkRectangle rect;
837  GdkDrawable *cursor;
838  GdkColor color = {0, 0, 0, 0};
839  int x_start = 0, y_start = 0, x_end = 4096, y_end = 4096;
840  int x_left_clip = 0, x_right_clip = 0, y_top_clip = 0, y_bottom_clip = 0;
841  int csize = 0;
842 
843 #ifdef ZOOM_REGION_DEBUG
844  g_assert (zoom_region->alive);
845 #endif
846  if (!(magnifier &&
847  gtk_widget_get_window (zoom_region->priv->w) &&
848  GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)) &&
849  magnifier->crosswire_size > 0)) return;
850 
851  if (zoom_region->priv->crosswire_gc == NULL)
852  {
853  zoom_region->priv->crosswire_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w));
854  cmap = gdk_gc_get_colormap(zoom_region->priv->crosswire_gc);
855  last_color_init = FALSE;
856  }
857 
858  if (magnifier->crosswire_color == 0)
859  {
860  color.red = 0xFFFF;
861  color.blue = 0xFFFF;
862  color.green = 0xFFFF;
863  values.function = GDK_INVERT;
864  }
865  else
866  {
867  color.red = (magnifier->crosswire_color & 0xFF0000) >> 8;
868  color.green = (magnifier->crosswire_color & 0xFF00);
869  color.blue = (magnifier->crosswire_color & 0xFF) << 8;
870  values.function = GDK_COPY;
871  }
872 
873  values.foreground = color;
874 
875  /* Only reset colors if they have changed */
876  if (!last_color_init || color.red != last_color.red ||
877  color.blue != last_color.blue || color.green != last_color.green)
878  {
879  if (cmap)
880  {
881  gdk_rgb_find_color (cmap, &(values.foreground));
882  gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
883  }
884  else
885  {
886  gdk_gc_set_values(zoom_region->priv->crosswire_gc, &values, GDK_GC_FUNCTION);
887  }
888 
889  last_color.red = color.red;
890  last_color.blue = color.blue;
891  last_color.green = color.green;
892  last_color_init = TRUE;
893  }
894 
895  rect.x = zoom_region->priv->last_cursor_pos.x;
896  rect.y = zoom_region->priv->last_cursor_pos.y;
897  rect.width = 0;
898  rect.height = 0;
899  rect = zoom_region_view_rect_from_source_rect (zoom_region, rect);
900  if (clip_rect) gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, clip_rect);
901  else gdk_gc_set_clip_rectangle (zoom_region->priv->crosswire_gc, NULL);
902 
903  if ((cursor = magnifier_get_cursor (magnifier))) {
904  gdk_drawable_get_size (cursor, &csize, &csize);
905  }
906 
907  if (magnifier->crosswire_length) {
908  if (magnifier->crosswire_clip) {
909  x_start = rect.x - magnifier->cursor_hotspot.x -
910  magnifier->crosswire_length;
911  x_end = rect.x +
912  (csize - magnifier->cursor_hotspot.x) +
913  magnifier->crosswire_length;
914  y_start = rect.y - magnifier->cursor_hotspot.y -
915  magnifier->crosswire_length;
916  y_end = rect.y +
917  (csize - magnifier->cursor_hotspot.y) +
918  magnifier->crosswire_length;
919  } else {
920  x_start = rect.x - magnifier->crosswire_length;
921  x_end = rect.x + magnifier->crosswire_length;
922  y_start = rect.y - magnifier->crosswire_length;
923  y_end = rect.y + magnifier->crosswire_length;
924  }
925  }
926 
927  if (magnifier->crosswire_clip)
928  {
929  y_top_clip = rect.y - magnifier->cursor_hotspot.y -
930  magnifier->crosswire_size;
931  y_bottom_clip = rect.y +
932  (csize - magnifier->cursor_hotspot.y) +
933  magnifier->crosswire_size;
934  x_left_clip = rect.x - magnifier->cursor_hotspot.x -
935  magnifier->crosswire_size;
936  x_right_clip = rect.x +
937  (csize - magnifier->cursor_hotspot.x) +
938  magnifier->crosswire_size;
939 
940  }
941  if (magnifier->crosswire_size == 1) {
942  if (magnifier->crosswire_clip) {
943  gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w),
944  zoom_region->priv->crosswire_gc,
945  rect.x, y_top_clip, rect.x,
946  y_bottom_clip);
947  gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w),
948  zoom_region->priv->crosswire_gc,
949  x_left_clip, rect.y, x_right_clip,
950  rect.y);
951  }
952  gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w),
953  zoom_region->priv->crosswire_gc,
954  rect.x, y_start, rect.x, y_end);
955  gdk_draw_line (gtk_widget_get_window (zoom_region->priv->w),
956  zoom_region->priv->crosswire_gc,
957  x_start, rect.y, x_end, rect.y);
958  }
959  else {
960  if (magnifier->crosswire_clip ) {
961  gdk_draw_rectangle (
962  gtk_widget_get_window (zoom_region->priv->w),
963  zoom_region->priv->crosswire_gc, TRUE,
964  rect.x - magnifier->crosswire_size / 2,
965  y_top_clip, magnifier->crosswire_size,
966  y_bottom_clip - y_top_clip);
967  gdk_draw_rectangle (
968  gtk_widget_get_window (zoom_region->priv->w),
969  zoom_region->priv->crosswire_gc, TRUE,
970  x_left_clip,
971  rect.y - magnifier->crosswire_size / 2,
972  x_right_clip - x_left_clip,
973  magnifier->crosswire_size);
974  }
975  gdk_draw_rectangle (
976  gtk_widget_get_window (zoom_region->priv->w),
977  zoom_region->priv->crosswire_gc, TRUE,
978  rect.x - magnifier->crosswire_size / 2, y_start,
979  magnifier->crosswire_size, y_end - y_start);
980  gdk_draw_rectangle (
981  gtk_widget_get_window (zoom_region->priv->w),
982  zoom_region->priv->crosswire_gc, TRUE,
983  x_start, rect.y - magnifier->crosswire_size / 2,
984  x_end - x_start, magnifier->crosswire_size);
985  }
986 }
987 
988 static void
990 {
991 #ifdef ZOOM_REGION_DEBUG
992  g_assert (zoom_region->alive);
993 #endif
994  zoom_region_paint_pixmap (zoom_region,
995  &zoom_region->priv->cursor_backing_rect);
996 }
997 
998 
999 static void
1001  GdkRectangle *clip_rect)
1002 {
1003  GdkGCValues values;
1004  GdkRectangle rect, intersct;
1005  GdkRectangle fullscreen;
1006  Magnifier *magnifier = zoom_region->priv->parent;
1007  rect = zoom_region_cursor_rect (zoom_region);
1008 #ifdef ZOOM_REGION_DEBUG
1009  g_assert (zoom_region->alive);
1010 #endif
1011  if (!zoom_region->draw_cursor)
1012  return;
1013 
1014  if (clip_rect == NULL)
1015  {
1016  fullscreen = zoom_region_rect_from_bounds (zoom_region,
1017  &zoom_region->viewport);
1018  clip_rect = &fullscreen;
1019  }
1020  /* save the unclipped cursor pos for 'undrawing' the crosswire, the clipped one is no good */
1021  zoom_region->priv->last_drawn_crosswire_pos.x = rect.x + magnifier->cursor_hotspot.x;
1022  zoom_region->priv->last_drawn_crosswire_pos.y = rect.y + magnifier->cursor_hotspot.y;
1023 
1024  if (gdk_rectangle_intersect (clip_rect, &rect, &intersct))
1025  {
1026  int width = 0, height = 0;
1027 
1028  GdkDrawable *cursor = magnifier_get_cursor (magnifier);
1029  if (!cursor)
1030  return;
1031  else if (!GDK_IS_DRAWABLE (cursor)) g_message ("cursor isn't DRAWABLE!");
1032  zoom_region->priv->cursor_backing_rect = rect;
1033  if (zoom_region->priv->cursor_backing_pixels) {
1034  gdk_drawable_get_size (zoom_region->priv->cursor_backing_pixels,
1035  &width, &height);
1036  }
1037  if (rect.width != width || rect.height != height)
1038  {
1039  if (zoom_region->priv->cursor_backing_pixels) {
1040  g_object_unref (zoom_region->priv->cursor_backing_pixels);
1041  }
1042  zoom_region->priv->cursor_backing_pixels =
1043  gdk_pixmap_new (gtk_widget_get_window (zoom_region->priv->w),
1044  rect.width,
1045  rect.height,
1046  -1);
1047  }
1048  if (gtk_widget_get_window (zoom_region->priv->w) != NULL)
1049  {
1050  if (zoom_region->priv->default_gc == NULL)
1051  zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w));
1052  gdk_draw_drawable (zoom_region->priv->cursor_backing_pixels,
1053  zoom_region->priv->default_gc,
1054  gtk_widget_get_window (zoom_region->priv->w),
1055  rect.x,
1056  rect.y,
1057  0, 0,
1058  rect.width,
1059  rect.height);
1060  }
1061  DEBUG_RECT ("painting", rect);
1062  if (cursor && zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
1063  {
1064  if (zoom_region->priv->paint_cursor_gc == NULL)
1065  zoom_region->priv->paint_cursor_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w));
1066 
1067  gdk_gc_set_clip_rectangle (zoom_region->priv->paint_cursor_gc, clip_rect);
1068  values.clip_x_origin = rect.x;
1069  values.clip_y_origin = rect.y;
1070  values.clip_mask = magnifier->priv->cursor_mask;
1071  gdk_gc_set_values(zoom_region->priv->paint_cursor_gc, &values, GDK_GC_CLIP_X_ORIGIN |
1072  GDK_GC_CLIP_Y_ORIGIN | GDK_GC_CLIP_MASK);
1073 
1074  gdk_draw_rectangle (gtk_widget_get_window (zoom_region->priv->w),
1075  zoom_region->priv->paint_cursor_gc,
1076  TRUE,
1077  rect.x, rect.y, rect.width, rect.height);
1078 
1079  gdk_draw_drawable (gtk_widget_get_window (zoom_region->priv->w),
1080  zoom_region->priv->paint_cursor_gc,
1081  cursor,
1082  0, 0,
1083  rect.x,
1084  rect.y,
1085  rect.width,
1086  rect.height);
1087  }
1088  }
1089 }
1090 
1095 static void
1097 {
1098  /* TODO: lock the queue ? */
1099  GList *q;
1100  int lookahead_n = 4; /* 'distance' to look ahead in queue */
1101  int max_qlen = 50;
1102 
1103  if (zoom_region->priv && zoom_region->priv->q && g_list_length (zoom_region->priv->q) > max_qlen)
1104  {
1105  g_list_free (zoom_region->priv->q);
1106  zoom_region->priv->q = NULL; /* just discard and update everything */
1107  /* CAUTION: this can be an expensive operation! */
1109  (zoom_region, &zoom_region->priv->source_area));
1110  }
1111  else
1112 
1113  if (zoom_region->priv && zoom_region->priv->q &&
1114  (g_list_length (zoom_region->priv->q) > 1) && can_coalesce)
1115  {
1116  q = g_list_reverse (g_list_copy (zoom_region->priv->q));
1117  if (q)
1118  {
1119  GList *coalesce_copy;
1120  if (zoom_region->coalesce_func)
1121  {
1122  GList *new;
1123  coalesce_copy = (*zoom_region->coalesce_func) (q, lookahead_n);
1124  new = g_list_reverse (coalesce_copy);
1125  g_list_free (zoom_region->priv->q);
1126  zoom_region->priv->q = new;
1127  }
1128  g_list_free (q);
1129  }
1130  }
1131 }
1132 
1133 
1134 static void
1136 {
1137  GdkColor color;
1138 
1139 #ifdef ZOOM_REGION_DEBUG
1140  g_assert (zoom_region->alive);
1141 #endif
1142  if ((zoom_region->border_size_left > 0 ||
1143  zoom_region->border_size_top > 0 ||
1144  zoom_region->border_size_right > 0 ||
1145  zoom_region->border_size_bottom > 0) &&
1146  (gtk_widget_get_window (zoom_region->priv->border))) {
1147  color.red = (((zoom_region->border_color & 0xFF0000) >> 16) *
1148  65535) / 255;
1149  color.green = (((zoom_region->border_color & 0xFF00) >> 8) *
1150  65535) / 255;
1151  color.blue = ((zoom_region->border_color & 0xFF) * 65535) /
1152  255;
1153 
1154 #ifdef DEBUG_BORDER
1155  fprintf (stderr, "border color triple RGB=%d|%d|%d\n",
1156  color.red, color.green, color.blue);
1157 #endif
1158 
1159  gtk_widget_modify_bg (zoom_region->priv->border,
1160  GTK_STATE_NORMAL, &color);
1161  }
1162 }
1163 
1164 static void
1166  GdkRectangle *area)
1167 {
1168 #ifdef ZOOM_REGION_DEBUG
1169  g_assert (zoom_region->alive);
1170 #endif
1171  g_assert (zoom_region->priv);
1172  g_assert (zoom_region->priv->w);
1173 
1174  if (!GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w))) return;
1175  if (zoom_region->priv->default_gc == NULL)
1176  zoom_region->priv->default_gc = gdk_gc_new (gtk_widget_get_window (zoom_region->priv->w));
1177 
1178  if (zoom_region->priv->pixmap && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
1179  {
1180  gdk_draw_drawable (gtk_widget_get_window (zoom_region->priv->w),
1181  zoom_region->priv->default_gc,
1182  zoom_region->priv->pixmap,
1183  area->x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
1184  area->y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
1185  area->x,
1186  area->y,
1187  area->width,
1188  area->height);
1189  }
1190 }
1191 
1195 static void
1197  GdkRectangle *area)
1198 {
1199  GdkRectangle paint_area;
1200 
1201 #ifdef ZOOM_REGION_DEBUG
1202  g_assert (zoom_region->alive);
1203 #endif
1204  DEBUG_RECT ("painting (clipped)", *area);
1205  paint_area = zoom_region_clip_to_window (zoom_region, *area);
1206  zoom_region_paint_pixmap (zoom_region, &paint_area);
1207  zoom_region_paint_cursor (zoom_region, &paint_area);
1208  zoom_region_paint_crosswire_cursor (zoom_region, &paint_area);
1209 }
1210 
1213 {
1214 #ifdef ZOOM_REGION_DEBUG
1215  g_assert (zoom_region->alive);
1216 #endif
1217  if (zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
1218  {
1219  long width = (zoom_region->priv->source_area.x2 -
1220  zoom_region->priv->source_area.x1) * zoom_region->xscale;
1221  long height = (zoom_region->priv->source_area.y2 -
1222  zoom_region->priv->source_area.y1) * zoom_region->yscale;
1223  zoom_region->priv->pixmap =
1224  gdk_pixmap_new (
1225  gtk_widget_get_window (zoom_region->priv->w),
1226  width,
1227  height,
1228  gdk_drawable_get_depth (
1229  gtk_widget_get_window (zoom_region->priv->w)));
1230 
1231  if (gmag_gs_error_check ()) {
1232  zoom_region->priv->pixmap = NULL;
1234  }
1235 
1237  (zoom_region, &zoom_region->viewport));
1239  (zoom_region, &((Magnifier*)zoom_region->priv->parent)->source_bounds));
1240 
1241  return ZOOM_REGION_ERROR_NONE;
1242  }
1243 
1245 }
1246 
1247 static void
1249  GdkEventExpose *event,
1250  gpointer data)
1251 {
1252  ZoomRegion *zoom_region = data;
1253  DEBUG_RECT ("expose", event->area);
1254 
1255 #ifdef ZOOM_REGION_DEBUG
1256  g_assert (zoom_region->alive);
1257 #endif
1258  if (zoom_region->priv->pixmap == NULL)
1259  {
1261  /* TODO: scale down if this fails here */
1262  while ((ret = zoom_region_create_pixmap (zoom_region)) ==
1264  zoom_region->xscale -= 1.0;
1265  zoom_region->yscale -= 1.0;
1266  zoom_region->priv->pixmap = NULL;
1267  g_warning ("Scale factor too big to fit in memory; shrinking.");
1268  }
1270  g_warning ("create-pixmap: no target drawable");
1271  else
1272  zoom_region_update_pixmap (zoom_region, event->area,
1273  NULL);
1274  }
1275  zoom_region_paint (zoom_region, &event->area);
1276 }
1277 
1278 static void
1280  GdkRectangle *clip_rect)
1281 {
1282 #ifdef ZOOM_REGION_DEBUG
1283  g_assert (zoom_region->alive);
1284 #endif
1285  zoom_region_unpaint_crosswire_cursor (zoom_region, clip_rect);
1286  zoom_region_unpaint_cursor (zoom_region, clip_rect);
1287  zoom_region->priv->cursor_backing_rect.x += dx;
1288  zoom_region->priv->cursor_backing_rect.y += dy;
1289  zoom_region->priv->last_drawn_crosswire_pos.x += dx;
1290  zoom_region->priv->last_drawn_crosswire_pos.y += dy;
1291  zoom_region_paint_cursor (zoom_region, clip_rect);
1292  zoom_region_paint_crosswire_cursor (zoom_region, clip_rect);
1293  if (GTK_IS_WIDGET (zoom_region->priv->w) &&
1294  GDK_IS_WINDOW (gtk_widget_get_window (zoom_region->priv->w)))
1295  gdk_display_sync (gdk_drawable_get_display (
1296  gtk_widget_get_window (zoom_region->priv->w)));
1297 }
1298 
1299 static gboolean
1301  int dx, int dy,
1302  GdkRectangle *scroll_rect,
1303  GdkRectangle *expose_rect_h,
1304  GdkRectangle *expose_rect_v)
1305 {
1306  GdkWindow *window = NULL;
1307  GdkRectangle rect = {0, 0, 0, 0};
1308  gboolean retval = TRUE;
1309 
1310 #ifdef ZOOM_REGION_DEBUG
1311  g_assert (zoom_region->alive);
1312 #endif
1313  rect.x = 0;
1314  rect.y = 0;
1315  if (zoom_region && zoom_region->priv->w &&
1316  gtk_widget_get_window (zoom_region->priv->w))
1317  window = gtk_widget_get_window (zoom_region->priv->w);
1318  else
1319  retval = FALSE;
1320  if (!window)
1321  retval = FALSE;
1322 
1323  if (window != NULL)
1324  gdk_drawable_get_size (GDK_DRAWABLE (window),
1325  &rect.width,
1326  &rect.height);
1327 
1328  if ((ABS (dx) >= rect.width) || (ABS (dy) >= rect.height)) {
1329  *scroll_rect = rect;
1330  DBG(fprintf (stderr, "deltas too big to scroll\n"));
1331  retval = FALSE;
1332  }
1333  else {
1334  scroll_rect->x = MAX (0, dx);
1335  scroll_rect->y = MAX (0, dy);
1336  scroll_rect->width = MIN (rect.width + dx, rect.width - dx);
1337  scroll_rect->height = MIN (rect.height + dy, rect.height - dy);
1338  }
1339 
1340  expose_rect_h->x = 0;
1341  expose_rect_h->y = (scroll_rect->y == 0) ? scroll_rect->height : 0;
1342  expose_rect_h->width = rect.width;
1343  expose_rect_h->height = rect.height - scroll_rect->height;
1344 
1345  expose_rect_v->x = (scroll_rect->x == 0) ? scroll_rect->width : 0;
1346  expose_rect_v->y = scroll_rect->y;
1347  expose_rect_v->width = rect.width - scroll_rect->width;
1348  expose_rect_v->height = scroll_rect->height;
1349 
1350  return retval;
1351 }
1352 
1353 static void
1355  GdkRectangle *scroll_rect,
1356  GdkRectangle *expose_rect_h,
1357  GdkRectangle *expose_rect_v)
1358 {
1359  GdkWindow *window;
1360 
1361 #ifdef ZOOM_REGION_DEBUG
1362  g_assert (zoom_region->alive);
1363 #endif
1364  if (zoom_region->priv->w && gtk_widget_get_window (zoom_region->priv->w))
1365  window = gtk_widget_get_window (zoom_region->priv->w);
1366  else {
1367  processing_updates = FALSE;
1368  return;
1369  }
1370  zoom_region_unpaint_crosswire_cursor (zoom_region, scroll_rect);
1371  zoom_region_unpaint_cursor (zoom_region, scroll_rect);
1372  gdk_window_scroll (window, dx, dy);
1373  zoom_region_paint_cursor (zoom_region, scroll_rect);
1374  zoom_region_paint_crosswire_cursor (zoom_region, scroll_rect);
1375  gdk_window_process_updates (window, FALSE);
1376  /* sync reduces cursor flicker, but slows things down */
1377  if (zoom_region->smooth_scroll_policy >
1379  gdk_display_sync (gdk_drawable_get_display (window));
1380 }
1381 
1382 static void
1384  GdkRectangle *scroll_rect,
1385  GdkRectangle *expose_rect_h,
1386  GdkRectangle *expose_rect_v)
1387 {
1388  GdkWindow *window = NULL;
1389  GdkRectangle window_rect;
1390 
1391 #ifdef ZOOM_REGION_DEBUG
1392  g_assert (zoom_region->alive);
1393 #endif
1394  if (zoom_region->priv->w && GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
1395  window = gtk_widget_get_window (zoom_region->priv->w);
1396  else
1397  return;
1398  window_rect.x = 0;
1399  window_rect.y = 0;
1400  gdk_drawable_get_size (GDK_DRAWABLE (window),
1401  &window_rect.width, &window_rect.height);
1402  gdk_window_begin_paint_rect (window, &window_rect);
1403  gdk_window_invalidate_rect (window, &window_rect, FALSE);
1404  gdk_window_process_updates (window, FALSE);
1405  gdk_window_end_paint (window);
1406 }
1407 
1408 static void
1410 {
1411  GdkRectangle scroll_rect, expose_rect_h, expose_rect_v;
1412  gboolean can_scroll;
1413 
1414 #ifdef ZOOM_REGION_DEBUG
1415  g_assert (zoom_region->alive);
1416 #endif
1417  if (timing_test) {
1419  mag_timing.dx = abs(dx);
1420  mag_timing.dy = abs(dy);
1423  if (zoom_region->timing_output) {
1424  fprintf(stderr, " Panning Increment (x) = %d (avg. %f) lines/frame\n",
1426  fprintf(stderr, " Panning Increment (y) = %d (avg. %f) lines/frame\n",
1428  }
1429  }
1430 
1431  /*
1432  * Currently processing a screen update. This flag used to disallow
1433  * other updates to occur until this one finishes
1434  */
1435  processing_updates = TRUE;
1436 
1437  can_scroll = zoom_region_calculate_scroll_rects (zoom_region, dx, dy,
1438  &scroll_rect,
1439  &expose_rect_h,
1440  &expose_rect_v);
1441 
1442  if (can_scroll) {
1443  zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_h), NULL);
1444  zoom_region_update_pixmap (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, expose_rect_v), NULL);
1445 
1447  zoom_region_scroll_smooth (zoom_region, dx, dy,
1448  &scroll_rect,
1449  &expose_rect_h,
1450  &expose_rect_v);
1451  } else {
1452  zoom_region_scroll_fast (zoom_region, dx, dy,
1453  &scroll_rect,
1454  &expose_rect_h,
1455  &expose_rect_v);
1456  }
1457  } else {
1458  zoom_region_queue_update (zoom_region, zoom_region_source_rect_from_view_rect (zoom_region, scroll_rect));
1459  }
1460 }
1461 
1462 static void
1464 {
1465  zoom_region->priv->exposed_bounds.x2 = zoom_region->priv->exposed_bounds.x1
1466  + (zoom_region->viewport.x2 - zoom_region->viewport.x1);
1467  zoom_region->priv->exposed_bounds.y2 = zoom_region->priv->exposed_bounds.y1
1468  + (zoom_region->viewport.y2 - zoom_region->viewport.y1);
1469 }
1470 
1471 static void
1473 {
1474  if (zoom_region->priv)
1475  {
1476  zoom_region->priv->last_cursor_pos.x = x;
1477  zoom_region->priv->last_cursor_pos.y = y;
1478  }
1479 }
1480 
1481 static gboolean
1483 {
1484  Magnifier *magnifier;
1485  gint mouse_x_return, mouse_y_return;
1486  guint mask_return;
1487 
1488 #ifdef ZOOM_REGION_DEBUG
1489  g_assert (zoom_region->alive);
1490 #endif
1491  if (!zoom_region->priv || !zoom_region->priv->parent
1492  || !zoom_region->poll_mouse)
1493  return FALSE;
1494 
1495  magnifier = zoom_region->priv->parent;
1496 
1497  /* TODO: there's really no reason we should be using magnifier->priv->root here */
1498  if (magnifier && magnifier->priv && magnifier_get_root (magnifier))
1499  {
1500  gdk_window_get_pointer (
1501  magnifier_get_root (magnifier),
1502  &mouse_x_return,
1503  &mouse_y_return,
1504  &mask_return);
1505 
1506  if (zoom_region->priv->last_cursor_pos.x != mouse_x_return
1507  || zoom_region->priv->last_cursor_pos.y != mouse_y_return)
1508  {
1509  zoom_region_set_cursor_pos (zoom_region,
1510  mouse_x_return,
1511  mouse_y_return);
1512  if (draw_cursor)
1513  zoom_region_update_cursor (zoom_region, 0, 0,
1514  NULL);
1515 
1516  return TRUE;
1517  }
1518  }
1519  return FALSE;
1520 }
1521 
1522 static int
1524 {
1525  ZoomRegion *zoom_region = (ZoomRegion *) data;
1526 
1527  if (zoom_region_update_pointer (zoom_region, TRUE))
1528  return TRUE;
1529  else {
1530  if (zoom_region->priv)
1531  zoom_region->priv->update_pointer_id =
1532  g_timeout_add_full (G_PRIORITY_DEFAULT,
1533  100,
1535  zoom_region,
1536  NULL);
1537  return FALSE;
1538  }
1539 }
1540 
1541 static int
1543 {
1544  ZoomRegion *zoom_region = data;
1545 
1546  if (zoom_region->priv && zoom_region_update_pointer (zoom_region,
1547  TRUE)) {
1548  zoom_region->priv->update_pointer_id =
1549  g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1551  data,
1552  NULL);
1553  return FALSE;
1554  } else
1555  return TRUE;
1556 }
1557 
1558 static void
1560  const long x, const long y)
1561 {
1562  long dx = x * zoom_region->xscale - zoom_region->priv->exposed_bounds.x1;
1563  long dy = y * zoom_region->yscale - zoom_region->priv->exposed_bounds.y1;
1564 #ifdef ZOOM_REGION_DEBUG
1565  g_assert (zoom_region->alive);
1566 #endif
1567 /* fprintf (stderr, "moveto %ld %ld\n", x, y); */
1568 
1569  mag_timing.dx = 0;
1570  mag_timing.dy = 0;
1571 
1572  if ((dx != 0) || (dy != 0)) {
1573  zoom_region_update_pointer (zoom_region, FALSE);
1574  zoom_region->priv->exposed_bounds.x1 = x * zoom_region->xscale;
1575  zoom_region->priv->exposed_bounds.y1 = y * zoom_region->yscale;
1577  zoom_region_scroll (zoom_region,
1578  -dx, -dy);
1579  }
1580 }
1581 
1582 /*
1583  * Process that must be made in-line in the current pixbuf.
1584  */
1585 static void
1587 {
1588  int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1589  int i, j, t;
1590  int w = gdk_pixbuf_get_width (pixbuf);
1591  int h = gdk_pixbuf_get_height (pixbuf);
1592  int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
1593  guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
1594  guchar *pixels_row;
1595 
1596  gboolean manipulate_contrast = FALSE;
1597  gboolean manipulate_brightness = FALSE;
1598  gboolean color_blind_filter = FALSE;
1599 
1600  if (zoom_region->contrast_r != 0 || zoom_region->contrast_g != 0 ||
1601  zoom_region->contrast_b != 0) {
1602  manipulate_contrast = TRUE;
1603  }
1604 
1605  if (zoom_region->bright_r != 0 || zoom_region->bright_g != 0 ||
1606  zoom_region->bright_b != 0) {
1607  manipulate_brightness = TRUE;
1608  }
1609 
1610 #ifdef HAVE_COLORBLIND
1611  if (zoom_region->color_blind_filter !=
1613  color_blind_filter = TRUE;
1614  }
1615 #endif /* HAVE_COLORBLIND */
1616 
1617  if (!manipulate_contrast && !zoom_region->invert &&
1618  !manipulate_brightness && !color_blind_filter)
1619  return;
1620 
1621 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
1622 #define CLAMP_LOW_MID(v) (t = (v), CLAMP (t, 0, 127))
1623 #define CLAMP_MID_HIGH(v) (t = (v), CLAMP (t, 127, 255))
1624 
1625  for (j = 0; j < h; ++j) {
1626  pixels_row = pixels;
1627  for (i = 0; i < w; ++i) {
1628  if (manipulate_contrast) {
1629  /* Set the RED contrast */
1630  if (pixels_row[0] <= 127)
1631  pixels_row[0] = CLAMP_LOW_MID (pixels_row[0] - zoom_region->contrast_r * 127);
1632  else
1633  pixels_row[0] = CLAMP_MID_HIGH (pixels_row[0] + zoom_region->contrast_r * 127);
1634 
1635  /* Set the GREEN contrast */
1636  if (pixels_row[1] <= 127)
1637  pixels_row[1] = CLAMP_LOW_MID (pixels_row[1] - zoom_region->contrast_g * 127);
1638  else
1639  pixels_row[1] = CLAMP_MID_HIGH (pixels_row[1] + zoom_region->contrast_g * 127);
1640 
1641  /* Set the BLUE contrast */
1642  if (pixels_row[2] <= 127)
1643  pixels_row[2] = CLAMP_LOW_MID (pixels_row[2] - zoom_region->contrast_b * 127);
1644  else
1645  pixels_row[2] = CLAMP_MID_HIGH (pixels_row[2] + zoom_region->contrast_b * 127);
1646  }
1647 
1648  if (manipulate_brightness) {
1649  /* Set the RED brightness */
1650  pixels_row[0] = CLAMP_UCHAR (pixels_row[0] + zoom_region->bright_r * 255);
1651 
1652  /* Set the GREEN brightness */
1653  pixels_row[1] = CLAMP_UCHAR (pixels_row[1] + zoom_region->bright_g * 255);
1654 
1655  /* Set the BLUE brightness */
1656  pixels_row[2] = CLAMP_UCHAR (pixels_row[2] + zoom_region->bright_b * 255);
1657  }
1658 
1659  if (zoom_region->invert) {
1660  pixels_row[0] = ~(pixels_row[0]);
1661  pixels_row[1] = ~(pixels_row[1]);
1662  pixels_row[2] = ~(pixels_row[2]);
1663  }
1664 
1665 #ifdef HAVE_COLORBLIND
1666  if (color_blind_filter) {
1667  color->red = pixels_row[0];
1668  color->green = pixels_row[1];
1669  color->blue = pixels_row[2];
1670  if (colorblind_filter (cbr, color)) {
1671  pixels_row[0] = color->red;
1672  pixels_row[1] = color->green;
1673  pixels_row[2] = color->blue;
1674  }
1675  }
1676 #endif /* HAVE_COLORBLIND */
1677 
1678  pixels_row += n_channels;
1679  }
1680  pixels += rowstride;
1681  }
1682 
1683 }
1684 
1685 static void
1687  GdkPixbuf *subimage,
1688  GdkPixbuf *scaled_image)
1689 {
1690  /* nothing yet */
1700 }
1701 
1702 static GdkPixbuf *
1704  const GdkRectangle bounds)
1705 {
1706  int i, j, width, height;
1707  Magnifier *magnifier = zoom_region->priv->parent;
1708  GdkPixbuf *subimage = NULL;
1709 
1710 #ifdef ZOOM_REGION_DEBUG
1711  g_assert (zoom_region->alive);
1712 #endif
1713  width = gdk_screen_get_width (
1714  gdk_display_get_screen (magnifier->source_display,
1715  magnifier->source_screen_num));
1716  height = gdk_screen_get_height (
1717  gdk_display_get_screen (magnifier->source_display,
1718  magnifier->source_screen_num));
1719 
1720  if ((bounds.width <= 0) || (bounds.height <= 0))
1721  {
1722  return NULL;
1723  }
1724 
1725  if (!zoom_region->priv->source_drawable)
1726  {
1727  /* TESTING ONLY */
1728  if (zoom_region->priv->test) {
1729  GdkImage *test_image = NULL;
1730 
1731  test_image = gdk_image_new (GDK_IMAGE_FASTEST,
1732  gdk_visual_get_system (),
1733  width,
1734  height);
1735 
1736  for (i = 0; i < width; ++i)
1737  for (j = 0; j < height; ++j)
1738  gdk_image_put_pixel (test_image, i, j, i*j);
1739 
1740  zoom_region->priv->source_drawable = gdk_pixmap_new (gtk_widget_get_window (zoom_region->priv->w), width, height, -1);
1741 
1742  if (zoom_region->priv->default_gc == NULL)
1743  zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w));
1744 
1745  gdk_draw_image (zoom_region->priv->source_drawable,
1746  zoom_region->priv->default_gc,
1747  test_image,
1748  0, 0,
1749  0, 0,
1750  width, height);
1751  }
1752  else
1753  {
1754  if (magnifier->priv->source_drawable) {
1755  zoom_region->priv->source_drawable =
1756  magnifier->priv->source_drawable;
1757  } else
1758  zoom_region->priv->source_drawable = gdk_screen_get_root_window (gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num));
1759  }
1760  if (zoom_region->cache_source)
1761  {
1762  zoom_region->priv->source_pixbuf_cache =
1763  gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1764  FALSE,
1765  8, /* FIXME: not always 8? */
1766  width, height);
1767  }
1768  }
1769  DEBUG_RECT ("getting subimage from ", bounds);
1770 
1771  subimage = gdk_pixbuf_get_from_drawable (NULL, zoom_region->priv->source_drawable,
1772  gdk_colormap_get_system (),
1773  bounds.x,
1774  bounds.y,
1775  0,
1776  0,
1777  bounds.width,
1778  bounds.height);
1779 
1780  /* TODO: blank the region overlapped by the target display if source == target */
1781 
1782  if (!subimage)
1783  _debug_announce_rect ("update of invalid subregion!\n", bounds);
1784 
1785  /* if this zoom-region keeps a cache, do a diff to see if update is necessary */
1786  if (zoom_region->cache_source && subimage) {
1787  GdkPixbuf *cache_subpixbuf =
1788  gdk_pixbuf_new_subpixbuf (zoom_region->priv->source_pixbuf_cache,
1789  bounds.x, bounds.y, bounds.width, bounds.height);
1790  if (_diff_pixbufs (subimage, cache_subpixbuf)) {
1791  gdk_pixbuf_copy_area (subimage, 0, 0, bounds.width, bounds.height,
1792  zoom_region->priv->source_pixbuf_cache,
1793  bounds.x, bounds.y);
1794  }
1795  else
1796  {
1797  if (subimage)
1798  g_object_unref (subimage);
1799  subimage = NULL;
1800  }
1801  g_object_unref (cache_subpixbuf);
1802  }
1803  return subimage;
1804 }
1805 
1806 static GdkRectangle
1808  const GdkRectangle update_rect,
1809  GdkRectangle *p_rect)
1810 {
1811  GdkPixbuf *subimage;
1812  GdkRectangle source_rect;
1813 
1814 #ifdef ZOOM_REGION_DEBUG
1815  g_assert (zoom_region->alive);
1816 #endif
1817  DEBUG_RECT ("unclipped update rect", update_rect);
1818  source_rect = zoom_region_clip_to_source (zoom_region, update_rect);
1819  DEBUG_RECT ("clipped to source", source_rect);
1820  source_rect = zoom_region_clip_to_exposed_target (zoom_region, source_rect);
1821  DEBUG_RECT ("update rect clipped to exposed target", source_rect);
1822 
1823  subimage = zoom_region_get_source_subwindow (zoom_region, source_rect);
1824 
1825  if (subimage)
1826  {
1827  GdkRectangle paint_rect;
1828  g_timer_start (mag_timing.scale);
1829  DEBUG_RECT ("source rect", source_rect);
1830  paint_rect = zoom_region_view_rect_from_source_rect (zoom_region, source_rect);
1831  if (p_rect) {
1832  *p_rect = paint_rect;
1833  }
1834  /* paint_rect = zoom_region_clip_to_scaled_pixmap (zoom_region, paint_rect); */
1835  DEBUG_RECT ("paint rect", paint_rect);
1836 
1837  zoom_region_process_pixbuf (zoom_region, subimage);
1838 
1843  gdk_pixbuf_scale (subimage,
1844  zoom_region->priv->scaled_pixbuf,
1845  0,
1846  0,
1847  paint_rect.width,
1848  paint_rect.height,
1849  0,
1850  0,
1851  zoom_region->xscale,
1852  zoom_region->yscale,
1853  zoom_region->priv->gdk_interp_type);
1854 
1855  zoom_region_post_process_pixbuf (zoom_region, subimage,
1856  zoom_region->priv->scaled_pixbuf);
1857  if (zoom_region->priv->default_gc == NULL)
1858  zoom_region->priv->default_gc = gdk_gc_new(gtk_widget_get_window (zoom_region->priv->w));
1859 
1860 #ifndef USE_GDK_PIXBUF_RENDER_TO_DRAWABLE
1861  if (GDK_IS_DRAWABLE (zoom_region->priv->pixmap))
1862  gdk_draw_pixbuf (zoom_region->priv->pixmap,
1863  zoom_region->priv->default_gc,
1864  zoom_region->priv->scaled_pixbuf,
1865  0,
1866  0,
1867  paint_rect.x + zoom_region->priv->exposed_bounds.x1 - zoom_region->priv->source_area.x1 * zoom_region->xscale,
1868  paint_rect.y + zoom_region->priv->exposed_bounds.y1 - zoom_region->priv->source_area.y1 * zoom_region->yscale,
1869  paint_rect.width,
1870  paint_rect.height,
1871  GDK_RGB_DITHER_NONE,
1872  0,
1873  0);
1874  else
1875  g_warning ("updating non-drawable pixmap: region %p", zoom_region);
1876 #else
1877  gdk_pixbuf_render_to_drawable (zoom_region->priv->scaled_pixbuf,
1878  zoom_region->priv->pixmap,
1879  zoom_region->priv->default_gc,
1880  0,
1881  0,
1882  paint_rect.x + zoom_region->priv->exposed_bounds.x1,
1883  paint_rect.y + zoom_region->priv->exposed_bounds.y1,
1884  paint_rect.width,
1885  paint_rect.height,
1886  GDK_RGB_DITHER_NONE,
1887  0,
1888  0);
1889 #endif
1890  if (gmag_gs_error_check ())
1891  g_warning ("Could not render scaled image to drawable; out of memory!\n");
1892  g_object_unref (subimage);
1893 
1894  g_timer_stop (mag_timing.scale);
1895  }
1896  return source_rect;
1897 }
1898 
1905 static void
1907  const GdkRectangle update_rect)
1908 {
1909  GdkRectangle paint_rect = {0, 0, 0, 0};
1910  if (zoom_region->priv->w && gtk_widget_get_window (zoom_region->priv->w)) {
1911  GdkRectangle source_rect = zoom_region_update_pixmap (zoom_region, update_rect, &paint_rect);
1912  if (paint_rect.x != 0 || paint_rect.y != 0 ||
1913  paint_rect.width != 0 || paint_rect.height != 0) {
1914  gdk_window_begin_paint_rect (
1915  gtk_widget_get_window (zoom_region->priv->w), &paint_rect);
1916  zoom_region_paint (zoom_region, &paint_rect);
1917  gdk_window_end_paint (gtk_widget_get_window (zoom_region->priv->w));
1918  }
1919  if (timing_test) {
1921 
1922  gulong microseconds;
1923 
1925  g_timer_elapsed (mag_timing.scale,
1926  &microseconds);
1928 
1929  if (mag_timing.scale_val != 0 && (timing_scale_max == 0 ||
1930  (1.0/(float)mag_timing.scale_val) > (1.0/(float)timing_scale_max)))
1931  timing_scale_max = mag_timing.scale_val;
1932  if ((source_rect.height * source_rect.width / mag_timing.scale_val) > update_nrr_max)
1933  update_nrr_max = source_rect.height * source_rect.width / mag_timing.scale_val;
1934 
1935  mag_timing.update_pixels_total += source_rect.height * source_rect.width;
1936 
1937  if (zoom_region->timing_output) {
1938  fprintf(stderr, " Update Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
1940  mag_timing.num_scale_samples), timing_scale_max, mag_timing.scale_total);
1941  fprintf(stderr, " Update Pixels = %ld (avg. %ld) pixels/frame\n",
1942  (long) source_rect.height * source_rect.width,
1944  fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n",
1945  1.0/(mag_timing.scale_total / mag_timing.num_scale_samples), 1.0/(float)timing_scale_max);
1946  fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n",
1947  ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
1948  update_nrr_max / 1000000.0);
1949  }
1950  }
1951  } else {
1952  fprintf (stderr, "update on uninitialized zoom region!\n");
1953  }
1954 }
1955 
1956 static void
1958 {
1959  GtkFixed *parent;
1960  GtkWidget *zoomer, *border;
1961  DBG(fprintf (stderr, "window not yet created...\n"));
1962  parent = GTK_FIXED (
1963  ((Magnifier *)zoom_region->priv->parent)->priv->canvas);
1964  zoomer = gtk_drawing_area_new ();
1965  border = gtk_drawing_area_new ();
1966  zoom_region->priv->border = border;
1967  zoom_region->priv->w = zoomer;
1968 
1969 #ifdef ZOOM_REGION_DEBUG
1970  g_assert (zoom_region->alive);
1971 #endif
1972  gtk_widget_set_size_request (GTK_WIDGET (border),
1973  zoom_region->viewport.x2 -
1974  zoom_region->viewport.x1,
1975  zoom_region->viewport.y2 -
1976  zoom_region->viewport.y1);
1977  gtk_widget_set_size_request (GTK_WIDGET (zoomer),
1978  zoom_region->viewport.x2 -
1979  zoom_region->viewport.x1 -
1980  (zoom_region->border_size_right +
1981  zoom_region->border_size_left),
1982  zoom_region->viewport.y2 -
1983  zoom_region->viewport.y1 -
1984  (zoom_region->border_size_bottom +
1985  zoom_region->border_size_top));
1986  gtk_fixed_put (parent, border,
1987  zoom_region->viewport.x1,
1988  zoom_region->viewport.y1);
1989  gtk_fixed_put (parent, zoomer,
1990  zoom_region->viewport.x1 +
1991  zoom_region->border_size_left,
1992  zoom_region->viewport.y1 +
1993  zoom_region->border_size_top);
1994  gtk_widget_show (GTK_WIDGET (border));
1995  gtk_widget_show (GTK_WIDGET (zoomer));
1996  gtk_widget_show (GTK_WIDGET (parent));
1997  zoom_region->priv->expose_handler_id =
1998  g_signal_connect (G_OBJECT (zoom_region->priv->w),
1999  "expose_event",
2000  G_CALLBACK (zoom_region_expose_handler),
2001  zoom_region);
2002  DBG(fprintf (stderr, "New window created\n"));
2003 }
2004 
2005 static int
2007 {
2008  ZoomRegion *zoom_region = (ZoomRegion *) data;
2009 
2010  /* TODO: lock the queue when copying it? */
2011  zoom_region_coalesce_updates (zoom_region);
2012 
2013  if (zoom_region->priv->q != NULL) {
2014  GList *last = g_list_last (zoom_region->priv->q);
2015 #ifdef ZOOM_REGION_DEBUG
2016  fprintf (stderr, "qlen=%d\n", g_list_length (zoom_region->priv->q));
2017 #endif
2018  if (last) {
2019  zoom_region->priv->q = g_list_remove_link (zoom_region->priv->q,
2020  last);
2021  zoom_region_update (zoom_region,
2022  * (GdkRectangle *) last->data);
2023  g_list_free (last);
2024 #ifdef DEBUG
2025  fputs (".\n", stderr); /* debug output, means we actually did something. */
2026 #endif
2027  }
2028  return TRUE;
2029  }
2030  else
2031  {
2032  if (zoom_region->priv)
2033  zoom_region->priv->update_handler_id = 0;
2034  return FALSE;
2035  }
2036 }
2037 
2038 void
2040 {
2041  float frame_avg;
2042  float x_scroll_incr, y_scroll_incr;
2043  int width, height, x, y;
2044 
2045  if (timing_test) {
2046  width = (zoom_region->viewport.x2 -
2047  zoom_region->viewport.x1) / zoom_region->xscale;
2048  height = (zoom_region->viewport.y2 -
2049  zoom_region->viewport.y1) / zoom_region->yscale;
2050 
2052 
2053  x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
2054  y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
2055 
2056  gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)),
2057  &x, &y);
2058 
2059  fprintf(stderr, " Frames Processed = %ld\n",
2061  fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y,
2062  gdk_drawable_get_depth (gtk_widget_get_window (zoom_region->priv->w)));
2063  fprintf(stderr, " Zoom Factor (x/y) = %f/%f\n", zoom_region->xscale,
2064  zoom_region->yscale);
2065  if (mag_timing.num_scale_samples != 0) {
2066  fprintf(stderr, " Update Duration = (avg. %f) (max. %f) (tot. %f) seconds\n",
2068  fprintf(stderr, " Update Pixels = (avg. %ld) pixels/frame\n",
2070  fprintf(stderr, " Update Rate = (avg. %f) (max. %f) updates/second\n",
2071  1.0/((float)mag_timing.scale_total / (float)mag_timing.num_scale_samples),
2072  1.0/(float)timing_scale_max);
2073  fprintf(stderr, " Net Update Rate = (avg. %f) (max. %f) Mpex/second\n",
2074  ((float)mag_timing.update_pixels_total / (float)mag_timing.scale_total) / 1000000.0,
2075  update_nrr_max / 1000000.0);
2076  }
2077  fprintf(stderr, " Pan Latency = (avg. %f) (max. %f) seconds\n",
2079  fprintf(stderr, " Total Frame Duration = (avg. %f) (max. %f) (tot. %f) seconds\n",
2081  fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n",
2083  fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n",
2084  x_scroll_incr, mag_timing.dx_total);
2085  fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n",
2086  y_scroll_incr, mag_timing.dy_total);
2087  fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n",
2088  x_scroll_incr / frame_avg);
2089  fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n",
2090  y_scroll_incr / frame_avg);
2091 
2092  fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n\n",
2093  (height * width *
2094  ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
2095  nrr_max / 1000000.0);
2096  }
2097 }
2098 
2099 static void
2101 {
2102  float frame_avg;
2103  float x_scroll_incr, y_scroll_incr;
2104  int width = magnifier->target_bounds.x2 - magnifier->target_bounds.x1;
2105  int height = magnifier->target_bounds.y2 - magnifier->target_bounds.y1;
2106 
2108  g_timer_stop (mag_timing.frame);
2109 
2110  gulong microseconds;
2111 
2112  mag_timing.frame_val = g_timer_elapsed (mag_timing.frame,
2113  &microseconds);
2114 
2118  if (mag_timing.frame_val != 0 && 1.0/mag_timing.frame_val > cps_max)
2120 
2122 
2123  x_scroll_incr = (float)mag_timing.dx_total / (float)mag_timing.num_line_samples;
2124  y_scroll_incr = (float)mag_timing.dy_total / (float)mag_timing.num_line_samples;
2125 
2126  if ((height * width / mag_timing.frame_val) > nrr_max)
2127  nrr_max = height * width / mag_timing.frame_val;
2128 
2129  if (zoom_region->timing_output) {
2130  fprintf(stderr, " Total Frame Duration = %f (avg. %f) (max. %f) (tot. %f) seconds\n",
2132  fprintf(stderr, " Frame Rate = (avg. %f) (max. %f) frames/second\n",
2133  1.0 /frame_avg, cps_max);
2134  fprintf(stderr, " Scroll Delta (x) = (avg. %f) (tot. %d) lines\n",
2135  x_scroll_incr, mag_timing.dx_total);
2136  fprintf(stderr, " Scroll Delta (y) = (avg. %f) (tot. %d) lines\n",
2137  y_scroll_incr, mag_timing.dy_total);
2138  fprintf(stderr, " Scroll Rate (x) = (avg. %f) lines/second\n",
2139  x_scroll_incr / frame_avg);
2140  fprintf(stderr, " Scroll Rate (y) = (avg. %f) lines/second\n",
2141  y_scroll_incr / frame_avg);
2142 
2143  fprintf(stderr, " Net Render Rate = (avg. %f) (max. %f) Mpex/second\n",
2144  (height * width *
2145  ((float)mag_timing.num_frame_samples / (float)mag_timing.frame_total)) / 1000000.0,
2146  nrr_max / 1000000.0);
2147  }
2148 
2151 
2152  if (reset_timing) {
2153  fprintf(stderr, "\n### Updates summary:\n\n");
2154  timing_report (zoom_region);
2155  fprintf(stderr, "\n### Updates finished, starting panning test\n");
2157  reset_timing = FALSE;
2158  }
2159 }
2160 
2161 static void
2163 {
2164  while (zoom_region->priv->q)
2165  zoom_region_process_updates (zoom_region);
2166 }
2167 
2168 static gboolean
2169 gdk_timing_idle (gpointer data)
2170 {
2171  ZoomRegion *zoom_region = data;
2172 
2173  /* Now update has finished, reset processing_updates */
2174  processing_updates = FALSE;
2175  g_timer_stop (mag_timing.idle);
2176 
2177  if (timing_test) {
2179 
2180  gulong microseconds;
2181 
2182  mag_timing.idle_val = g_timer_elapsed (mag_timing.idle,
2183  &microseconds);
2185 
2188 
2189  if (zoom_region->timing_output) {
2190  fprintf(stderr, " Pan Latency = %f (avg. %f) (max. %f) seconds\n",
2193  }
2194  }
2195 
2196  return FALSE;
2197 }
2198 
2199 static void
2201 {
2202  long width, height;
2203 
2204  width = (zoom_region->viewport.x2 - zoom_region->viewport.x1) /
2205  zoom_region->xscale;
2206  height = (zoom_region->viewport.y2 - zoom_region->viewport.y1) /
2207  zoom_region->yscale;
2208 
2209  switch (zoom_region->x_align_policy) {
2211  *x = zoom_region->roi.x2 - width;
2212  break;
2214  *x = zoom_region->roi.x1;
2215  break;
2217  default:
2218  *x = ((zoom_region->roi.x1 + zoom_region->roi.x2) - width ) /
2219  2;
2220  }
2221 
2222  switch (zoom_region->y_align_policy) {
2224  *y = zoom_region->roi.y2 - height;
2225  break;
2227  *y = zoom_region->roi.y1;
2228  break;
2230  default:
2231  *y = ((zoom_region->roi.y1 + zoom_region->roi.y2) - height ) /
2232  2;
2233  }
2234 }
2235 
2236 static void
2238 {
2239  Magnifier *magnifier = zoom_region->priv->parent;
2240  long x = 0, y = 0;
2241 
2242  if (timing_start)
2243  zoom_region_time_frame(zoom_region, magnifier);
2244 
2245  if (timing_test) {
2246  g_timer_start (mag_timing.frame);
2247 
2248  if (zoom_region->timing_output) {
2249  gint x, y;
2250 
2251  gdk_drawable_get_size (GDK_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)),
2252  &x, &y);
2253 
2254  fprintf(stderr, "\nTiming Information - ROI = (%d, %d) (%d, %d):\n",
2255  zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
2256  zoom_region->roi.y2);
2257  fprintf(stderr, " Frame Number = %ld\n",
2259  fprintf(stderr, " Width/Height/Depth = %d/%d/%d\n", x, y,
2260  gdk_drawable_get_depth (gtk_widget_get_window (zoom_region->priv->w)));
2261  }
2262 
2263  /*
2264  * The timing_start flag makes sure that we don't start displaying output
2265  * until we have processed an entire frame.
2266  */
2267  if (!timing_start)
2268  g_timer_start (mag_timing.process);
2269 
2270  timing_start = TRUE;
2271  }
2272 
2273  g_timer_start (mag_timing.idle);
2274 
2275  /*
2276  * zoom_region_align calls
2277  * zoom_region_moveto calls
2278  * zoom_region_scroll calls
2279  * zoom_region_scroll_fast or zoom_region_scroll_smooth calls
2280  * gdk_window_scroll or gdk_window_invalidate_rect calls
2281  * gdk_window_invalidate_region calls
2282  * gdk_window_invalidate_maybe_recurse
2283  *
2284  * The last function in the stack will set up an idle handler of
2285  * priority GDK_PRIORITY_REDRAW (gdk_window_update_idle) to be called
2286  * to handle the work of updateing the screen.
2287  *
2288  * By setting up an idle handler of priority GDK_PRIORITY_REDRAW + 1,
2289  * it will be called immediately after and we can determine when GTK+
2290  * is finished with the update.
2291  */
2292  g_idle_add_full (GDK_PRIORITY_REDRAW + 1,
2293  gdk_timing_idle, zoom_region, NULL);
2294 
2295  zoom_region_get_move_x_y (zoom_region, &x, &y);
2296 
2297  zoom_region_moveto (zoom_region, x, y);
2298 }
2299 
2300 static void
2302  const GNOME_Magnifier_RectBounds *viewport)
2303 {
2304 #ifdef ZOOM_REGION_DEBUG
2305  g_assert (zoom_region->alive);
2306 #endif
2307  if (zoom_region->viewport.x1 == viewport->x1 &&
2308  zoom_region->viewport.y1 == viewport->y1 &&
2309  zoom_region->viewport.x2 == viewport->x2 &&
2310  zoom_region->viewport.y2 == viewport->y2) {
2311  return;
2312  }
2313  zoom_region->viewport = *viewport;
2314 #ifdef DEBUG
2315  fprintf (stderr, "Setting viewport %d,%d - %d,%d\n",
2316  (int) viewport->x1, (int) viewport->y1,
2317  (int) viewport->x2, (int) viewport->y2);
2318 #endif
2319  zoom_region_align (zoom_region);
2320  if (!zoom_region->priv->w) {
2321  zoom_region_init_window (zoom_region);
2322  } else {
2323  CORBA_any *any;
2324  CORBA_Environment ev;
2325  Bonobo_PropertyBag properties;
2326  Magnifier *magnifier = (Magnifier *) zoom_region->priv->parent;
2327  GtkFixed *fixed = GTK_FIXED (magnifier->priv->canvas);
2328  gtk_fixed_move (fixed,
2329  zoom_region->priv->border,
2330  zoom_region->viewport.x1,
2331  zoom_region->viewport.y1);
2332  gtk_fixed_move (fixed,
2333  zoom_region->priv->w,
2334  zoom_region->viewport.x1 +
2335  zoom_region->border_size_left,
2336  zoom_region->viewport.y1 +
2337  zoom_region->border_size_top);
2338  gtk_widget_set_size_request (
2339  GTK_WIDGET (zoom_region->priv->border),
2340  zoom_region->viewport.x2 - zoom_region->viewport.x1,
2341  zoom_region->viewport.y2 - zoom_region->viewport.y1);
2342  gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
2343  zoom_region->viewport.x2 -
2344  zoom_region->viewport.x1 -
2345  (zoom_region->border_size_right +
2346  zoom_region->border_size_left),
2347  zoom_region->viewport.y2 -
2348  zoom_region->viewport.y1 -
2349  (zoom_region->border_size_bottom +
2350  zoom_region->border_size_top));
2351  CORBA_exception_init (&ev);
2352  properties =
2354  BONOBO_OBJREF (
2355  (Magnifier *) zoom_region->priv->parent), &ev);
2356  if (!BONOBO_EX (&ev))
2358  properties, "source-display-bounds", &ev);
2359  if (!BONOBO_EX (&ev))
2360  zoom_region->priv->source_area =
2361  *((GNOME_Magnifier_RectBounds *) any->_value);
2362  if (zoom_region->priv->pixmap)
2363  g_object_unref (zoom_region->priv->pixmap);
2364  zoom_region_create_pixmap (zoom_region);
2365  if (zoom_region->priv->scaled_pixbuf)
2366  g_object_unref (zoom_region->priv->scaled_pixbuf);
2367 
2368  zoom_region->priv->scaled_pixbuf =
2369  gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
2370  (zoom_region->priv->source_area.x2 -
2371  zoom_region->priv->source_area.x1) * zoom_region->xscale + 1,
2372  (zoom_region->priv->source_area.y2 -
2373  zoom_region->priv->source_area.y1) * zoom_region->yscale + 1);
2374  }
2375  zoom_region_queue_update (zoom_region,
2377  zoom_region, &zoom_region->viewport));
2378 }
2379 
2380 static void
2381 zoom_region_get_property (BonoboPropertyBag *bag,
2382  BonoboArg *arg,
2383  guint arg_id,
2384  CORBA_Environment *ev,
2385  gpointer user_data)
2386 {
2387  ZoomRegion *zoom_region = user_data;
2388 
2389 #ifdef ZOOM_REGION_DEBUG
2390  g_assert (zoom_region->alive);
2391 #endif
2392  DBG (fprintf (stderr, "Get zoom-region property: %s\n", prop_names[arg_id]));
2393 
2394  switch (arg_id) {
2396  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->is_managed);
2397  break;
2399  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->poll_mouse);
2400  break;
2402  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->draw_cursor);
2403  break;
2405  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->invert);
2406  break;
2408  BONOBO_ARG_SET_SHORT (arg, zoom_region->smooth_scroll_policy);
2409  break;
2411  BONOBO_ARG_SET_SHORT (arg, zoom_region->color_blind_filter);
2412  break;
2414  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->priv->test);
2415  break;
2417  BONOBO_ARG_SET_STRING (arg, zoom_region->smoothing);
2418  break;
2420  BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_r);
2421  break;
2423  BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_g);
2424  break;
2426  BONOBO_ARG_SET_FLOAT (arg, zoom_region->contrast_b);
2427  break;
2429  BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_r);
2430  break;
2432  BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_g);
2433  break;
2435  BONOBO_ARG_SET_FLOAT (arg, zoom_region->bright_b);
2436  break;
2438  BONOBO_ARG_SET_FLOAT (arg, zoom_region->xscale);
2439  break;
2441  BONOBO_ARG_SET_FLOAT (arg, zoom_region->yscale);
2442  break;
2444  BONOBO_ARG_SET_LONG (
2445  arg, (zoom_region->border_size_top +
2446  zoom_region->border_size_left +
2447  zoom_region->border_size_right +
2448  zoom_region->border_size_bottom) / 4);
2449  break;
2451  BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_top);
2452  break;
2454  BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_left);
2455  break;
2457  BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_right);
2458  break;
2460  BONOBO_ARG_SET_LONG (arg, zoom_region->border_size_bottom);
2461  break;
2463  /* TODO: enums here */
2464  BONOBO_ARG_SET_INT (arg, zoom_region->x_align_policy);
2465  break;
2467  BONOBO_ARG_SET_INT (arg, zoom_region->y_align_policy);
2468  break;
2470  BONOBO_ARG_SET_LONG (arg,
2471  zoom_region->border_color);
2472  break;
2474  BONOBO_ARG_SET_GENERAL (arg, zoom_region->viewport,
2477  NULL);
2478  break;
2480  BONOBO_ARG_SET_INT (arg, zoom_region->timing_iterations);
2481  break;
2483  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->timing_output);
2484  break;
2486  BONOBO_ARG_SET_INT (arg, zoom_region->timing_pan_rate);
2487  break;
2489  BONOBO_ARG_SET_BOOLEAN (arg, zoom_region->exit_magnifier);
2490  break;
2491  default:
2492  bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
2493  };
2494 }
2495 
2496 static void
2498 {
2499  gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->border),
2500  zoom_region->viewport.x2 -
2501  zoom_region->viewport.x1,
2502  zoom_region->viewport.y2 -
2503  zoom_region->viewport.y1);
2504  gtk_widget_set_size_request (GTK_WIDGET (zoom_region->priv->w),
2505  zoom_region->viewport.x2 -
2506  zoom_region->viewport.x1 -
2507  (zoom_region->border_size_right +
2508  zoom_region->border_size_left),
2509  zoom_region->viewport.y2 -
2510  zoom_region->viewport.y1 -
2511  (zoom_region->border_size_bottom +
2512  zoom_region->border_size_top));
2513  gtk_fixed_move (GTK_FIXED (((Magnifier *)zoom_region->priv->parent)->priv->canvas), zoom_region->priv->border, zoom_region->viewport.x1, zoom_region->viewport.y1);
2514  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);
2515 }
2516 
2517 gboolean
2519 {
2520  zoom_region->is_managed = managed;
2521 
2522  return TRUE;
2523 }
2524 
2525 gboolean
2527 {
2528  return zoom_region->is_managed;
2529 }
2530 
2531 gboolean
2533 {
2534  zoom_region->poll_mouse = poll_mouse;
2535  if (zoom_region->poll_mouse) {
2536  g_message ("Adding polling timer");
2537  zoom_region->priv->update_pointer_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
2538  200,
2540  zoom_region,
2541  NULL);
2542  } else if (zoom_region->priv->update_pointer_id) {
2543  g_message ("Removing polling time");
2544  g_source_remove (zoom_region->priv->update_pointer_id);
2545  zoom_region->priv->update_pointer_id = 0;
2546  }
2547 
2548  return TRUE;
2549 }
2550 
2551 gboolean
2553 {
2554  return zoom_region->poll_mouse;
2555 }
2556 
2557 gboolean
2559 {
2560  zoom_region->draw_cursor = draw_cursor;
2561  if (!zoom_region->draw_cursor) {
2562  zoom_region_unpaint_cursor (zoom_region, NULL);
2563  }
2564 
2565  return TRUE;
2566 }
2567 
2568 gboolean
2570 {
2571  return zoom_region->draw_cursor;
2572 }
2573 
2574 gboolean
2576 {
2577  zoom_region->invert = invert;
2578  zoom_region_update_current (zoom_region);
2579 
2580  return TRUE;
2581 }
2582 
2583 gboolean
2585 {
2586  return zoom_region->invert;
2587 }
2588 
2589 gboolean
2591 {
2592  zoom_region->smooth_scroll_policy = smoothscroll;
2593 
2594  return TRUE;
2595 }
2596 
2597 gshort
2599 {
2600  return zoom_region->smooth_scroll_policy;
2601 }
2602 
2603 gboolean
2605 {
2606  zoom_region->color_blind_filter = colorblind;
2607  zoom_region_update_current (zoom_region);
2608 
2609  return TRUE;
2610 }
2611 
2612 gshort
2614 {
2615  return zoom_region->color_blind_filter;
2616 }
2617 
2618 gboolean
2620 {
2621  zoom_region->smoothing = g_strdup (smoothing);
2622  if (!strncmp (zoom_region->smoothing, "bilinear", 8)) {
2623  zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR;
2624  } else {
2625  zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST;
2626  }
2627  zoom_region_update_current (zoom_region);
2628 
2629  return TRUE;
2630 }
2631 
2632 gchar*
2634 {
2635  return g_strdup (zoom_region->smoothing);
2636 }
2637 
2638 gboolean
2640 {
2641  zoom_region->priv->test = test;
2642  if (zoom_region->priv->source_drawable) {
2643  g_object_unref (zoom_region->priv->source_drawable);
2644  zoom_region->priv->source_drawable = NULL;
2645  }
2646  zoom_region_update_current (zoom_region);
2647 
2648  return TRUE;
2649 }
2650 
2651 gboolean
2653 {
2654  return zoom_region->priv->test;
2655 }
2656 
2657 gboolean
2659 {
2660  zoom_region->border_size_left = (*bordersizes)[0];
2661  zoom_region->border_size_top = (*bordersizes)[1];
2662  zoom_region->border_size_right = (*bordersizes)[2];
2663  zoom_region->border_size_bottom = (*bordersizes)[3];
2664  zoom_region_update_borders (zoom_region);
2665 
2666  return TRUE;
2667 }
2668 
2669 GArray*
2671 {
2672  GArray *ret;
2673 
2674  ret = g_array_new (FALSE, FALSE, sizeof (gint32));
2675 
2676  g_array_append_val (ret, zoom_region->border_size_left);
2677  g_array_append_val (ret, zoom_region->border_size_top);
2678  g_array_append_val (ret, zoom_region->border_size_right);
2679  g_array_append_val (ret, zoom_region->border_size_bottom);
2680 
2681  return ret;
2682 }
2683 
2684 gboolean
2686 {
2687  zoom_region->border_color = bordercolor;
2688  zoom_region_paint_border (zoom_region);
2689 
2690  return TRUE;
2691 }
2692 
2693 guint32
2695 {
2696  return zoom_region->border_color;
2697 }
2698 
2699 gboolean
2701 {
2702  zoom_region->x_align_policy = align;
2703  zoom_region_align (zoom_region);
2704 
2705  return TRUE;
2706 }
2707 
2708 gint32
2710 {
2711  return zoom_region->x_align_policy;
2712 }
2713 
2714 gboolean
2716 {
2717  zoom_region->y_align_policy = align;
2718  zoom_region_align (zoom_region);
2719 
2720  return TRUE;
2721 }
2722 
2723 gint32
2725 {
2726  return zoom_region->y_align_policy;
2727 }
2728 
2729 gboolean
2731 {
2732  GNOME_Magnifier_RectBounds *bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds));
2733 
2734  bounds->x1 = (*viewport)[0];
2735  bounds->y1 = (*viewport)[1];
2736  bounds->x2 = (*viewport)[2];
2737  bounds->y2 = (*viewport)[3];
2738 
2739  zoom_region_set_viewport (zoom_region, bounds);
2740 
2741  g_free (bounds);
2742 
2743  return TRUE;
2744 }
2745 
2746 GArray*
2748 {
2749  GArray *ret;
2750 
2751  ret = g_array_new (FALSE, FALSE, sizeof (gint32));
2752 
2753  g_array_append_val (ret, zoom_region->viewport.x1);
2754  g_array_append_val (ret, zoom_region->viewport.y1);
2755  g_array_append_val (ret, zoom_region->viewport.x2);
2756  g_array_append_val (ret, zoom_region->viewport.y2);
2757 
2758  return ret;
2759 }
2760 
2761 gboolean
2763 {
2764  zoom_region->timing_iterations = timing_iterations;
2765  timing_test = TRUE;
2766 
2767  return TRUE;
2768 }
2769 
2770 gint32
2772 {
2773  return zoom_region->timing_iterations;
2774 }
2775 
2776 gboolean
2778 {
2779  zoom_region->timing_output = timing_output;
2780 
2781  return TRUE;
2782 }
2783 
2784 gboolean
2786 {
2787  return zoom_region->timing_output;
2788 }
2789 
2790 gboolean
2792 {
2793  zoom_region->timing_pan_rate = timing_pan_rate;
2794  timing_test = TRUE;
2795 
2796  return TRUE;
2797 }
2798 
2799 gint32
2801 {
2802  return zoom_region->timing_pan_rate;
2803 }
2804 
2805 gboolean
2807 {
2808  zoom_region->exit_magnifier = exit_magnifier;
2809 
2810  return TRUE;
2811 }
2812 
2813 gboolean
2815 {
2816  return zoom_region->exit_magnifier;
2817 }
2818 
2819 static void
2820 zoom_region_set_property (BonoboPropertyBag *bag,
2821  BonoboArg *arg,
2822  guint arg_id,
2823  CORBA_Environment *ev,
2824  gpointer user_data)
2825 {
2826  ZoomRegion *zoom_region = user_data;
2828  gfloat t;
2829 
2830 #ifdef ZOOM_REGION_DEBUG
2831  g_assert (zoom_region->alive);
2832 #endif
2833  DBG (fprintf (stderr, "Set zoom-region property: %s\n", prop_names[arg_id]));
2834 
2835  switch (arg_id) {
2837  zoom_region->is_managed = BONOBO_ARG_GET_BOOLEAN (arg);
2838  break;
2840  zoom_region->poll_mouse = BONOBO_ARG_GET_BOOLEAN (arg);
2841  if (zoom_region->poll_mouse)
2842  {
2843  g_message ("Adding polling timer");
2844  zoom_region->priv->update_pointer_id =
2845  g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
2846  200,
2848  zoom_region,
2849  NULL);
2850  }
2851  else if (zoom_region->priv->update_pointer_id)
2852  {
2853  g_message ("Removing polling timer");
2854  g_source_remove (zoom_region->priv->update_pointer_id);
2855  zoom_region->priv->update_pointer_id = 0;
2856  }
2857  break;
2859  zoom_region->draw_cursor = BONOBO_ARG_GET_BOOLEAN (arg);
2860  if (!zoom_region->draw_cursor)
2861  zoom_region_unpaint_cursor (zoom_region, NULL);
2862  break;
2864  zoom_region->invert = BONOBO_ARG_GET_BOOLEAN (arg);
2865  zoom_region_update_current (zoom_region);
2866  break;
2868  zoom_region->smooth_scroll_policy = BONOBO_ARG_GET_SHORT (arg);
2869  break;
2871  zoom_region->color_blind_filter = BONOBO_ARG_GET_SHORT (arg);
2872 
2873  switch (zoom_region->color_blind_filter) {
2875  break; /* This entry is only to avoid a warning */
2877  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_red);
2878  break;
2880  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_green);
2881  break;
2883  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate_blue);
2884  break;
2886  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_red);
2887  break;
2889  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_green);
2890  break;
2892  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate_blue);
2893  break;
2895  colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_positive);
2896  break;
2898  colorblind_set_filter_type (cbr, colorblind_filter_t_hue_shift_negative);
2899  break;
2901  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_saturate);
2902  break;
2904  colorblind_set_filter_type (cbr, colorblind_filter_t_selective_dessaturate);
2905  break;
2907  colorblind_set_filter_type (cbr, colorblind_filter_t_monochrome_others);
2908  break;
2909  }
2910 
2911  zoom_region_update_current (zoom_region);
2912  break;
2914  zoom_region->smoothing = BONOBO_ARG_GET_STRING (arg);
2915  if (!strncmp (zoom_region->smoothing, "bilinear", 8))
2916  zoom_region->priv->gdk_interp_type = GDK_INTERP_BILINEAR;
2917  else
2918  zoom_region->priv->gdk_interp_type = GDK_INTERP_NEAREST;
2919  zoom_region_update_current (zoom_region);
2920  break;
2922  zoom_region->priv->test = BONOBO_ARG_GET_BOOLEAN (arg);
2923  if (zoom_region->priv->source_drawable) {
2924  g_object_unref (zoom_region->priv->source_drawable);
2925  zoom_region->priv->source_drawable = NULL;
2926  }
2927  zoom_region_update_current (zoom_region);
2928  break;
2930  zoom_region->contrast_r =
2931  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2932  zoom_region_update_current (zoom_region);
2933  break;
2935  zoom_region->contrast_g =
2936  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2937  zoom_region_update_current (zoom_region);
2938  break;
2940  zoom_region->contrast_b =
2941  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2942  zoom_region_update_current (zoom_region);
2943  break;
2945  zoom_region->bright_r =
2946  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2947  zoom_region_update_current (zoom_region);
2948  break;
2950  zoom_region->bright_g =
2951  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2952  zoom_region_update_current (zoom_region);
2953  break;
2955  zoom_region->bright_b =
2956  CLAMP_B_C (BONOBO_ARG_GET_FLOAT (arg));
2957  zoom_region_update_current (zoom_region);
2958  break;
2960  (void) zoom_region_update_scale (zoom_region,
2961  BONOBO_ARG_GET_FLOAT (arg),
2962  zoom_region->yscale);
2963  break;
2965  (void) zoom_region_update_scale (zoom_region,
2966  zoom_region->xscale,
2967  BONOBO_ARG_GET_FLOAT (arg));
2968 
2969  break;
2971  zoom_region->border_size_left =
2972  zoom_region->border_size_top =
2973  zoom_region->border_size_right =
2974  zoom_region->border_size_bottom =
2975  BONOBO_ARG_GET_LONG (arg);
2976  zoom_region_update_borders (zoom_region);
2977  break;
2979  zoom_region->border_size_left = BONOBO_ARG_GET_LONG (arg);
2980  zoom_region_update_borders (zoom_region);
2981  break;
2983  zoom_region->border_size_top = BONOBO_ARG_GET_LONG (arg);
2984  zoom_region_update_borders (zoom_region);
2985  break;
2987  zoom_region->border_size_right = BONOBO_ARG_GET_LONG (arg);
2988  zoom_region_update_borders (zoom_region);
2989  break;
2991  zoom_region->border_size_bottom = BONOBO_ARG_GET_LONG (arg);
2992  zoom_region_update_borders (zoom_region);
2993  break;
2995  zoom_region->border_color =
2996  BONOBO_ARG_GET_LONG (arg);
2997  zoom_region_paint_border (zoom_region);
2998  break;
3000  zoom_region->x_align_policy = BONOBO_ARG_GET_INT (arg);
3001  zoom_region_align (zoom_region);
3002  break;
3004  /* TODO: enums here */
3005  zoom_region->y_align_policy = BONOBO_ARG_GET_INT (arg);
3006  zoom_region_align (zoom_region);
3007  break;
3009  bounds = BONOBO_ARG_GET_GENERAL (arg,
3012  NULL);
3013  zoom_region_set_viewport (zoom_region, &bounds);
3014  break;
3016  zoom_region->timing_iterations = BONOBO_ARG_GET_INT (arg);
3017  timing_test = TRUE;
3018  break;
3020  zoom_region->timing_output = BONOBO_ARG_GET_BOOLEAN (arg);
3021  break;
3023  zoom_region->timing_pan_rate = BONOBO_ARG_GET_INT (arg);
3024  timing_test = TRUE;
3025  break;
3027  zoom_region->exit_magnifier = BONOBO_ARG_GET_BOOLEAN (arg);
3028  break;
3029  default:
3030  bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
3031  };
3032 }
3033 
3034 static int
3036 {
3037  ZoomRegion *zoom_region = (ZoomRegion *) data;
3038 
3039 #ifdef ZOOM_REGION_DEBUG
3040  g_assert (zoom_region->alive);
3041 #endif
3042  zoom_region_align (zoom_region);
3043  return FALSE;
3044 }
3045 
3046 static int
3047 zoom_region_pan_test (gpointer data)
3048 {
3049  ZoomRegion *zoom_region = (ZoomRegion *) data;
3050  Magnifier *magnifier = zoom_region->priv->parent;
3051  GNOME_Magnifier_ZoomRegionList *zoom_regions;
3053  CORBA_Environment ev;
3054  static int counter = 0;
3055  static gboolean finished_update = !TRUE;
3056  static float last_pixels_at_speed = -1;
3057  float pixels_at_speed;
3058  float total_time;
3059  int screen_height, height;
3060  int pixel_position;
3061  int pixel_direction;
3062 
3063  screen_height = gdk_screen_get_height (
3064  gdk_display_get_screen (magnifier->source_display,
3065  magnifier->source_screen_num));
3066 
3067  height = (zoom_region->viewport.y2 -
3068  zoom_region->viewport.y1) / zoom_region->yscale;
3069 
3070  roi.x1 = zoom_region->roi.x1;
3071  roi.x2 = zoom_region->roi.x2;
3072 
3073  g_timer_stop (mag_timing.process);
3074 
3075  gulong microseconds;
3076 
3077  total_time = g_timer_elapsed (mag_timing.process, &microseconds);
3078 
3079  if (mag_timing.frame_total != 0.0)
3080  pixels_at_speed = total_time * zoom_region->timing_pan_rate;
3081  else
3082  pixels_at_speed = 0.0;
3083 
3084  /* Wait until it is actually necessary to update the screen */
3085  if ((int)(last_pixels_at_speed) == (int)(pixels_at_speed))
3086  return TRUE;
3087 
3088  pixel_position = (int)(pixels_at_speed) % (screen_height - height);
3089  counter = (int)(pixels_at_speed) / (screen_height - height);
3090  pixel_direction = counter % 2;
3091 
3092  if (!finished_update) {
3093  if ((int)(pixels_at_speed) > (zoom_region->roi.y1 + height))
3094  roi.y1 = zoom_region->roi.y1 + height;
3095  else
3096  roi.y1 = (int)(pixels_at_speed);
3097 
3098  if (roi.y1 >= screen_height - height) {
3099  roi.y1 = screen_height - height;
3100  }
3101  } else {
3102  if (pixel_direction == 0)
3103  roi.y1 = screen_height - height - pixel_position;
3104  else
3105  roi.y1 = pixel_position;
3106  }
3107 
3108  roi.y2 = roi.y1 + height;
3109  magnifier->priv->cursor_x = (roi.x2 + roi.x1) / 2;
3110  magnifier->priv->cursor_y = (roi.y2 + roi.y1) / 2;
3111 
3112  /* Add one since in first loop we call zoom_region_process_updates */
3113  if (counter > zoom_region->timing_iterations - 1)
3114  zoom_region->exit_magnifier = TRUE;
3115 
3117  BONOBO_OBJREF (magnifier), &ev);
3118 
3119  if (zoom_regions && (zoom_regions->_length > 0)) {
3121  zoom_regions->_buffer[0], &roi, &ev);
3122  }
3123 
3124  if (!finished_update) {
3125  zoom_region_process_updates(zoom_region);
3126  if (roi.y1 == screen_height - height) {
3127  finished_update = TRUE;
3128  reset_timing = TRUE;
3129  }
3130  }
3131 
3132  last_pixels_at_speed = pixels_at_speed;
3133 
3134  return FALSE;
3135 }
3136 
3137 static void
3138 impl_zoom_region_set_pointer_pos (PortableServer_Servant servant,
3139  const CORBA_long mouse_x,
3140  const CORBA_long mouse_y,
3141  CORBA_Environment *ev)
3142 {
3144  ZOOM_REGION (bonobo_object_from_servant (servant));
3145  GdkRectangle paint_area, *clip = NULL;
3146 
3147 #ifdef ZOOM_REGION_DEBUG
3148  g_assert (zoom_region->alive);
3149 #endif
3150  DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
3151  (long) mouse_x, (long) mouse_y));
3152 
3153  fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
3154  (long) mouse_x, (long) mouse_y);
3155 
3156  zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y);
3157 
3158  if (GTK_IS_WIDGET (zoom_region->priv->w) &&
3159  GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
3160  {
3161  gdk_drawable_get_size (
3162  GDK_DRAWABLE (
3163  gtk_widget_get_window (zoom_region->priv->w)),
3164  &paint_area.width, &paint_area.height);
3165  paint_area.x = 0;
3166  paint_area.y = 0;
3167  clip = &paint_area;
3168  paint_area = zoom_region_clip_to_source (
3169  zoom_region, paint_area);
3170  }
3171  /*
3172  * if we update the cursor now, it causes flicker if the client
3173  * subsequently calls setROI, so we wait for a redraw.
3174  * Perhaps we should cue a redraw on idle instead?
3175  */
3176 }
3177 
3178 static void
3179 impl_zoom_region_set_contrast (PortableServer_Servant servant,
3180  const CORBA_float R,
3181  const CORBA_float G,
3182  const CORBA_float B,
3183  CORBA_Environment *ev)
3184 {
3186  ZOOM_REGION (bonobo_object_from_servant (servant));
3187  gfloat t;
3188 
3189 #ifdef ZOOM_REGION_DEBUG
3190  g_assert (zoom_region->alive);
3191 #endif
3192  DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B));
3193 
3194  /* if the contrast values are the same, this is a NOOP */
3195  if (zoom_region->contrast_r == R &&
3196  zoom_region->contrast_g == G &&
3197  zoom_region->contrast_b == B)
3198  return;
3199 
3200  zoom_region->contrast_r = CLAMP_B_C (R);
3201  zoom_region->contrast_g = CLAMP_B_C (G);
3202  zoom_region->contrast_b = CLAMP_B_C (B);
3203 
3204  zoom_region_update_current (zoom_region);
3205 }
3206 
3207 static void
3208 impl_zoom_region_get_contrast (PortableServer_Servant servant,
3209  CORBA_float *R,
3210  CORBA_float *G,
3211  CORBA_float *B,
3212  CORBA_Environment *ev)
3213 {
3215  ZOOM_REGION (bonobo_object_from_servant (servant));
3216 
3217 #ifdef ZOOM_REGION_DEBUG
3218  g_assert (zoom_region->alive);
3219 #endif
3220 
3221  *R = zoom_region->contrast_r;
3222  *G = zoom_region->contrast_g;
3223  *B = zoom_region->contrast_b;
3224 }
3225 
3226 static void
3227 impl_zoom_region_set_brightness (PortableServer_Servant servant,
3228  const CORBA_float R,
3229  const CORBA_float G,
3230  const CORBA_float B,
3231  CORBA_Environment *ev)
3232 {
3234  ZOOM_REGION (bonobo_object_from_servant (servant));
3235  gfloat t;
3236 
3237 #ifdef ZOOM_REGION_DEBUG
3238  g_assert (zoom_region->alive);
3239 #endif
3240  DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B));
3241 
3242  /* if the contrast values are the same, this is a NOOP */
3243  if (zoom_region->bright_r == R &&
3244  zoom_region->bright_g == G &&
3245  zoom_region->bright_b == B)
3246  return;
3247 
3248  zoom_region->bright_r = CLAMP_B_C (R);
3249  zoom_region->bright_g = CLAMP_B_C (G);
3250  zoom_region->bright_b = CLAMP_B_C (B);
3251 
3252  zoom_region_update_current (zoom_region);
3253 }
3254 
3255 static void
3256 impl_zoom_region_get_brightness (PortableServer_Servant servant,
3257  CORBA_float *R,
3258  CORBA_float *G,
3259  CORBA_float *B,
3260  CORBA_Environment *ev)
3261 {
3263  ZOOM_REGION (bonobo_object_from_servant (servant));
3264 
3265 #ifdef ZOOM_REGION_DEBUG
3266  g_assert (zoom_region->alive);
3267 #endif
3268 
3269  *R = zoom_region->bright_r;
3270  *G = zoom_region->bright_g;
3271  *B = zoom_region->bright_b;
3272 }
3273 
3274 static void
3275 impl_zoom_region_set_roi (PortableServer_Servant servant,
3276  const GNOME_Magnifier_RectBounds *bounds,
3277  CORBA_Environment *ev)
3278 {
3280  ZOOM_REGION (bonobo_object_from_servant (servant));
3281 
3282 #ifdef ZOOM_REGION_DEBUG
3283  g_assert (zoom_region->alive);
3284 #endif
3285  DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n",
3286  bounds->x1, bounds->y1, bounds->x2, bounds->y2));
3287 
3288  if ((zoom_region->roi.x1 == bounds->x1) &&
3289  (zoom_region->roi.x2 == bounds->x2) &&
3290  (zoom_region->roi.y1 == bounds->y1) &&
3291  (zoom_region->roi.y2 == bounds->y2)) {
3292  return;
3293  }
3294 
3295  /* if these bounds are clearly bogus, warn and ignore */
3296  if (!bounds || (bounds->x2 <= bounds->x1)
3297  || (bounds->y2 < bounds->y1) ||
3298  ((bounds->x1 + bounds->x2)/2 < 0) ||
3299  ((bounds->y1 + bounds->y2)/2 < 0))
3300  {
3301  g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n",
3302  bounds->x1, bounds->y1, bounds->x2, bounds->y2);
3303  return;
3304  }
3305 
3306  zoom_region->roi = *bounds;
3307 
3308  if (zoom_region->timing_pan_rate > 0) {
3309  /* Set idle handler to do panning test */
3310  g_idle_add_full (GDK_PRIORITY_REDRAW + 3,
3311  zoom_region_pan_test, zoom_region, NULL);
3312  }
3313 
3314  if (zoom_region->exit_magnifier) {
3315  if (timing_test) {
3316  fprintf(stderr, "\n### Timing Summary:\n\n");
3317  if (zoom_region->timing_pan_rate)
3318  fprintf(stderr, " Pan Rate = %d\n", zoom_region->timing_pan_rate);
3319  timing_report(zoom_region);
3320  }
3321  exit(0);
3322  }
3323 
3324  /*
3325  * Do not bother trying to update the screen if the last
3326  * screen update has not had time to complete.
3327  */
3328  if (processing_updates) {
3329  /* Remove any previous idle handler */
3330  if (pending_idle_handler != 0) {
3331  g_source_remove(pending_idle_handler);
3333  }
3334 
3335  /* Set idle handler to process this pending update when possible */
3336 
3337  pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2,
3338  zoom_region_process_pending, zoom_region, NULL);
3339 
3340  if (zoom_region->timing_output) {
3341  fprintf(stderr,
3342  "\n [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n",
3343  zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
3344  zoom_region->roi.y2);
3345  }
3346  } else {
3347  zoom_region_align (zoom_region);
3348  }
3349 }
3350 
3351 static CORBA_boolean
3352 impl_zoom_region_set_mag_factor (PortableServer_Servant servant,
3353  const CORBA_float mag_factor_x,
3354  const CORBA_float mag_factor_y,
3355  CORBA_Environment *ev)
3356 {
3358  ZOOM_REGION (bonobo_object_from_servant (servant));
3359 
3360 #ifdef ZOOM_REGION_DEBUG
3361  g_assert (zoom_region->alive);
3362 #endif
3363  CORBA_any *any;
3364  CORBA_boolean retval = CORBA_TRUE;
3365 
3366  if ((zoom_region->xscale == mag_factor_x) &&
3367  (zoom_region->yscale == mag_factor_y)) {
3368  return retval;
3369  }
3370 
3371  /* TODO: assert that parent is magnifier object */
3372  Bonobo_PropertyBag properties =
3374  BONOBO_OBJREF (
3375  (Magnifier *) zoom_region->priv->parent), ev);
3377  properties, "source-display-bounds", ev);
3378  if (!BONOBO_EX (ev))
3379  zoom_region->priv->source_area =
3380  *((GNOME_Magnifier_RectBounds *) any->_value);
3381  else
3382  retval = CORBA_FALSE;
3383 
3384  retval = zoom_region_update_scale (zoom_region,
3385  mag_factor_x, mag_factor_y);
3386  zoom_region_sync (zoom_region);
3387 
3388  bonobo_object_release_unref (properties, NULL);
3389  return retval;
3390 }
3391 
3392 static void
3393 impl_zoom_region_get_mag_factor (PortableServer_Servant servant,
3394  CORBA_float *mag_factor_x,
3395  CORBA_float *mag_factor_y,
3396  CORBA_Environment *ev)
3397 {
3399  ZOOM_REGION (bonobo_object_from_servant (servant));
3400 
3401 #ifdef ZOOM_REGION_DEBUG
3402  g_assert (zoom_region->alive);
3403 #endif
3404  *mag_factor_x = zoom_region->xscale;
3405  *mag_factor_y = zoom_region->yscale;
3406 }
3407 
3408 static Bonobo_PropertyBag
3409 impl_zoom_region_get_properties (PortableServer_Servant servant,
3410  CORBA_Environment *ev)
3411 {
3413  ZOOM_REGION (bonobo_object_from_servant (servant));
3414 
3415 #ifdef ZOOM_REGION_DEBUG
3416  g_assert (zoom_region->alive);
3417 #endif
3418  return bonobo_object_dup_ref (
3419  BONOBO_OBJREF (zoom_region->properties), ev);
3420 }
3421 
3422 static void
3423 impl_zoom_region_update_pointer (PortableServer_Servant servant,
3424  CORBA_Environment *ev)
3425 {
3427  ZOOM_REGION (bonobo_object_from_servant (servant));
3428 
3429 #ifdef ZOOM_REGION_DEBUG
3430  g_assert (zoom_region->alive);
3431 #endif
3432 
3433  zoom_region_update_cursor (zoom_region, 0, 0, NULL);
3434 }
3435 
3436 static void
3437 impl_zoom_region_mark_dirty (PortableServer_Servant servant,
3438  const GNOME_Magnifier_RectBounds *roi_dirty,
3439  CORBA_Environment *ev)
3440 {
3442  ZOOM_REGION (bonobo_object_from_servant (servant));
3443 
3444 #ifdef ZOOM_REGION_DEBUG
3445  g_assert (zoom_region->alive);
3446 #endif
3447  DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds (
3448  zoom_region, roi_dirty) );
3449 
3450  zoom_region_update_pointer (zoom_region, TRUE);
3451  /* XXX ? should we clip here, or wait till process_updates? */
3452  zoom_region_queue_update (zoom_region,
3453  zoom_region_clip_to_source (zoom_region,
3454  zoom_region_rect_from_bounds (zoom_region, roi_dirty)));
3455 }
3456 
3458 impl_zoom_region_get_roi (PortableServer_Servant servant,
3459  CORBA_Environment *ev)
3460 {
3462  ZOOM_REGION (bonobo_object_from_servant (servant));
3463 
3464 #ifdef ZOOM_REGION_DEBUG
3465  g_assert (zoom_region->alive);
3466 #endif
3467  return zoom_region->roi;
3468 }
3469 
3470 static void
3471 impl_zoom_region_move_resize (PortableServer_Servant servant,
3472  const GNOME_Magnifier_RectBounds *viewport_bounds,
3473  CORBA_Environment *ev)
3474 {
3476  ZOOM_REGION (bonobo_object_from_servant (servant));
3477 
3478 #ifdef ZOOM_REGION_DEBUG
3479  g_assert (zoom_region->alive);
3480 #endif
3481  zoom_region_set_viewport (zoom_region, viewport_bounds);
3482 }
3483 
3484 /* could be called multiple times... */
3485 static void
3487 {
3488  DBG(g_message ("disposing region %p", zoom_region));
3489  if (zoom_region->priv && zoom_region->priv->expose_handler_id &&
3490  GTK_IS_WIDGET (zoom_region->priv->w)) {
3491  g_signal_handler_disconnect (
3492  zoom_region->priv->w,
3493  zoom_region->priv->expose_handler_id);
3494  zoom_region->priv->expose_handler_id = 0;
3495  }
3496  if (zoom_region->priv && zoom_region->priv->update_pointer_id)
3497  g_source_remove (zoom_region->priv->update_pointer_id);
3498  if (zoom_region->priv && zoom_region->priv->update_handler_id)
3499  g_source_remove (zoom_region->priv->update_handler_id);
3500  g_idle_remove_by_data (zoom_region);
3501 
3502 #ifdef ZOOM_REGION_DEBUG
3503  zoom_region->alive = FALSE;
3504 #endif
3505 }
3506 
3507 static void
3508 impl_zoom_region_dispose (PortableServer_Servant servant,
3509  CORBA_Environment *ev)
3510 {
3512  ZOOM_REGION (bonobo_object_from_servant (servant));
3513  zoom_region_do_dispose (zoom_region);
3514 }
3515 
3516 gboolean
3518 {
3519  zoom_region_do_dispose (zoom_region);
3520 
3521  return TRUE;
3522 }
3523 
3524 gboolean
3525 impl_dbus_zoom_region_set_mag_factor (ZoomRegion *zoom_region, const gdouble mag_factor_x, const gdouble mag_factor_y)
3526 {
3527 #ifdef ZOOM_REGION_DEBUG
3528  g_assert (zoom_region->alive);
3529 #endif
3530  CORBA_Environment ev;
3531  CORBA_exception_init (&ev);
3532  CORBA_any *any;
3533  gboolean retval = TRUE;
3534 
3535  if ((zoom_region->xscale == mag_factor_x) &&
3536  (zoom_region->yscale == mag_factor_y)) {
3537  return retval;
3538  }
3539 
3540  /* TODO: assert that parent is magnifier object */
3541  Bonobo_PropertyBag properties =
3543  BONOBO_OBJREF (
3544  (Magnifier *) zoom_region->priv->parent), &ev);
3546  properties, "source-display-bounds", &ev);
3547  if (!BONOBO_EX (&ev))
3548  zoom_region->priv->source_area =
3549  *((GNOME_Magnifier_RectBounds *) any->_value);
3550  else {
3551  retval = FALSE;
3552  return retval;
3553  }
3554 
3555  retval = zoom_region_update_scale (zoom_region, mag_factor_x, mag_factor_y);
3556  zoom_region_sync (zoom_region);
3557 
3558  return retval;
3559 }
3560 
3561 GArray*
3563 {
3564  GArray *ret;
3565 
3566  ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
3567 
3568  g_array_append_val (ret, zoom_region->xscale);
3569  g_array_append_val (ret, zoom_region->yscale);
3570 
3571  return ret;
3572 }
3573 
3574 gboolean
3576 {
3577  RectBounds *bounds = g_malloc(sizeof(RectBounds));
3578  _set_bounds (bounds, roi);
3579 
3580  #ifdef ZOOM_REGION_DEBUG
3581  g_assert (zoom_region->alive);
3582 #endif
3583  DBG (fprintf (stderr, "Set ROI: \t%d,%d %d,%d\n",
3584  bounds->x1, bounds->y1, bounds->x2, bounds->y2));
3585 
3586  if ((zoom_region->roi.x1 == bounds->x1) &&
3587  (zoom_region->roi.x2 == bounds->x2) &&
3588  (zoom_region->roi.y1 == bounds->y1) &&
3589  (zoom_region->roi.y2 == bounds->y2)) {
3590  return TRUE;
3591  }
3592 
3593  /* if these bounds are clearly bogus, warn and ignore */
3594  if (!bounds || (bounds->x2 <= bounds->x1)
3595  || (bounds->y2 < bounds->y1) ||
3596  ((bounds->x1 + bounds->x2)/2 < 0) ||
3597  ((bounds->y1 + bounds->y2)/2 < 0))
3598  {
3599  g_warning ("Bad bounds request (%d,%d to %d,%d), ignoring.\n",
3600  bounds->x1, bounds->y1, bounds->x2, bounds->y2);
3601  return FALSE;
3602  }
3603 
3604  zoom_region->roi.x1 = bounds->x1;
3605  zoom_region->roi.y1 = bounds->y1;
3606  zoom_region->roi.x2 = bounds->x2;
3607  zoom_region->roi.y2 = bounds->y2;
3608 
3609  if (zoom_region->timing_pan_rate > 0) {
3610  /* Set idle handler to do panning test */
3611  g_idle_add_full (GDK_PRIORITY_REDRAW + 3,
3612  zoom_region_pan_test, zoom_region, NULL);
3613  }
3614 
3615  if (zoom_region->exit_magnifier) {
3616  if (timing_test) {
3617  fprintf(stderr, "\n### Timing Summary:\n\n");
3618  if (zoom_region->timing_pan_rate)
3619  fprintf(stderr, " Pan Rate = %d\n", zoom_region->timing_pan_rate);
3620  timing_report(zoom_region);
3621  }
3622  exit(0);
3623  }
3624 
3625  /*
3626  * Do not bother trying to update the screen if the last
3627  * screen update has not had time to complete.
3628  */
3629  if (processing_updates) {
3630  /* Remove any previous idle handler */
3631  if (pending_idle_handler != 0) {
3632  g_source_remove(pending_idle_handler);
3634  }
3635 
3636  /* Set idle handler to process this pending update when possible */
3637 
3638  pending_idle_handler = g_idle_add_full (GDK_PRIORITY_REDRAW + 2,
3639  zoom_region_process_pending, zoom_region, NULL);
3640 
3641  if (zoom_region->timing_output) {
3642  fprintf(stderr,
3643  "\n [Last update not finished, pending - ROI=(%d, %d) (%d, %d)]\n\n",
3644  zoom_region->roi.x1, zoom_region->roi.y1, zoom_region->roi.x2,
3645  zoom_region->roi.y2);
3646  }
3647  } else {
3648  zoom_region_align (zoom_region);
3649  }
3650 
3651  return TRUE;
3652 }
3653 
3654 /* TODO: Deprecate this RPC */
3655 gboolean
3657 {
3658 #ifdef ZOOM_REGION_DEBUG
3659  g_assert (zoom_region->alive);
3660 #endif
3661 
3662  zoom_region_update_cursor (zoom_region, 0, 0, NULL);
3663 
3664  return TRUE;
3665 }
3666 
3667 gboolean
3669 {
3670  GNOME_Magnifier_RectBounds *roi_dirty = g_malloc(sizeof(GNOME_Magnifier_RectBounds));
3671  roi_dirty->x1 = (*bounds)[0];
3672  roi_dirty->y1 = (*bounds)[1];
3673  roi_dirty->x2 = (*bounds)[2];
3674  roi_dirty->y2 = (*bounds)[3];
3675 
3676 #ifdef ZOOM_REGION_DEBUG
3677  g_assert (zoom_region->alive);
3678 #endif
3679  DEBUG_RECT ("mark dirty", zoom_region_rect_from_bounds (
3680  zoom_region, roi_dirty) );
3681 
3682  zoom_region_update_pointer (zoom_region, TRUE);
3683  /* XXX ? should we clip here, or wait till process_updates? */
3684  zoom_region_queue_update (zoom_region,
3685  zoom_region_clip_to_source (zoom_region,
3686  zoom_region_rect_from_bounds (zoom_region, roi_dirty)));
3687 
3688  return TRUE;
3689 }
3690 
3691 GArray*
3693 {
3694  GArray *ret;
3695 
3696  ret = g_array_new (FALSE, FALSE, sizeof (gint32));
3697 
3698  g_array_append_val (ret, zoom_region->roi.x1);
3699  g_array_append_val (ret, zoom_region->roi.y1);
3700  g_array_append_val (ret, zoom_region->roi.x2);
3701  g_array_append_val (ret, zoom_region->roi.y2);
3702 
3703  return ret;
3704 }
3705 
3706 gboolean
3708 {
3709 #ifdef ZOOM_REGION_DEBUG
3710  g_assert (zoom_region->alive);
3711 #endif
3712  GNOME_Magnifier_RectBounds *viewport_bounds = g_malloc (sizeof (GNOME_Magnifier_RectBounds));
3713  viewport_bounds->x1 = (*viewport)[0];
3714  viewport_bounds->y1 = (*viewport)[1];
3715  viewport_bounds->x2 = (*viewport)[2];
3716  viewport_bounds->y2 = (*viewport)[3];
3717 
3718  zoom_region_set_viewport (zoom_region, viewport_bounds);
3719 
3720  return TRUE;
3721 }
3722 
3723 gboolean
3725 {
3726  GdkRectangle paint_area, *clip = NULL;
3727 
3728 #ifdef ZOOM_REGION_DEBUG
3729  g_assert (zoom_region->alive);
3730 #endif
3731  DBG (fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
3732  (long) mouse_x, (long) mouse_y));
3733 
3734  fprintf (stderr, "Set Pointer: \t%ld,%ld\n",
3735  (long) mouse_x, (long) mouse_y);
3736 
3737  zoom_region_set_cursor_pos (zoom_region, (int) mouse_x, (int) mouse_y);
3738 
3739  if (GTK_IS_WIDGET (zoom_region->priv->w) &&
3740  GDK_IS_DRAWABLE (gtk_widget_get_window (zoom_region->priv->w)))
3741  {
3742  gdk_drawable_get_size (
3743  GDK_DRAWABLE (
3744  gtk_widget_get_window (zoom_region->priv->w)),
3745  &paint_area.width, &paint_area.height);
3746  paint_area.x = 0;
3747  paint_area.y = 0;
3748  clip = &paint_area;
3749  paint_area = zoom_region_clip_to_source (
3750  zoom_region, paint_area);
3751  }
3752  /*
3753  * if we update the cursor now, it causes flicker if the client
3754  * subsequently calls setROI, so we wait for a redraw.
3755  * Perhaps we should cue a redraw on idle instead?
3756  */
3757 
3758  return TRUE;
3759 }
3760 
3761 gboolean
3762 impl_dbus_zoom_region_set_contrast (ZoomRegion *zoom_region, gdouble R, gdouble G, gdouble B)
3763 {
3764  gfloat t;
3765 
3766 #ifdef ZOOM_REGION_DEBUG
3767  g_assert (zoom_region->alive);
3768 #endif
3769  DBG (fprintf (stderr, "Set contrast: \t%f,%f %f\n", R, G, B));
3770 
3771  /* if the contrast values are the same, this is a NOOP */
3772  if (zoom_region->contrast_r == R &&
3773  zoom_region->contrast_g == G &&
3774  zoom_region->contrast_b == B)
3775  return TRUE;
3776 
3777  zoom_region->contrast_r = CLAMP_B_C (R);
3778  zoom_region->contrast_g = CLAMP_B_C (G);
3779  zoom_region->contrast_b = CLAMP_B_C (B);
3780 
3781  zoom_region_update_current (zoom_region);
3782 
3783  return TRUE;
3784 }
3785 
3786 GArray*
3788 {
3789  GArray *ret;
3790 
3791  ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
3792 
3793  g_array_append_val (ret, zoom_region->contrast_r);
3794  g_array_append_val (ret, zoom_region->contrast_g);
3795  g_array_append_val (ret, zoom_region->contrast_b);
3796 
3797  return ret;
3798 }
3799 
3800 gboolean
3802 {
3803  gfloat t;
3804 
3805 #ifdef ZOOM_REGION_DEBUG
3806  g_assert (zoom_region->alive);
3807 #endif
3808  DBG (fprintf (stderr, "Set brightness: \t%f,%f %f\n", R, G, B));
3809 
3810  /* if the contrast values are the same, this is a NOOP */
3811  if (zoom_region->bright_r == R &&
3812  zoom_region->bright_g == G &&
3813  zoom_region->bright_b == B)
3814  return TRUE;
3815 
3816  zoom_region->bright_r = CLAMP_B_C (R);
3817  zoom_region->bright_g = CLAMP_B_C (G);
3818  zoom_region->bright_b = CLAMP_B_C (B);
3819 
3820  zoom_region_update_current (zoom_region);
3821 
3822  return TRUE;
3823 }
3824 
3825 GArray*
3827 {
3828  GArray *ret;
3829 
3830  ret = g_array_new (FALSE, FALSE, sizeof (gdouble));
3831 
3832  g_array_append_val (ret, zoom_region->bright_r);
3833  g_array_append_val (ret, zoom_region->bright_g);
3834  g_array_append_val (ret, zoom_region->bright_b);
3835 
3836  return ret;
3837 }
3838 
3839 /* could be called multiple times */
3840 static void
3841 zoom_region_dispose (GObject *object)
3842 {
3843  ZoomRegion *zoom_region = ZOOM_REGION (object);
3844 
3845  zoom_region_do_dispose (zoom_region);
3846 
3847  BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3848 }
3849 
3850 static void
3852 {
3853  GObjectClass * object_class = (GObjectClass *) klass;
3855  parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT); /* needed by BONOBO_CALL_PARENT! */
3856 
3857  object_class->dispose = zoom_region_dispose;
3858  object_class->finalize = zoom_region_finalize;
3859 
3874 
3876 #ifdef DEBUG_CLIENT_CALLS
3877  client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL);
3878 #endif
3879 }
3880 
3881 static void
3883 {
3884  BonoboArg *def;
3885 
3886  zoom_region->properties =
3887  bonobo_property_bag_new_closure (
3888  g_cclosure_new_object (
3889  G_CALLBACK (zoom_region_get_property),
3890  G_OBJECT (zoom_region)),
3891  g_cclosure_new_object (
3892  G_CALLBACK (zoom_region_set_property),
3893  G_OBJECT (zoom_region)));
3894 
3895  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
3896  BONOBO_ARG_SET_BOOLEAN (def, TRUE);
3897 
3898  bonobo_property_bag_add (zoom_region->properties,
3899  "is-managed",
3901  BONOBO_ARG_BOOLEAN,
3902  def,
3903  "If false, zoom region does not auto-update, but is drawn into directly by the client",
3906 
3907  bonobo_arg_release (def);
3908  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
3909  BONOBO_ARG_SET_BOOLEAN (def, TRUE);
3910 
3911  bonobo_property_bag_add (zoom_region->properties,
3912  "poll-mouse",
3914  BONOBO_ARG_BOOLEAN,
3915  NULL,
3916  "If false, zoom region does not poll for pointer location, but is (exclusively) given it by the client",
3919 
3920  bonobo_arg_release (def);
3921  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
3922  BONOBO_ARG_SET_BOOLEAN (def, TRUE);
3923 
3924  bonobo_property_bag_add (zoom_region->properties,
3925  "draw-cursor",
3927  BONOBO_ARG_BOOLEAN,
3928  NULL,
3929  "If false, zoom region does not draw the cursor.",
3932 
3933  bonobo_arg_release (def);
3934  def = bonobo_arg_new (BONOBO_ARG_SHORT);
3935  BONOBO_ARG_SET_SHORT (def, GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST);
3936 
3937  bonobo_property_bag_add (zoom_region->properties,
3938  "smooth-scroll-policy",
3940  BONOBO_ARG_SHORT,
3941  def,
3942  "scrolling policy, slower versus faster",
3945 
3946  bonobo_arg_release (def);
3947  def = bonobo_arg_new (BONOBO_ARG_SHORT);
3948  BONOBO_ARG_SET_SHORT (
3949  def,
3951 
3952  bonobo_property_bag_add (zoom_region->properties,
3953  "color-blind-filter",
3955  BONOBO_ARG_SHORT,
3956  def,
3957  "color blind filter to apply in an image",
3960 
3961  bonobo_arg_release (def);
3962  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
3963  BONOBO_ARG_SET_BOOLEAN (def, FALSE);
3964 
3965  bonobo_property_bag_add (zoom_region->properties,
3966  "use-test-pattern",
3968  BONOBO_ARG_BOOLEAN,
3969  def,
3970  "use test pattern for source",
3973 
3974  bonobo_arg_release (def);
3975  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
3976  BONOBO_ARG_SET_BOOLEAN (def, TRUE);
3977 
3978  bonobo_property_bag_add (zoom_region->properties,
3979  "inverse-video",
3981  BONOBO_ARG_BOOLEAN,
3982  def,
3983  "inverse video display",
3986 
3987  bonobo_arg_release (def);
3988 
3989  bonobo_property_bag_add (zoom_region->properties,
3990  "smoothing-type",
3992  BONOBO_ARG_STRING,
3993  NULL,
3994  "image smoothing algorithm used",
3997 
3998  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
3999  BONOBO_ARG_SET_FLOAT (def, 0.0);
4000 
4001  bonobo_property_bag_add (zoom_region->properties,
4002  "red-contrast",
4004  BONOBO_ARG_FLOAT,
4005  def,
4006  "red image contrast ratio",
4009  bonobo_arg_release (def);
4010 
4011  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4012  BONOBO_ARG_SET_FLOAT (def, 0.0);
4013 
4014  bonobo_property_bag_add (zoom_region->properties,
4015  "green-contrast",
4017  BONOBO_ARG_FLOAT,
4018  def,
4019  "green image contrast ratio",
4022  bonobo_arg_release (def);
4023 
4024  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4025  BONOBO_ARG_SET_FLOAT (def, 0.0);
4026 
4027  bonobo_property_bag_add (zoom_region->properties,
4028  "blue-contrast",
4030  BONOBO_ARG_FLOAT,
4031  def,
4032  "blue image contrast ratio",
4035  bonobo_arg_release (def);
4036 
4037  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4038  BONOBO_ARG_SET_FLOAT (def, 0.0);
4039 
4040  bonobo_property_bag_add (zoom_region->properties,
4041  "red-brightness",
4043  BONOBO_ARG_FLOAT,
4044  def,
4045  "red image brightness ratio",
4048  bonobo_arg_release (def);
4049 
4050  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4051  BONOBO_ARG_SET_FLOAT (def, 0.0);
4052 
4053  bonobo_property_bag_add (zoom_region->properties,
4054  "green-brightness",
4056  BONOBO_ARG_FLOAT,
4057  def,
4058  "green image brightness ratio",
4061  bonobo_arg_release (def);
4062 
4063  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4064  BONOBO_ARG_SET_FLOAT (def, 0.0);
4065 
4066  bonobo_property_bag_add (zoom_region->properties,
4067  "blue-brightness",
4069  BONOBO_ARG_FLOAT,
4070  def,
4071  "blue image brightness ratio",
4074  bonobo_arg_release (def);
4075 
4076  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4077  BONOBO_ARG_SET_FLOAT (def, 2.0);
4078 
4079  bonobo_property_bag_add (zoom_region->properties,
4080  "mag-factor-x",
4082  BONOBO_ARG_FLOAT,
4083  def,
4084  "x scale factor",
4087 
4088  bonobo_arg_release (def);
4089  def = bonobo_arg_new (BONOBO_ARG_FLOAT);
4090  BONOBO_ARG_SET_FLOAT (def, 2.0);
4091 
4092  bonobo_property_bag_add (zoom_region->properties,
4093  "mag-factor-y",
4095  BONOBO_ARG_FLOAT,
4096  def,
4097  "y scale factor",
4100 
4101  bonobo_arg_release (def);
4102  def = bonobo_arg_new (BONOBO_ARG_LONG);
4103  BONOBO_ARG_SET_LONG (def, 0);
4104 
4105  bonobo_property_bag_add (zoom_region->properties,
4106  "border-size",
4108  BONOBO_ARG_LONG,
4109  def,
4110  "size of zoom-region borders, in pixels",
4113 
4114  bonobo_arg_release (def);
4115  def = bonobo_arg_new (BONOBO_ARG_LONG);
4116  BONOBO_ARG_SET_LONG (def, 0);
4117 
4118  bonobo_property_bag_add (zoom_region->properties,
4119  "border-size-left",
4121  BONOBO_ARG_LONG,
4122  def,
4123  "size of left zoom-region border, in pixels",
4126 
4127  bonobo_arg_release (def);
4128  def = bonobo_arg_new (BONOBO_ARG_LONG);
4129  BONOBO_ARG_SET_LONG (def, 0);
4130 
4131  bonobo_property_bag_add (zoom_region->properties,
4132  "border-size-top",
4134  BONOBO_ARG_LONG,
4135  def,
4136  "size of top zoom-region border, in pixels",
4139 
4140  bonobo_arg_release (def);
4141  def = bonobo_arg_new (BONOBO_ARG_LONG);
4142  BONOBO_ARG_SET_LONG (def, 0);
4143 
4144  bonobo_property_bag_add (zoom_region->properties,
4145  "border-size-right",
4147  BONOBO_ARG_LONG,
4148  def,
4149  "size of right zoom-region border, in pixels",
4152 
4153  bonobo_arg_release (def);
4154  def = bonobo_arg_new (BONOBO_ARG_LONG);
4155  BONOBO_ARG_SET_LONG (def, 0);
4156 
4157  bonobo_property_bag_add (zoom_region->properties,
4158  "border-size-bottom",
4160  BONOBO_ARG_LONG,
4161  def,
4162  "size of bottom zoom-region border, in "
4163  "pixels",
4166 
4167  bonobo_arg_release (def);
4168  def = bonobo_arg_new (BONOBO_ARG_LONG);
4169  BONOBO_ARG_SET_LONG (def, 0x00000000);
4170 
4171  bonobo_property_bag_add (zoom_region->properties,
4172  "border-color",
4174  BONOBO_ARG_LONG,
4175  def,
4176  "border color, as RGBA32",
4179 
4180  bonobo_arg_release (def);
4181  def = bonobo_arg_new (BONOBO_ARG_INT);
4182  BONOBO_ARG_SET_INT (def, 0);
4183 
4184  bonobo_property_bag_add (zoom_region->properties,
4185  "x-alignment",
4187  BONOBO_ARG_INT,
4188  def,
4189  "x-alignment policy for this region",
4192 
4193  bonobo_arg_release (def);
4194  def = bonobo_arg_new (BONOBO_ARG_INT);
4195  BONOBO_ARG_SET_INT (def, 0);
4196 
4197  bonobo_property_bag_add (zoom_region->properties,
4198  "y-alignment",
4200  BONOBO_ARG_INT,
4201  def,
4202  "y-alignment policy for this region",
4205  bonobo_arg_release (def);
4206 
4207  bonobo_property_bag_add (zoom_region->properties,
4208  "viewport",
4211  NULL,
4212  "viewport bounding box",
4215 
4216  def = bonobo_arg_new (BONOBO_ARG_INT);
4217  BONOBO_ARG_SET_INT (def, 0);
4218 
4219  bonobo_property_bag_add (zoom_region->properties,
4220  "timing-iterations",
4222  BONOBO_ARG_INT,
4223  def,
4224  "timing iterations",
4227  bonobo_arg_release (def);
4228 
4229  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
4230  BONOBO_ARG_SET_BOOLEAN (def, FALSE);
4231 
4232  bonobo_property_bag_add (zoom_region->properties,
4233  "timing-output",
4235  BONOBO_ARG_BOOLEAN,
4236  def,
4237  "timing output",
4240 
4241  bonobo_arg_release (def);
4242 
4243  def = bonobo_arg_new (BONOBO_ARG_INT);
4244  BONOBO_ARG_SET_INT (def, 0);
4245 
4246  bonobo_property_bag_add (zoom_region->properties,
4247  "timing-pan-rate",
4249  BONOBO_ARG_INT,
4250  def,
4251  "timing pan rate",
4254  bonobo_arg_release (def);
4255 
4256  def = bonobo_arg_new (BONOBO_ARG_BOOLEAN);
4257  BONOBO_ARG_SET_BOOLEAN (def, FALSE);
4258 
4259  bonobo_property_bag_add (zoom_region->properties,
4260  "exit-magnifier",
4262  BONOBO_ARG_BOOLEAN,
4263  def,
4264  "timing output",
4267 
4268  bonobo_arg_release (def);
4269 
4270 }
4271 
4272 static void
4274 {
4275  GdkRectangle rect = {0, 0, 0, 0};
4276  GNOME_Magnifier_RectBounds rectbounds = {0, 0, 0, 0};
4277  priv->parent = NULL;
4278  priv->w = NULL;
4279  priv->default_gc = NULL;
4280  priv->paint_cursor_gc = NULL;
4281  priv->crosswire_gc = NULL;
4282  priv->q = NULL;
4283  priv->scaled_pixbuf = NULL;
4284  priv->source_pixbuf_cache = NULL;
4285  priv->source_drawable = NULL;
4286  priv->pixmap = NULL;
4287  priv->cursor_backing_rect = rect;
4288  priv->cursor_backing_pixels = NULL;
4289  priv->gdk_interp_type = GDK_INTERP_NEAREST;
4290  priv->expose_handler_id = 0;
4291  priv->test = FALSE;
4292  priv->last_cursor_pos.x = 0;
4293  priv->last_cursor_pos.y = 0;
4294  priv->last_drawn_crosswire_pos.x = 0;
4295  priv->last_drawn_crosswire_pos.y = 0;
4296  priv->exposed_bounds = rectbounds;
4297  priv->source_area = rectbounds;
4298  priv->update_pointer_id = 0;
4299  priv->update_handler_id = 0;
4300 }
4301 
4302 
4303 
4304 static void
4306 {
4307  DBG(g_message ("initializing region %p", zoom_region));
4308 
4309 #ifdef HAVE_COLORBLIND
4310  cbr = colorblind_create();
4311  color = malloc (sizeof (COLORBLIND_XCOLOR));
4312 #endif /* HAVE_COLORBLIND */
4313 
4314  zoom_region_properties_init (zoom_region);
4315  zoom_region->draw_cursor = TRUE;
4316  zoom_region->smooth_scroll_policy =
4318  zoom_region->color_blind_filter =
4320  zoom_region->contrast_r = 0.0;
4321  zoom_region->contrast_g = 0.0;
4322  zoom_region->contrast_b = 0.0;
4323  zoom_region->bright_r = 0.0;
4324  zoom_region->bright_g = 0.0;
4325  zoom_region->bright_b = 0.0;
4326  zoom_region->invert = FALSE;
4327  zoom_region->cache_source = FALSE;
4328  zoom_region->border_size_left = 0;
4329  zoom_region->border_size_top = 0;
4330  zoom_region->border_size_right = 0;
4331  zoom_region->border_size_bottom = 0;
4332  zoom_region->border_color = 0;
4333  zoom_region->roi.x1 = 0;
4334  zoom_region->roi.x1 = 0;
4335  zoom_region->roi.x2 = 1;
4336  zoom_region->roi.x2 = 1;
4339  zoom_region->coalesce_func = _coalesce_update_rects;
4340  zoom_region->poll_mouse = TRUE;
4341  zoom_region->priv = g_malloc (sizeof (ZoomRegionPrivate));
4342  zoom_region_private_init (zoom_region->priv);
4343  bonobo_object_add_interface (BONOBO_OBJECT (zoom_region),
4344  BONOBO_OBJECT (zoom_region->properties));
4345  zoom_region->timing_output = FALSE;
4346 #ifdef ZOOM_REGION_DEBUG
4347  zoom_region->alive = TRUE;
4348 #endif
4349  zoom_region->priv->update_pointer_id =
4350  g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
4351  200,
4353  zoom_region,
4354  NULL);
4355 }
4356 
4357 ZoomRegion *
4359 {
4360  ZoomRegionClass *klass = NULL;
4361  GError *error = NULL;
4362  ZoomRegion *_this_zoom_region = g_object_new (zoom_region_get_type(), NULL);
4363  _this_zoom_region->object_path = g_strdup_printf("/org/freedesktop/gnome/ZoomRegion/%i", zoom_region_number);
4364 
4365  klass = ZOOM_REGION_GET_CLASS (_this_zoom_region);
4366 
4367  klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
4368  if (klass->connection == NULL) {
4369  g_warning ("Unable to connect to dbus: %s", error->message);
4370  g_error_free (error);
4371  return NULL;
4372  }
4373 
4374  dbus_g_object_type_install_info (ZOOM_REGION_TYPE, &dbus_glib_impl_dbus_zoom_region_object_info);
4375 
4376  dbus_g_connection_register_g_object (klass->connection, _this_zoom_region->object_path,
4377  G_OBJECT (_this_zoom_region));
4378 
4380 
4381  return _this_zoom_region;
4382 }
4383 
4384 /* this one really shuts down the object - called once only */
4385 static void
4386 zoom_region_finalize (GObject *region)
4387 {
4388  ZoomRegion *zoom_region = (ZoomRegion *) region;
4389 
4390  DBG(g_message ("finalizing region %p", zoom_region));
4391 
4392  if (zoom_region->priv && zoom_region->priv->q)
4393  {
4394  g_list_free (zoom_region->priv->q);
4395  zoom_region->priv->q = NULL;
4396  }
4397  if (GTK_IS_WIDGET (zoom_region->priv->w))
4398  gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->w));
4399  if (GTK_IS_WIDGET (zoom_region->priv->border))
4400  gtk_container_remove (GTK_CONTAINER (((Magnifier *) zoom_region->priv->parent)->priv->canvas), GTK_WIDGET (zoom_region->priv->border));
4401  if (zoom_region->priv->source_pixbuf_cache)
4402  g_object_unref (zoom_region->priv->source_pixbuf_cache);
4403  if (zoom_region->priv->scaled_pixbuf)
4404  g_object_unref (zoom_region->priv->scaled_pixbuf);
4405  if (zoom_region->priv->pixmap)
4406  g_object_unref (zoom_region->priv->pixmap);
4407  zoom_region->priv->pixmap = NULL;
4408  zoom_region->priv->parent = NULL;
4409  if (zoom_region->priv->cursor_backing_pixels)
4410  g_object_unref (zoom_region->priv->cursor_backing_pixels);
4411  g_free (zoom_region->priv);
4412  zoom_region->priv = NULL;
4413 
4414 #ifdef HAVE_COLORBLIND
4415  free(cbr);
4416  free(color);
4417 #endif /* HAVE_COLORBLIND */
4418 
4419 #ifdef ZOOM_REGION_DEBUG
4420  zoom_region->alive = FALSE;
4421 #endif
4422  BONOBO_CALL_PARENT (G_OBJECT_CLASS, finalize, (region));
4423 }
4424 
4427  BONOBO_TYPE_OBJECT,
4428  zoom_region);