gmag-events.c

Go to the documentation of this file.
00001 /*
00002  * GNOME-MAG Magnification service for GNOME
00003  *
00004  * Copyright 2006 Carlos Eduardo Rodrigues Diógenes
00005  * Copyright 2004 Sun Microsystems Inc. (damage-client.c)
00006  * Copyright 2001 Sun Microsystems Inc. (magnifier.c)
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public
00019  * License along with this library; if not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00021  * Boston, MA 02111-1307, USA.
00022  */
00023 
00024 #include "config.h"
00025 #include "magnifier.h"
00026 #include "magnifier-private.h"
00027 #include "gmag-events.h"
00028 
00029 #include <stdlib.h>
00030 
00031 #include <X11/Xlib.h>
00032 #ifdef HAVE_XFIXES
00033 #include <X11/extensions/Xfixes.h>
00034 #ifdef HAVE_DAMAGE
00035 #include <X11/extensions/Xdamage.h>
00036 #ifdef HAVE_COMPOSITE
00037 #include <X11/extensions/Xrender.h>
00038 #include <X11/extensions/Xcomposite.h>
00039 #endif /* HAVE_COMPOSITE */
00040 #endif /* HAVE_DAMAGE */
00041 #endif /* HAVE_XFIXES */
00042 
00043 #include <glib.h>
00044 
00045 #include <gdk/gdkx.h>
00046 #include <gtk/gtk.h>
00047 
00048 static Display       *dpy_conn = NULL;
00049 static guint          dpy_gsource = 0;
00050 static Window         root_window, mag_window;
00051 
00052 static gboolean       use_damage, use_composite;
00053 
00054 gint                  fixes_event_base = 0, fixes_error_base;
00055 #ifdef HAVE_XFIXES
00056 #ifdef HAVE_DAMAGE
00057 static gint           damage_event_base, damage_error_base;
00058 static Damage         root_window_damage;
00059 static XserverRegion  gmag_events_tmp_region;
00060 #ifdef HAVE_COMPOSITE
00061 static GQueue        *mag_windows_list;
00062 static Damage         off_screen_damage;
00063 static Picture        off_screen_picture;
00064 static XserverRegion  off_screen_region;
00065 static XserverRegion  tmp_region, new_region, old_region, exp_region;
00066 #endif /* HAVE_COMPOSITE */
00067 #endif /* HAVE_DAMAGE */
00068 #endif /* HAVE_XFIXES */
00069 
00070 #define EVENTS_DEBUG
00071 #undef  EVENTS_DEBUG
00072 
00073 #ifdef  EVENTS_DEBUG
00074 
00075 #ifdef HAVE_DAMAGE
00076 #define DAMAGE_DEBUG
00077 #undef  DAMAGE_DEBUG
00078 #endif /* HAVE_DAMAGE */
00079 
00080 #ifdef HAVE_COMPOSITE
00081 #define COMPOSITE_DEBUG
00082 #undef  COMPOSITE_DEBUG
00083 #endif /* HAVE_COMPOSITE */
00084 
00085 #ifdef HAVE_XFIXES
00086 #define CURSOR_DEBUG
00087 #undef  CURSOR_DEBUG
00088 #define XFIXES_DEBUG
00089 #undef  XFIXES_DEBUG
00090 #endif /* HAVE_XFIXES */
00091 
00092 #endif /* EVENTS_DEBUG */
00093 
00094 #ifdef HAVE_XFIXES
00095 #ifdef HAVE_COMPOSITE
00096 
00097 /*
00098  * GCompareFunc used in g_queue_find_custom to find windows in
00099  * mag_windows_list.
00100  */
00101 static gint
00102 gmag_events_g_compare_func (GmagWinPtr pgmag_win, Window xwin)
00103 {
00104         if (pgmag_win->xwin == xwin)
00105                 return 0;
00106 
00107         return 1;
00108 }
00109 
00110 /*
00111  * Calculates the clip for all windows in mag_windows_list.
00112  */
00113 static void
00114 gmag_events_calculate_windows_clip ()
00115 {
00116         GList         *elem = NULL;
00117         XserverRegion clipSum;
00118 
00119         clipSum = XFixesCreateRegion (dpy_conn, 0, 0);
00120         elem = g_queue_peek_tail_link (mag_windows_list);
00121         if (!elem) {
00122                 XFixesDestroyRegion (dpy_conn, clipSum);
00123                 return;
00124         }
00125         do {
00126                 GmagWinPtr pgmag_win = (GmagWinPtr) elem->data;
00127                 if (pgmag_win->pic)
00128                         if (pgmag_win->attr.map_state == IsViewable) {
00129                                 XFixesCopyRegion (
00130                                         dpy_conn,
00131                                         pgmag_win->clip,
00132                                         XFixesCreateRegionFromWindow (
00133                                                 dpy_conn,
00134                                                 pgmag_win->xwin,
00135                                                 WindowRegionBounding));
00136                                 XFixesTranslateRegion (
00137                                         dpy_conn,
00138                                         pgmag_win->clip, pgmag_win->attr.x,
00139                                         pgmag_win->attr.y);
00140                                 XFixesCopyRegion (
00141                                         dpy_conn,
00142                                         pgmag_win->win_region,
00143                                         pgmag_win->clip);
00144                                 XFixesSubtractRegion (
00145                                         dpy_conn,
00146                                         pgmag_win->clip, pgmag_win->clip,
00147                                         clipSum);
00148                                 XFixesUnionRegion (
00149                                         dpy_conn,
00150                                         clipSum, clipSum,
00151                                         pgmag_win->win_region);
00152                         }
00153         } while ((elem = g_list_previous (elem)));
00154         XFixesDestroyRegion (dpy_conn, clipSum);
00155 }
00156 
00157 /*
00158  * Calculates the clip of a single window in mag_windows_list.
00159  */
00160 static void
00161 gmag_events_calculate_window_clip (GmagWinPtr pgmag_win_newclip)
00162 {
00163         GList         *elem = NULL;
00164         XserverRegion clipSum;
00165 
00166         clipSum = XFixesCreateRegion (dpy_conn, 0, 0);
00167         elem = g_queue_peek_tail_link (mag_windows_list);
00168         if (!elem) {
00169                 XFixesDestroyRegion (dpy_conn, clipSum);
00170                 return;
00171         }
00172         do {
00173                 GmagWinPtr pgmag_win = (GmagWinPtr) elem->data;
00174                 if (pgmag_win->xwin == pgmag_win_newclip->xwin) {
00175                         /* the window that must have a new clip was founded */
00176                         XFixesCopyRegion (
00177                                 dpy_conn,
00178                                 pgmag_win->clip,
00179                                 XFixesCreateRegionFromWindow (
00180                                         dpy_conn,
00181                                         pgmag_win->xwin,
00182                                         WindowRegionBounding));
00183                         XFixesTranslateRegion (dpy_conn,
00184                                                pgmag_win->clip,
00185                                                pgmag_win->attr.x,
00186                                                pgmag_win->attr.y);
00187                         XFixesCopyRegion (dpy_conn,
00188                                           pgmag_win->win_region,
00189                                           pgmag_win->clip);
00190                         XFixesSubtractRegion (dpy_conn,
00191                                               pgmag_win->clip, pgmag_win->clip,
00192                                               clipSum);
00193                         break;
00194                 }
00195                 if (pgmag_win->pic)
00196                         if (pgmag_win->attr.map_state == IsViewable) {
00197                                 XFixesUnionRegion (
00198                                         dpy_conn,
00199                                         clipSum, clipSum,
00200                                         pgmag_win->win_region);
00201                         }
00202         } while ((elem = g_list_previous (elem)));
00203         XFixesDestroyRegion (dpy_conn, clipSum);
00204 }
00205 
00206 /*
00207  * Paint a window. If region is None, the window clip region is painted, else
00208  * the intersection of the window clip region and region is painted.
00209  */
00210 static void
00211 gmag_events_paint_window (GmagWinPtr pgmag_win, XserverRegion region)
00212 {
00213         static XserverRegion final_clip = None;
00214 
00215         if (!pgmag_win->damaged && !region)
00216                 return;
00217         if (!pgmag_win->pic)
00218                 return;
00219         if (pgmag_win->attr.map_state != IsViewable)
00220                 return;
00221 
00222         if (!final_clip)
00223                 final_clip = XFixesCreateRegion (
00224                         dpy_conn, 0, 0);
00225 
00226         XFixesSetRegion (dpy_conn, final_clip, 0, 0);
00227 
00228         if (region) {
00229                 XFixesIntersectRegion (dpy_conn,
00230                                        final_clip, region, pgmag_win->clip);
00231                 XFixesSetPictureClipRegion (dpy_conn,
00232                                             pgmag_win->pic,
00233                                             -(pgmag_win->attr.x),
00234                                             -(pgmag_win->attr.y), final_clip);
00235         } else
00236                 XFixesSetPictureClipRegion (dpy_conn,
00237                                             pgmag_win->pic,
00238                                             -(pgmag_win->attr.x),
00239                                             -(pgmag_win->attr.y),
00240                                             pgmag_win->clip);
00241         XRenderComposite (dpy_conn, PictOpSrc,
00242                           pgmag_win->pic, None, off_screen_picture,
00243                           0, 0, 0, 0, pgmag_win->attr.x, pgmag_win->attr.y,
00244                           pgmag_win->attr.width, pgmag_win->attr.height);
00245 }
00246 
00247 /*
00248  * Paint all the windows in mag_windows_list with the specified
00249  * exposedRegion.
00250  */
00251 static void
00252 gmag_events_paint_windows (XserverRegion exposedRegion)
00253 {
00254         GList      *elem;
00255         GmagWinPtr  pgmag_win;
00256 
00257         elem = g_queue_peek_head_link (mag_windows_list);
00258 
00259         while (elem) {
00260                 pgmag_win = (GmagWinPtr) elem->data;
00261                 gmag_events_paint_window (pgmag_win, exposedRegion);
00262                 elem = g_list_next (elem);
00263         }
00264 }
00265 
00266 /*
00267  * Sometimes XGetWindowAttributes fail (when the window is destroied), so we
00268  * put default values in it to not have problems in other parts of the program.
00269  * I think that only some ones need to be setted, but this was copied from
00270  * Compiz, so...
00271  */
00272 static void
00273 gmag_events_set_default_window_attributes (XWindowAttributes *wa)
00274 {
00275         wa->x                     = 0;
00276         wa->y                     = 0;
00277         wa->width                 = 1;
00278         wa->height                = 1;
00279         wa->border_width          = 0;
00280         wa->depth                 = 0;
00281         wa->visual                = NULL;
00282         wa->root                  = None;
00283         wa->class                 = InputOnly;
00284         wa->bit_gravity           = NorthWestGravity;
00285         wa->win_gravity           = NorthWestGravity;
00286         wa->backing_store         = NotUseful;
00287         wa->backing_planes        = 0;
00288         wa->backing_pixel         = 0;
00289         wa->save_under            = FALSE;
00290         wa->colormap              = None;
00291         wa->map_installed         = FALSE;
00292         wa->map_state             = IsUnviewable;
00293         wa->all_event_masks       = 0;
00294         wa->your_event_mask       = 0;
00295         wa->do_not_propagate_mask = 0;
00296         wa->override_redirect     = TRUE;
00297         wa->screen                = NULL;
00298 }
00299 
00300 /*
00301  * Creates the necessary information of a redirected window and add it to
00302  * mag_windows_list.
00303  */
00304 static void
00305 gmag_events_add_window (Window xwin)
00306 {
00307         GmagWinPtr                new;
00308         XRenderPictureAttributes  pic_attr;
00309         XRenderPictFormat        *format;
00310 
00311         new = (GmagWinPtr) malloc (sizeof (GmagWin));
00312         if (!new)
00313                 g_error ("can't allocate GmagWin (struct _GmagWin)");
00314 
00315         if (!XGetWindowAttributes (dpy_conn, xwin,
00316                                    &new->attr))
00317                 gmag_events_set_default_window_attributes (&new->attr);
00318 
00319         new->xwin = xwin;
00320 
00321         if (new->attr.class == InputOnly) {
00322                 new->pic = None;
00323                 new->damage = None;
00324                 new->damaged = FALSE;
00325                 new->damaged_region = None;
00326         } else {
00327                 format = XRenderFindVisualFormat (
00328                         dpy_conn, new->attr.visual);
00329                 pic_attr.subwindow_mode = IncludeInferiors;
00330                 new->pic = XRenderCreatePicture (
00331                         dpy_conn, xwin, format,
00332                         CPSubwindowMode, &pic_attr);
00333                 new->damage = XDamageCreate (dpy_conn, xwin,
00334                                              XDamageReportDeltaRectangles);
00335                 new->damaged = TRUE;
00336                 new->damaged_region = XFixesCreateRegion (dpy_conn, 0, 0);
00337                 new->clip = XFixesCreateRegion (dpy_conn, 0, 0);
00338                 new->win_region = XFixesCreateRegion (dpy_conn, 0, 0);
00339         }
00340         
00341         g_queue_push_tail (mag_windows_list, new);
00342 }
00343 
00344 /*
00345  * Create the mag_windows_list querying the xserver for the actual
00346  * windows and adding them to the windows list.
00347  */
00348 static void
00349 gmag_events_create_windows_list ()
00350 {
00351         Window  root_return, parent_return, *children;
00352         guint   nchildren;
00353         gint    i;
00354 
00355         if (!mag_windows_list)
00356                 mag_windows_list = g_queue_new ();
00357 
00358         XGrabServer (dpy_conn);
00359         XSelectInput (dpy_conn, root_window,
00360                       SubstructureNotifyMask);
00361         XQueryTree (dpy_conn, root_window,
00362                     &root_return, &parent_return, &children, &nchildren);
00363         for (i = 0; i < nchildren; i++)
00364                 gmag_events_add_window (children[i]);
00365         XFree (children);
00366         XUngrabServer (dpy_conn);
00367 }
00368 
00369 /*
00370  * Destroy the window resources and remove it from the
00371  * mag_windows_list.
00372  */
00373 static void
00374 gmag_events_remove_window (Window xwin)
00375 {
00376         GList     *elem = NULL;
00377         GmagWinPtr pgmag_win;
00378 
00379         elem = g_queue_find_custom (mag_windows_list,
00380                                     (gconstpointer) xwin,
00381                                     (GCompareFunc) gmag_events_g_compare_func);
00382         if (elem) {
00383                 pgmag_win = (GmagWinPtr) elem->data;
00384                 g_queue_remove (mag_windows_list, pgmag_win);
00385                 XFixesDestroyRegion (dpy_conn,
00386                                      pgmag_win->clip);
00387                 XFixesDestroyRegion (dpy_conn,
00388                                      pgmag_win->win_region);
00389                 free (pgmag_win);
00390         }
00391 }
00392 
00393 /*
00394  * Add a window damaged region, making a union with the actual damaged region,
00395  * to the window in mag_windows_list.
00396  */
00397 static void
00398 gmag_events_add_win_damaged_region (Window xwin, XserverRegion region)
00399 {
00400         GList      *elem;
00401         GmagWinPtr  pgmag_win;
00402 
00403         elem = g_queue_find_custom (mag_windows_list,
00404                                     (gconstpointer) xwin,
00405                                     (GCompareFunc) gmag_events_g_compare_func);
00406         if (elem) {
00407                 pgmag_win = (GmagWinPtr) elem->data;
00408                 XFixesTranslateRegion (dpy_conn, region,
00409                                        pgmag_win->attr.x, pgmag_win->attr.y);
00410                 XFixesUnionRegion (dpy_conn,
00411                                    pgmag_win->damaged_region,
00412                                    pgmag_win->damaged_region, region);
00413                 pgmag_win->damaged = TRUE;
00414         }
00415 }
00416 
00417 /*
00418  * Paint all the windows that have some damage.
00419  */
00420 static void
00421 gmag_events_paint_damaged_windows ()
00422 {
00423         GList      *elem;
00424         GmagWinPtr  pgmag_win;
00425 
00426         elem = g_queue_peek_head_link (mag_windows_list);
00427         while (elem) {
00428                 pgmag_win = (GmagWinPtr) elem->data;
00429                 if (pgmag_win->damaged) {
00430                         gmag_events_paint_window (pgmag_win,
00431                                                   pgmag_win->damaged_region);
00432                         XFixesSetRegion (dpy_conn,
00433                                          pgmag_win->damaged_region, 0, 0);
00434                         pgmag_win->damaged = FALSE;
00435                 }
00436 
00437                 elem = g_list_next (elem);
00438         }
00439 }
00440 
00441 static void
00442 gmag_events_circulate_notify_handler (XEvent *ev)
00443 {
00444         GList      *elem;
00445         GmagWinPtr  pgmag_win;
00446 
00447 #ifdef COMPOSITE_DEBUG
00448         printf ("Received CirculateNotify event: 0x%x\n",
00449                 (guint) ev->xcirculate.window);
00450 #endif /* COMPOSITE_DEBUG */
00451         if (ev->xcirculate.window == mag_window) {
00452 #ifdef HAVE_OVERLAY
00453 #ifdef COMPOSITE_DEBUG
00454                 printf ("Overlay window = 0x%x\n",
00455                         (guint) gmag_events_overlay_window);
00456 #endif /* COMPOSITE_DEBUG */
00457 #endif /* HAVE_OVERLAY */
00458                 return;
00459         }
00460         elem = g_queue_find_custom (mag_windows_list,
00461                                     (gconstpointer) ev->xcirculate.window,
00462                                     (GCompareFunc) gmag_events_g_compare_func);
00463         if (elem) {
00464                 pgmag_win = (GmagWinPtr) elem->data;
00465                 g_queue_remove (mag_windows_list, pgmag_win);
00466                 if (ev->xcirculate.place == PlaceOnTop) {
00467                         g_queue_push_tail (mag_windows_list,
00468                                            pgmag_win);
00469                         if (pgmag_win->attr.map_state == IsViewable) {
00470                                 XFixesSubtractRegion (
00471                                         dpy_conn,
00472                                         tmp_region, pgmag_win->win_region,
00473                                         pgmag_win->clip);
00474                                 XFixesUnionRegion (
00475                                         dpy_conn,
00476                                         exp_region, exp_region, tmp_region);
00477                         }
00478                 } else {
00479                         g_queue_push_head (mag_windows_list,
00480                                            pgmag_win);
00481                         if (pgmag_win->attr.map_state == IsViewable)
00482                                 XFixesUnionRegion (
00483                                         dpy_conn,
00484                                         exp_region, exp_region,
00485                                         pgmag_win->clip);
00486                 }
00487         }
00488 }
00489 
00490 static void
00491 gmag_events_configure_notify_handler (XEvent *ev)
00492 {
00493         GList      *elem;
00494         GmagWinPtr  pgmag_win;
00495         
00496 #ifdef COMPOSITE_DEBUG
00497         printf ("Received ConfigureNotify event: 0x%x\n",
00498                 (guint) ev->xconfigure.window);
00499 #endif /* COMPOSITE_DEBUG */
00500         if (ev->xconfigure.window == mag_window) {
00501 #ifdef HAVE_OVERLAY
00502 #ifdef COMPOSITE_DEBUG
00503                 printf ("Overlay window = 0x%x\n",
00504                         (guint) gmag_events_overlay_window);
00505 #endif /* COMPOSITE_DEBUG */
00506 #endif /* HAVE_OVERLAY */
00507                 return;
00508         }
00509         elem = g_queue_find_custom (mag_windows_list,
00510                                     (gconstpointer) ev->xconfigure.window,
00511                                     (GCompareFunc) gmag_events_g_compare_func);
00512         if (elem) {
00513                 pgmag_win = (GmagWinPtr) elem->data;
00514                 if ((pgmag_win->attr.x != ev->xconfigure.x) ||
00515                     (pgmag_win->attr.y != ev->xconfigure.y) ||
00516                     (pgmag_win->attr.width != ev->xconfigure.width) ||
00517                     (pgmag_win->attr.height != ev->xconfigure.height) ||
00518                     (pgmag_win->attr.border_width !=
00519                      ev->xconfigure.border_width)) {
00520                         /* If an attribute of the window has changed we could
00521                          * have an exposed area that is not reported due to the
00522                          * overlay window. So we subtract the new region, from
00523                          * the old one, and we have the value of the exposed
00524                          * region that must be repainted.
00525                          */
00526                         pgmag_win->attr.x = ev->xconfigure.x;
00527                         pgmag_win->attr.y = ev->xconfigure.y;
00528                         pgmag_win->attr.width = ev->xconfigure.width;
00529                         pgmag_win->attr.height = ev->xconfigure.height;
00530                         pgmag_win->attr.border_width =
00531                                 ev->xconfigure.border_width;
00532                               
00533                         if (pgmag_win->attr.map_state == IsViewable) {
00534                                 XFixesCopyRegion (
00535                                         dpy_conn,
00536                                         old_region, pgmag_win->clip);
00537                                 gmag_events_calculate_window_clip (pgmag_win);
00538                                 XFixesCopyRegion (
00539                                         dpy_conn,
00540                                         new_region, pgmag_win->clip);
00541                                 XFixesUnionRegion (
00542                                         dpy_conn,
00543                                         exp_region, exp_region, old_region);
00544                                 XFixesUnionRegion (
00545                                         dpy_conn,
00546                                         exp_region, exp_region, new_region);
00547                         }
00548                 }
00549                 if (!ev->xconfigure.above) {
00550                         g_queue_remove (mag_windows_list, pgmag_win);
00551                         g_queue_push_head (mag_windows_list,
00552                                            pgmag_win);
00553                         if (pgmag_win->attr.map_state == IsViewable) {
00554                                 XFixesUnionRegion (
00555                                         dpy_conn,
00556                                         exp_region, exp_region,
00557                                         pgmag_win->win_region);
00558                         }
00559                 } else {
00560                         elem = g_queue_find_custom (
00561                                 mag_windows_list,
00562                                 (gconstpointer) ev->xconfigure.above,
00563                                 (GCompareFunc) gmag_events_g_compare_func);
00564                         if (elem) {
00565                                 g_queue_remove (mag_windows_list,
00566                                                 pgmag_win);
00567                                 g_queue_insert_after (mag_windows_list,
00568                                                       elem, pgmag_win);
00569                                 if (pgmag_win->attr.map_state == IsViewable) {
00570                                         XFixesUnionRegion (
00571                                                 dpy_conn,
00572                                                 exp_region, exp_region,
00573                                                 pgmag_win->win_region);
00574                                 }
00575                         }
00576                 }
00577         }
00578 }
00579 
00580 static void
00581 gmag_events_create_notify_handler (XEvent *ev)
00582 {
00583         GList      *elem;
00584         GmagWinPtr  pgmag_win;
00585 
00586 #ifdef COMPOSITE_DEBUG
00587         printf ("Received CreateNotify event: 0x%x\n",
00588                 (guint) ev->xcreatewindow.window);
00589 #endif /* COMPOSITE_DEBUG */
00590         if (ev->xcreatewindow.window == mag_window) {
00591 #ifdef HAVE_OVERLAY
00592 #ifdef COMPOSITE_DEBUG
00593                 printf ("Overlay window = 0x%x\n",
00594                         (guint) gmag_events_overlay_window);
00595 #endif /* COMPOSITE_DEBUG */
00596 #endif /* HAVE_OVERLAY */
00597                 return;
00598         }
00599         gmag_events_add_window (ev->xcreatewindow.window);
00600         elem = g_queue_find_custom (mag_windows_list,
00601                                     (gconstpointer) ev->xcreatewindow.window,
00602                                     (GCompareFunc) gmag_events_g_compare_func);
00603         if (elem) {
00604                 pgmag_win = (GmagWinPtr) elem->data;
00605                 if (pgmag_win->attr.map_state == IsViewable) {
00606                         gmag_events_calculate_window_clip (pgmag_win);
00607                         XFixesUnionRegion (dpy_conn,
00608                                            exp_region, exp_region,
00609                                            pgmag_win->clip);
00610                 }
00611         }
00612 }
00613 
00614 static void
00615 gmag_events_destroy_notify_handler (XEvent *ev)
00616 {
00617         GList      *elem;
00618         GmagWinPtr  pgmag_win;
00619 
00620 #ifdef COMPOSITE_DEBUG
00621         printf ("Received DestroyNotify event: 0x%x\n",
00622                 (guint) ev->xdestroywindow.window);
00623 #endif /* COMPOSITE_DEBUG */
00624         if (ev->xdestroywindow.window == mag_window) {
00625 #ifdef HAVE_OVERLAY
00626 #ifdef COMPOSITE_DEBUG
00627                 printf ("Overlay window = 0x%x\n",
00628                         (guint) gmag_events_overlay_window);
00629 #endif /* COMPOSITE_DEBUG */
00630 #endif /* HAVE_OVERLAY */
00631                 return;
00632         }
00633         elem = g_queue_find_custom (mag_windows_list,
00634                                     (gconstpointer) ev->xdestroywindow.window,
00635                                     (GCompareFunc) gmag_events_g_compare_func);
00636         if (elem) {
00637                 pgmag_win = (GmagWinPtr) elem->data;
00638                 if (pgmag_win->attr.map_state == IsViewable)
00639                         XFixesUnionRegion (dpy_conn,
00640                                            exp_region, exp_region,
00641                                            pgmag_win->clip);
00642                 gmag_events_remove_window (ev->xdestroywindow.window);
00643         }
00644 }
00645 
00646 static void
00647 gmag_events_map_notify_handler (XEvent *ev)
00648 {
00649         GList      *elem;
00650         GmagWinPtr  pgmag_win;
00651 
00652 #ifdef COMPOSITE_DEBUG
00653         printf ("Received MapNotify event: 0x%x\n",
00654                 (guint) ev->xmap.window);
00655 #endif /* COMPOSITE_DEBUG */
00656         if (ev->xmap.window == mag_window) {
00657 #ifdef HAVE_OVERLAY
00658 #ifdef COMPOSITE_DEBUG
00659                 printf ("Overlay window = 0x%x\n",
00660                         (guint) gmag_events_overlay_window);
00661 #endif /* COMPOSITE_DEBUG */
00662 #endif /* HAVE_OVERLAY */
00663                 return;
00664         }
00665         elem = g_queue_find_custom (mag_windows_list,
00666                                     (gconstpointer) ev->xmap.window,
00667                                     (GCompareFunc) gmag_events_g_compare_func);
00668         if (elem) {
00669                 pgmag_win = (GmagWinPtr) elem->data;
00670                 pgmag_win->attr.map_state = IsViewable;
00671                 gmag_events_calculate_window_clip (pgmag_win);
00672                 XFixesUnionRegion (dpy_conn, exp_region,
00673                                    exp_region, pgmag_win->clip);
00674         }
00675 }
00676 
00677 static void
00678 gmag_events_unmap_notify_handler (XEvent *ev)
00679 {
00680         GList      *elem;
00681         GmagWinPtr  pgmag_win;
00682 
00683 #ifdef COMPOSITE_DEBUG
00684         printf ("Received UnmapNotify event: 0x%x\n",
00685                 (guint) ev->xunmap.window);
00686 #endif /* COMPOSITE_DEBUG */
00687         if (ev->xunmap.window == mag_window) {
00688 #ifdef HAVE_OVERLAY
00689 #ifdef COMPOSITE_DEBUG
00690                 printf ("Overlay window = 0x%x\n",
00691                         (guint) gmag_events_overlay_window);
00692 #endif /* COMPOSITE_DEBUG */
00693 #endif /* HAVE_OVERLAY */
00694                 return;
00695         }
00696         elem = g_queue_find_custom (mag_windows_list,
00697                                     (gconstpointer) ev->xunmap.window,
00698                                     (GCompareFunc) gmag_events_g_compare_func);
00699         if (elem) {
00700                 pgmag_win = (GmagWinPtr) elem->data;
00701                 pgmag_win->attr.map_state = IsUnmapped;
00702                 XFixesUnionRegion (dpy_conn, exp_region,
00703                                    exp_region, pgmag_win->clip);
00704         }
00705 }
00706 
00707 static void
00708 gmag_events_reparent_notify_handler (XEvent *ev)
00709 {
00710         GList      *elem;
00711         GmagWinPtr  pgmag_win;
00712 
00713 #ifdef COMPOSITE_DEBUG
00714         printf ("Received ReparentNotify event: 0x%x (Window), 0x%x (Parent)\n", (guint) ev->xreparent.window, (guint) ev->xreparent.parent);
00715 #endif /* COMPOSITE_DEBUG */
00716         if  (ev->xreparent.window == mag_window) {
00717 #ifdef HAVE_OVERLAY
00718 #ifdef COMPOSITE_DEBUG
00719                 printf ("Overlay window = 0x%x\n",
00720                         (guint) gmag_events_overlay_window);
00721 #endif /* COMPOSITE_DEBUG */
00722 #endif /* HAVE_OVERLAY */
00723                 return;
00724         }
00725         if (ev->xreparent.parent != root_window) {
00726                 gmag_events_remove_window (ev->xreparent.window);
00727         } else {
00728                 gmag_events_add_window (ev->xreparent.window);
00729                 elem = g_queue_find_custom (
00730                         mag_windows_list,
00731                         (gconstpointer) ev->xreparent.window,
00732                         (GCompareFunc) gmag_events_g_compare_func);
00733                 if (elem) {
00734                         pgmag_win = (GmagWinPtr) elem->data;
00735                         if (pgmag_win->attr.map_state == IsViewable) {
00736                                 gmag_events_calculate_window_clip (pgmag_win);
00737                                 XFixesUnionRegion (
00738                                         dpy_conn,
00739                                         exp_region, exp_region,
00740                                         pgmag_win->clip);
00741                         }
00742                 }
00743         }
00744 }
00745 
00746 #endif /* HAVE_COMPOSITE */
00747 
00748 #ifdef HAVE_DAMAGE
00749 
00750 static void
00751 gmag_events_damage_notify_handler (XEvent *ev)
00752 {
00753         XDamageNotifyEvent *dev = (XDamageNotifyEvent *) ev;
00754 #ifdef DAMAGE_DEBUG
00755         g_message ("Damage area %3d, %3d x %3d, %3d",
00756                    (int) dev->area.x, (int) dev->area.x + dev->area.width,
00757                    (int) dev->area.y, (int) dev->area.y + dev->area.height);
00758         g_message ("Damage geometry %3d, %3d x %3d, %3d",
00759                    (int) dev->geometry.x,
00760                    (int) dev->geometry.x + dev->geometry.width,
00761                    (int) dev->geometry.y,
00762                    (int) dev->geometry.y + dev->geometry.height);
00763 #endif /* DAMAGE_DEBUG */
00764 
00765 #ifdef HAVE_COMPOSITE
00766         if (use_composite) {
00767                 if (dev->damage == off_screen_damage) {
00768 #ifdef DAMAGE_DEBUG
00769                         g_message ("off_screen_damage damaged");
00770 #endif /* DAMAGE_DEBUG */
00771                         XDamageSubtract (dpy_conn, dev->damage, None,
00772                                          gmag_events_tmp_region);
00773                         XFixesUnionRegion (dpy_conn,
00774                                            off_screen_region,
00775                                            off_screen_region,
00776                                            gmag_events_tmp_region);
00777                 } else {
00778 #ifdef DAMAGE_DEBUG
00779                         g_message ("Window with damage: 0x%x", dev->drawable);
00780 #endif /* DAMAGE_DEBUG */
00781                         XDamageSubtract (dpy_conn, dev->damage, None,
00782                                          gmag_events_tmp_region);
00783                         gmag_events_add_win_damaged_region (
00784                                 dev->drawable, gmag_events_tmp_region);
00785                 }
00786         }
00787 #endif /* HAVE_COMPOSITE */
00788 }
00789 
00790 #endif /* HAVE_DAMAGE */
00791 
00792 static void
00793 gmag_events_cursor_convert_to_rgba (Magnifier *magnifier,
00794                                     XFixesCursorImage *cursor_image)
00795 {
00796         int i, count = cursor_image->width * cursor_image->height;
00797         for (i = 0; i < count; ++i) {
00798                 guint32 pixval = GUINT_TO_LE (cursor_image->pixels[i]);
00799                 cursor_image->pixels[i] = pixval;
00800         }
00801 }
00802 
00803 static void
00804 gmag_events_free_cursor_pixels (guchar *pixels, gpointer data)
00805 {
00806     /* XFree (data); FIXME why doesn't this work properly? */
00807 }
00808 
00809 #endif /* HAVE_XFIXES */
00810 
00811 GdkPixbuf *
00812 gmag_events_get_source_pixbuf (Magnifier *magnifier)
00813 {
00814 #ifdef HAVE_XFIXES
00815         XFixesCursorImage *cursor_image = XFixesGetCursorImage (
00816                 dpy_conn);
00817         GdkPixbuf *cursor_pixbuf = NULL;
00818         gchar s[6];
00819         if (cursor_image)
00820         {
00821                 gmag_events_cursor_convert_to_rgba (magnifier, cursor_image);
00822                 cursor_pixbuf = gdk_pixbuf_new_from_data (
00823                         (guchar *) cursor_image->pixels, GDK_COLORSPACE_RGB,
00824                         TRUE, 8, cursor_image->width, cursor_image->height,
00825                         cursor_image->width * 4,
00826                         gmag_events_free_cursor_pixels, cursor_image);
00827                 gdk_pixbuf_set_option (cursor_pixbuf, "x_hot", 
00828                                        g_ascii_dtostr (
00829                                                s, 6,
00830                                                (gdouble) cursor_image->xhot));
00831                 gdk_pixbuf_set_option (cursor_pixbuf, "y_hot", 
00832                                        g_ascii_dtostr (
00833                                                s, 6,
00834                                                (gdouble) cursor_image->yhot));
00835         }
00836         return cursor_pixbuf;
00837 #else
00838         return NULL;
00839 #endif /* HAVE_XFIXES */
00840 }
00841 
00842 gboolean
00843 gmag_events_source_has_damage_extension (Magnifier *magnifier)
00844 {
00845 #ifdef HAVE_DAMAGE
00846         gint event_base, error_base;
00847         Display *dpy;
00848         g_assert (magnifier);
00849         dpy = GDK_DISPLAY_XDISPLAY (magnifier->source_display);
00850         if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
00851                 return FALSE;
00852         if (XDamageQueryExtension (dpy, &event_base, &error_base))
00853                 return TRUE;
00854 #endif /* HAVE_DAMAGE */
00855         return FALSE;
00856 }
00857 
00858 static gboolean
00859 gmag_events_handler (GIOChannel *source, GIOCondition condition, gpointer data)
00860 {
00861 #ifdef HAVE_XFIXES
00862         XEvent                   ev;
00863         XFixesCursorNotifyEvent *cev = NULL;
00864         gboolean                 cursor_changed = FALSE;
00865         Magnifier               *magnifier = (Magnifier *) data;
00866         XRectangle              *rectlist;
00867 #ifdef HAVE_COMPOSITE
00868         gboolean                 calc_clip = FALSE;
00869 #endif /* HAVE_COMPOSITE */
00870 
00871 #ifdef HAVE_OVERLAY
00872         if (magnifier->priv->overlay)
00873                 mag_window = GDK_WINDOW_XID (magnifier->priv->overlay);
00874 #else
00875         if (magnifier->priv->w && magnifier->priv->w->window)
00876                 mag_window = GDK_WINDOW_XID (magnifier->priv->w->window);
00877 #endif /* HAVE_OVERLAY */
00878 
00879         do
00880         {
00881                 XNextEvent(dpy_conn, &ev);
00882 
00883 #ifdef HAVE_COMPOSITE
00884                 if (use_composite) {
00885                         switch (ev.type) {
00886                         case CirculateNotify:
00887                                 gmag_events_circulate_notify_handler (&ev);
00888                                 calc_clip = TRUE;
00889                                 break;
00890                         case ConfigureNotify:
00891                                 gmag_events_configure_notify_handler (&ev);
00892                                 calc_clip = TRUE;
00893                                 break;
00894                         case CreateNotify:
00895                                 gmag_events_create_notify_handler (&ev);
00896                                 calc_clip = TRUE;
00897                                 break;
00898                         case DestroyNotify:
00899                                 gmag_events_destroy_notify_handler (&ev);
00900                                 calc_clip = TRUE;
00901                                 break;
00902                         case MapNotify:
00903                                 gmag_events_map_notify_handler (&ev);
00904                                 calc_clip = TRUE;
00905                                 break;
00906                         case UnmapNotify:
00907                                 gmag_events_unmap_notify_handler (&ev);
00908                                 calc_clip = TRUE;
00909                                 break;
00910                         case ReparentNotify:
00911                                 gmag_events_reparent_notify_handler (&ev);
00912                                 calc_clip = TRUE;
00913                                 break;
00914                         }
00915                 }
00916 #endif /* HAVE_COMPOSITE */
00917 
00918 #ifdef HAVE_DAMAGE
00919                 if (use_damage) {
00920                         if (ev.type == damage_event_base + XDamageNotify) {
00921                                 gmag_events_damage_notify_handler (&ev);
00922                         }
00923                 }
00924 #endif /* HAVE_DAMAGE */
00925 
00926 #ifdef HAVE_XFIXES
00927                 if (ev.type == fixes_event_base + XFixesCursorNotify) {
00928                         cursor_changed = TRUE;
00929                         cev = (XFixesCursorNotifyEvent *) &ev;
00930                 }
00931 #endif /* HAVE_XFIXES */
00932 
00933         } while (XPending (dpy_conn));
00934 
00935 #ifndef HAVE_OVERLAY
00936         if (use_composite && mag_window) {
00937                 XRaiseWindow (dpy_conn, mag_window);
00938         }
00939 #endif /* HAVE_OVERLAY */
00940 
00941 #ifdef HAVE_DAMAGE
00942         if (!use_composite) {
00943                 XDamageSubtract (dpy_conn, root_window_damage, None,
00944                                  gmag_events_tmp_region);
00945         }
00946 
00947         if (use_damage) {
00948                 if (magnifier) {
00949                         int i, howmany;
00950                         /* TODO: maintain this list on the client instead, to
00951                          * avoid the roundtrip below */
00952 #ifdef HAVE_COMPOSITE
00953                         if (use_composite) {
00954                                 rectlist = XFixesFetchRegion (
00955                                         dpy_conn,
00956                                         off_screen_region,
00957                                         &howmany);
00958                         } else {
00959 #endif /* HAVE_COMPOSITE */
00960                                 rectlist = XFixesFetchRegion (
00961                                         dpy_conn, gmag_events_tmp_region,
00962                                         &howmany);
00963 #ifdef HAVE_COMPOSITE
00964                         }
00965 #endif /* HAVE_COMPOSITE */
00966                         if (rectlist == NULL) /* no reply from fetch */
00967                                 return TRUE;
00968                         for (i=0; i < howmany; ++i) {
00969                                 magnifier_notify_damage (magnifier,
00970                                                          &rectlist[i]);
00971                         }
00972                         XFree (rectlist);
00973                 }
00974         }
00975 #endif /* HAVE_DAMAGE */
00976 
00977 #ifdef HAVE_COMPOSITE
00978         if (use_composite) {
00979                 if (calc_clip) {
00980                         gmag_events_calculate_windows_clip ();
00981                         gmag_events_paint_windows (exp_region);
00982                 }
00983                 gmag_events_paint_damaged_windows ();
00984         }
00985 #endif /* HAVE_COMPOSITE */
00986 
00987 #ifdef HAVE_XFIXES
00988         if (cursor_changed) {
00989                 if (magnifier->priv->use_source_cursor) {
00990                         GdkPixbuf *cursor_pixbuf =
00991                                 gmag_events_get_source_pixbuf (magnifier);
00992                         magnifier_set_cursor_from_pixbuf (magnifier,
00993                                                           cursor_pixbuf);
00994                         if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
00995                 } else {
00996                         magnifier_set_cursor_pixmap_by_name (magnifier, cev ? gdk_x11_get_xatom_name (cev->cursor_name) : "default", TRUE);
00997                 }
00998           
00999                 magnifier_transform_cursor (magnifier);
01000 #ifdef CURSOR_DEBUG
01001                 if (cev)
01002                         g_message ("cursor changed: subtype=%d, " \
01003                                    "cursor_serial=%lu, name=[%x] %s\n",
01004                                    (int) cev->subtype, cev->cursor_serial,
01005                                    (int) cev->cursor_name,
01006                                    gdk_x11_get_xatom_name (cev->cursor_name));
01007 #endif /* CURSOR_DEBUG */
01008                 cursor_changed = FALSE;
01009         }
01010 #endif /* HAVE_XFIXES */
01011 
01012 #ifdef HAVE_COMPOSITE
01013         if (use_composite) {
01014                 XFixesSetRegion (dpy_conn, tmp_region, 0, 0);
01015                 XFixesSetRegion (dpy_conn, new_region, 0, 0);
01016                 XFixesSetRegion (dpy_conn, old_region, 0, 0);
01017                 XFixesSetRegion (dpy_conn, exp_region, 0, 0);
01018                 XFixesSetRegion (dpy_conn, off_screen_region, 0, 0);
01019         }
01020 #endif /* HAVE_COMPOSITE */
01021 
01022         XFlush (dpy_conn);
01023 #else
01024         return FALSE;
01025 #endif /* HAVE_XFIXES */
01026         return TRUE;
01027 }
01028 
01029 static gboolean
01030 gmag_events_use_damage ()
01031 {
01032 #ifdef HAVE_DAMAGE
01033         gint major, event, error;
01034         if (XQueryExtension (dpy_conn, "DAMAGE", &major, &event, &error) &&
01035             !g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
01036                 return TRUE;
01037         return FALSE;
01038 #else
01039         return FALSE;
01040 #endif /* HAVE_DAMAGE */
01041 }
01042 
01043 static gboolean
01044 gmag_events_use_composite ()
01045 {
01046         if (!gmag_events_use_damage ()) {
01047                 return FALSE;
01048         }
01049 #ifdef HAVE_COMPOSITE
01050         gint major, event, error;
01051         if (XQueryExtension (dpy_conn, "Composite", &major, &event, &error) &&
01052             !g_getenv ("MAGNIFIER_IGNORE_COMPOSITE"))
01053                 return TRUE;
01054         return FALSE;
01055 #else
01056         return FALSE;
01057 #endif /* HAVE_COMPOSITE */
01058 }
01059 
01060 void
01061 gmag_events_client_init (Magnifier *magnifier)
01062 {
01063         GIOChannel               *ioc;
01064         gint                      fd;
01065         gint                      event_base, error_base;
01066 #ifdef HAVE_COMPOSITE
01067         XRenderPictureAttributes  pic_attr;
01068         XRenderPictFormat        *format;
01069         GdkDisplay               *gdk_display_connection;
01070         GdkScreen                *gdkscr;
01071         gint                      scr = 0, root_w, root_h;
01072 #endif /* HAVE_COMPOSITE */
01073 
01074         if (dpy_conn) {
01075                 /* remove the old watch */
01076                 if (dpy_gsource) 
01077                         g_source_remove (dpy_gsource);
01078                 XCloseDisplay (dpy_conn);
01079         }
01080 
01081         if (magnifier) {
01082                 /* we need our own connection here to keep from gumming up the
01083                  * works */
01084                 dpy_conn = XOpenDisplay (magnifier->source_display_name); 
01085                 root_window = GDK_WINDOW_XWINDOW (magnifier->priv->root);
01086         } else {
01087                 dpy_conn = XOpenDisplay (NULL);
01088                 root_window = RootWindow (dpy_conn, DefaultScreen (dpy_conn));
01089                 g_message ("warning - using DefaultScreen for X connection.");
01090         }
01091 
01092 #ifdef EVENTS_DEBUG
01093         XSynchronize (dpy_conn, True);
01094 #endif /* EVENTS_DEBUG */
01095 
01096         fd = ConnectionNumber (dpy_conn);
01097         ioc = g_io_channel_unix_new (fd);
01098         dpy_gsource = g_io_add_watch (ioc,
01099                                       G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR,
01100                                       gmag_events_handler, magnifier);
01101         g_io_channel_unref (ioc); 
01102 
01103 #ifdef HAVE_XFIXES
01104 
01105         use_damage = gmag_events_use_damage ();
01106         use_composite = gmag_events_use_composite ();
01107 
01108         if (!XFixesQueryExtension (dpy_conn, &fixes_event_base,
01109                                    &fixes_error_base)) {
01110                 g_warning ("XFixes extension not currently active.\n");
01111         } else {
01112                 XFixesSelectCursorInput (dpy_conn, root_window,
01113                                          XFixesDisplayCursorNotifyMask);
01114                 g_message ("added event source to xfixes cursor-notify " \
01115                            "connection");
01116         }
01117 
01118 #ifdef HAVE_DAMAGE
01119         if (!XDamageQueryExtension (dpy_conn, &damage_event_base,
01120                                     &damage_error_base)) {
01121                 g_warning ("Damage extension not currently active.\n");
01122         } else if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE")) {
01123                 g_warning ("Damage extension being ignored at user request.");
01124         } else {
01125                 gmag_events_tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01126                 if (!use_composite) {
01127                         root_window_damage = XDamageCreate (
01128                                 dpy_conn, root_window,
01129                                 XDamageReportDeltaRectangles);
01130                         /* I don't know why, but without this XDamageSubtract
01131                          * call below the damage events aren't hanled normally.
01132                          * They start to be handled normally, without the call
01133                          * below, only after you move your mouse.
01134                          */
01135                         XDamageSubtract (dpy_conn, root_window_damage, None,
01136                                          None);
01137                 }
01138                 g_message ("added event source to damage connection");
01139         }
01140 #else
01141         g_warning ("this copy of gnome-mag was built without damage " \
01142                    "extension support.\n");
01143 #endif /* HAVE_DAMAGE */
01144 
01145 #ifdef HAVE_COMPOSITE
01146         if (!XCompositeQueryExtension (dpy_conn, &event_base, &error_base)) {
01147                 g_warning ("Composite extension not currently active.\n");
01148         } else if (g_getenv ("MAGNIFIER_IGNORE_COMPOSITE")) {
01149                 g_warning ("Composite extension being ignored at user " \
01150                            "request.");
01151         } else if (!use_damage) {
01152                 g_setenv ("MAGNIFIER_IGNORE_COMPOSITE", "1", TRUE);
01153                 g_warning ("Composite extension being ignored due Damage " \
01154                            "is not actived.");
01155         } else {
01156 #ifndef HAVE_OVERLAY
01157                 g_warning ("update composite to version 0.3 or higher to " \
01158                            "have overlay window support.\n");
01159 #endif /* HAVE_OVERLAY */
01160 
01161                 gdk_drawable_get_size (magnifier->priv->root, &root_w,
01162                                        &root_h);
01163                 magnifier->priv->source_drawable = gdk_pixmap_new (
01164                         magnifier->priv->root, root_w, root_h, -1);
01165                 /* GTK+ uses it's own connection with X, so we must flush that
01166                  * to not receive a BadDrawable when creating a picture of this
01167                  * drawable below. */
01168                 gdk_flush ();
01169 
01170                 gdk_display_connection = gdk_drawable_get_display (
01171                         magnifier->priv->root);
01172                 gdkscr = gdk_display_get_default_screen (
01173                         gdk_display_connection);
01174             
01175                 scr = GDK_SCREEN_XNUMBER (gdkscr);
01176 
01177                 XCompositeRedirectSubwindows (dpy_conn, root_window,
01178                                               CompositeRedirectAutomatic);
01179                 off_screen_region = XFixesCreateRegion (
01180                         dpy_conn, 0, 0);
01181                 tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01182                 new_region = XFixesCreateRegion (dpy_conn, 0, 0);
01183                 old_region = XFixesCreateRegion (dpy_conn, 0, 0);
01184                 exp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01185                 off_screen_damage = XDamageCreate (
01186                                 dpy_conn, 
01187                                 GDK_DRAWABLE_XID (
01188                                         magnifier->priv->source_drawable),
01189                                 XDamageReportDeltaRectangles);
01190 
01191                 format = XRenderFindVisualFormat (
01192                         dpy_conn,
01193                         DefaultVisual (dpy_conn, scr));
01194                 pic_attr.subwindow_mode = IncludeInferiors;
01195                 off_screen_picture = XRenderCreatePicture (
01196                         dpy_conn,
01197                         GDK_DRAWABLE_XID (magnifier->priv->source_drawable),
01198                         format, CPSubwindowMode, &pic_attr);
01199 
01200                 gmag_events_create_windows_list (gdk_display_connection,
01201                                                  gdkscr);
01202                 gmag_events_calculate_windows_clip ();
01203                 g_message ("added event source to composite connection");
01204         }
01205 #else
01206         g_warning ("this copy of gnome-mag was built without composite " \
01207                    "extension support.\n");
01208 #endif /* HAVE_COMPOSITE */
01209 
01210 #else
01211         g_warning ("this copy of gnome-mag was built without xfixes " \
01212                    "extension support.\n");     
01213 #endif /* HAVE_XFIXES */
01214         XFlush (dpy_conn);
01215 }

Generated on Wed May 23 10:47:17 2007 for gnome-mag by  doxygen 1.5.1