magnifier.c

Go to the documentation of this file.
00001 /*
00002  * AT-SPI - Assistive Technology Service Provider Interface
00003  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
00004  *
00005  * Copyright 2001 Sun Microsystems Inc.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Library General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Library General Public
00018  * License along with this library; if not, write to the
00019  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  * Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #include "config.h"
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <strings.h>
00027 #include <popt.h>
00028 #include <gdk/gdk.h>
00029 #include <gdk-pixbuf/gdk-pixbuf-io.h>
00030 #include <libbonobo.h>
00031 #include <login-helper/login-helper.h>
00032 #include <gdk/gdkx.h>
00033 #include <gtk/gtk.h>
00034 #include <X11/Xatom.h>
00035 #ifdef HAVE_XFIXES
00036 #include <X11/extensions/Xfixes.h>
00037 #endif
00038 #include "magnifier.h"
00039 #include "magnifier-private.h"
00040 #include "zoom-region.h"
00041 #include "zoom-region-private.h"
00042 #include "damage-client.h"
00043 #include "GNOME_Magnifier.h"
00044 
00045 /* if you #define this, don't forget to set MAG_CLIENT_DEBUG env variable */
00046 #define DEBUG_CLIENT_CALLS
00047 
00048 #ifdef DEBUG_CLIENT_CALLS
00049 static gboolean client_debug = FALSE;
00050 #define DBG(a) if (client_debug) { (a); }
00051 #else
00052 #define DBG(a)
00053 #endif
00054 
00055 typedef struct
00056 {
00057     LoginHelper parent;
00058     Magnifier *mag;
00059 } MagLoginHelper;
00060 
00061 typedef struct 
00062 {
00063     LoginHelperClass parent_class;
00064 } MagLoginHelperClass;
00065 
00066 static GObjectClass *parent_class = NULL;
00067 
00068 enum {
00069         STRUT_LEFT = 0,
00070         STRUT_RIGHT = 1,
00071         STRUT_TOP = 2,
00072         STRUT_BOTTOM = 3,
00073         STRUT_LEFT_START = 4,
00074         STRUT_LEFT_END = 5,
00075         STRUT_RIGHT_START = 6,
00076         STRUT_RIGHT_END = 7,
00077         STRUT_TOP_START = 8,
00078         STRUT_TOP_END = 9,
00079         STRUT_BOTTOM_START = 10,
00080         STRUT_BOTTOM_END = 11
00081 };
00082 
00083 enum {
00084         MAGNIFIER_SOURCE_DISPLAY_PROP,
00085         MAGNIFIER_TARGET_DISPLAY_PROP,
00086         MAGNIFIER_SOURCE_SIZE_PROP,
00087         MAGNIFIER_TARGET_SIZE_PROP,
00088         MAGNIFIER_CURSOR_SET_PROP,
00089         MAGNIFIER_CURSOR_SIZE_PROP,
00090         MAGNIFIER_CURSOR_ZOOM_PROP,
00091         MAGNIFIER_CURSOR_COLOR_PROP,
00092         MAGNIFIER_CURSOR_HOTSPOT_PROP,
00093         MAGNIFIER_CURSOR_DEFAULT_SIZE_PROP,
00094         MAGNIFIER_CROSSWIRE_SIZE_PROP,
00095         MAGNIFIER_CROSSWIRE_CLIP_PROP,
00096         MAGNIFIER_CROSSWIRE_COLOR_PROP
00097 } PropIdx;
00098 
00099 typedef struct
00100 {
00101         GNOME_Magnifier_RectBounds rectbounds;
00102         GNOME_Magnifier_RectBounds viewport;
00103         gboolean is_managed;
00104         gint scroll_policy;
00105         gfloat contrast;
00106         gfloat zx;
00107         gfloat zy;
00108         gint32 xalign;
00109         gint32 yalign;
00110         guint32 border_color;
00111         gint32 border_size;
00112         gchar *smoothing_type;
00113         gboolean inverse;
00114 
00115 } MagnifierZoomRegionSaveProps;
00116 
00117 #ifdef DEBUG_CLIENT_CALLS
00118 gchar* mag_prop_names[MAGNIFIER_CROSSWIRE_COLOR_PROP + 1] = {
00119     "SOURCE_DISPLAY",
00120     "TARGET_DISPLAY",
00121     "SOURCE_SIZE",
00122     "TARGET_SIZE",
00123     "CURSOR_SET",
00124     "CURSOR_SIZE",
00125     "CURSOR_ZOOM",
00126     "CURSOR_COLOR",
00127     "CURSOR_HOTSPOT",
00128     "CURSOR_DEFAULT_SIZE",
00129     "CROSSWIRE_SIZE",
00130     "CROSSWIRE_CLIP",
00131     "CROSSWIRE_COLOR"
00132 };
00133 #endif
00134 
00135 static int _x_error = 0;
00136 static int fixes_event_base = 0, fixes_error_base;
00137 static Display *cursor_client_connection;
00138 static guint    cursor_client_gsource = 0;
00139 static Magnifier *_this_magnifier = NULL;
00140 
00141 static void magnifier_transform_cursor (Magnifier *magnifier);
00142 static void magnifier_init_cursor_set (Magnifier *magnifier, gchar *cursor_set);
00143 static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);
00144 static gboolean magnifier_check_set_struts (Magnifier *magnifier);
00145 static gboolean magnifier_reset_struts_at_idle (gpointer data);
00146 static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);
00147 static void magnifier_adjust_source_size (Magnifier *magnifier);
00148 static gboolean _is_override_redirect = FALSE;
00149 
00150 static Window*
00151 mag_login_helper_get_raise_windows (LoginHelper *helper)
00152 {
00153     Window *mainwin = NULL;
00154     MagLoginHelper *mag_helper = (MagLoginHelper *) helper;
00155     Magnifier *magnifier = MAGNIFIER (mag_helper->mag);
00156 
00157     if (magnifier && magnifier->priv && magnifier->priv->w)
00158     {
00159         mainwin = g_new0 (Window, 2);
00160         mainwin[0] = GDK_WINDOW_XWINDOW (magnifier->priv->w->window);
00161         mainwin[1] = None;
00162     }
00163     return mainwin;
00164 }
00165 
00166 static LoginHelperDeviceReqFlags
00167 mag_login_helper_get_device_reqs (LoginHelper *helper)
00168 {
00169     /* means "don't grab the xserver or core pointer", 
00170        and "we need to raise windows" */
00171 
00172     return LOGIN_HELPER_GUI_EVENTS | 
00173         LOGIN_HELPER_POST_WINDOWS | 
00174         LOGIN_HELPER_CORE_POINTER;
00175 }
00176 
00177 static gboolean
00178 mag_login_helper_set_safe (LoginHelper *helper, gboolean ignored)
00179 {
00180     return TRUE;
00181 }
00182 
00183 static void
00184 mag_login_helper_class_init (MagLoginHelperClass *klass)
00185 {
00186         LoginHelperClass *login_helper_class = LOGIN_HELPER_CLASS(klass);
00187         login_helper_class->get_raise_windows = mag_login_helper_get_raise_windows;
00188         login_helper_class->get_device_reqs = mag_login_helper_get_device_reqs;
00189         login_helper_class->set_safe = mag_login_helper_set_safe;
00190 }
00191 
00192 static void
00193 mag_login_helper_init (MagLoginHelper *helper)
00194 {
00195     helper->mag = NULL; /* we set this with mag_login_helper_set_magnifier */
00196 }
00197 
00198 static void
00199 mag_login_helper_set_magnifier (MagLoginHelper *helper, Magnifier *mag)
00200 {
00201     if (helper) 
00202         helper->mag = mag;
00203 }
00204 
00205 BONOBO_TYPE_FUNC (MagLoginHelper, 
00206                   LOGIN_HELPER_TYPE,
00207                   mag_login_helper)
00208 
00209 gboolean
00210 magnifier_error_check (void)
00211 {
00212         if (_x_error) {
00213                 _x_error = 0;
00214                 return TRUE;
00215         }
00216         return FALSE;
00217 }
00218 
00219 static int
00220 magnifier_x_error_handler (Display       *display,
00221                            XErrorEvent *error)
00222 {
00223         if (error->error_code == BadAlloc) {
00224                 _x_error = error->error_code;
00225         }
00226         else {
00227                 return -1;
00228         }
00229         return 0;
00230 }
00231 
00232 static gboolean
00233 can_open_display (gchar *display_name)
00234 {
00235     Display *d;
00236     if ((d = XOpenDisplay (display_name)))
00237     {
00238         XCloseDisplay (d);
00239         return TRUE;
00240     }
00241     return FALSE;
00242 }
00243 
00244 static void
00245 magnifier_warp_cursor_to_screen (Magnifier *magnifier)
00246 {
00247         int x, y, unused_x, unused_y;
00248         unsigned int mask;
00249         Window root_return, child_return;
00250 
00251         if (magnifier->source_display)
00252         {
00253             if (!XQueryPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display), 
00254                                 GDK_WINDOW_XWINDOW (magnifier->priv->root), 
00255                                 &root_return,
00256                                 &child_return,
00257                                 &x, &y,
00258                                 &unused_x, &unused_y,
00259                                 &mask))
00260             {
00261                 XWarpPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display),
00262                               None,
00263                               GDK_WINDOW_XWINDOW (magnifier->priv->root),
00264                               0, 0, 0, 0,
00265                               x, y);
00266                 XSync (GDK_DISPLAY_XDISPLAY (magnifier->source_display), FALSE);
00267             }
00268         }
00269 }
00270 
00271 static void
00272 magnifier_zoom_regions_mark_dirty (Magnifier *magnifier, GNOME_Magnifier_RectBounds rect_bounds)
00273 {
00274         GList *list;
00275 
00276         g_assert (magnifier);
00277 
00278         list = magnifier->zoom_regions;
00279         while (list) 
00280         {
00281                 /* propagate the expose events to the zoom regions */
00282                 GNOME_Magnifier_ZoomRegion zoom_region;
00283                 CORBA_Environment ev;
00284                 zoom_region = list->data;
00285                 CORBA_exception_init (&ev);
00286                 if (zoom_region)
00287                         GNOME_Magnifier_ZoomRegion_markDirty (CORBA_Object_duplicate (zoom_region, &ev),
00288                                                               &rect_bounds,
00289                                                               &ev);
00290                 list = g_list_next (list);
00291         }
00292 }
00293 
00294 void
00295 magnifier_set_cursor_from_pixbuf (Magnifier *magnifier, GdkPixbuf *cursor_pixbuf)
00296 {
00297         GdkPixmap *pixmap, *mask;
00298         gint width, height;
00299         GdkGC *gc;
00300         GdkDrawable *drawable = magnifier->priv->w->window;
00301 
00302         if (magnifier->priv->cursor) {
00303                 g_object_unref (magnifier->priv->cursor);
00304                 magnifier->priv->cursor = NULL;
00305         }
00306         if (drawable && cursor_pixbuf)
00307         {
00308                 const gchar *xhot_string = NULL, *yhot_string = NULL;
00309                 width = gdk_pixbuf_get_width (cursor_pixbuf);
00310                 height = gdk_pixbuf_get_height (cursor_pixbuf);
00311                 pixmap = gdk_pixmap_new (drawable, width, height, -1);
00312                 gc = gdk_gc_new (pixmap);
00313                 if (GDK_IS_DRAWABLE (pixmap))
00314                     gdk_draw_pixbuf (pixmap, gc, cursor_pixbuf, 0, 0, 0, 0, 
00315                                      width, height,
00316                                      GDK_RGB_DITHER_NONE, 0, 0);
00317                 else
00318                     DBG (g_warning ("empty cursor pixmap created."));
00319                 mask = gdk_pixmap_new (drawable, width, height, 1);
00320                 gdk_pixbuf_render_threshold_alpha (cursor_pixbuf, mask, 0, 0, 0, 0, 
00321                                                    width, height,
00322                                                    200);
00323                 g_object_unref (gc);
00324                 magnifier->priv->cursor = pixmap;
00325                 magnifier->priv->cursor_mask = mask;
00326                 xhot_string = gdk_pixbuf_get_option (cursor_pixbuf,"x_hot");
00327                 yhot_string = gdk_pixbuf_get_option (cursor_pixbuf,"y_hot");
00328                 if (xhot_string) magnifier->cursor_hotspot.x = atoi (xhot_string);
00329                 if (yhot_string) magnifier->cursor_hotspot.y = atoi (yhot_string);
00330 
00331                 if (pixmap) {
00332                         gdk_drawable_get_size (pixmap,
00333                                                &magnifier->priv->cursor_default_size_x,
00334                                                &magnifier->priv->cursor_default_size_y);
00335                         magnifier->priv->cursor_hotspot_x = magnifier->cursor_hotspot.x;
00336                         magnifier->priv->cursor_hotspot_y = magnifier->cursor_hotspot.y;
00337                 }
00338         }
00339 }
00340 
00341 
00342 void
00343 magnifier_free_cursor_pixels (guchar *pixels, gpointer data)
00344 {
00345     /* XFree (data); FIXME why doesn't this work properly? */
00346 }
00347 
00348 #ifdef HAVE_XFIXES
00349 static void
00350 magnifier_cursor_convert_to_rgba (Magnifier *magnifier, XFixesCursorImage *cursor_image)
00351 {
00352         int i, count = cursor_image->width * cursor_image->height;
00353         for (i = 0; i < count; ++i) 
00354         {
00355                 guint32 pixval = GUINT_TO_LE (cursor_image->pixels[i]);
00356                 cursor_image->pixels[i] = pixval;
00357         }
00358 }
00359 #endif
00360 
00361 GdkPixbuf *
00362 magnifier_get_source_pixbuf (Magnifier *magnifier)
00363 {
00364 #ifdef HAVE_XFIXES
00365         XFixesCursorImage *cursor_image = XFixesGetCursorImage (cursor_client_connection);
00366         GdkPixbuf *cursor_pixbuf = NULL;
00367         gchar s[6];
00368         if (cursor_image)
00369         {
00370                 magnifier_cursor_convert_to_rgba (magnifier, cursor_image);
00371                 cursor_pixbuf = gdk_pixbuf_new_from_data ((guchar *) cursor_image->pixels, 
00372                                                           GDK_COLORSPACE_RGB, 
00373                                                           TRUE, 8,  
00374                                                           cursor_image->width, cursor_image->height,
00375                                                           cursor_image->width * 4, 
00376                                                           magnifier_free_cursor_pixels, 
00377                                                           cursor_image );
00378                 gdk_pixbuf_set_option (cursor_pixbuf, "x_hot", 
00379                                        g_ascii_dtostr (s, 6, (gdouble) cursor_image->xhot));
00380                 gdk_pixbuf_set_option (cursor_pixbuf, "y_hot", 
00381                                        g_ascii_dtostr (s, 6, (gdouble) cursor_image->yhot));
00382         }
00383         return cursor_pixbuf;
00384 #else
00385         return NULL;
00386 #endif
00387 }
00388 
00389 GdkPixbuf *
00390 magnifier_get_pixbuf_for_name (Magnifier *magnifier, const gchar *cursor_name)
00391 {
00392     GdkPixbuf *retval = NULL;
00393     if (magnifier->priv->cursorlist) 
00394             retval = g_hash_table_lookup (magnifier->priv->cursorlist, cursor_name);
00395     if (retval) 
00396             g_object_ref (retval);
00397     return retval;
00398 }
00399 
00400 void
00401 magnifier_set_cursor_pixmap_by_name (Magnifier *magnifier, const gchar *cursor_name, 
00402                                      gboolean source_fallback)
00403 {
00404         GdkPixbuf *pixbuf;
00405         /* search local table; if not found, use source screen's cursor if source_fallback is TRUE */
00406         if ((pixbuf = magnifier_get_pixbuf_for_name (magnifier, cursor_name)) == NULL) {
00407 #ifndef HAVE_XFIXES
00408                 source_fallback = FALSE;
00409 #endif
00410                 if (source_fallback == TRUE)
00411                 {
00412                         pixbuf = magnifier_get_source_pixbuf (magnifier);
00413                 }
00414                 else
00415                 {
00416                         pixbuf = magnifier_get_pixbuf_for_name (magnifier, "default");
00417                 }
00418         }
00419         magnifier_set_cursor_from_pixbuf (magnifier, pixbuf);
00420         if (pixbuf) g_object_unref (pixbuf);
00421 }
00422 
00423 gboolean
00424 magnifier_cursor_notify (GIOChannel *source, GIOCondition condition, gpointer data)
00425 {
00426 #ifdef HAVE_XFIXES
00427   XEvent ev;
00428   Magnifier *magnifier = (Magnifier *) data;
00429   XFixesCursorNotifyEvent  *cev = NULL;
00430 
00431   /* TODO: don't ask for name unless xfixes version >= 2 available */
00432   do
00433   {
00434       XNextEvent(cursor_client_connection, &ev);
00435       if (ev.type == fixes_event_base + XFixesCursorNotify) 
00436       {
00437           cev = (XFixesCursorNotifyEvent *) &ev;
00438       }
00439   } while (XPending (cursor_client_connection));
00440 
00441   if (magnifier->priv->use_source_cursor) 
00442   {
00443       GdkPixbuf *cursor_pixbuf = magnifier_get_source_pixbuf (magnifier);
00444       magnifier_set_cursor_from_pixbuf (magnifier, cursor_pixbuf);
00445       if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
00446   }
00447   else
00448   {
00449       magnifier_set_cursor_pixmap_by_name (magnifier, 
00450                                            cev ? gdk_x11_get_xatom_name (cev->cursor_name) : "default",
00451                                            TRUE);
00452   }
00453 
00454   magnifier_transform_cursor (magnifier);
00455 #ifdef DEBUG_CURSOR
00456   if (cev)
00457   g_message ("cursor changed: subtype=%d, cursor_serial=%lu, name=[%x] %s\n",
00458              (int) cev->subtype, cev->cursor_serial, (int) cev->cursor_name,
00459              gdk_x11_get_xatom_name (cev->cursor_name));
00460 #endif
00461 
00462   return TRUE;
00463 #else
00464   return FALSE;
00465 #endif
00466 }
00467 
00468 gboolean
00469 magnifier_cursor_notification_init (Magnifier *magnifier)
00470 {
00471 #ifdef HAVE_XFIXES
00472     GIOChannel *ioc;
00473     int fd;
00474     Window rootwin;
00475 
00476     if (!magnifier->source_display) return FALSE;
00477 
00478     if (cursor_client_connection)
00479     {
00480         /* remove the old watch */
00481         if (cursor_client_gsource) 
00482           g_source_remove (cursor_client_gsource);
00483         XCloseDisplay (cursor_client_connection);
00484     }
00485 
00486     cursor_client_connection = XOpenDisplay (magnifier->source_display_name);
00487     rootwin = GDK_WINDOW_XWINDOW (magnifier->priv->root);
00488 
00489     if (!XFixesQueryExtension (cursor_client_connection, &fixes_event_base, &fixes_error_base))
00490     {
00491         g_warning ("XFixes extension not currently active.\n");
00492         return FALSE;
00493     }
00494     else
00495     {
00496         XFixesSelectCursorInput (cursor_client_connection, rootwin, XFixesDisplayCursorNotifyMask);
00497         fd = ConnectionNumber (cursor_client_connection);
00498         ioc = g_io_channel_unix_new (fd);
00499         cursor_client_gsource = 
00500             g_io_add_watch (ioc, G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR, magnifier_cursor_notify, 
00501                             magnifier);
00502         g_io_channel_unref (ioc); 
00503         g_message ("added event source to xfixes cursor-notify connection");
00504         XFlush (cursor_client_connection); 
00505    }
00506     return TRUE;
00507 #else
00508     g_warning ("this copy of gnome-mag was built without xfixes extension support.\n");
00509     return FALSE;
00510 #endif
00511 }
00512 
00513 void
00514 magnifier_notify_damage (Magnifier *magnifier, XRectangle *rect)
00515 {
00516         GNOME_Magnifier_RectBounds rect_bounds;
00517         rect_bounds.x1 = rect->x;
00518         rect_bounds.y1 = rect->y;
00519         rect_bounds.x2 = rect->x + rect->width;
00520         rect_bounds.y2 = rect->y + rect->height;
00521 #undef DEBUG_DAMAGE
00522 #ifdef DEBUG_DAMAGE
00523         g_message ("damage");
00524         g_message ("dirty %d, %d to %d, %d", rect_bounds.x1, rect_bounds.y1, rect_bounds.x2, rect_bounds.y2);
00525 #endif
00526         magnifier_zoom_regions_mark_dirty (magnifier, rect_bounds);
00527 }
00528 
00529 static void
00530 magnifier_set_extension_listeners (Magnifier *magnifier, GdkWindow *root)
00531 {
00532         if (!magnifier_damage_client_init (magnifier))
00533             g_warning ("Damage client hooks were not initialized.");
00534         if (!magnifier_cursor_notification_init (magnifier))
00535             g_warning ("Cursor change notification hooks were not initialized.");
00536         magnifier->source_initialized = TRUE;
00537 }
00538 
00539 static void
00540 magnifier_size_allocate (GtkWidget *widget)
00541 {
00542         magnifier_check_set_struts (_this_magnifier);
00543 }
00544 
00545 static void
00546 magnifier_realize (GtkWidget *widget)
00547 {
00548         XWMHints wm_hints;
00549         Atom wm_window_protocols[2];
00550         Atom wm_type_atoms[1];
00551         Atom net_wm_window_type;
00552         GdkDisplay *target_display = gdk_drawable_get_display (widget->window);
00553         
00554         static gboolean initialized = FALSE;
00555 
00556 #ifndef MAG_WINDOW_OVERRIDE_REDIRECT    
00557         if (!initialized) {
00558                 wm_window_protocols[0] = gdk_x11_get_xatom_by_name_for_display (target_display,
00559                                                                                 "WM_DELETE_WINDOW");
00560                 wm_window_protocols[1] = gdk_x11_get_xatom_by_name_for_display (target_display,
00561                                                                                 "_NET_WM_PING");
00562                 /* use DOCK until Metacity RFE for new window type goes in */
00563                 wm_type_atoms[0] = gdk_x11_get_xatom_by_name_for_display (target_display,
00564                                                                           "_NET_WM_WINDOW_TYPE_DOCK");
00565         }
00566   
00567         wm_hints.flags = InputHint;
00568         wm_hints.input = False;
00569         
00570         XSetWMHints (GDK_WINDOW_XDISPLAY (widget->window),
00571                      GDK_WINDOW_XWINDOW (widget->window), &wm_hints);
00572         
00573         XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window),
00574                          GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2);
00575 
00576         net_wm_window_type = gdk_x11_get_xatom_by_name_for_display 
00577                 (target_display, "_NET_WM_WINDOW_TYPE");
00578 
00579         if (net_wm_window_type && wm_type_atoms[0])
00580                 XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window),
00581                                  GDK_WINDOW_XWINDOW (widget->window),
00582                                  net_wm_window_type,
00583                                  XA_ATOM, 32, PropModeReplace,
00584                                  (guchar *)wm_type_atoms,
00585                                  1);
00586 #else
00587 #endif
00588         /* TODO: make sure this works/is reset if the DISPLAY 
00589          * (as well as the SCREEN) changes.
00590          */
00591 
00592         XSetErrorHandler (magnifier_x_error_handler);
00593 }
00594 
00595 GdkWindow*
00596 magnifier_get_root (Magnifier *magnifier)
00597 {
00598     if (!magnifier->priv->root && magnifier->source_display) {
00599         magnifier->priv->root = gdk_screen_get_root_window (
00600             gdk_display_get_screen (magnifier->source_display,
00601                                     magnifier->source_screen_num));
00602     }
00603     return magnifier->priv->root;
00604 }
00605 
00606 static gint
00607 magnifier_parse_display_name (Magnifier *magnifier, gchar *full_display_string,
00608                               gchar **display_name)
00609 {
00610         gchar *screen_ptr;
00611         gchar **strings;
00612         
00613         if (display_name != NULL) {
00614                 strings = g_strsplit (full_display_string, ":", 2);
00615                 *display_name = strings [0];
00616                 if (strings [1] != NULL)
00617                         g_free (strings [1]);
00618         }
00619 
00620         screen_ptr = rindex (full_display_string, '.');
00621         if (screen_ptr != NULL) {
00622                 return (gint) strtol (++screen_ptr, NULL, 10);
00623         }
00624         return 0;
00625 }
00626 
00627 static void
00628 magnifier_get_display_rect_bounds (Magnifier *magnifier, GNOME_Magnifier_RectBounds *rect_bounds, gboolean is_target)
00629 {
00630     if (is_target)
00631     {
00632         rect_bounds->x1 = 0;
00633         rect_bounds->x2 = gdk_screen_get_width (
00634             gdk_display_get_screen (magnifier->target_display,
00635                                     magnifier->target_screen_num));
00636         rect_bounds->y1 = 0;
00637         rect_bounds->y2 = gdk_screen_get_height (
00638             gdk_display_get_screen (magnifier->target_display,
00639                                     magnifier->target_screen_num));
00640 
00641     }
00642     else 
00643     {
00644         rect_bounds->x1 = 0;
00645         rect_bounds->x2 = gdk_screen_get_width (
00646             gdk_display_get_screen (magnifier->source_display,
00647                                     magnifier->source_screen_num));
00648         rect_bounds->y1 = 0;
00649         rect_bounds->y2 = gdk_screen_get_height (
00650             gdk_display_get_screen (magnifier->source_display,
00651                                     magnifier->source_screen_num));
00652 
00653     }
00654 }
00655 
00656 static void
00657 magnifier_adjust_source_size (Magnifier *magnifier)
00658 {
00659         GNOME_Magnifier_RectBounds rect_bounds; 
00660         gdouble vfract_top, vfract_bottom, hfract_left, hfract_right;
00661         magnifier_get_display_rect_bounds (magnifier, &rect_bounds, FALSE);
00662         hfract_left = (double) (magnifier->target_bounds.x1) / (double) rect_bounds.x2;
00663         vfract_top = (double) (magnifier->target_bounds.y1) / (double) rect_bounds.y2;
00664         hfract_right = (double) (rect_bounds.x2 - magnifier->target_bounds.x2) / (double) rect_bounds.x2;
00665         vfract_bottom = (double) (rect_bounds.y2 - magnifier->target_bounds.y2) / (double) rect_bounds.y2;
00666         /* we make our 'source' rectangle the largest available subsection which we aren't occupying */
00667         if (MAX (hfract_left, hfract_right) > MAX (vfract_top, vfract_bottom))  /* vertical split, approximately */
00668         {
00669                 if (hfract_right > hfract_left) {
00670                         magnifier->source_bounds.x1 = magnifier->target_bounds.x2;
00671                         magnifier->source_bounds.x2 = rect_bounds.x2;
00672                 }
00673                 else 
00674                 {
00675                         magnifier->source_bounds.x1 = rect_bounds.x1;
00676                         magnifier->source_bounds.x2 = magnifier->target_bounds.x1;
00677                 }
00678                 magnifier->source_bounds.y1 = rect_bounds.y1;
00679                 magnifier->source_bounds.y2 = rect_bounds.y2;
00680         }
00681         else /* more-or-less horizontally split */
00682         {
00683                 if (vfract_bottom > vfract_top) {
00684                         magnifier->source_bounds.y1 = magnifier->target_bounds.y2;
00685                         magnifier->source_bounds.y2 = rect_bounds.y2;
00686                 }
00687                 else 
00688                 {
00689                         magnifier->source_bounds.y1 = rect_bounds.y1;
00690                         magnifier->source_bounds.y2 = magnifier->target_bounds.y1;
00691                 }
00692                 magnifier->source_bounds.x1 = rect_bounds.x1;
00693                 magnifier->source_bounds.x2 = rect_bounds.x2;
00694         }
00695         g_message ("set source bounds to %d,%d; %d,%d", 
00696                    magnifier->source_bounds.x1, magnifier->source_bounds.y1, magnifier->source_bounds.x2, magnifier->source_bounds.y2);
00697 }
00698 
00699 static void
00700 magnifier_unref_zoom_region (gpointer data, gpointer user_data)
00701 {
00702 /*      Magnifier *magnifier = user_data; NOT USED */
00703         CORBA_Environment ev;
00704         GNOME_Magnifier_ZoomRegion zoom_region = data;
00705         CORBA_exception_init (&ev);
00706         
00707         DBG(g_message ("unreffing zoom region"));
00708 
00709         GNOME_Magnifier_ZoomRegion_dispose (zoom_region, &ev);
00710         if (!BONOBO_EX (&ev))
00711             Bonobo_Unknown_unref (zoom_region, &ev);
00712 }
00713 
00714 static GSList*
00715 magnifier_zoom_regions_save (Magnifier *magnifier)
00716 {
00717     GList *list;
00718     GSList *save_props = NULL;
00719     
00720     g_assert (magnifier);
00721     list = magnifier->zoom_regions;
00722 
00723     DBG(g_message ("saving %d regions", g_list_length (list)));
00724 
00725     while (list) 
00726     {
00727         GNOME_Magnifier_ZoomRegion zoom_region;
00728         CORBA_Environment ev;
00729         zoom_region = list->data;
00730         CORBA_exception_init (&ev);
00731         if (zoom_region)
00732         {
00733             Bonobo_PropertyBag properties;
00734             CORBA_any *value;
00735             MagnifierZoomRegionSaveProps *zoomer_props = g_new0 (MagnifierZoomRegionSaveProps, 1);
00736 
00737             zoomer_props->rectbounds = GNOME_Magnifier_ZoomRegion_getROI (zoom_region, &ev);
00738             properties = GNOME_Magnifier_ZoomRegion_getProperties (zoom_region, &ev);
00739             value = bonobo_pbclient_get_value (properties, "viewport", TC_GNOME_Magnifier_RectBounds, &ev);
00740             memcpy (&zoomer_props->viewport, value->_value, sizeof (GNOME_Magnifier_RectBounds));
00741             CORBA_free (value);
00742             zoomer_props->is_managed = bonobo_pbclient_get_boolean (properties, "is-managed", NULL);
00743             zoomer_props->scroll_policy = bonobo_pbclient_get_short (properties, "smooth-scroll-policy", NULL);
00744             zoomer_props->contrast = bonobo_pbclient_get_float (properties, "contrast", NULL);
00745             zoomer_props->zx = bonobo_pbclient_get_float (properties, "mag-factor-x", NULL);
00746             zoomer_props->zy = bonobo_pbclient_get_float (properties, "mag-factor-y", NULL);
00747             zoomer_props->xalign = bonobo_pbclient_get_long (properties, "x-alignment", NULL);
00748             zoomer_props->yalign = bonobo_pbclient_get_long (properties, "y-alignment", NULL);
00749             zoomer_props->border_color = bonobo_pbclient_get_long (properties, "border-color", NULL); 
00750             zoomer_props->border_size = bonobo_pbclient_get_long (properties, "border-size", NULL);
00751             zoomer_props->smoothing_type = bonobo_pbclient_get_string (properties, "smoothing-type", NULL); 
00752             zoomer_props->inverse = bonobo_pbclient_get_boolean (properties, "inverse-video", NULL); 
00753 
00754             bonobo_object_release_unref (properties, &ev);
00755             magnifier_unref_zoom_region ((gpointer) zoom_region, NULL);
00756             save_props = g_slist_append (save_props, zoomer_props);
00757         }
00758         list = g_list_next (list);
00759     }   
00760 
00761     magnifier->zoom_regions = NULL;
00762 
00763     return save_props;
00764 }
00765 
00766 static void
00767 magnifier_zoom_regions_restore (Magnifier *magnifier, GSList *region_params)
00768 {
00769         GSList *list = region_params;
00770 
00771         while (list)
00772         {
00773                 CORBA_Environment ev;
00774                 MagnifierZoomRegionSaveProps *zoomer_props = list->data;
00775                 GNOME_Magnifier_ZoomRegion new_region;
00776                 Bonobo_PropertyBag new_properties;
00777 
00778                 CORBA_exception_init (&ev);
00779                 new_region = GNOME_Magnifier_Magnifier_createZoomRegion (BONOBO_OBJREF (magnifier), zoomer_props->zx, zoomer_props->zy, &zoomer_props->rectbounds, &zoomer_props->viewport, &ev);
00780                 new_properties = GNOME_Magnifier_ZoomRegion_getProperties (new_region, &ev);
00781                 bonobo_pbclient_set_boolean (new_properties, "is-managed", 
00782                                              zoomer_props->is_managed, NULL);
00783                 bonobo_pbclient_set_short (new_properties, "smooth-scroll-policy", 
00784                                            zoomer_props->scroll_policy, NULL);
00785                 bonobo_pbclient_set_float (new_properties, "contrast", 
00786                                            zoomer_props->contrast, NULL);
00787 /* NOT YET USED
00788                 bonobo_pbclient_set_long (new_properties, "x-alignment", 
00789                                              zoomer_props->xalign, NULL);
00790                 bonobo_pbclient_set_long (new_properties, "y-alignment", 
00791                                              zoomer_props->yalign, NULL);
00792 */
00793                 bonobo_pbclient_set_long (new_properties, "border-color", 
00794                                              zoomer_props->border_color, NULL);
00795                 bonobo_pbclient_set_long (new_properties, "border-size", 
00796                                              zoomer_props->border_size, NULL);
00797                 bonobo_pbclient_set_string (new_properties, "smoothing-type", 
00798                                              zoomer_props->smoothing_type, NULL);
00799                 bonobo_pbclient_set_boolean (new_properties, "inverse-video", 
00800                                              zoomer_props->inverse, NULL);
00801                 GNOME_Magnifier_Magnifier_addZoomRegion (BONOBO_OBJREF (magnifier), new_region, &ev);
00802                 g_free (zoomer_props->smoothing_type);
00803                 g_free (zoomer_props);
00804                 bonobo_object_release_unref (new_properties, &ev);
00805                 list = g_slist_next (list);
00806         }
00807         g_slist_free (region_params);
00808 }
00809 
00810 static void
00811 magnifier_init_display (Magnifier *magnifier, gchar *display_name, gboolean is_target)
00812 {
00813     if (!can_open_display (display_name))
00814         return;
00815 
00816     if (is_target)
00817     {
00818         magnifier->target_screen_num =
00819             magnifier_parse_display_name (magnifier,
00820                                           display_name,
00821                                           NULL);
00822         magnifier->target_display =
00823             gdk_display_open (display_name);
00824         if (magnifier->target_display_name) g_free (magnifier->target_display_name);
00825         magnifier->target_display_name = g_strdup (display_name);
00826         magnifier->priv->root =
00827             gdk_screen_get_root_window (
00828                 gdk_display_get_screen (
00829                     magnifier->target_display,
00830                     magnifier->target_screen_num));
00831     }
00832     else 
00833     {
00834         magnifier->source_screen_num =
00835             magnifier_parse_display_name (magnifier,
00836                                           display_name,
00837                                           NULL);
00838         magnifier->source_display =
00839             gdk_display_open (display_name);
00840         if (magnifier->source_display)
00841         {
00842             if (magnifier->source_display_name) g_free (magnifier->source_display_name);
00843             magnifier->source_display_name = g_strdup (display_name);
00844             magnifier->priv->root =
00845                 gdk_screen_get_root_window (
00846                     gdk_display_get_screen (
00847                         magnifier->source_display,
00848                         magnifier->source_screen_num));
00849         }
00850     }
00851 }
00852 
00853 static void
00854 magnifier_exit (GtkObject *object)
00855 {
00856         gtk_main_quit ();
00857         exit (0);
00858 }
00859 
00860 #define GET_PIXEL(a,i,j,s,b) \
00861 (*(guint32 *)(memcpy (b,(a) + ((j) * s + (i) * pixel_size_t), pixel_size_t)))
00862 
00863 #define PUT_PIXEL(a,i,j,s,b) \
00864 (memcpy (a + ((j) * s + (i) * pixel_size_t), &(b), pixel_size_t))
00865 
00866 static void
00867 magnifier_recolor_pixbuf (Magnifier *magnifier, GdkPixbuf *pixbuf)
00868 {
00869         int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
00870         int i, j;
00871         int w = gdk_pixbuf_get_width (pixbuf);
00872         int h = gdk_pixbuf_get_height (pixbuf);
00873         guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
00874         guint32 pixval = 0, cursor_color = 0;
00875         size_t pixel_size_t = 3; /* FIXME: invalid assumption ? */
00876 
00877         cursor_color = ((magnifier->cursor_color & 0xFF0000) >> 16) +
00878                 (magnifier->cursor_color & 0x00FF00) +
00879                 ((magnifier->cursor_color & 0x0000FF) << 16);
00880         for (j = 0; j < h; ++j) {
00881                 for (i = 0; i < w; ++i) {
00882                         pixval = GET_PIXEL (pixels, i, j, rowstride, &pixval);
00883                         if ((pixval & 0x808080) == 0)
00884                         {
00885                                 pixval = cursor_color;
00886                                 PUT_PIXEL (pixels, i, j, rowstride,
00887                                            pixval);
00888                         }
00889                 }
00890         }
00891 }
00892 
00893 static void
00894 magnifier_transform_cursor (Magnifier *magnifier)
00895 {
00896         if (magnifier->priv->cursor) /* don't do this if cursor isn't intialized yet */
00897         {
00898                 int width, height;
00899                 int size_x, size_y;
00900                 GdkPixbuf *scaled_cursor_pixbuf;
00901                 GdkPixbuf *scaled_mask_pixbuf;
00902                 GdkPixbuf *scaled_mask_pixbuf_alpha;
00903                 GdkPixbuf *cursor_pixbuf;
00904                 GdkPixbuf *mask_pixbuf;
00905                 GdkPixmap *cursor_pixmap = magnifier->priv->cursor;
00906                 GdkPixmap *mask_pixmap = magnifier->priv->cursor_mask;
00907                 GdkGC *cgc;
00908                 GdkGC *mgc;
00909 
00910                 if (magnifier->cursor_size_x)
00911                 {
00912                         size_x = magnifier->cursor_size_x;
00913                         size_y = magnifier->cursor_size_y;
00914                 }
00915                 else
00916                 {
00917                         size_x = magnifier->priv->cursor_default_size_x * 
00918                                magnifier->cursor_scale_factor;
00919                         size_y = magnifier->priv->cursor_default_size_y * 
00920                                magnifier->cursor_scale_factor;
00921                 }
00922                 gdk_drawable_get_size (magnifier->priv->cursor, &width, &height);
00923                 if ((size_x == width) && (size_y == height) 
00924                     && (magnifier->cursor_color == 0xFF000000)) {
00925                         return; /* nothing changes */
00926                 }
00927                 cgc = gdk_gc_new (cursor_pixmap);
00928                 mgc = gdk_gc_new (mask_pixmap);
00929                 cursor_pixbuf = gdk_pixbuf_get_from_drawable (NULL, cursor_pixmap,
00930                                                               NULL, 0, 0, 0, 0,
00931                                                               width, height);
00932                 if (magnifier->cursor_color != 0xFF000000)
00933                         magnifier_recolor_pixbuf (magnifier, cursor_pixbuf);
00934                 mask_pixbuf = gdk_pixbuf_get_from_drawable (NULL,
00935                                                             mask_pixmap,
00936                                                             NULL, 0, 0, 0, 0,
00937                                                             width, height);
00938                 scaled_cursor_pixbuf = gdk_pixbuf_scale_simple (
00939                         cursor_pixbuf, size_x, size_y, GDK_INTERP_NEAREST);
00940                 
00941                 magnifier->cursor_hotspot.x = magnifier->priv->cursor_hotspot_x * size_x 
00942                                             / magnifier->priv->cursor_default_size_x;
00943                 magnifier->cursor_hotspot.y = magnifier->priv->cursor_hotspot_y * size_y 
00944                                             / magnifier->priv->cursor_default_size_y;
00945                                             
00946                 scaled_mask_pixbuf = gdk_pixbuf_scale_simple (
00947                         mask_pixbuf, size_x, size_y, GDK_INTERP_NEAREST);
00948                 g_object_unref (cursor_pixbuf);
00949                 g_object_unref (mask_pixbuf);
00950                 g_object_unref (cursor_pixmap);
00951                 g_object_unref (mask_pixmap);
00952                 magnifier->priv->cursor = gdk_pixmap_new (
00953                         magnifier->priv->w->window,
00954                         size_x, size_y,
00955                         -1);
00956                 if (!GDK_IS_DRAWABLE (magnifier->priv->cursor)) 
00957                 {
00958                     DBG (g_warning ("NULL magnifier cursor pixmap."));
00959                     return;
00960                 }
00961                 magnifier->priv->cursor_mask = gdk_pixmap_new (
00962                         magnifier->priv->w->window,
00963                         size_x, size_y,
00964                         1);
00965                 if (GDK_IS_DRAWABLE (magnifier->priv->cursor)) {
00966                     gdk_draw_pixbuf (magnifier->priv->cursor,
00967                                      cgc,
00968                                      scaled_cursor_pixbuf,
00969                                      0, 0, 0, 0, size_x, size_y,
00970                                      GDK_RGB_DITHER_NONE, 0, 0 );
00971                 }
00972                 else
00973                     DBG (g_warning ("cursor pixmap is non-drawable."));
00974                 scaled_mask_pixbuf_alpha = gdk_pixbuf_add_alpha (
00975                         scaled_mask_pixbuf, True, 0, 0, 0);
00976                 gdk_pixbuf_render_threshold_alpha (scaled_mask_pixbuf_alpha,
00977                                                    magnifier->priv->cursor_mask,
00978                                                    0, 0, 0, 0, size_x, size_y,
00979                                                    0x80);
00980                 g_object_unref (scaled_mask_pixbuf_alpha);
00981                 g_object_unref (scaled_cursor_pixbuf);
00982                 g_object_unref (scaled_mask_pixbuf);
00983                 g_object_unref (mgc);
00984                 g_object_unref (cgc);
00985         }       
00986 }
00987 
00988 static void
00989 magnifier_init_cursor_set (Magnifier *magnifier, gchar *cursor_set)
00990 {
00991         /*
00992          * we check the cursor-set property string here,
00993          * and create/apply the appropriate cursor settings
00994          */
00995         magnifier->cursor_set = cursor_set;
00996 #ifdef HAVE_XFIXES      
00997         magnifier->priv->use_source_cursor = 
00998             (!strcmp (cursor_set, "default") && 
00999              (fixes_event_base != 0));
01000 #else
01001         magnifier->priv->use_source_cursor = FALSE;
01002 #endif
01003         if (magnifier->priv->use_source_cursor) return;
01004 
01005         if (!strcmp (magnifier->cursor_set, "none")) {
01006                 magnifier->priv->cursor = NULL;
01007                 return;
01008         }
01009         else 
01010         {
01011                 GDir *cursor_dir;
01012                 const gchar *filename;
01013                 gchar *cursor_dirname;
01014 
01015                 if (magnifier->priv->cursorlist)
01016                 {
01017                         g_hash_table_destroy (magnifier->priv->cursorlist);
01018                 }
01019                 magnifier->priv->cursorlist = g_hash_table_new_full (g_str_hash, g_str_equal,
01020                                                                      g_free, g_object_unref);
01021 
01022                 cursor_dirname = g_strconcat (CURSORSDIR, "/", magnifier->cursor_set, NULL);
01023                 cursor_dir = g_dir_open (cursor_dirname, 0, NULL);
01024                 /* assignment, not comparison, is intentional */
01025                 while (cursor_dir && (filename = g_dir_read_name (cursor_dir)) != NULL) 
01026                 {
01027                         if (filename) 
01028                         {
01029                                 gchar *path = g_strconcat (cursor_dirname, "/", filename, NULL);
01030                                 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (path, NULL);
01031                                 if (pixbuf)
01032                                 {
01033                                         /* add this pixbuf and its name to our list */
01034                                         gchar **sv, *cname;
01035                                         cname = g_path_get_basename (filename);
01036                                         sv = g_strsplit (cname, ".", 2);
01037                                         g_hash_table_insert (magnifier->priv->cursorlist, 
01038                                                              g_strdup (sv[0]),
01039                                                              pixbuf);
01040                                         g_free (cname);
01041                                         g_strfreev (sv);
01042                                 }
01043                                 g_free (path);
01044                         }
01045                 } 
01046                 g_free (cursor_dirname);
01047                 if (cursor_dir) g_dir_close (cursor_dir);
01048         }
01049         /* don't fallover to source cursor here, we haven't initialized X yet */
01050         magnifier_set_cursor_pixmap_by_name (magnifier, "default", FALSE);
01051         magnifier_transform_cursor (magnifier);
01052 }
01053 
01054 static gboolean 
01055 magnifier_reset_struts_at_idle (gpointer data)
01056 {
01057         if (data)
01058         {
01059                 Magnifier *magnifier = MAGNIFIER (data);
01060                 if (magnifier->priv && GTK_WIDGET_REALIZED (magnifier->priv->w) && 
01061                     magnifier_check_set_struts (magnifier))
01062                 {
01063                         return FALSE;
01064                 }
01065         }
01066         return TRUE;
01067 }
01068 
01069 static gboolean
01070 magnifier_check_set_struts (Magnifier *magnifier)
01071 {
01072         /* TODO: don't do this if we're using Composite */
01073         if (magnifier &&
01074             magnifier->priv && magnifier->priv->w && GTK_WIDGET_REALIZED (magnifier->priv->w) &&
01075             magnifier->priv->w->window) 
01076         {
01077                 Atom atom_strut = gdk_x11_get_xatom_by_name ("_NET_WM_STRUT");
01078                 Atom atom_strut_partial = gdk_x11_get_xatom_by_name ("_NET_WM_STRUT_PARTIAL");
01079                 guint32 struts[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
01080                 GtkWidget *widget = magnifier->priv->w;
01081                 gint width = gdk_screen_get_width (
01082                         gdk_display_get_screen (magnifier->target_display,
01083                                                 magnifier->target_screen_num));
01084                 gint height = gdk_screen_get_height (
01085                         gdk_display_get_screen (magnifier->target_display,
01086                                                 magnifier->target_screen_num));
01087 
01088                 gint right_margin, left_margin, top_margin, bottom_margin;
01089                 gint wx, wy, ww, wh;
01090 
01091                 gtk_window_get_position (GTK_WINDOW (magnifier->priv->w), &wx, &wy);
01092                 gtk_window_get_size (GTK_WINDOW (magnifier->priv->w), &ww, &wh);
01093 
01094                 left_margin = wx;
01095                 right_margin = (width - ww) - wx;
01096                 top_margin = wy;
01097                 bottom_margin = (height - wh) - wy;
01098 
01099                 /* set the WM_STRUT properties on the appropriate side */
01100                 if (bottom_margin > top_margin && 
01101                     bottom_margin > left_margin &&
01102                     bottom_margin > right_margin)
01103                 {
01104                         struts[STRUT_TOP] = wh + wy;
01105                         struts[STRUT_TOP_START] = wx;
01106                         struts[STRUT_TOP_END] = wx + ww;
01107                 } 
01108                 else if (top_margin > bottom_margin && 
01109                          top_margin > left_margin &&
01110                          top_margin > right_margin)
01111                 {
01112                         struts[STRUT_BOTTOM] = height - wy;
01113                         struts[STRUT_BOTTOM_START] = wx;
01114                         struts[STRUT_BOTTOM_END] = wx + ww;
01115                 }
01116                 else if (right_margin > left_margin &&
01117                          right_margin > top_margin &&
01118                          right_margin > bottom_margin)
01119                 {
01120                         struts[STRUT_LEFT] = wx;
01121                         struts[STRUT_LEFT_START] = wy;
01122                         struts[STRUT_LEFT_END] = wh + wy;
01123                 }
01124                 else 
01125                 {
01126                         struts[STRUT_RIGHT] = width - wx;
01127                         struts[STRUT_RIGHT_START] = wy;
01128                         struts[STRUT_RIGHT_END] = wy + wh;
01129                 }
01130                 
01131                 gdk_error_trap_push ();
01132                 XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), 
01133                                  GDK_WINDOW_XWINDOW (widget->window), 
01134                                  atom_strut,
01135                                  XA_CARDINAL, 32, PropModeReplace,
01136                                  (guchar *) &struts, 4);
01137                 XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), 
01138                                  GDK_WINDOW_XWINDOW (widget->window), 
01139                                  atom_strut_partial,
01140                                  XA_CARDINAL, 32, PropModeReplace,
01141                                  (guchar *) &struts, 12); 
01142                 gdk_error_trap_pop ();
01143 
01144 #ifdef DEBUG_STRUTS
01145                 g_message ("struts TOP %d (%d - %d)", struts[STRUT_TOP], struts[STRUT_TOP_START], struts[STRUT_TOP_END]);
01146                 g_message ("struts BOTTOM %d (%d - %d)", struts[STRUT_BOTTOM], struts[STRUT_BOTTOM_START], struts[STRUT_BOTTOM_END]);
01147                 g_message ("struts LEFT %d (%d - %d)", struts[STRUT_LEFT], struts[STRUT_LEFT_START], struts[STRUT_LEFT_END]);
01148                 g_message ("struts RIGHT %d (%d - %d)", struts[STRUT_RIGHT], struts[STRUT_RIGHT_START], struts[STRUT_RIGHT_END]);
01149 #endif
01150                 return TRUE;
01151         }
01152         return FALSE;
01153 }
01154 
01155 static void
01156 magnifier_get_property (BonoboPropertyBag *bag,
01157                         BonoboArg *arg,
01158                         guint arg_id,
01159                         CORBA_Environment *ev,
01160                         gpointer user_data)
01161 {
01162         Magnifier *magnifier = user_data;
01163         int csize = 0;
01164 
01165         DBG (fprintf (stderr, "Get property: \t%s\n", mag_prop_names[arg_id]));
01166         
01167         switch (arg_id) {
01168         case MAGNIFIER_SOURCE_SIZE_PROP:
01169                 BONOBO_ARG_SET_GENERAL (arg, magnifier->source_bounds,
01170                                         TC_GNOME_Magnifier_RectBounds,
01171                                         GNOME_Magnifier_RectBounds, NULL);
01172                 break;
01173         case MAGNIFIER_TARGET_SIZE_PROP:
01174                 BONOBO_ARG_SET_GENERAL (arg, magnifier->target_bounds,
01175                                         TC_GNOME_Magnifier_RectBounds,
01176                                         GNOME_Magnifier_RectBounds, NULL);
01177 
01178                 break;
01179         case MAGNIFIER_CURSOR_SET_PROP:
01180                 BONOBO_ARG_SET_STRING (arg, magnifier->cursor_set);
01181                 break;
01182         case MAGNIFIER_CURSOR_SIZE_PROP:
01183                 BONOBO_ARG_SET_INT (arg, magnifier->cursor_size_x);
01184                 BONOBO_ARG_SET_INT (arg, magnifier->cursor_size_y);
01185                 break;
01186         case MAGNIFIER_CURSOR_ZOOM_PROP:
01187                 BONOBO_ARG_SET_FLOAT (arg, magnifier->cursor_scale_factor);
01188                 break;
01189         case MAGNIFIER_CURSOR_COLOR_PROP:
01190                 BONOBO_ARG_SET_GENERAL (arg, magnifier->cursor_color,
01191                                         TC_CORBA_unsigned_long,
01192                                         CORBA_unsigned_long, NULL);
01193                 break;
01194         case MAGNIFIER_CURSOR_HOTSPOT_PROP:
01195                 BONOBO_ARG_SET_GENERAL (arg, magnifier->cursor_hotspot,
01196                                         TC_GNOME_Magnifier_Point,
01197                                         GNOME_Magnifier_Point, NULL);
01198 
01199                 break;
01200         case MAGNIFIER_CURSOR_DEFAULT_SIZE_PROP:
01201                 if (magnifier->priv->cursor)
01202                         gdk_drawable_get_size (magnifier->priv->cursor,
01203                                                &csize, &csize);
01204                 BONOBO_ARG_SET_INT (arg, csize);
01205                 break;
01206         case MAGNIFIER_CROSSWIRE_SIZE_PROP:
01207                 BONOBO_ARG_SET_INT (arg, magnifier->crosswire_size);
01208                 break;
01209         case MAGNIFIER_CROSSWIRE_CLIP_PROP:
01210                 BONOBO_ARG_SET_BOOLEAN (arg, magnifier->crosswire_clip);
01211                 break;
01212         case MAGNIFIER_CROSSWIRE_COLOR_PROP:
01213                 BONOBO_ARG_SET_LONG (arg, magnifier->crosswire_color);
01214                 break;
01215         case MAGNIFIER_SOURCE_DISPLAY_PROP:
01216                 BONOBO_ARG_SET_STRING (arg, magnifier->source_display_name);
01217                 break;
01218         case MAGNIFIER_TARGET_DISPLAY_PROP:
01219                 BONOBO_ARG_SET_STRING (arg, magnifier->target_display_name);
01220                 break;
01221         default:
01222                 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
01223         };
01224 }
01225 
01226 static void
01227 magnifier_set_property (BonoboPropertyBag *bag,
01228                         BonoboArg *arg,
01229                         guint arg_id,
01230                         CORBA_Environment *ev,
01231                         gpointer user_data)
01232 {
01233         Magnifier *magnifier = user_data;
01234         gchar *full_display_string;
01235 
01236         switch (arg_id) {
01237         case MAGNIFIER_SOURCE_DISPLAY_PROP:
01238                 full_display_string = BONOBO_ARG_GET_STRING (arg);
01239                 if (can_open_display (full_display_string))
01240                 {
01241                     GSList *zoom_region_params = NULL;
01242                     magnifier->source_screen_num =
01243                         magnifier_parse_display_name (magnifier,
01244                                                       full_display_string,
01245                                                       NULL);
01246                     magnifier->source_display =
01247                         gdk_display_open (full_display_string);
01248                     magnifier->source_display_name = g_strdup (full_display_string);
01249                     zoom_region_params = magnifier_zoom_regions_save (magnifier);
01250                     magnifier->priv->root =
01251                         gdk_screen_get_root_window (
01252                             gdk_display_get_screen (
01253                                 magnifier->source_display,
01254                                 magnifier->source_screen_num));
01255                      /* attach listeners for DAMAGE, "dirty region", XFIXES cursor changes */
01256                     magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
01257                     magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
01258                     magnifier_zoom_regions_restore (magnifier, zoom_region_params);
01259                     magnifier_warp_cursor_to_screen (magnifier);
01260                     magnifier_check_set_struts (magnifier);
01261                 }
01262                 DBG(fprintf (stderr, "Set source display: \t%s\n", full_display_string));
01263                 break;
01264         case MAGNIFIER_TARGET_DISPLAY_PROP:
01265                 full_display_string = BONOBO_ARG_GET_STRING (arg);
01266                 if (can_open_display (full_display_string))
01267                 {
01268                     magnifier->target_screen_num =
01269                         magnifier_parse_display_name (magnifier,
01270                                                       full_display_string,
01271                                                       NULL);
01272                     magnifier->target_display =
01273                         gdk_display_open (full_display_string);
01274                     magnifier->target_display_name = g_strdup (full_display_string);
01275                     if (GTK_IS_WINDOW (magnifier->priv->w)) 
01276                     {
01277 #ifdef REPARENT_GTK_WINDOW_WORKS
01278                         gtk_window_set_screen (GTK_WINDOW (magnifier->priv->w), 
01279                                                gdk_display_get_screen (
01280                                                    magnifier->target_display,
01281                                                    magnifier->target_screen_num));
01282 #else
01283                         GSList *zoom_region_params = NULL;
01284                         /* disconnect from the old window's destroy signal */
01285                         g_object_disconnect (magnifier->priv->w,
01286                                   "any_signal::realize", magnifier_realize, NULL,
01287                                   "any_signal::size_allocate", magnifier_size_allocate, NULL,
01288                                   "any_signal::destroy", magnifier_exit, NULL,
01289                                   NULL);
01290                         /* save the old zoom region state */
01291                         zoom_region_params = magnifier_zoom_regions_save (magnifier);
01292                         /* destroy the old window */
01293                         gtk_widget_destroy (magnifier->priv->w);
01294                         /* and re-initialize... */
01295                         magnifier_init_window (magnifier, gdk_display_get_screen (
01296                                                    magnifier->target_display,
01297                                                    magnifier->target_screen_num));
01298                         /* restore the zoom regions in their new host magnifier window */
01299                         magnifier_zoom_regions_restore (magnifier, zoom_region_params);
01300 #endif
01301                     }
01302                     magnifier_get_display_rect_bounds (magnifier, &magnifier->source_bounds, FALSE);
01303                     magnifier_init_cursor_set (magnifier, magnifier->cursor_set); /* needed to reset pixmaps */
01304                     gtk_window_move (GTK_WINDOW (magnifier->priv->w),
01305                                      magnifier->target_bounds.x1,
01306                                      magnifier->target_bounds.y1);
01307                     
01308                     if ((magnifier->target_bounds.x2 - magnifier->target_bounds.x1 > 0) &&
01309                         (magnifier->target_bounds.y2 - magnifier->target_bounds.y1) > 0)
01310                     {
01311                         gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
01312                                        magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
01313                                        magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
01314                     DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n", 
01315                              magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
01316                     }
01317                     /* N. B. we don't reset the target bounds to the limits of the new display, because */
01318                     /* doing so would override the client-specified magnifier size */
01319                     /* magnifier_get_display_rect_bounds (magnifier, &magnifier->target_bounds, TRUE); */
01320                     magnifier_check_set_struts (magnifier);
01321                 }
01322                 DBG(fprintf (stderr, "Set target display: \t%s (screen %d)\n", 
01323                               full_display_string, magnifier->target_screen_num));
01324                 break;
01325         case MAGNIFIER_SOURCE_SIZE_PROP:
01326                 magnifier->source_bounds = BONOBO_ARG_GET_GENERAL (arg,
01327                                                                    TC_GNOME_Magnifier_RectBounds,
01328                                                                    GNOME_Magnifier_RectBounds,
01329                                                                    NULL);
01330                 DBG (fprintf (stderr, "Set source size: \t%d,%d to %d,%d\n", 
01331                               magnifier->source_bounds.x1, magnifier->source_bounds.y1, magnifier->source_bounds.x2, magnifier->source_bounds.y2));
01332                 break;
01333         case MAGNIFIER_TARGET_SIZE_PROP:
01334                 magnifier->target_bounds = BONOBO_ARG_GET_GENERAL (arg,
01335                                                                    TC_GNOME_Magnifier_RectBounds,
01336                                                                    GNOME_Magnifier_RectBounds,
01337                                                                    NULL);
01338                 gtk_window_move (GTK_WINDOW (magnifier->priv->w),
01339                                  magnifier->target_bounds.x1,
01340                                  magnifier->target_bounds.y1);
01341                 
01342                 gtk_window_resize (GTK_WINDOW (magnifier->priv->w),
01343                                    magnifier->target_bounds.x2 - magnifier->target_bounds.x1,
01344                                    magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
01345                 magnifier_check_set_struts (magnifier);
01346                 DBG(fprintf (stderr, "Set target size: \t%d,%d to %d,%d\n", 
01347                               magnifier->target_bounds.x1, magnifier->target_bounds.y1, magnifier->target_bounds.x2, magnifier->target_bounds.y2));
01348                 if (!strcmp (magnifier->target_display_name, magnifier->source_display_name) && 
01349                     (magnifier->target_screen_num == magnifier->source_screen_num)) 
01350                     magnifier_adjust_source_size (magnifier);
01351                 break;
01352         case MAGNIFIER_CURSOR_SET_PROP:
01353                 magnifier_init_cursor_set (magnifier, g_strdup (BONOBO_ARG_GET_STRING (arg)));
01354                 DBG (fprintf (stderr, "Setting cursor set: \t%s\n", BONOBO_ARG_GET_STRING (arg)));
01355                 break;
01356         case MAGNIFIER_CURSOR_SIZE_PROP:
01357                 magnifier->cursor_size_x = BONOBO_ARG_GET_INT (arg);
01358                 magnifier->cursor_size_y = BONOBO_ARG_GET_INT (arg);
01359                 magnifier_transform_cursor (magnifier);
01360                 DBG (fprintf (stderr, "Setting cursor size: \t%d\n", magnifier->cursor_size_x));
01361                 break;
01362         case MAGNIFIER_CURSOR_ZOOM_PROP:
01363                 magnifier->cursor_scale_factor = BONOBO_ARG_GET_FLOAT (arg);
01364                 DBG (fprintf (stderr, "Setting cursor scale factor: \t%f\n", (float) magnifier->cursor_scale_factor));
01365                 magnifier_transform_cursor (magnifier);
01366                 break;
01367         case MAGNIFIER_CURSOR_COLOR_PROP:
01368                 magnifier->cursor_color = BONOBO_ARG_GET_GENERAL (arg,
01369                                                                   TC_CORBA_unsigned_long, 
01370                                                                   CORBA_unsigned_long, 
01371                                                                   NULL);
01372                 magnifier_transform_cursor (magnifier);
01373                 DBG (fprintf (stderr, "Setting cursor color: \t%u\n", (unsigned) magnifier->cursor_color));
01374                 break;
01375         case MAGNIFIER_CURSOR_HOTSPOT_PROP:
01376                 magnifier->cursor_hotspot = BONOBO_ARG_GET_GENERAL (arg,
01377                                                                     TC_GNOME_Magnifier_Point,
01378                                                                     GNOME_Magnifier_Point,
01379                                                                     NULL);
01380                 /* TODO: notify zoomers */
01381                 /* FIXME: don't call init_cursor, it overwrites this property! */
01382                 magnifier_transform_cursor (magnifier); 
01383                 break;
01384         case MAGNIFIER_CURSOR_DEFAULT_SIZE_PROP:
01385                 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_ReadOnly);
01386                 break;
01387         case MAGNIFIER_CROSSWIRE_SIZE_PROP:
01388                 magnifier->crosswire_size = BONOBO_ARG_GET_INT (arg);
01389                 DBG (fprintf (stderr, "Setting crosswire size: \t%d\n", magnifier->crosswire_size));
01390                 /* TODO: notify zoomers */
01391                 break;
01392         case MAGNIFIER_CROSSWIRE_CLIP_PROP:
01393                 magnifier->crosswire_clip = BONOBO_ARG_GET_BOOLEAN (arg);
01394                 DBG (fprintf (stderr, "Setting crosswire clip: \t%s\n", magnifier->crosswire_clip ? "true" : "false"));
01395                 break;
01396         case MAGNIFIER_CROSSWIRE_COLOR_PROP:
01397                 magnifier->crosswire_color = BONOBO_ARG_GET_LONG (arg);
01398                 DBG (fprintf (stderr, "Setting crosswire size: \t%ld\n", (long) magnifier->crosswire_color));
01399                 break;
01400         default:
01401                 bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
01402                 break;
01403         };
01404 }
01405 
01406 static void
01407 magnifier_do_dispose (Magnifier *magnifier)
01408 {
01409         /* FIXME: this is dead ropey code structuring */
01410         bonobo_activation_active_server_unregister (
01411                 MAGNIFIER_OAFIID, BONOBO_OBJREF (magnifier));
01412 
01413         if (magnifier->zoom_regions)
01414                 g_list_free (magnifier->zoom_regions);
01415         magnifier->zoom_regions = NULL;
01416         
01417         bonobo_main_quit ();
01418 }
01419 
01420 static void
01421 magnifier_gobject_dispose (GObject *object)
01422 {
01423         magnifier_do_dispose (MAGNIFIER (object));
01424 
01425         BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
01426 }
01427 
01428 static void
01429 impl_magnifier_set_source_display (PortableServer_Servant servant,
01430                                    const CORBA_char *display,
01431                                    CORBA_Environment *ev)
01432 {
01433         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01434         BonoboArg *arg = bonobo_arg_new (BONOBO_ARG_STRING);
01435         BONOBO_ARG_SET_STRING (arg, display);
01436         
01437         DBG (fprintf (stderr, "Set source display: \t%s\n", display));
01438 
01439         if (strcmp (display, magnifier->source_display_name)) {
01440 
01441             magnifier_set_property (magnifier->property_bag,
01442                                     arg,
01443                                     MAGNIFIER_SOURCE_DISPLAY_PROP,
01444                                     ev,
01445                                     magnifier);
01446         }
01447         else
01448         {
01449             DBG (fprintf (stderr, "Attempt to set source to same value as previous: %s\n",
01450                           display));
01451         }
01452         bonobo_arg_release (arg);
01453 }
01454 
01455 static void
01456 impl_magnifier_set_target_display (PortableServer_Servant servant,
01457                                    const CORBA_char *display,
01458                                    CORBA_Environment *ev)
01459 {
01460         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01461         BonoboArg *arg = bonobo_arg_new (BONOBO_ARG_STRING);
01462         BONOBO_ARG_SET_STRING (arg, display);
01463         
01464         DBG (fprintf (stderr, "Set target display: \t%s\n", display));
01465 
01466         if (strcmp (display, magnifier->target_display_name)) 
01467         {
01468             magnifier_set_property (magnifier->property_bag,
01469                                     arg,
01470                                     MAGNIFIER_TARGET_DISPLAY_PROP,
01471                                     ev,
01472                                     magnifier);
01473         }
01474         else
01475         {
01476             DBG (fprintf (stderr, "Attempt to set target to same value as previous: %s\n",
01477                           display));
01478         }
01479         bonobo_arg_release (arg);
01480 }
01481 
01482 static 
01483 CORBA_string
01484 impl_magnifier_get_source_display (PortableServer_Servant servant,
01485                                    CORBA_Environment *ev)
01486 {
01487         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01488         DBG (fprintf (stderr, "Get source display: \t%s\n", magnifier->source_display_name));
01489 
01490         return CORBA_string_dup (magnifier->source_display_name ? magnifier->source_display_name : "");
01491 }
01492 
01493 static 
01494 CORBA_string
01495 impl_magnifier_get_target_display (PortableServer_Servant servant,
01496                                    CORBA_Environment *ev)
01497 {
01498         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01499         DBG (fprintf (stderr, "Get target display: \t%s\n", 
01500                       magnifier->target_display_name));
01501 
01502         return CORBA_string_dup (magnifier->target_display_name ? magnifier->target_display_name : "");
01503 }
01504 
01505 static GNOME_Magnifier_ZoomRegion
01506 impl_magnifier_create_zoom_region (PortableServer_Servant servant,
01507                                    const CORBA_float zx,
01508                                    const CORBA_float zy,
01509                                    const GNOME_Magnifier_RectBounds *roi,
01510                                    const GNOME_Magnifier_RectBounds *viewport,
01511                                    CORBA_Environment *ev)
01512 {
01513         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01514         CORBA_any viewport_any;
01515         ZoomRegion *zoom_region = zoom_region_new ();
01516         Bonobo_PropertyBag properties;
01517         GNOME_Magnifier_ZoomRegion retval;
01518 
01519         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));
01520 
01521         /* FIXME:
01522          * shouldn't do this here, since it causes the region to get
01523          * mapped onto the parent, if if it's not explicitly added!
01524          */
01525         DBG(g_message ("creating zoom region with parent %p", magnifier));
01526         zoom_region->priv->parent = magnifier;
01527 
01528         retval = BONOBO_OBJREF (zoom_region);
01529         /* XXX: should check ev after each call, below */
01530         CORBA_exception_init (ev);
01531         GNOME_Magnifier_ZoomRegion_setMagFactor (retval, zx, zy, ev);
01532 
01533         if (ev->_major != CORBA_NO_EXCEPTION)
01534                 fprintf (stderr, "EXCEPTION setMagFactor\n");
01535 
01536         CORBA_exception_init (ev);
01537         properties = GNOME_Magnifier_ZoomRegion_getProperties (retval, ev);
01538         if (ev->_major != CORBA_NO_EXCEPTION)
01539                 fprintf (stderr, "EXCEPTION getProperties\n");
01540 
01541         viewport_any._type = TC_GNOME_Magnifier_RectBounds;
01542         viewport_any._value = (gpointer) viewport;
01543         Bonobo_PropertyBag_setValue (
01544                 properties, "viewport", &viewport_any, ev);
01545 
01546         GNOME_Magnifier_ZoomRegion_setROI (retval, roi, ev);
01547         if (ev->_major != CORBA_NO_EXCEPTION)
01548                 fprintf (stderr, "EXCEPTION setROI\n");
01549 
01550         CORBA_exception_init (ev);
01551 
01552         gtk_widget_set_size_request (magnifier->priv->canvas,
01553                            viewport->x2 - viewport->x1,
01554                            viewport->y2 - viewport->y1);
01555         gtk_widget_show (magnifier->priv->canvas);
01556         gtk_widget_show (magnifier->priv->w);
01557 
01558         bonobo_object_release_unref (properties, ev);
01559         
01560         return CORBA_Object_duplicate (retval, ev);
01561 }
01562 
01563 static
01564 CORBA_boolean
01565 impl_magnifier_add_zoom_region (PortableServer_Servant servant,
01566                                 const GNOME_Magnifier_ZoomRegion region,
01567                                 CORBA_Environment * ev)
01568 {
01569         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01570 
01571         if (!magnifier->source_initialized) 
01572         {
01573                 magnifier_set_extension_listeners (magnifier, magnifier_get_root (magnifier));
01574         }
01575 
01576         /* FIXME: this needs proper lifecycle management */
01577         magnifier->zoom_regions = g_list_append (magnifier->zoom_regions, region);
01578         magnifier_check_set_struts (magnifier);
01579 
01580         return CORBA_TRUE;
01581 }
01582 
01583 static Bonobo_PropertyBag
01584 impl_magnifier_get_properties (PortableServer_Servant servant,
01585                                CORBA_Environment *ev)
01586 {
01587         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01588         return bonobo_object_dup_ref (
01589                 BONOBO_OBJREF (magnifier->property_bag), ev);
01590 }
01591 
01592 GNOME_Magnifier_ZoomRegionList *
01593 impl_magnifier_get_zoom_regions (PortableServer_Servant servant,
01594                                  CORBA_Environment * ev)
01595 {
01596         Magnifier *magnifier =
01597                 MAGNIFIER (bonobo_object_from_servant (servant));
01598 
01599         GNOME_Magnifier_ZoomRegionList *list;
01600         CORBA_Object objref;
01601         int i, len;
01602 
01603         len = g_list_length (magnifier->zoom_regions);
01604         list = GNOME_Magnifier_ZoomRegionList__alloc ();
01605         list->_length = len;
01606         list->_buffer =
01607                 GNOME_Magnifier_ZoomRegionList_allocbuf (list->_length);
01608         for (i = 0; i < len; ++i) {
01609                 objref = g_list_nth_data (magnifier->zoom_regions, i);
01610                 list->_buffer [i] =
01611                         CORBA_Object_duplicate (objref, ev);
01612         }
01613         CORBA_sequence_set_release (list, CORBA_TRUE);
01614 
01615         DBG (fprintf (stderr, "Get zoom regions: \t%d\n", len));
01616         
01617         return list; 
01618 }
01619 
01620 static void
01621 impl_magnifier_clear_all_zoom_regions (PortableServer_Servant servant,
01622                                        CORBA_Environment * ev)
01623 {
01624         Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
01625         fprintf (stderr, "Clear all zoom regions.\n");
01626 
01627         g_list_foreach (magnifier->zoom_regions,
01628                         magnifier_unref_zoom_region, magnifier);
01629         g_list_free (magnifier->zoom_regions);
01630         magnifier->zoom_regions = NULL;
01631 }
01632 
01633 static void
01634 impl_magnifier_dispose (PortableServer_Servant servant,
01635                         CORBA_Environment *ev)
01636 {
01637         magnifier_do_dispose (
01638                 MAGNIFIER (bonobo_object_from_servant (servant)));
01639 }
01640 
01641 static void
01642 magnifier_class_init (MagnifierClass *klass)
01643 {
01644         GObjectClass * object_class = (GObjectClass *) klass;
01645         POA_GNOME_Magnifier_Magnifier__epv *epv = &klass->epv;
01646         parent_class = g_type_class_peek (BONOBO_TYPE_OBJECT); /* needed by BONOBO_CALL_PARENT! */
01647 
01648         object_class->dispose = magnifier_gobject_dispose;
01649 
01650         epv->_set_SourceDisplay = impl_magnifier_set_source_display;
01651         epv->_set_TargetDisplay = impl_magnifier_set_target_display;
01652         epv->_get_SourceDisplay = impl_magnifier_get_source_display;
01653         epv->_get_TargetDisplay = impl_magnifier_get_target_display;
01654         epv->getProperties = impl_magnifier_get_properties;
01655         epv->getZoomRegions = impl_magnifier_get_zoom_regions;
01656         epv->createZoomRegion = impl_magnifier_create_zoom_region;
01657         epv->addZoomRegion = impl_magnifier_add_zoom_region;
01658         epv->clearAllZoomRegions = impl_magnifier_clear_all_zoom_regions;
01659         epv->dispose = impl_magnifier_dispose;
01660 }
01661 
01662 static void
01663 magnifier_properties_init (Magnifier *magnifier)
01664 {
01665         BonoboArg *def;
01666         GNOME_Magnifier_RectBounds rect_bounds;
01667         gchar *display_env;
01668 
01669         magnifier->property_bag =
01670                 bonobo_property_bag_new_closure (
01671                         g_cclosure_new_object (
01672                                 G_CALLBACK (magnifier_get_property),
01673                                 G_OBJECT (magnifier)),
01674                         g_cclosure_new_object (
01675                                 G_CALLBACK (magnifier_set_property),
01676                                 G_OBJECT (magnifier)));
01677 
01678         /* Aggregate so magnifier implements Bonobo_PropertyBag */
01679         bonobo_object_add_interface (BONOBO_OBJECT (magnifier),
01680                                      BONOBO_OBJECT (magnifier->property_bag));
01681 
01682         def = bonobo_arg_new (BONOBO_ARG_STRING);
01683         display_env = getenv ("DISPLAY");
01684         BONOBO_ARG_SET_STRING (def, display_env);
01685 
01686         bonobo_property_bag_add (magnifier->property_bag,
01687                                  "source-display-screen",
01688                                  MAGNIFIER_SOURCE_DISPLAY_PROP,
01689                                  BONOBO_ARG_STRING,
01690                                  def,
01691                                  "source display screen",
01692                                  Bonobo_PROPERTY_WRITEABLE);
01693 
01694         bonobo_property_bag_add (magnifier->property_bag,
01695                                  "target-display-screen",
01696                                  MAGNIFIER_TARGET_DISPLAY_PROP,
01697                                  BONOBO_ARG_STRING,
01698                                  def,
01699                                  "target display screen",
01700                                  Bonobo_PROPERTY_WRITEABLE);
01701 
01702         bonobo_arg_release (def);
01703 
01704         magnifier_init_display (magnifier, display_env, TRUE);
01705         magnifier_init_display (magnifier, display_env, FALSE);
01706 
01707         magnifier_get_display_rect_bounds (magnifier, &rect_bounds, FALSE);
01708         def = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, &rect_bounds);
01709         
01710         bonobo_property_bag_add (magnifier->property_bag,
01711                                  "source-display-bounds",
01712                                  MAGNIFIER_SOURCE_SIZE_PROP,
01713                                  TC_GNOME_Magnifier_RectBounds,
01714                                  def,
01715                                  "source display bounds/size",
01716                                  Bonobo_PROPERTY_READABLE |
01717                                  Bonobo_PROPERTY_WRITEABLE);
01718         bonobo_arg_release (def);
01719         
01720         magnifier_get_display_rect_bounds (magnifier, &rect_bounds, TRUE);
01721         def = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, &rect_bounds);
01722 
01723         bonobo_property_bag_add (magnifier->property_bag,
01724                                  "target-display-bounds",
01725                                  MAGNIFIER_TARGET_SIZE_PROP,
01726                                  TC_GNOME_Magnifier_RectBounds,
01727                                  def,
01728                                  "target display bounds/size",
01729                                  Bonobo_PROPERTY_READABLE |
01730                                  Bonobo_PROPERTY_WRITEABLE);
01731         bonobo_arg_release (def);
01732 
01733         bonobo_property_bag_add (magnifier->property_bag,
01734                                  "cursor-set",
01735                                  MAGNIFIER_CURSOR_SET_PROP,
01736                                  BONOBO_ARG_STRING,
01737                                  NULL,
01738                                  "name of cursor set",
01739                                  Bonobo_PROPERTY_READABLE |
01740                                  Bonobo_PROPERTY_WRITEABLE);
01741 
01742         def = bonobo_arg_new (BONOBO_ARG_INT);
01743         BONOBO_ARG_SET_INT (def, 64);
01744         
01745         bonobo_property_bag_add (magnifier->property_bag,
01746                                  "cursor-size",
01747                                  MAGNIFIER_CURSOR_SIZE_PROP,
01748                                  BONOBO_ARG_INT,
01749                                  def,
01750                                  "cursor size, in pixels",
01751                                  Bonobo_PROPERTY_READABLE |
01752                                  Bonobo_PROPERTY_WRITEABLE);
01753         bonobo_arg_release (def);
01754         
01755         bonobo_property_bag_add (magnifier->property_bag,
01756                                  "cursor-scale-factor",
01757                                  MAGNIFIER_CURSOR_ZOOM_PROP,
01758                                  BONOBO_ARG_FLOAT,
01759                                  NULL,
01760                                  "scale factor for cursors (overrides size)",
01761                                  Bonobo_PROPERTY_READABLE |
01762                                  Bonobo_PROPERTY_WRITEABLE);
01763         
01764         bonobo_property_bag_add (magnifier->property_bag,
01765                                  "cursor-color",
01766                                  MAGNIFIER_CURSOR_COLOR_PROP,
01767                                  TC_CORBA_unsigned_long,
01768                                  NULL,
01769                                  "foreground color for 1-bit cursors, as ARGB",
01770                                  Bonobo_PROPERTY_READABLE |
01771                                  Bonobo_PROPERTY_WRITEABLE);    
01772 
01773         bonobo_property_bag_add (magnifier->property_bag,
01774                                  "cursor-hotspot",
01775                                  MAGNIFIER_CURSOR_HOTSPOT_PROP,
01776                                  TC_GNOME_Magnifier_Point,
01777                                  NULL,
01778                                  "hotspot relative to cursor's upper-left-corner, at default resolition",
01779                                  Bonobo_PROPERTY_READABLE |
01780                                  Bonobo_PROPERTY_WRITEABLE);
01781         
01782         bonobo_property_bag_add (magnifier->property_bag,
01783                                  "cursor-default-size",
01784                                  MAGNIFIER_CURSOR_DEFAULT_SIZE_PROP,
01785                                  BONOBO_ARG_INT,
01786                                  NULL,
01787                                  "default size of current cursor set",
01788                                  Bonobo_PROPERTY_READABLE);
01789 
01790         bonobo_property_bag_add (magnifier->property_bag,
01791                                  "crosswire-size",
01792                                  MAGNIFIER_CROSSWIRE_SIZE_PROP,
01793                                  BONOBO_ARG_INT,
01794                                  NULL,
01795                                  "thickness of crosswire cursor, in target pixels",
01796                                  Bonobo_PROPERTY_READABLE |
01797                                  Bonobo_PROPERTY_WRITEABLE);
01798         
01799         bonobo_property_bag_add (magnifier->property_bag,
01800                                  "crosswire-color",
01801                                  MAGNIFIER_CROSSWIRE_COLOR_PROP,
01802                                  BONOBO_ARG_LONG,
01803                                  NULL,
01804                                  "color of crosswire, as A-RGB; note that alpha is required. (use 0 for XOR wire)",
01805                                  Bonobo_PROPERTY_READABLE |
01806                                  Bonobo_PROPERTY_WRITEABLE);
01807 
01808         bonobo_property_bag_add (magnifier->property_bag,
01809                                  "crosswire-clip",
01810                                  MAGNIFIER_CROSSWIRE_CLIP_PROP,
01811                                  BONOBO_ARG_BOOLEAN,
01812                                  NULL,
01813                                  "whether to inset the cursor over the crosswire or not",
01814                                  Bonobo_PROPERTY_READABLE |
01815                                  Bonobo_PROPERTY_WRITEABLE);
01816 }
01817 
01818 static void
01819 magnifier_init_window (Magnifier *magnifier, GdkScreen *screen)
01820 {
01821         GtkWindowType mag_win_type = GTK_WINDOW_TOPLEVEL;
01822         if (_is_override_redirect) mag_win_type = GTK_WINDOW_POPUP;
01823 
01824         magnifier->priv->w =
01825                 g_object_connect (gtk_widget_new (gtk_window_get_type (),
01826                                                   "user_data", NULL,
01827                                                   "can_focus", FALSE,
01828                                                   "type", mag_win_type,  
01829                                                   "title", "magnifier",
01830                                                   "allow_grow", TRUE,
01831                                                   "allow_shrink", TRUE,
01832                                                   "border_width", 0,
01833                                                   NULL),
01834                                   "signal::realize", magnifier_realize, NULL,
01835                                   "signal::size_allocate", magnifier_size_allocate, NULL,
01836                                   "signal::destroy", magnifier_exit, NULL,
01837                                   NULL);
01838         gtk_window_set_screen (GTK_WINDOW (magnifier->priv->w), screen);
01839         magnifier->priv->canvas = gtk_fixed_new ();
01840         gtk_container_add (GTK_CONTAINER (magnifier->priv->w),
01841                            magnifier->priv->canvas);
01842         magnifier->priv->root = NULL;
01843 }
01844 
01845 static void
01846 magnifier_init (Magnifier *magnifier)
01847 {
01848         magnifier->priv = g_new0 (MagnifierPrivate, 1);
01849         magnifier_properties_init (magnifier);
01850         magnifier->zoom_regions = NULL;
01851         magnifier->source_screen_num = 0;
01852         magnifier->target_screen_num = 0;
01853         magnifier->source_display_name = g_strdup (":0.0");
01854         magnifier->target_display_name = g_strdup (":0.0");
01855         magnifier->cursor_size_x = 0;
01856         magnifier->cursor_size_y = 0;
01857         magnifier->cursor_scale_factor = 1.0F;
01858         magnifier->cursor_color = 0xFF000000;
01859         magnifier->crosswire_size = 1;
01860         magnifier->crosswire_color = 0;
01861         magnifier->crosswire_clip = FALSE;
01862         magnifier->cursor_hotspot.x = 0;
01863         magnifier->cursor_hotspot.y = 0;
01864         magnifier->priv->cursor = NULL;
01865         magnifier->priv->w = NULL;
01866         magnifier->priv->use_source_cursor = TRUE;
01867         magnifier->priv->cursorlist = NULL;
01868         magnifier_init_window (magnifier, 
01869                                gdk_display_get_screen (magnifier->target_display, 
01870                                                        magnifier->target_screen_num));
01871         magnifier_init_cursor_set (magnifier, "default");
01872 
01873         mag_timing.process = g_timer_new ();
01874         mag_timing.frame = g_timer_new ();
01875         mag_timing.scale = g_timer_new ();
01876         mag_timing.idle = g_timer_new ();
01877 #ifdef DEBUG_CLIENT_CALLS
01878         client_debug = (g_getenv ("MAG_CLIENT_DEBUG") != NULL);
01879 #endif
01880 }
01881 
01882 GdkDrawable *
01883 magnifier_get_cursor (Magnifier *magnifier)
01884 {
01885         if (magnifier->priv->cursor == NULL) {
01886             if ((fixes_event_base == 0) && 
01887                 strcmp (magnifier->cursor_set, "none")) 
01888             {
01889                 GdkPixbuf *pixbuf;
01890                 gchar *default_cursor_filename = 
01891                     g_strconcat (CURSORSDIR, "/", "default-cursor.xpm", NULL);
01892                 pixbuf = gdk_pixbuf_new_from_file (default_cursor_filename, NULL);
01893                 if (pixbuf) 
01894                 {
01895                     magnifier_set_cursor_from_pixbuf (magnifier, pixbuf);
01896                     g_object_unref (pixbuf);
01897                     magnifier_transform_cursor (magnifier);
01898                 }
01899                 g_free (default_cursor_filename);
01900             }
01901 #ifdef HAVE_XFIXES
01902             else {
01903                 GdkPixbuf *cursor_pixbuf = magnifier_get_source_pixbuf (magnifier);
01904                 magnifier_set_cursor_from_pixbuf (magnifier, cursor_pixbuf);
01905                 if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
01906                 magnifier_transform_cursor (magnifier);
01907             }
01908 #endif
01909         }
01910         return magnifier->priv->cursor;
01911 }
01912 
01913 Magnifier *
01914 magnifier_new (gboolean override_redirect)
01915 {
01916         Magnifier *mag;
01917         MagLoginHelper *helper;
01918         int ret;
01919 
01920         _is_override_redirect = override_redirect;
01921 
01922         mag = g_object_new (magnifier_get_type(), NULL);
01923 
01924         _this_magnifier = mag; /* FIXME what about multiple instances? */
01925 
01926         helper = g_object_new (mag_login_helper_get_type (), NULL);
01927         mag_login_helper_set_magnifier (helper, mag);
01928 
01929         bonobo_object_add_interface (bonobo_object (mag), 
01930                                      BONOBO_OBJECT (helper));
01931         
01932         ret = bonobo_activation_active_server_register (
01933                 MAGNIFIER_OAFIID, BONOBO_OBJREF (mag));
01934         if (ret != Bonobo_ACTIVATION_REG_SUCCESS)
01935             g_error ("Error registering magnifier server.\n");
01936 
01937         g_idle_add (magnifier_reset_struts_at_idle, mag);
01938 
01939         return mag;
01940 }
01941 
01942 BONOBO_TYPE_FUNC_FULL (Magnifier, 
01943                        GNOME_Magnifier_Magnifier,
01944                        BONOBO_TYPE_OBJECT,
01945                        magnifier)
01946 

Generated on Fri Dec 15 19:26:51 2006 for gnome-mag by  doxygen 1.4.7