gnome-mag
magnifier.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 "magnifier.h"
25 #include "magnifier-private.h"
26 #include "zoom-region.h"
27 #include "zoom-region-private.h"
28 #include "gmag-cursor.h"
29 #include "gmag-graphical-server.h"
30 #include "GNOME_Magnifier.h"
31 #include "magnifier-server.h"
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 
37 #include <libbonobo.h>
38 #include <login-helper/login-helper.h>
39 
40 #include <dbus/dbus-glib-bindings.h>
41 
42 #include <gdk-pixbuf/gdk-pixbuf.h>
43 #include <gdk/gdkx.h>
44 #include <gdk/gdk.h>
45 #include <gtk/gtk.h>
46 
47 /* if you #define this, don't forget to set MAG_CLIENT_DEBUG env variable */
48 #define DEBUG_CLIENT_CALLS
49 
50 #ifdef DEBUG_CLIENT_CALLS
51 static gboolean client_debug = FALSE;
52 #define DBG(a) if (client_debug) { (a); }
53 #else
54 #define DBG(a)
55 #endif
56 
57 typedef struct
58 {
59  LoginHelper parent;
62 
63 typedef struct
64 {
65  LoginHelperClass parent_class;
67 
68 static GObjectClass *parent_class = NULL;
69 
70 enum {
85 } PropIdx;
86 
87 typedef struct
88 {
93  gboolean is_managed;
95  gfloat contrast;
96  gfloat zx;
97  gfloat zy;
98  gint32 xalign;
99  gint32 yalign;
100  guint32 border_color;
101  gint32 border_size;
103  gboolean inverse;
105 
106 #ifdef DEBUG_CLIENT_CALLS
108  "SOURCE_DISPLAY",
109  "TARGET_DISPLAY",
110  "SOURCE_SIZE",
111  "TARGET_SIZE",
112  "CURSOR_SET",
113  "CURSOR_SIZE",
114  "CURSOR_ZOOM",
115  "CURSOR_COLOR",
116  "CURSOR_HOTSPOT",
117  "CURSOR_DEFAULT_SIZE",
118  "CROSSWIRE_SIZE",
119  "CROSSWIRE_LENGTH",
120  "CROSSWIRE_CLIP",
121  "CROSSWIRE_COLOR"
122 };
123 #endif
124 
125 static Magnifier *_this_magnifier = NULL;
126 extern gint fixes_event_base;
127 
128 static void magnifier_init_cursor_set (Magnifier *magnifier, gchar *cursor_set);
129 static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);
130 static gboolean magnifier_reset_struts_at_idle (gpointer data);
131 static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);
132 static void magnifier_adjust_source_size (Magnifier *magnifier);
133 static gboolean _is_override_redirect = FALSE;
134 
135 static GHashTable *zoom_hash = NULL;
136 
137 static Window*
139 {
140  Window *mainwin = NULL;
141  MagLoginHelper *mag_helper = (MagLoginHelper *) helper;
142  Magnifier *magnifier = MAGNIFIER (mag_helper->mag);
143 
144  if (magnifier && magnifier->priv && magnifier->priv->w)
145  {
146  mainwin = g_new0 (Window, 2);
147  mainwin[0] = GDK_WINDOW_XWINDOW (gtk_widget_get_window (magnifier->priv->w));
148  mainwin[1] = None;
149  }
150  return mainwin;
151 }
152 
153 static LoginHelperDeviceReqFlags
154 mag_login_helper_get_device_reqs (LoginHelper *helper)
155 {
156  /* means "don't grab the xserver or core pointer",
157  and "we need to raise windows" */
158  return LOGIN_HELPER_GUI_EVENTS |
159  LOGIN_HELPER_POST_WINDOWS |
160  LOGIN_HELPER_CORE_POINTER;
161 }
162 
163 static gboolean
164 mag_login_helper_set_safe (LoginHelper *helper, gboolean ignored)
165 {
166  return TRUE;
167 }
168 
169 static void
171 {
172  LoginHelperClass *login_helper_class = LOGIN_HELPER_CLASS(klass);
173  login_helper_class->get_raise_windows = mag_login_helper_get_raise_windows;
174  login_helper_class->get_device_reqs = mag_login_helper_get_device_reqs;
175  login_helper_class->set_safe = mag_login_helper_set_safe;
176 }
177 
178 static void
180 {
181  helper->mag = NULL; /* we set this with mag_login_helper_set_magnifier */
182 }
183 
184 static void
186 {
187  if (helper)
188  helper->mag = mag;
189 }
190 
192  LOGIN_HELPER_TYPE,
193  mag_login_helper)
194 
195 static gboolean
196 can_open_display (gchar *display_name)
197 {
198  Display *d;
199  if ((d = XOpenDisplay (display_name)))
200  {
201  XCloseDisplay (d);
202  return TRUE;
203  }
204  return FALSE;
205 }
206 
207 static void
209 {
210  int x, y, unused_x, unused_y;
211  unsigned int mask;
212  Window root_return, child_return;
213 
214  if (magnifier->source_display)
215  {
216  if (!XQueryPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display),
217  GDK_WINDOW_XWINDOW (magnifier->priv->root),
218  &root_return,
219  &child_return,
220  &x, &y,
221  &unused_x, &unused_y,
222  &mask))
223  {
224  XWarpPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display),
225  None,
226  GDK_WINDOW_XWINDOW (magnifier->priv->root),
227  0, 0, 0, 0,
228  x, y);
229  XSync (GDK_DISPLAY_XDISPLAY (magnifier->source_display), FALSE);
230  }
231  }
232 }
233 
234 void
236 {
237  GList *list;
238 
239  g_assert (magnifier);
240 
241  list = magnifier->zoom_regions;
242  while (list) {
243  /* propagate the expose events to the zoom regions */
245  CORBA_Environment ev;
246  zoom_region = list->data;
247  CORBA_exception_init (&ev);
248  if (zoom_region)
250  CORBA_Object_duplicate (zoom_region, &ev), &ev);
251  list = g_list_next (list);
252  }
253 }
254 
255 static void
257 {
258  GList *list;
259 
260  g_assert (magnifier);
261 
262  list = magnifier->zoom_regions;
263  while (list)
264  {
265  /* propagate the expose events to the zoom regions */
267  CORBA_Environment ev;
268  zoom_region = list->data;
269  CORBA_exception_init (&ev);
270  if (zoom_region)
271  GNOME_Magnifier_ZoomRegion_markDirty (CORBA_Object_duplicate (zoom_region, &ev),
272  &rect_bounds,
273  &ev);
274  list = g_list_next (list);
275  }
276 }
277 
278 void
280  GdkPixbuf *cursor_pixbuf)
281 {
282  GdkPixmap *pixmap, *mask;
283  gint width, height;
284  GdkGC *gc;
285  GdkDrawable *drawable = gtk_widget_get_window (magnifier->priv->w);
286 
287  if (magnifier->priv->cursor) {
288  g_object_unref (magnifier->priv->cursor);
289  magnifier->priv->cursor = NULL;
290  }
291  if (drawable && cursor_pixbuf) {
292  const gchar *xhot_string = NULL, *yhot_string = NULL;
293  width = gdk_pixbuf_get_width (cursor_pixbuf);
294  height = gdk_pixbuf_get_height (cursor_pixbuf);
295  pixmap = gdk_pixmap_new (drawable, width, height, -1);
296  gc = gdk_gc_new (pixmap);
297  if (GDK_IS_DRAWABLE (pixmap))
298  gdk_draw_pixbuf (pixmap, gc, cursor_pixbuf, 0, 0, 0, 0,
299  width, height, GDK_RGB_DITHER_NONE,
300  0, 0);
301  else
302  DBG (g_warning ("empty cursor pixmap created."));
303  mask = gdk_pixmap_new (drawable, width, height, 1);
304  gdk_pixbuf_render_threshold_alpha (cursor_pixbuf, mask,
305  0, 0, 0, 0,
306  width, height,
307  200);
308  g_object_unref (gc);
309  magnifier->priv->cursor = pixmap;
310  magnifier->priv->cursor_mask = mask;
311 
312  xhot_string = g_object_get_data (G_OBJECT(cursor_pixbuf), "x_hot");
313  yhot_string = g_object_get_data (G_OBJECT(cursor_pixbuf), "y_hot");
314 
315  if (xhot_string)
316  magnifier->cursor_hotspot.x = atoi (xhot_string);
317  if (yhot_string)
318  magnifier->cursor_hotspot.y = atoi (yhot_string);
319  if (pixmap) {
320  gdk_drawable_get_size (
321  pixmap,
322  &magnifier->priv->cursor_default_size_x,
323  &magnifier->priv->cursor_default_size_y);
324  magnifier->priv->cursor_hotspot_x =
325  magnifier->cursor_hotspot.x;
326  magnifier->priv->cursor_hotspot_y =
327  magnifier->cursor_hotspot.y;
328  }
329  }
330 }
331 
332 
333 GdkPixbuf *
334 magnifier_get_pixbuf_for_name (Magnifier *magnifier, const gchar *cursor_name)
335 {
336  GdkPixbuf *retval = NULL;
337  if (magnifier->priv->cursorlist)
338  retval = g_hash_table_lookup (magnifier->priv->cursorlist, cursor_name);
339  if (retval)
340  g_object_ref (retval);
341  return retval;
342 }
343 
344 void
346  const gchar *cursor_name,
347  gboolean source_fallback)
348 {
349  GdkPixbuf *pixbuf;
350  /* search local table; if not found, use source screen's cursor if source_fallback is TRUE */
351  if ((pixbuf = magnifier_get_pixbuf_for_name (magnifier, cursor_name)) == NULL) {
352  if (source_fallback == TRUE)
353  {
354  pixbuf = gmag_cursor_get_source_pixbuf (magnifier);
355  }
356  else
357  {
358  pixbuf = magnifier_get_pixbuf_for_name (magnifier, "default");
359  }
360  }
361  magnifier_set_cursor_from_pixbuf (magnifier, pixbuf);
362  if (pixbuf) g_object_unref (pixbuf);
363 }
364 
365 void
366 magnifier_notify_damage (Magnifier *magnifier, GdkRectangle *rect)
367 {
368  GNOME_Magnifier_RectBounds rect_bounds;
369  rect_bounds.x1 = rect->x;
370  rect_bounds.y1 = rect->y;
371  rect_bounds.x2 = rect->x + rect->width;
372  rect_bounds.y2 = rect->y + rect->height;
373 #undef DEBUG_DAMAGE
374 #ifdef DEBUG_DAMAGE
375  g_message ("damage");
376  g_message ("dirty %d, %d to %d, %d", rect_bounds.x1, rect_bounds.y1,
377  rect_bounds.x2, rect_bounds.y2);
378 #endif
379  magnifier_zoom_regions_mark_dirty (magnifier, rect_bounds);
380 }
381 
382 static void
383 magnifier_set_extension_listeners (Magnifier *magnifier, GdkWindow *root)
384 {
385  gmag_gs_client_init (magnifier);
386  magnifier->source_initialized = TRUE;
387 }
388 
389 static void
390 magnifier_size_allocate (GtkWidget *widget)
391 {
392  gmag_gs_check_set_struts (_this_magnifier);
393 }
394 
395 static void
396 magnifier_realize (GtkWidget *widget)
397 {
398  gmag_gs_magnifier_realize (widget);
399 }
400 
401 GdkWindow*
403 {
404  if (!magnifier->priv->root && magnifier->source_display) {
405  magnifier->priv->root = gdk_screen_get_root_window (
406  gdk_display_get_screen (magnifier->source_display,
407  magnifier->source_screen_num));
408  }
409  return magnifier->priv->root;
410 }
411 
412 static gint
413 magnifier_parse_display_name (Magnifier *magnifier, gchar *full_display_string,
414  gchar **display_name)
415 {
416  gchar *screen_ptr;
417  gchar **strings;
418 
419  if (display_name != NULL) {
420  strings = g_strsplit (full_display_string, ":", 2);
421  *display_name = strings [0];
422  if (strings [1] != NULL)
423  g_free (strings [1]);
424  }
425 
426  screen_ptr = rindex (full_display_string, '.');
427  if (screen_ptr != NULL) {
428  return (gint) strtol (++screen_ptr, NULL, 10);
429  }
430  return 0;
431 }
432 
433 static void
434 magnifier_get_display_rect_bounds (Magnifier *magnifier, GNOME_Magnifier_RectBounds *rect_bounds, gboolean is_target)
435 {
436  if (is_target)
437  {
438  rect_bounds->x1 = 0;
439  rect_bounds->x2 = gdk_screen_get_width (
440  gdk_display_get_screen (magnifier->target_display,
441  magnifier->target_screen_num));
442  rect_bounds->y1 = 0;
443  rect_bounds->y2 = gdk_screen_get_height (
444  gdk_display_get_screen (magnifier->target_display,
445  magnifier->target_screen_num));
446 
447  }
448  else
449  {
450  rect_bounds->x1 = 0;
451  rect_bounds->x2 = gdk_screen_get_width (
452  gdk_display_get_screen (magnifier->source_display,
453  magnifier->source_screen_num));
454  rect_bounds->y1 = 0;
455  rect_bounds->y2 = gdk_screen_get_height (
456  gdk_display_get_screen (magnifier->source_display,
457  magnifier->source_screen_num));
458 
459  }
460 }
461 
462 gboolean
464 {
465  if ((strcmp (magnifier->source_display_name,
466  magnifier->target_display_name) != 0) ||
467  gmag_gs_use_compositor (magnifier))
468  return TRUE;
469 
470  return FALSE;
471 }
472 
473 static void
475 {
476  GNOME_Magnifier_RectBounds rect_bounds;
477  gdouble vfract_top, vfract_bottom, hfract_left, hfract_right;
478 
479  magnifier_get_display_rect_bounds (magnifier, &rect_bounds, FALSE);
480 
481  hfract_left = (double) (magnifier->target_bounds.x1) /
482  (double) rect_bounds.x2;
483  vfract_top = (double) (magnifier->target_bounds.y1) /
484  (double) rect_bounds.y2;
485  hfract_right = (double) (rect_bounds.x2 -
486  magnifier->target_bounds.x2) /
487  (double) rect_bounds.x2;
488  vfract_bottom = (double) (rect_bounds.y2 -
489  magnifier->target_bounds.y2) /
490  (double) rect_bounds.y2;
491 
492  if (magnifier_full_screen_capable (magnifier)) {
493  /* we make our 'source' rectangle the largest available subsection which we aren't occupying */
494  magnifier->source_bounds = rect_bounds;
495  } else if (MAX (hfract_left, hfract_right) >
496  MAX (vfract_top, vfract_bottom)) { /* vertical split,
497  * approximately */
498  if (hfract_right > hfract_left) {
499  magnifier->source_bounds.x1 =
500  magnifier->target_bounds.x2;
501  magnifier->source_bounds.x2 = rect_bounds.x2;
502  } else {
503  magnifier->source_bounds.x1 = rect_bounds.x1;
504  magnifier->source_bounds.x2 =
505  magnifier->target_bounds.x1;
506  }
507  magnifier->source_bounds.y1 = rect_bounds.y1;
508  magnifier->source_bounds.y2 = rect_bounds.y2;
509  } else { /* more-or-less horizontally split */
510  if (vfract_bottom > vfract_top) {
511  magnifier->source_bounds.y1 =
512  magnifier->target_bounds.y2;
513  magnifier->source_bounds.y2 = rect_bounds.y2;
514  } else {
515  magnifier->source_bounds.y1 = rect_bounds.y1;
516  magnifier->source_bounds.y2 =
517  magnifier->target_bounds.y1;
518  }
519  magnifier->source_bounds.x1 = rect_bounds.x1;
520  magnifier->source_bounds.x2 = rect_bounds.x2;
521  }
522  g_message ("set source bounds to %d,%d; %d,%d",
523  magnifier->source_bounds.x1, magnifier->source_bounds.y1,
524  magnifier->source_bounds.x2, magnifier->source_bounds.y2);
525 }
526 
527 static void
528 magnifier_unref_zoom_region (gpointer data, gpointer user_data)
529 {
530 /* Magnifier *magnifier = user_data; NOT USED */
531  CORBA_Environment ev;
533  CORBA_exception_init (&ev);
534 
535  DBG(g_message ("unreffing zoom region"));
536 
537  GNOME_Magnifier_ZoomRegion_dispose (zoom_region, &ev);
538  if (!BONOBO_EX (&ev))
539  Bonobo_Unknown_unref (zoom_region, &ev);
540 }
541 
542 static void
543 magnifier_dbus_unref_zoom_region (gpointer data, gpointer user_data)
544 {
545 /* Magnifier *magnifier = user_data; NOT USED */
546  ZoomRegion *zoom_region = data;
547 
548  DBG(g_message ("unreffing zoom region"));
549 
550  impl_dbus_zoom_region_dispose (zoom_region);
551 }
552 
553 static GSList*
555 {
556  GList *list;
557  GSList *save_props = NULL;
558 
559  g_assert (magnifier);
560  list = magnifier->zoom_regions;
561 
562  DBG(g_message ("saving %d regions", g_list_length (list)));
563 
564  while (list)
565  {
567  CORBA_Environment ev;
568  zoom_region = list->data;
569  CORBA_exception_init (&ev);
570  if (zoom_region)
571  {
572  Bonobo_PropertyBag properties;
573  CORBA_any *value;
575 
576  zoomer_props->rectbounds = GNOME_Magnifier_ZoomRegion_getROI (zoom_region, &ev);
577  properties = GNOME_Magnifier_ZoomRegion_getProperties (zoom_region, &ev);
578  value = bonobo_pbclient_get_value (properties, "viewport", TC_GNOME_Magnifier_RectBounds, &ev);
579  memcpy (&zoomer_props->viewport, value->_value, sizeof (GNOME_Magnifier_RectBounds));
580  CORBA_free (value);
581  zoomer_props->is_managed = bonobo_pbclient_get_boolean (properties, "is-managed", NULL);
582  zoomer_props->scroll_policy = bonobo_pbclient_get_short (properties, "smooth-scroll-policy", NULL);
583  zoomer_props->contrast = bonobo_pbclient_get_float (properties, "contrast", NULL);
584  zoomer_props->zx = bonobo_pbclient_get_float (properties, "mag-factor-x", NULL);
585  zoomer_props->zy = bonobo_pbclient_get_float (properties, "mag-factor-y", NULL);
586  zoomer_props->xalign = bonobo_pbclient_get_long (properties, "x-alignment", NULL);
587  zoomer_props->yalign = bonobo_pbclient_get_long (properties, "y-alignment", NULL);
588  zoomer_props->border_color = bonobo_pbclient_get_long (properties, "border-color", NULL);
589  zoomer_props->border_size = bonobo_pbclient_get_long (properties, "border-size", NULL);
590  zoomer_props->smoothing_type = bonobo_pbclient_get_string (properties, "smoothing-type", NULL);
591  zoomer_props->inverse = bonobo_pbclient_get_boolean (properties, "inverse-video", NULL);
592 
593  bonobo_object_release_unref (properties, &ev);
594  magnifier_unref_zoom_region ((gpointer) zoom_region, NULL);
595  save_props = g_slist_append (save_props, zoomer_props);
596  }
597  list = g_list_next (list);
598  }
599 
600  magnifier->zoom_regions = NULL;
601  magnifier->zoom_regions_dbus = NULL;
602 
603  return save_props;
604 }
605 
606 static void
607 magnifier_zoom_regions_restore (Magnifier *magnifier, GSList *region_params)
608 {
609  GSList *list = region_params;
610 
611  while (list)
612  {
613  CORBA_Environment ev;
614  MagnifierZoomRegionSaveProps *zoomer_props = list->data;
615  GNOME_Magnifier_ZoomRegion new_region;
616  Bonobo_PropertyBag new_properties;
617 
618  CORBA_exception_init (&ev);
619  new_region = GNOME_Magnifier_Magnifier_createZoomRegion (BONOBO_OBJREF (magnifier), zoomer_props->zx, zoomer_props->zy, &zoomer_props->rectbounds, &zoomer_props->viewport, &ev);
620  new_properties = GNOME_Magnifier_ZoomRegion_getProperties (new_region, &ev);
621  bonobo_pbclient_set_boolean (new_properties, "is-managed",
622  zoomer_props->is_managed, NULL);
623  bonobo_pbclient_set_short (new_properties, "smooth-scroll-policy",
624  zoomer_props->scroll_policy, NULL);
625  bonobo_pbclient_set_float (new_properties, "contrast",
626  zoomer_props->contrast, NULL);
627 /* NOT YET USED
628  bonobo_pbclient_set_long (new_properties, "x-alignment",
629  zoomer_props->xalign, NULL);
630  bonobo_pbclient_set_long (new_properties, "y-alignment",
631  zoomer_props->yalign, NULL);
632 */
633  bonobo_pbclient_set_long (new_properties, "border-color",
634  zoomer_props->border_color, NULL);
635  bonobo_pbclient_set_long (new_properties, "border-size",
636  zoomer_props->border_size, NULL);
637  bonobo_pbclient_set_string (new_properties, "smoothing-type",
638  zoomer_props->smoothing_type, NULL);
639  bonobo_pbclient_set_boolean (new_properties, "inverse-video",
640  zoomer_props->inverse, NULL);
641  GNOME_Magnifier_Magnifier_addZoomRegion (BONOBO_OBJREF (magnifier), new_region, &ev);
642  g_free (zoomer_props->smoothing_type);
643  g_free (zoomer_props);
644  bonobo_object_release_unref (new_properties, &ev);
645  list = g_slist_next (list);
646  }
647  g_slist_free (region_params);
648 }
649 
650 static void
651 magnifier_init_display (Magnifier *magnifier, gchar *display_name, gboolean is_target)
652 {
653  if (!can_open_display (display_name))
654  return;
655 
656  if (is_target)
657  {
658  magnifier->target_screen_num =
659  magnifier_parse_display_name (magnifier,
660  display_name,
661  NULL);
662  magnifier->target_display =
663  gdk_display_open (display_name);
664  if (magnifier->target_display_name) g_free (magnifier->target_display_name);
665  magnifier->target_display_name = g_strdup (display_name);
666  magnifier->priv->root =
667  gdk_screen_get_root_window (
668  gdk_display_get_screen (
669  magnifier->target_display,
670  magnifier->target_screen_num));
671  }
672  else
673  {
674  magnifier->source_screen_num =
675  magnifier_parse_display_name (magnifier,
676  display_name,
677  NULL);
678  magnifier->source_display =
679  gdk_display_open (display_name);
680  if (magnifier->source_display)
681  {
682  if (magnifier->source_display_name) g_free (magnifier->source_display_name);
683  magnifier->source_display_name = g_strdup (display_name);
684  magnifier->priv->root =
685  gdk_screen_get_root_window (
686  gdk_display_get_screen (
687  magnifier->source_display,
688  magnifier->source_screen_num));
689  }
690  }
691 }
692 
693 static void
694 magnifier_exit (GtkObject *object)
695 {
696  gtk_main_quit ();
697  exit (0);
698 }
699 
700 #define GET_PIXEL(a,i,j,s,b) \
701 (*(guint32 *)(memcpy (b,(a) + ((j) * s + (i) * pixel_size_t), pixel_size_t)))
702 
703 #define PUT_PIXEL(a,i,j,s,b) \
704 (memcpy (a + ((j) * s + (i) * pixel_size_t), &(b), pixel_size_t))
705 
706 static void
707 magnifier_recolor_pixbuf (Magnifier *magnifier, GdkPixbuf *pixbuf)
708 {
709  int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
710  int i, j;
711  int w = gdk_pixbuf_get_width (pixbuf);
712  int h = gdk_pixbuf_get_height (pixbuf);
713  guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
714  guint32 pixval = 0, cursor_color = 0;
715  size_t pixel_size_t = 3; /* FIXME: invalid assumption ? */
716 
717  cursor_color = ((magnifier->cursor_color & 0xFF0000) >> 16) +
718  (magnifier->cursor_color & 0x00FF00) +
719  ((magnifier->cursor_color & 0x0000FF) << 16);
720  for (j = 0; j < h; ++j) {
721  for (i = 0; i < w; ++i) {
722  pixval = GET_PIXEL (pixels, i, j, rowstride, &pixval);
723  if ((pixval & 0x808080) == 0)
724  {
725  pixval = cursor_color;
726  PUT_PIXEL (pixels, i, j, rowstride,
727  pixval);
728  }
729  }
730  }
731 }
732 
733 void
735 {
736  if (magnifier->priv->cursor) /* don't do this if cursor isn't intialized yet */
737  {
738  int width, height;
739  int size_x, size_y;
740  GdkPixbuf *scaled_cursor_pixbuf;
741  GdkPixbuf *scaled_mask_pixbuf;
742  GdkPixbuf *scaled_mask_pixbuf_alpha;
743  GdkPixbuf *cursor_pixbuf;
744  GdkPixbuf *mask_pixbuf;
745  GdkPixmap *cursor_pixmap = magnifier->priv->cursor;
746  GdkPixmap *mask_pixmap = magnifier->priv->cursor_mask;
747  GdkGC *cgc;
748  GdkGC *mgc;
749 
750  if (magnifier->cursor_size_x)
751  {
752  size_x = magnifier->cursor_size_x;
753  size_y = magnifier->cursor_size_y;
754  }
755  else
756  {
757  size_x = magnifier->priv->cursor_default_size_x *
758  magnifier->cursor_scale_factor;
759  size_y = magnifier->priv->cursor_default_size_y *
760  magnifier->cursor_scale_factor;
761  }
762  gdk_drawable_get_size (magnifier->priv->cursor, &width, &height);
763  if ((size_x == width) && (size_y == height)
764  && (magnifier->cursor_color == 0xFF000000)) {
765  return; /* nothing changes */
766  }
767  cgc = gdk_gc_new (cursor_pixmap);
768  mgc = gdk_gc_new (mask_pixmap);
769  cursor_pixbuf = gdk_pixbuf_get_from_drawable (NULL, cursor_pixmap,
770  NULL, 0, 0, 0, 0,
771  width, height);
772  if (magnifier->cursor_color != 0xFF000000)
773  magnifier_recolor_pixbuf (magnifier, cursor_pixbuf);
774  mask_pixbuf = gdk_pixbuf_get_from_drawable (NULL,
775  mask_pixmap,
776  NULL, 0, 0, 0, 0,
777  width, height);
778  scaled_cursor_pixbuf = gdk_pixbuf_scale_simple (
779  cursor_pixbuf, size_x, size_y, GDK_INTERP_NEAREST);
780 
781  magnifier->cursor_hotspot.x = magnifier->priv->cursor_hotspot_x * size_x
782  / magnifier->priv->cursor_default_size_x;
783  magnifier->cursor_hotspot.y = magnifier->priv->cursor_hotspot_y * size_y
784  / magnifier->priv->cursor_default_size_y;
785 
786  scaled_mask_pixbuf = gdk_pixbuf_scale_simple (
787  mask_pixbuf, size_x, size_y, GDK_INTERP_NEAREST);
788  g_object_unref (cursor_pixbuf);
789  g_object_unref (mask_pixbuf);
790  g_object_unref (cursor_pixmap);
791  g_object_unref (mask_pixmap);
792  magnifier->priv->cursor = gdk_pixmap_new (
793  gtk_widget_get_window (magnifier->priv->w),
794  size_x, size_y,
795  -1);
796  if (!GDK_IS_DRAWABLE (magnifier->priv->cursor))
797  {
798  DBG (g_warning ("NULL magnifier cursor pixmap."));
799  return;
800  }
801  magnifier->priv->cursor_mask = gdk_pixmap_new (
802  gtk_widget_get_window (magnifier->priv->w),
803  size_x, size_y,
804  1);
805  if (GDK_IS_DRAWABLE (magnifier->priv->cursor)) {
806  gdk_draw_pixbuf (magnifier->priv->cursor,
807  cgc,
808  scaled_cursor_pixbuf,
809  0, 0, 0, 0, size_x, size_y,
810  GDK_RGB_DITHER_NONE, 0, 0 );
811  }
812  else
813  DBG (g_warning ("cursor pixmap is non-drawable."));
814  scaled_mask_pixbuf_alpha = gdk_pixbuf_add_alpha (
815  scaled_mask_pixbuf, True, 0, 0, 0);
816  gdk_pixbuf_render_threshold_alpha (scaled_mask_pixbuf_alpha,
817  magnifier->priv->cursor_mask,
818  0, 0, 0, 0, size_x, size_y,
819  0x80);
820  g_object_unref (scaled_mask_pixbuf_alpha);
821  g_object_unref (scaled_cursor_pixbuf);
822  g_object_unref (scaled_mask_pixbuf);
823  g_object_unref (mgc);
824  g_object_unref (cgc);
825  }
826 }
827 
828 static void
829 magnifier_init_cursor_set (Magnifier *magnifier, gchar *cursor_set)
830 {
831  /*
832  * we check the cursor-set property string here,
833  * and create/apply the appropriate cursor settings
834  */
835  magnifier->cursor_set = cursor_set;
836  magnifier->priv->use_source_cursor =
837  (!strcmp (cursor_set, "default") &&
838  (fixes_event_base != 0));
839  if (magnifier->priv->use_source_cursor) return;
840 
841  if (!strcmp (magnifier->cursor_set, "none")) {
842  magnifier->priv->cursor = NULL;
843  return;
844  }
845  else
846  {
847  GDir *cursor_dir;
848  const gchar *filename;
849  gchar *cursor_dirname;
850 
851  if (magnifier->priv->cursorlist)
852  {
853  g_hash_table_destroy (magnifier->priv->cursorlist);
854  }
855  magnifier->priv->cursorlist = g_hash_table_new_full (g_str_hash, g_str_equal,
856  g_free, g_object_unref);
857 
858  cursor_dirname = g_strconcat (CURSORSDIR, "/", magnifier->cursor_set, NULL);
859  cursor_dir = g_dir_open (cursor_dirname, 0, NULL);
860  /* assignment, not comparison, is intentional */
861  while (cursor_dir && (filename = g_dir_read_name (cursor_dir)) != NULL)
862  {
863  if (filename)
864  {
865  gchar *path = g_strconcat (cursor_dirname, "/", filename, NULL);
866  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (path, NULL);
867  if (pixbuf)
868  {
869  /* add this pixbuf and its name to our list */
870  gchar **sv, *cname;
871  cname = g_path_get_basename (filename);
872  sv = g_strsplit (cname, ".", 2);
873  g_hash_table_insert (magnifier->priv->cursorlist,
874  g_strdup (sv[0]),
875  pixbuf);
876  g_free (cname);
877  g_strfreev (sv);
878  }
879  g_free (path);
880  }
881  }
882  g_free (cursor_dirname);
883  if (cursor_dir) g_dir_close (cursor_dir);
884  }
885  /* don't fallover to source cursor here, we haven't initialized X yet */
886  magnifier_set_cursor_pixmap_by_name (magnifier, "default", FALSE);
887  magnifier_transform_cursor (magnifier);
888 }
889 
890 static gboolean
892 {
893  if (data)
894  {
895  Magnifier *magnifier = MAGNIFIER (data);
896 #if GTK_CHECK_VERSION (2,19,5)
897  if (magnifier->priv &&
898  gtk_widget_get_realized (magnifier->priv->w) &&
899  gmag_gs_check_set_struts (magnifier)) {
900  return FALSE;
901  }
902 #else
903  if (magnifier->priv &&
904  GTK_WIDGET_REALIZED (magnifier->priv->w) &&
905  gmag_gs_check_set_struts (magnifier)) {
906  return FALSE;
907  }
908 #endif
909  }
910  return TRUE;
911 }
912 
913 static void
914 magnifier_get_property (BonoboPropertyBag *bag,
915  BonoboArg *arg,
916  guint arg_id,
917  CORBA_Environment *ev,
918  gpointer user_data)
919 {
920  Magnifier *magnifier = user_data;
921  int csize = 0;
922 
923  DBG (fprintf (stderr, "Get property: \t%s\n", mag_prop_names[arg_id]));
924 
925  switch (arg_id) {
927  BONOBO_ARG_SET_GENERAL (arg, magnifier->source_bounds,
930  break;
932  BONOBO_ARG_SET_GENERAL (arg, magnifier->target_bounds,
935 
936  break;
938  BONOBO_ARG_SET_STRING (arg, magnifier->cursor_set);
939  break;
941  BONOBO_ARG_SET_INT (arg, magnifier->cursor_size_x);
942  BONOBO_ARG_SET_INT (arg, magnifier->cursor_size_y);
943  break;
945  BONOBO_ARG_SET_FLOAT (arg, magnifier->cursor_scale_factor);
946  break;
948  BONOBO_ARG_SET_GENERAL (arg, magnifier->cursor_color,
949  TC_CORBA_unsigned_long,
950  CORBA_unsigned_long, NULL);
951  break;
953  BONOBO_ARG_SET_GENERAL (arg, magnifier->cursor_hotspot,
955  GNOME_Magnifier_Point, NULL);
956 
957  break;
959  if (magnifier->priv->cursor)
960  gdk_drawable_get_size (magnifier->priv->cursor,
961  &csize, &csize);
962  BONOBO_ARG_SET_INT (arg, csize);
963  break;
965  BONOBO_ARG_SET_INT (arg, magnifier->crosswire_size);
966  break;
968  BONOBO_ARG_SET_INT (arg, magnifier->crosswire_length);
969  break;
971  BONOBO_ARG_SET_BOOLEAN (arg, magnifier->crosswire_clip);
972  break;
974  BONOBO_ARG_SET_LONG (arg, magnifier->crosswire_color);
975  break;
977  BONOBO_ARG_SET_STRING (arg, magnifier->source_display_name);
978  break;
980  BONOBO_ARG_SET_STRING (arg, magnifier->target_display_name);
981  break;
982  default:
983  bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
984  };
985 }
986 
987 gboolean
988 impl_dbus_magnifier_set_source_display (Magnifier *magnifier, gchar *source_display)
989 {
990  gchar *full_display_string = source_display;
991  if (can_open_display (full_display_string))
992  {
993  GSList *zoom_region_params = NULL;
994  magnifier->source_screen_num =
995  magnifier_parse_display_name (magnifier,
996  full_display_string,
997  NULL);
998  magnifier->source_display =
999  gdk_display_open (full_display_string);
1000  magnifier->source_display_name = g_strdup (full_display_string);
1001  zoom_region_params = magnifier_zoom_regions_save (magnifier);
1002  magnifier->priv->root =
1003  gdk_screen_get_root_window (
1004  gdk_display_get_screen (
1005  magnifier->source_display,
1006  magnifier->source_screen_num));
1007 
1008  /* remove the source_drawable, since in the new display the
1009  * composite can be unavailable and the source_drawable is
1010  * where the desktop screen is composed. If this is not
1011  * freed it will be used even if the display doesn't use
1012  * composite what will lead to wrong behavior and crashes.
1013  * If composite is used in the new display this variable is
1014  * re-created */
1015  if (magnifier->priv->source_drawable) {
1016  g_object_unref (magnifier->priv->source_drawable);
1017  magnifier->priv->source_drawable = NULL;
1018  }
1019 
1020  /* attach listeners for DAMAGE, "dirty region", XFIXES
1021  * cursor changes */
1022  magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
1023  magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
1024  magnifier_adjust_source_size (magnifier);
1025  magnifier_zoom_regions_restore (magnifier, zoom_region_params);
1026  magnifier_warp_cursor_to_screen (magnifier);
1027  gmag_gs_check_set_struts (magnifier);
1028  gmag_gs_reset_overlay_at_idle (magnifier);
1029  }
1030  DBG(fprintf (stderr, "Set source display: \t%s\n", full_display_string));
1031 
1032  return TRUE;
1033 }
1034 
1035 gchar*
1037 {
1038  return g_strdup (magnifier->source_display_name);
1039 }
1040 
1041 gboolean
1042 impl_dbus_magnifier_set_target_display (Magnifier *magnifier, gchar *target_display)
1043 {
1044  gchar *full_display_string = target_display;
1045  if (can_open_display (full_display_string))
1046  {
1047  magnifier->target_screen_num =
1048  magnifier_parse_display_name (magnifier,
1049  full_display_string,
1050  NULL);
1051  magnifier->target_display =
1052  gdk_display_open (full_display_string);
1053  magnifier->target_display_name = g_strdup (full_display_string);
1054  if (GTK_IS_WINDOW (magnifier->priv->w))
1055  {
1056 #ifdef REPARENT_GTK_WINDOW_WORKS
1057  gtk_window_set_screen (GTK_WINDOW (magnifier->priv->w),
1058  gdk_display_get_screen (
1059  magnifier->target_display,
1060  magnifier->target_screen_num));
1061 #else
1062  GSList *zoom_region_params = NULL;
1063  /* disconnect from the old window's destroy signal */
1064  g_object_disconnect (magnifier->priv->w,
1065  "any_signal::realize", magnifier_realize, NULL,
1066  "any_signal::size_allocate", magnifier_size_allocate, NULL,
1067  "any_signal::destroy", magnifier_exit, NULL,
1068  NULL);
1069  /* save the old zoom region state */
1070  zoom_region_params = magnifier_zoom_regions_save (magnifier);
1071  /* destroy the old window */
1072  gtk_widget_destroy (magnifier->priv->w);
1073  /* and re-initialize... */
1074  magnifier_init_window (magnifier, gdk_display_get_screen (
1075  magnifier->target_display,
1076  magnifier->target_screen_num));
1077  /* restore the zoom regions in their new host magnifier window */
1078  magnifier_zoom_regions_restore (magnifier, zoom_region_params);
1079 #endif
1080  }
1081  magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
1082  magnifier_init_cursor_set (magnifier, magnifier->cursor_set); /* needed to reset pixmaps */
1083  if (magnifier->priv->overlay)
1084  gdk_window_move (magnifier->priv->overlay,
1085  magnifier->target_bounds.x1,
1086  magnifier->target_bounds.y1);
1087  else
1088  gtk_window_move (GTK_WINDOW (magnifier->priv->w),
1089  magnifier->target_bounds.x1,
1090  magnifier->target_bounds.y1);
1091 
1092  if ((magnifier->target_bounds.x2 - magnifier->target_bounds.x1 > 0) &&
1093  (magnifier->target_bounds.y2 - magnifier->target_bounds.y1) > 0)
1094  {
1095  if (magnifier->priv->overlay)
1096  gdk_window_resize (
1097  magnifier->priv->overlay,
1098  magnifier->target_bounds.x2 -
1099  magnifier->target_bounds.x1,
1100  magnifier->target_bounds.y2 -
1101  magnifier->target_bounds.y1);
1102  gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
1103  magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
1104  magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
1105  DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n",
1106  magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
1107  }
1108  /* N. B. we don't reset the target bounds to the limits of the new display, because */
1109  /* doing so would override the client-specified magnifier size */
1110  /* magnifier_get_display_rect_bounds (magnifier, &magnifier->target_bounds, TRUE); */
1111  gmag_gs_check_set_struts (magnifier);
1112  }
1113  DBG(fprintf (stderr, "Set target display: \t%s (screen %d)\n",
1114  full_display_string, magnifier->target_screen_num));
1115 
1116  return TRUE;
1117 }
1118 
1119 gchar*
1121 {
1122  return g_strdup (magnifier->target_display_name);
1123 }
1124 
1125 gboolean
1126 impl_dbus_magnifier_set_source_size (Magnifier *magnifier, gint32 **bounds)
1127 {
1128  magnifier->source_bounds.x1 = (*bounds)[0];
1129  magnifier->source_bounds.y1 = (*bounds)[1];
1130  magnifier->source_bounds.x2 = (*bounds)[2];
1131  magnifier->source_bounds.y2 = (*bounds)[3];
1132  DBG (fprintf (stderr, "Set source size: \t%d,%d to %d,%d\n",
1133  magnifier->source_bounds.x1, magnifier->source_bounds.y1, magnifier->source_bounds.x2, magnifier->source_bounds.y2));
1134 
1135  return TRUE;
1136 }
1137 
1138 GArray*
1140 {
1141  GArray *ret = g_array_new (FALSE, FALSE, sizeof (gint32));
1142 
1143  g_array_append_val (ret, magnifier->source_bounds.x1);
1144  g_array_append_val (ret, magnifier->source_bounds.y1);
1145  g_array_append_val (ret, magnifier->source_bounds.x2);
1146  g_array_append_val (ret, magnifier->source_bounds.y2);
1147 
1148  return ret;
1149 }
1150 
1151 gboolean
1152 impl_dbus_magnifier_set_target_size (Magnifier *magnifier, gint32 **bounds)
1153 {
1154  magnifier->target_bounds.x1 = (*bounds)[0];
1155  magnifier->target_bounds.y1 = (*bounds)[1];
1156  magnifier->target_bounds.x2 = (*bounds)[2];
1157  magnifier->target_bounds.y2 = (*bounds)[3];
1158 
1159  if (magnifier->priv->overlay)
1160  gdk_window_move_resize (magnifier->priv->overlay,
1161  magnifier->target_bounds.x1,
1162  magnifier->target_bounds.y1,
1163  magnifier->target_bounds.x2 -
1164  magnifier->target_bounds.x1,
1165  magnifier->target_bounds.y2 -
1166  magnifier->target_bounds.y1);
1167  else
1168  gtk_window_move (GTK_WINDOW (magnifier->priv->w),
1169  magnifier->target_bounds.x1,
1170  magnifier->target_bounds.y1);
1171 
1172  gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
1173  magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
1174  magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
1175  gmag_gs_check_set_struts (magnifier);
1176  DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n",
1177  magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
1178  if (!strcmp (magnifier->target_display_name, magnifier->source_display_name) &&
1179  (magnifier->target_screen_num == magnifier->source_screen_num))
1180  magnifier_adjust_source_size (magnifier);
1181 
1182  return TRUE;
1183 }
1184 
1185 GArray*
1187 {
1188  GArray *ret = g_array_new (FALSE, FALSE, sizeof (gint32));
1189 
1190  g_array_append_val (ret, magnifier->target_bounds.x1);
1191  g_array_append_val (ret, magnifier->target_bounds.y1);
1192  g_array_append_val (ret, magnifier->target_bounds.x2);
1193  g_array_append_val (ret, magnifier->target_bounds.y2);
1194 
1195  return ret;
1196 }
1197 
1198 gboolean
1199 impl_dbus_magnifier_set_cursor_set (Magnifier *magnifier, gchar *cursor_set)
1200 {
1201  magnifier_init_cursor_set (magnifier, g_strdup (cursor_set));
1202  DBG (fprintf (stderr, "Setting cursor set: \t%s\n", cursor_set));
1203 
1204  return TRUE;
1205 }
1206 
1207 gchar*
1209 {
1210  return g_strdup (magnifier->cursor_set);
1211 }
1212 
1213 gboolean
1215 {
1216  magnifier->cursor_size_x = x;
1217  magnifier->cursor_size_y = y;
1218  magnifier_transform_cursor (magnifier);
1219  DBG (fprintf (stderr, "Setting cursor size: \t%d\n", magnifier->cursor_size_x));
1220 
1221  return TRUE;
1222 }
1223 
1224 GArray*
1226 {
1227  GArray *ret = g_array_new (FALSE, FALSE, sizeof (gint));
1228 
1229  g_array_append_val (ret, magnifier->cursor_size_x);
1230  g_array_append_val (ret, magnifier->cursor_size_y);
1231 
1232  return ret;
1233 }
1234 
1235 gboolean
1237 {
1238  magnifier->cursor_scale_factor = factor;
1239  DBG (fprintf (stderr, "Setting cursor scale factor: \t%f\n", magnifier->cursor_scale_factor));
1240  magnifier_transform_cursor (magnifier);
1241 
1242  return TRUE;
1243 }
1244 
1245 double
1247 {
1248  return magnifier->cursor_scale_factor;
1249 }
1250 
1251 gboolean
1253 {
1254  magnifier->cursor_color = color;
1255  magnifier_transform_cursor (magnifier);
1256  DBG (fprintf (stderr, "Setting cursor color: \t%u\n", (unsigned) magnifier->cursor_color));
1257 
1258  return TRUE;
1259 }
1260 
1261 guint32
1263 {
1264  return magnifier->cursor_color;
1265 }
1266 
1267 gboolean
1268 impl_dbus_magnifier_set_cursor_hotspot (Magnifier *magnifier, gint32 x, gint32 y)
1269 {
1270  magnifier->cursor_hotspot.x = x;
1271  magnifier->cursor_hotspot.y = y;
1272  magnifier_transform_cursor (magnifier);
1273 
1274  return TRUE;
1275 }
1276 
1277 GArray*
1279 {
1280  GArray *ret = g_array_new (FALSE, FALSE, sizeof (gint32));
1281 
1282  g_array_append_val (ret, magnifier->cursor_hotspot.x);
1283  g_array_append_val (ret, magnifier->cursor_hotspot.y);
1284 
1285  return ret;
1286 }
1287 
1288 gint32
1290 {
1291  gint32 csize;
1292 
1293  if (magnifier->priv->cursor) {
1294  gdk_drawable_get_size (magnifier->priv->cursor, &csize, &csize);
1295  }
1296 
1297  return csize;
1298 }
1299 
1300 gboolean
1302 {
1303  magnifier->crosswire_size = size;
1304  DBG (fprintf (stderr, "Setting crosswire size: \t%d\n", magnifier->crosswire_size));
1306 
1307  return TRUE;
1308 }
1309 
1310 gint
1312 {
1313  return magnifier->crosswire_size;
1314 }
1315 
1316 gboolean
1318 {
1319  GNOME_Magnifier_RectBounds rect_bounds;
1320  rect_bounds.x1 = 0;
1321  rect_bounds.y1 = 0;
1322  rect_bounds.x2 = 4096;
1323  rect_bounds.y2 = 4096;
1324 
1325  magnifier->crosswire_length = length;
1326  DBG (fprintf (stderr, "Setting crosswire length: \t%d\n", magnifier->crosswire_length));
1327  magnifier_zoom_regions_mark_dirty (magnifier, rect_bounds);
1328 
1329  return TRUE;
1330 }
1331 
1332 gboolean
1334 {
1335  magnifier->crosswire_clip = clip;
1336  DBG (fprintf (stderr, "Setting crosswire clip: \t%s\n", magnifier->crosswire_clip ? "true" : "false"));
1338 
1339  return TRUE;
1340 }
1341 
1342 gboolean
1344 {
1345  return magnifier->crosswire_clip;
1346 }
1347 
1348 gint
1350  return magnifier->crosswire_length;
1351 }
1352 
1353 gboolean
1355 {
1356  magnifier->crosswire_color = color;
1357  DBG (fprintf (stderr, "Setting crosswire color: \t%ld\n", (long) magnifier->crosswire_color));
1358 
1359  return TRUE;
1360 }
1361 
1362 guint32
1364 {
1365  return magnifier->crosswire_color;
1366 }
1367 
1368 static void
1369 magnifier_set_property (BonoboPropertyBag *bag,
1370  BonoboArg *arg,
1371  guint arg_id,
1372  CORBA_Environment *ev,
1373  gpointer user_data)
1374 {
1375  Magnifier *magnifier = user_data;
1376  gchar *full_display_string;
1377 
1378  GNOME_Magnifier_RectBounds rect_bounds;
1379  rect_bounds.x1 = 0;
1380  rect_bounds.y1 = 0;
1381  rect_bounds.x2 = 4096;
1382  rect_bounds.y2 = 4096;
1383 
1384  switch (arg_id) {
1386  full_display_string = BONOBO_ARG_GET_STRING (arg);
1387  if (can_open_display (full_display_string))
1388  {
1389  GSList *zoom_region_params = NULL;
1390  magnifier->source_screen_num =
1391  magnifier_parse_display_name (magnifier,
1392  full_display_string,
1393  NULL);
1394  magnifier->source_display =
1395  gdk_display_open (full_display_string);
1396  magnifier->source_display_name = g_strdup (full_display_string);
1397  zoom_region_params = magnifier_zoom_regions_save (magnifier);
1398  magnifier->priv->root =
1399  gdk_screen_get_root_window (
1400  gdk_display_get_screen (
1401  magnifier->source_display,
1402  magnifier->source_screen_num));
1403 
1404  /* remove the source_drawable, since in the new display the
1405  * composite can be unavailable and the source_drawable is
1406  * where the desktop screen is composed. If this is not
1407  * freed it will be used even if the display doesn't use
1408  * composite what will lead to wrong behavior and crashes.
1409  * If composite is used in the new display this variable is
1410  * re-created */
1411  if (magnifier->priv->source_drawable) {
1412  g_object_unref (magnifier->priv->source_drawable);
1413  magnifier->priv->source_drawable = NULL;
1414  }
1415 
1416  /* attach listeners for DAMAGE, "dirty region", XFIXES
1417  * cursor changes */
1418  magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
1419  magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
1420  magnifier_adjust_source_size (magnifier);
1421  magnifier_zoom_regions_restore (magnifier, zoom_region_params);
1422  magnifier_warp_cursor_to_screen (magnifier);
1423  gmag_gs_check_set_struts (magnifier);
1424  gmag_gs_reset_overlay_at_idle (magnifier);
1425  }
1426  DBG(fprintf (stderr, "Set source display: \t%s\n", full_display_string));
1427  break;
1429  full_display_string = BONOBO_ARG_GET_STRING (arg);
1430  if (can_open_display (full_display_string))
1431  {
1432  magnifier->target_screen_num =
1433  magnifier_parse_display_name (magnifier,
1434  full_display_string,
1435  NULL);
1436  magnifier->target_display =
1437  gdk_display_open (full_display_string);
1438  magnifier->target_display_name = g_strdup (full_display_string);
1439  if (GTK_IS_WINDOW (magnifier->priv->w))
1440  {
1441 #ifdef REPARENT_GTK_WINDOW_WORKS
1442  gtk_window_set_screen (GTK_WINDOW (magnifier->priv->w),
1443  gdk_display_get_screen (
1444  magnifier->target_display,
1445  magnifier->target_screen_num));
1446 #else
1447  GSList *zoom_region_params = NULL;
1448  /* disconnect from the old window's destroy signal */
1449  g_object_disconnect (magnifier->priv->w,
1450  "any_signal::realize", magnifier_realize, NULL,
1451  "any_signal::size_allocate", magnifier_size_allocate, NULL,
1452  "any_signal::destroy", magnifier_exit, NULL,
1453  NULL);
1454  /* save the old zoom region state */
1455  zoom_region_params = magnifier_zoom_regions_save (magnifier);
1456  /* destroy the old window */
1457  gtk_widget_destroy (magnifier->priv->w);
1458  /* and re-initialize... */
1459  magnifier_init_window (magnifier, gdk_display_get_screen (
1460  magnifier->target_display,
1461  magnifier->target_screen_num));
1462  /* restore the zoom regions in their new host magnifier window */
1463  magnifier_zoom_regions_restore (magnifier, zoom_region_params);
1464 #endif
1465  }
1466  magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
1467  magnifier_init_cursor_set (magnifier, magnifier->cursor_set); /* needed to reset pixmaps */
1468  if (magnifier->priv->overlay)
1469  gdk_window_move (magnifier->priv->overlay,
1470  magnifier->target_bounds.x1,
1471  magnifier->target_bounds.y1);
1472  else
1473  gtk_window_move (GTK_WINDOW (magnifier->priv->w),
1474  magnifier->target_bounds.x1,
1475  magnifier->target_bounds.y1);
1476 
1477  if ((magnifier->target_bounds.x2 - magnifier->target_bounds.x1 > 0) &&
1478  (magnifier->target_bounds.y2 - magnifier->target_bounds.y1) > 0)
1479  {
1480  if (magnifier->priv->overlay)
1481  gdk_window_resize (
1482  magnifier->priv->overlay,
1483  magnifier->target_bounds.x2 -
1484  magnifier->target_bounds.x1,
1485  magnifier->target_bounds.y2 -
1486  magnifier->target_bounds.y1);
1487  gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
1488  magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
1489  magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
1490  DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n",
1491  magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
1492  }
1493  /* N. B. we don't reset the target bounds to the limits of the new display, because */
1494  /* doing so would override the client-specified magnifier size */
1495  /* magnifier_get_display_rect_bounds (magnifier, &magnifier->target_bounds, TRUE); */
1496  gmag_gs_check_set_struts (magnifier);
1497  }
1498  DBG(fprintf (stderr, "Set target display: \t%s (screen %d)\n",
1499  full_display_string, magnifier->target_screen_num));
1500  break;
1502  magnifier->source_bounds = BONOBO_ARG_GET_GENERAL (arg,
1505  NULL);
1506  DBG (fprintf (stderr, "Set source size: \t%d,%d to %d,%d\n",
1507  magnifier->source_bounds.x1, magnifier->source_bounds.y1, magnifier->source_bounds.x2, magnifier->source_bounds.y2));
1508  break;
1510  magnifier->target_bounds = BONOBO_ARG_GET_GENERAL (arg,
1513 
1514  NULL);
1515  if (magnifier->priv->overlay)
1516  gdk_window_move_resize (magnifier->priv->overlay,
1517  magnifier->target_bounds.x1,
1518  magnifier->target_bounds.y1,
1519  magnifier->target_bounds.x2 -
1520  magnifier->target_bounds.x1,
1521  magnifier->target_bounds.y2 -
1522  magnifier->target_bounds.y1);
1523  else
1524  gtk_window_move (GTK_WINDOW (magnifier->priv->w),
1525  magnifier->target_bounds.x1,
1526  magnifier->target_bounds.y1);
1527 
1528  gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
1529  magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
1530  magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
1531  gmag_gs_check_set_struts (magnifier);
1532  DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n",
1533  magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
1534  if (!strcmp (magnifier->target_display_name, magnifier->source_display_name) &&
1535  (magnifier->target_screen_num == magnifier->source_screen_num))
1536  magnifier_adjust_source_size (magnifier);
1537  break;
1539  magnifier_init_cursor_set (magnifier, g_strdup (BONOBO_ARG_GET_STRING (arg)));
1540  DBG (fprintf (stderr, "Setting cursor set: \t%s\n", BONOBO_ARG_GET_STRING (arg)));
1541  break;
1543  magnifier->cursor_size_x = BONOBO_ARG_GET_INT (arg);
1544  magnifier->cursor_size_y = BONOBO_ARG_GET_INT (arg);
1545  magnifier_transform_cursor (magnifier);
1546  DBG (fprintf (stderr, "Setting cursor size: \t%d\n", magnifier->cursor_size_x));
1547  break;
1549  magnifier->cursor_scale_factor = BONOBO_ARG_GET_FLOAT (arg);
1550  DBG (fprintf (stderr, "Setting cursor scale factor: \t%f\n", (float) magnifier->cursor_scale_factor));
1551  magnifier_transform_cursor (magnifier);
1552  break;
1554  magnifier->cursor_color = BONOBO_ARG_GET_GENERAL (arg,
1555  TC_CORBA_unsigned_long,
1556  CORBA_unsigned_long,
1557  NULL);
1558  magnifier_transform_cursor (magnifier);
1559  DBG (fprintf (stderr, "Setting cursor color: \t%u\n", (unsigned) magnifier->cursor_color));
1560  break;
1562  magnifier->cursor_hotspot = BONOBO_ARG_GET_GENERAL (arg,
1565  NULL);
1566  /* TODO: notify zoomers */
1567  /* FIXME: don't call init_cursor, it overwrites this property! */
1568  magnifier_transform_cursor (magnifier);
1569  break;
1571  bonobo_exception_set (ev, ex_Bonobo_PropertyBag_ReadOnly);
1572  break;
1574  magnifier->crosswire_size = BONOBO_ARG_GET_INT (arg);
1575  DBG (fprintf (stderr, "Setting crosswire size: \t%d\n", magnifier->crosswire_size));
1577  break;
1579  magnifier->crosswire_length = BONOBO_ARG_GET_INT (arg);
1580  DBG (fprintf (stderr, "Setting crosswire length: \t%d\n", magnifier->crosswire_length));
1581  /* FIXME: The call below forces the repaint of all the screen,
1582  * but I can't figure a better solution right now to the case
1583  * where the crosswire lenght decrease */
1584  magnifier_zoom_regions_mark_dirty (magnifier, rect_bounds);
1585  break;
1587  magnifier->crosswire_clip = BONOBO_ARG_GET_BOOLEAN (arg);
1588  DBG (fprintf (stderr, "Setting crosswire clip: \t%s\n", magnifier->crosswire_clip ? "true" : "false"));
1590  break;
1592  magnifier->crosswire_color = BONOBO_ARG_GET_LONG (arg);
1593  DBG (fprintf (stderr, "Setting crosswire size: \t%ld\n", (long) magnifier->crosswire_color));
1594  break;
1595  default:
1596  bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
1597  break;
1598  };
1599 }
1600 
1601 static void
1603 {
1604  /* FIXME: this is dead ropey code structuring */
1605  bonobo_activation_active_server_unregister (
1606  MAGNIFIER_OAFIID, BONOBO_OBJREF (magnifier));
1607 
1608  if (magnifier->zoom_regions_dbus)
1609  g_list_free (magnifier->zoom_regions_dbus);
1610  if (magnifier->zoom_regions)
1611  g_list_free (magnifier->zoom_regions);
1612  magnifier->zoom_regions = NULL;
1613  magnifier->zoom_regions_dbus = NULL;
1614 
1615  bonobo_main_quit ();
1616 }
1617 
1618 static void
1619 magnifier_gobject_dispose (GObject *object)
1620 {
1621  magnifier_do_dispose (MAGNIFIER (object));
1622 
1623  BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
1624 }
1625 
1626 static inline
1627 CORBA_boolean
1628 impl_magnifier_support_colorblind_filters (PortableServer_Servant _servant G_GNUC_UNUSED,
1629  CORBA_Environment *ev G_GNUC_UNUSED)
1630 {
1631 #ifdef HAVE_COLORBLIND
1632  return CORBA_TRUE;
1633 #else
1634  return CORBA_FALSE;
1635 #endif
1636 }
1637 
1638 static void
1639 impl_magnifier_hide_cursor (PortableServer_Servant servant,
1640  CORBA_Environment *ev)
1641 {
1642  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1643 
1644  gmag_gs_hide_cursor (magnifier);
1645 }
1646 
1647 static void
1648 impl_magnifier_show_cursor (PortableServer_Servant servant,
1649  CORBA_Environment *ev)
1650 {
1651  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1652 
1653  gmag_gs_show_cursor (magnifier);
1654 }
1655 
1656 static
1657 CORBA_boolean
1658 impl_magnifier_full_screen_capable (PortableServer_Servant servant,
1659  CORBA_Environment * ev)
1660 {
1661  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1662 
1663  if ((strcmp (magnifier->source_display_name,
1664  magnifier->target_display_name) != 0) ||
1665  gmag_gs_use_compositor (magnifier))
1666  return CORBA_TRUE;
1667 
1668  return CORBA_FALSE;
1669 }
1670 
1671 gboolean
1673 {
1674  if ((strcmp (magnifier->source_display_name,
1675  magnifier->target_display_name) != 0) ||
1676  gmag_gs_use_compositor (magnifier)) {
1677  return TRUE;
1678  }
1679 
1680  return FALSE;
1681 }
1682 
1683 gboolean
1685 {
1686  gmag_gs_hide_cursor (magnifier);
1687 
1688  return TRUE;
1689 }
1690 
1691 gboolean
1693 {
1694  gmag_gs_show_cursor (magnifier);
1695 
1696  return TRUE;
1697 }
1698 
1699 gboolean
1701 {
1702 #ifdef HAVE_COLORBLIND
1703  return TRUE;
1704 #else
1705  return FALSE;
1706 #endif
1707 }
1708 
1709 gchar*
1711  const double zx,
1712  const double zy,
1713  const gint32 **roi,
1714  const gint32 **viewport)
1715 {
1717 
1718  DBG (fprintf (stderr, "Create zoom region: \tzoom %f,%f, viewport %d,%d to %d,%d\n", (float) zx, (float) zy, (*viewport)[0]/*x1*/, (*viewport)[1]/*y1*/, (*viewport)[2]/*x2*/, (*viewport)[3]/*y3*/));
1719 
1720  /* FIXME:
1721  * shouldn't do this here, since it causes the region to get
1722  * mapped onto the parent, if if it's not explicitly added!
1723  */
1724  DBG(g_message ("creating zoom region with parent %p", magnifier));
1725  zoom_region->priv->parent = magnifier;
1726 
1727  impl_dbus_zoom_region_set_mag_factor (zoom_region, zx, zy);
1728 
1729  impl_dbus_zoom_region_move_resize (zoom_region, viewport);
1730 
1731  impl_dbus_zoom_region_set_roi (zoom_region, roi);
1732 
1733  gtk_widget_set_size_request (magnifier->priv->canvas,
1734  (*viewport)[2] - (*viewport)[0],
1735  (*viewport)[3] - (*viewport)[1]);
1736  gtk_widget_show (magnifier->priv->canvas);
1737  gtk_widget_show (magnifier->priv->w);
1738 
1739  g_hash_table_insert (zoom_hash, g_strdup(zoom_region->object_path), zoom_region);
1740 
1741  return g_strdup (zoom_region->object_path);
1742 }
1743 
1744 gchar**
1746 {
1748  gchar **list;
1749  int i, len;
1750 
1751  len = g_list_length (magnifier->zoom_regions);
1752  list = g_malloc0 (sizeof (gchar *) * len);
1753  for (i = 0; i < len; ++i) {
1754  zoom_region = g_list_nth_data (magnifier->zoom_regions_dbus, i);
1755  list[i] = g_strdup (zoom_region->object_path);
1756  }
1757 
1758  DBG (fprintf (stderr, "Get zoom regions: \t%d\n", len));
1759 
1760  return list;
1761 }
1762 
1763 gboolean
1764 impl_dbus_magnifier_add_zoom_region (Magnifier *magnifier, gchar *zoom_region_path)
1765 {
1766  if (!magnifier->source_initialized)
1767  {
1768  magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
1769  }
1770 
1771  /* FIXME: this needs proper lifecycle management */
1772  ZoomRegion *zoom_region = g_hash_table_lookup (zoom_hash, zoom_region_path);
1773  magnifier->zoom_regions = g_list_append (magnifier->zoom_regions, BONOBO_OBJREF (zoom_region));
1774  magnifier->zoom_regions_dbus = g_list_append (magnifier->zoom_regions_dbus, zoom_region);
1775  g_hash_table_remove (zoom_hash, zoom_region_path);
1776  gmag_gs_check_set_struts (magnifier);
1777 
1778  return TRUE;
1779 }
1780 
1781 gboolean
1783 {
1784  g_list_foreach (magnifier->zoom_regions_dbus,
1786  g_list_foreach (magnifier->zoom_regions,
1787  magnifier_unref_zoom_region, magnifier);
1788  g_list_free (magnifier->zoom_regions);
1789  g_list_free (magnifier->zoom_regions_dbus);
1790  magnifier->zoom_regions = NULL;
1791  magnifier->zoom_regions_dbus = NULL;
1792 
1793  return TRUE;
1794 }
1795 
1796 gboolean
1798 {
1799  magnifier_do_dispose (magnifier);
1800 
1801  return TRUE;
1802 }
1803 
1804 static void
1805 impl_magnifier_set_source_display (PortableServer_Servant servant,
1806  const CORBA_char *display,
1807  CORBA_Environment *ev)
1808 {
1809  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1810  BonoboArg *arg = bonobo_arg_new (BONOBO_ARG_STRING);
1811  gchar *full_display_string;
1812 
1813  full_display_string = g_strdup (display);
1814  if (strcmp (full_display_string, "") == 0)
1815  full_display_string = (gchar *) g_getenv ("DISPLAY");
1816 
1817  BONOBO_ARG_SET_STRING (arg, full_display_string);
1818 
1819  DBG (fprintf (stderr, "Set source display: \t%s\n",
1820  full_display_string));
1821 
1822  if (strcmp (full_display_string, magnifier->source_display_name)) {
1824  arg,
1826  ev,
1827  magnifier);
1828  }
1829  else
1830  {
1831  DBG (fprintf (stderr, "Attempt to set source to same value as previous: %s\n",
1832  full_display_string));
1833  }
1834  bonobo_arg_release (arg);
1835 }
1836 
1837 static void
1838 impl_magnifier_set_target_display (PortableServer_Servant servant,
1839  const CORBA_char *display,
1840  CORBA_Environment *ev)
1841 {
1842  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1843  BonoboArg *arg = bonobo_arg_new (BONOBO_ARG_STRING);
1844  gchar *full_display_string;
1845 
1846  full_display_string = g_strdup (display);
1847  if (strcmp (full_display_string, "") == 0)
1848  full_display_string = (gchar *) g_getenv ("DISPLAY");
1849 
1850  BONOBO_ARG_SET_STRING (arg, full_display_string);
1851 
1852  DBG (fprintf (stderr, "Set target display: \t%s\n",
1853  full_display_string));
1854 
1855  if (strcmp (full_display_string, magnifier->target_display_name))
1856  {
1858  arg,
1860  ev,
1861  magnifier);
1862  }
1863  else
1864  {
1865  DBG (fprintf (stderr, "Attempt to set target to same value as previous: %s\n",
1866  full_display_string));
1867  }
1868  bonobo_arg_release (arg);
1869 }
1870 
1871 static
1872 CORBA_string
1873 impl_magnifier_get_source_display (PortableServer_Servant servant,
1874  CORBA_Environment *ev)
1875 {
1876  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1877  DBG (fprintf (stderr, "Get source display: \t%s\n", magnifier->source_display_name));
1878 
1879  return CORBA_string_dup (magnifier->source_display_name ? magnifier->source_display_name : "");
1880 }
1881 
1882 static
1883 CORBA_string
1884 impl_magnifier_get_target_display (PortableServer_Servant servant,
1885  CORBA_Environment *ev)
1886 {
1887  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1888  DBG (fprintf (stderr, "Get target display: \t%s\n",
1889  magnifier->target_display_name));
1890 
1891  return CORBA_string_dup (magnifier->target_display_name ? magnifier->target_display_name : "");
1892 }
1893 
1895 impl_magnifier_create_zoom_region (PortableServer_Servant servant,
1896  const CORBA_float zx,
1897  const CORBA_float zy,
1898  const GNOME_Magnifier_RectBounds *roi,
1899  const GNOME_Magnifier_RectBounds *viewport,
1900  CORBA_Environment *ev)
1901 {
1902  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1903  CORBA_any viewport_any;
1905  Bonobo_PropertyBag properties;
1907 
1908  DBG (fprintf (stderr, "Create zoom region: \tzoom %f,%f, viewport %d,%d to %d,%d\n", (float) zx, (float) zy, viewport->x1, viewport->y1, viewport->x2, viewport->y2));
1909 
1910  /* FIXME:
1911  * shouldn't do this here, since it causes the region to get
1912  * mapped onto the parent, if if it's not explicitly added!
1913  */
1914  DBG(g_message ("creating zoom region with parent %p", magnifier));
1915  zoom_region->priv->parent = magnifier;
1916 
1917  retval = BONOBO_OBJREF (zoom_region);
1918 
1919  /* XXX: should check ev after each call, below */
1920  CORBA_exception_init (ev);
1921  GNOME_Magnifier_ZoomRegion_setMagFactor (retval, zx, zy, ev);
1922 
1923  if (ev->_major != CORBA_NO_EXCEPTION)
1924  fprintf (stderr, "EXCEPTION setMagFactor\n");
1925 
1926  CORBA_exception_init (ev);
1927  properties = GNOME_Magnifier_ZoomRegion_getProperties (retval, ev);
1928  if (ev->_major != CORBA_NO_EXCEPTION)
1929  fprintf (stderr, "EXCEPTION getProperties\n");
1930 
1931  viewport_any._type = TC_GNOME_Magnifier_RectBounds;
1932  viewport_any._value = (gpointer) viewport;
1934  properties, "viewport", &viewport_any, ev);
1935 
1936  GNOME_Magnifier_ZoomRegion_setROI (retval, roi, ev);
1937  if (ev->_major != CORBA_NO_EXCEPTION)
1938  fprintf (stderr, "EXCEPTION setROI\n");
1939 
1940  CORBA_exception_init (ev);
1941 
1942  gtk_widget_set_size_request (magnifier->priv->canvas,
1943  viewport->x2 - viewport->x1,
1944  viewport->y2 - viewport->y1);
1945  gtk_widget_show (magnifier->priv->canvas);
1946  gtk_widget_show (magnifier->priv->w);
1947 
1948  bonobo_object_release_unref (properties, ev);
1949 
1950  return CORBA_Object_duplicate (retval, ev);
1951 }
1952 
1953 static
1954 CORBA_boolean
1955 impl_magnifier_add_zoom_region (PortableServer_Servant servant,
1956  const GNOME_Magnifier_ZoomRegion region,
1957  CORBA_Environment * ev)
1958 {
1959  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1960 
1961  if (!magnifier->source_initialized)
1962  {
1963  magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
1964  }
1965 
1966  /* FIXME: this needs proper lifecycle management */
1967  magnifier->zoom_regions = g_list_append (magnifier->zoom_regions, region);
1968  gmag_gs_check_set_struts (magnifier);
1969 
1970  return CORBA_TRUE;
1971 }
1972 
1973 static Bonobo_PropertyBag
1974 impl_magnifier_get_properties (PortableServer_Servant servant,
1975  CORBA_Environment *ev)
1976 {
1977  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
1978  return bonobo_object_dup_ref (
1979  BONOBO_OBJREF (magnifier->property_bag), ev);
1980 }
1981 
1983 impl_magnifier_get_zoom_regions (PortableServer_Servant servant,
1984  CORBA_Environment * ev)
1985 {
1986  Magnifier *magnifier =
1987  MAGNIFIER (bonobo_object_from_servant (servant));
1988 
1990  CORBA_Object objref;
1991  int i, len;
1992 
1993  len = g_list_length (magnifier->zoom_regions);
1995  list->_length = len;
1996  list->_buffer =
1998  for (i = 0; i < len; ++i) {
1999  objref = g_list_nth_data (magnifier->zoom_regions, i);
2000  list->_buffer [i] =
2001  CORBA_Object_duplicate (objref, ev);
2002  }
2003  CORBA_sequence_set_release (list, CORBA_TRUE);
2004 
2005  DBG (fprintf (stderr, "Get zoom regions: \t%d\n", len));
2006 
2007  return list;
2008 }
2009 
2010 static void
2011 impl_magnifier_clear_all_zoom_regions (PortableServer_Servant servant,
2012  CORBA_Environment * ev)
2013 {
2014  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
2015  fprintf (stderr, "Clear all zoom regions.\n");
2016 
2017  g_list_foreach (magnifier->zoom_regions,
2018  magnifier_unref_zoom_region, magnifier);
2019  g_list_free (magnifier->zoom_regions);
2020  magnifier->zoom_regions = NULL;
2021  magnifier->zoom_regions_dbus = NULL;
2022 }
2023 
2024 static void
2025 impl_magnifier_dispose (PortableServer_Servant servant,
2026  CORBA_Environment *ev)
2027 {
2029  MAGNIFIER (bonobo_object_from_servant (servant)));
2030 }
2031 
2032 static void
2034 {
2035  GObjectClass * object_class = (GObjectClass *) klass;
2036  POA_GNOME_Magnifier_Magnifier__epv *epv = &klass->epv;
2037  parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT); /* needed by BONOBO_CALL_PARENT! */
2038 
2039  object_class->dispose = magnifier_gobject_dispose;
2040 
2055 }
2056 
2057 static void
2059 {
2060  BonoboArg *def;
2061  GNOME_Magnifier_RectBounds rect_bounds;
2062  gchar *display_env;
2063 
2064  magnifier->property_bag =
2065  bonobo_property_bag_new_closure (
2066  g_cclosure_new_object (
2067  G_CALLBACK (magnifier_get_property),
2068  G_OBJECT (magnifier)),
2069  g_cclosure_new_object (
2070  G_CALLBACK (magnifier_set_property),
2071  G_OBJECT (magnifier)));
2072  /* Aggregate so magnifier implements Bonobo_PropertyBag */
2073  bonobo_object_add_interface (BONOBO_OBJECT (magnifier),
2074  BONOBO_OBJECT (magnifier->property_bag));
2075 
2076  def = bonobo_arg_new (BONOBO_ARG_STRING);
2077  display_env = getenv ("DISPLAY");
2078  BONOBO_ARG_SET_STRING (def, display_env);
2079 
2080  bonobo_property_bag_add (magnifier->property_bag,
2081  "source-display-screen",
2083  BONOBO_ARG_STRING,
2084  def,
2085  "source display screen",
2087 
2088  bonobo_property_bag_add (magnifier->property_bag,
2089  "target-display-screen",
2091  BONOBO_ARG_STRING,
2092  def,
2093  "target display screen",
2095 
2096  bonobo_arg_release (def);
2097 
2098  magnifier_init_display (magnifier, display_env, TRUE);
2099  magnifier_init_display (magnifier, display_env, FALSE);
2100 
2101  magnifier_get_display_rect_bounds (magnifier, &rect_bounds, FALSE);
2102  def = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, &rect_bounds);
2103 
2104  bonobo_property_bag_add (magnifier->property_bag,
2105  "source-display-bounds",
2108  def,
2109  "source display bounds/size",
2112  bonobo_arg_release (def);
2113 
2114  magnifier_get_display_rect_bounds (magnifier, &rect_bounds, TRUE);
2115  def = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, &rect_bounds);
2116 
2117  bonobo_property_bag_add (magnifier->property_bag,
2118  "target-display-bounds",
2121  def,
2122  "target display bounds/size",
2125  bonobo_arg_release (def);
2126 
2127  bonobo_property_bag_add (magnifier->property_bag,
2128  "cursor-set",
2130  BONOBO_ARG_STRING,
2131  NULL,
2132  "name of cursor set",
2135 
2136  def = bonobo_arg_new (BONOBO_ARG_INT);
2137  BONOBO_ARG_SET_INT (def, 64);
2138 
2139  bonobo_property_bag_add (magnifier->property_bag,
2140  "cursor-size",
2142  BONOBO_ARG_INT,
2143  def,
2144  "cursor size, in pixels",
2147  bonobo_arg_release (def);
2148 
2149  bonobo_property_bag_add (magnifier->property_bag,
2150  "cursor-scale-factor",
2152  BONOBO_ARG_FLOAT,
2153  NULL,
2154  "scale factor for cursors (overrides size)",
2157 
2158  bonobo_property_bag_add (magnifier->property_bag,
2159  "cursor-color",
2161  TC_CORBA_unsigned_long,
2162  NULL,
2163  "foreground color for 1-bit cursors, as ARGB",
2166 
2167  bonobo_property_bag_add (magnifier->property_bag,
2168  "cursor-hotspot",
2171  NULL,
2172  "hotspot relative to cursor's upper-left-corner, at default resolition",
2175 
2176  bonobo_property_bag_add (magnifier->property_bag,
2177  "cursor-default-size",
2179  BONOBO_ARG_INT,
2180  NULL,
2181  "default size of current cursor set",
2183 
2184  bonobo_property_bag_add (magnifier->property_bag,
2185  "crosswire-size",
2187  BONOBO_ARG_INT,
2188  NULL,
2189  "thickness of crosswire cursor, in target pixels",
2192 
2193  bonobo_property_bag_add (magnifier->property_bag,
2194  "crosswire-length",
2196  BONOBO_ARG_INT,
2197  NULL,
2198  "length of crosswire cursor, in target pixels",
2201 
2202  bonobo_property_bag_add (magnifier->property_bag,
2203  "crosswire-color",
2205  BONOBO_ARG_LONG,
2206  NULL,
2207  "color of crosswire, as A-RGB; note that alpha is required. (use 0 for XOR wire)",
2210 
2211  bonobo_property_bag_add (magnifier->property_bag,
2212  "crosswire-clip",
2214  BONOBO_ARG_BOOLEAN,
2215  NULL,
2216  "whether to inset the cursor over the crosswire or not",
2219 }
2220 
2221 static void
2222 magnifier_init_window (Magnifier *magnifier, GdkScreen *screen)
2223 {
2224  GtkWindowType mag_win_type = GTK_WINDOW_TOPLEVEL;
2225  if (_is_override_redirect || gmag_gs_use_compositor (magnifier))
2226  mag_win_type = GTK_WINDOW_POPUP;
2227 
2228  magnifier->priv->w =
2229  g_object_connect (gtk_widget_new (gtk_window_get_type (),
2230  "user_data", NULL,
2231  "can_focus", FALSE,
2232  "type", mag_win_type,
2233  "title", "magnifier",
2234  "allow_grow", TRUE,
2235  "allow_shrink", TRUE,
2236  "border_width", 0,
2237  NULL),
2238  "signal::realize", magnifier_realize, NULL,
2239  "signal::size_allocate", magnifier_size_allocate, NULL,
2240  "signal::destroy", magnifier_exit, NULL,
2241  NULL);
2242  gtk_window_set_screen (GTK_WINDOW (magnifier->priv->w), screen);
2243  magnifier->priv->canvas = gtk_fixed_new ();
2244  gtk_container_add (GTK_CONTAINER (magnifier->priv->w),
2245  magnifier->priv->canvas);
2246  magnifier->priv->root = NULL;
2247 }
2248 
2249 static void
2251 {
2252  magnifier->priv = g_new0 (MagnifierPrivate, 1);
2253  magnifier_properties_init (magnifier);
2254  magnifier->zoom_regions = NULL;
2255  magnifier->zoom_regions_dbus = NULL;
2256  magnifier->source_screen_num = 0;
2257  magnifier->target_screen_num = 0;
2258  magnifier->source_display_name = g_strdup (":0.0");
2259  magnifier->target_display_name = g_strdup (":0.0");
2260  magnifier->cursor_size_x = 0;
2261  magnifier->cursor_size_y = 0;
2262  magnifier->cursor_scale_factor = 1.0F;
2263  magnifier->cursor_color = 0xFF000000;
2264  magnifier->crosswire_size = 1;
2265  magnifier->crosswire_length = 0;
2266  magnifier->crosswire_color = 0;
2267  magnifier->crosswire_clip = FALSE;
2268  magnifier->cursor_hotspot.x = 0;
2269  magnifier->cursor_hotspot.y = 0;
2270  magnifier->target_bounds.x1 = 0;
2271  magnifier->target_bounds.y1 = 0;
2272  magnifier->target_bounds.x2 = 0;
2273  magnifier->target_bounds.y2 = 0;
2274  magnifier->priv->cursor = NULL;
2275  magnifier->priv->w = NULL;
2276  magnifier->priv->use_source_cursor = TRUE;
2277  magnifier->priv->cursorlist = NULL;
2278  magnifier->priv->source_drawable = NULL;
2279  magnifier->priv->overlay = NULL;
2280  magnifier_init_window (magnifier,
2281  gdk_display_get_screen (magnifier->target_display,
2282  magnifier->target_screen_num));
2283  magnifier_init_cursor_set (magnifier, "default");
2284 
2285  mag_timing.process = g_timer_new ();
2286  mag_timing.frame = g_timer_new ();
2287  mag_timing.scale = g_timer_new ();
2288  mag_timing.idle = g_timer_new ();
2289 #ifdef DEBUG_CLIENT_CALLS
2290  client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL);
2291 #endif
2292 
2293  zoom_hash = g_hash_table_new (g_str_hash, g_str_equal);
2294 }
2295 
2296 GdkDrawable *
2298 {
2299  if (magnifier->priv->cursor == NULL) {
2300  if ((fixes_event_base == 0) &&
2301  strcmp (magnifier->cursor_set, "none"))
2302  {
2303  GdkPixbuf *pixbuf;
2304  gchar *default_cursor_filename =
2305  g_strconcat (CURSORSDIR, "/", "default-cursor.xpm", NULL);
2306  pixbuf = gdk_pixbuf_new_from_file (default_cursor_filename, NULL);
2307  if (pixbuf)
2308  {
2309  magnifier_set_cursor_from_pixbuf (magnifier, pixbuf);
2310  g_object_unref (pixbuf);
2311  magnifier_transform_cursor (magnifier);
2312  }
2313  g_free (default_cursor_filename);
2314  } else {
2315  GdkPixbuf *cursor_pixbuf = gmag_cursor_get_source_pixbuf (
2316  magnifier);
2317  magnifier_set_cursor_from_pixbuf (magnifier, cursor_pixbuf);
2318  if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
2319  magnifier_transform_cursor (magnifier);
2320  }
2321  }
2322  return magnifier->priv->cursor;
2323 }
2324 
2325 Magnifier *
2326 magnifier_new (gboolean override_redirect)
2327 {
2328  Magnifier *mag;
2329  MagLoginHelper *helper;
2330  GError *error = NULL;
2331  MagnifierClass *klass = NULL;
2332  DBusGProxy *driver_proxy;
2333  guint request_req;
2334  int ret;
2335 
2336  _is_override_redirect = override_redirect;
2337 
2338  mag = g_object_new (magnifier_get_type(), NULL);
2339 
2340  _this_magnifier = mag; /* FIXME what about multiple instances? */
2341 
2342  helper = g_object_new (mag_login_helper_get_type (), NULL);
2343  mag_login_helper_set_magnifier (helper, mag);
2344 
2345  bonobo_object_add_interface (bonobo_object (mag),
2346  BONOBO_OBJECT (helper));
2347 
2348  ret = bonobo_activation_active_server_register (
2349  MAGNIFIER_OAFIID, BONOBO_OBJREF (mag));
2350  if (ret != Bonobo_ACTIVATION_REG_SUCCESS) {
2351  if ( ret == Bonobo_ACTIVATION_REG_ALREADY_ACTIVE)
2352  {
2353  printf("An instance of magnifier is already active. Exiting Program.\n");
2354  exit(0);
2355  } else
2356  g_error ("Error registering magnifier server.\n");
2357  }
2358 
2359  klass = MAGNIFIER_GET_CLASS (mag);
2360 
2361  klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2362  if (klass->connection == NULL) {
2363  g_warning ("Unable to connect to dbus: %s", error->message);
2364  g_error_free (error);
2365  return NULL;
2366  }
2367 
2368  dbus_g_object_type_install_info (MAGNIFIER_TYPE, &dbus_glib_impl_dbus_magnifier_object_info);
2369 
2370  dbus_g_connection_register_g_object (klass->connection, "/org/freedesktop/gnome/Magnifier",
2371  G_OBJECT (_this_magnifier));
2372 
2373  driver_proxy = dbus_g_proxy_new_for_name (klass->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
2374  DBUS_INTERFACE_DBUS);
2375 
2376  if (!org_freedesktop_DBus_request_name (driver_proxy, "org.freedesktop.gnome.Magnifier", 0, &request_req,
2377  &error)) {
2378  g_warning ("Unable to register service: %s", error->message);
2379  g_error_free (error);
2380  }
2381 
2382  g_timeout_add (500, magnifier_reset_struts_at_idle, mag);
2383  g_timeout_add (500, gmag_gs_reset_overlay_at_idle, mag);
2384 
2385  return mag;
2386 }
2387 
2390  BONOBO_TYPE_OBJECT,
2391  magnifier)
2392