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_region = None;
00325         } else {
00326                 format = XRenderFindVisualFormat (
00327                         dpy_conn, new->attr.visual);
00328                 pic_attr.subwindow_mode = IncludeInferiors;
00329                 new->pic = XRenderCreatePicture (
00330                         dpy_conn, xwin, format,
00331                         CPSubwindowMode, &pic_attr);
00332                 new->damage = XDamageCreate (dpy_conn, xwin,
00333                                              XDamageReportDeltaRectangles);
00334                 new->damaged = TRUE;
00335                 new->damaged_region = XFixesCreateRegion (dpy_conn, 0, 0);
00336                 new->clip = XFixesCreateRegion (dpy_conn, 0, 0);
00337                 new->win_region = XFixesCreateRegion (dpy_conn, 0, 0);
00338         }
00339         
00340         g_queue_push_tail (mag_windows_list, new);
00341 }
00342 
00343 /*
00344  * Create the mag_windows_list querying the xserver for the actual
00345  * windows and adding them to the windows list.
00346  */
00347 static void
00348 gmag_events_create_windows_list ()
00349 {
00350         Window  root_return, parent_return, *children;
00351         guint   nchildren;
00352         gint    i;
00353 
00354         if (!mag_windows_list)
00355                 mag_windows_list = g_queue_new ();
00356 
00357         XGrabServer (dpy_conn);
00358         XSelectInput (dpy_conn, root_window,
00359                       SubstructureNotifyMask);
00360         XQueryTree (dpy_conn, root_window,
00361                     &root_return, &parent_return, &children, &nchildren);
00362         for (i = 0; i < nchildren; i++)
00363                 gmag_events_add_window (children[i]);
00364         XFree (children);
00365         XUngrabServer (dpy_conn);
00366 }
00367 
00368 /*
00369  * Destroy the window resources and remove it from the
00370  * mag_windows_list.
00371  */
00372 static void
00373 gmag_events_remove_window (Window xwin)
00374 {
00375         GList     *elem = NULL;
00376         GmagWinPtr pgmag_win;
00377 
00378         elem = g_queue_find_custom (mag_windows_list,
00379                                     (gconstpointer) xwin,
00380                                     (GCompareFunc) gmag_events_g_compare_func);
00381         if (elem) {
00382                 pgmag_win = (GmagWinPtr) elem->data;
00383                 g_queue_remove (mag_windows_list, pgmag_win);
00384                 XFixesDestroyRegion (dpy_conn,
00385                                      pgmag_win->clip);
00386                 XFixesDestroyRegion (dpy_conn,
00387                                      pgmag_win->win_region);
00388                 free (pgmag_win);
00389         }
00390 }
00391 
00392 /*
00393  * Add a window damaged region, making a union with the actual damaged region,
00394  * to the window in mag_windows_list.
00395  */
00396 static void
00397 gmag_events_add_win_damaged_region (Window xwin, XserverRegion region)
00398 {
00399         GList      *elem;
00400         GmagWinPtr  pgmag_win;
00401 
00402         elem = g_queue_find_custom (mag_windows_list,
00403                                     (gconstpointer) xwin,
00404                                     (GCompareFunc) gmag_events_g_compare_func);
00405         if (elem) {
00406                 pgmag_win = (GmagWinPtr) elem->data;
00407                 XFixesTranslateRegion (dpy_conn, region,
00408                                        pgmag_win->attr.x, pgmag_win->attr.y);
00409                 XFixesUnionRegion (dpy_conn,
00410                                    pgmag_win->damaged_region,
00411                                    pgmag_win->damaged_region, region);
00412                 pgmag_win->damaged = TRUE;
00413         }
00414 }
00415 
00416 /*
00417  * Paint all the windows that have some damage.
00418  */
00419 static void
00420 gmag_events_paint_damaged_windows ()
00421 {
00422         GList      *elem;
00423         GmagWinPtr  pgmag_win;
00424 
00425         elem = g_queue_peek_head_link (mag_windows_list);
00426         while (elem) {
00427                 pgmag_win = (GmagWinPtr) elem->data;
00428                 if (pgmag_win->damaged) {
00429                         gmag_events_paint_window (pgmag_win,
00430                                                   pgmag_win->damaged_region);
00431                         XFixesSetRegion (dpy_conn,
00432                                          pgmag_win->damaged_region, 0, 0);
00433                         pgmag_win->damaged = FALSE;
00434                 }
00435 
00436                 elem = g_list_next (elem);
00437         }
00438 }
00439 
00440 static void
00441 gmag_events_circulate_notify_handler (XEvent *ev)
00442 {
00443         GList      *elem;
00444         GmagWinPtr  pgmag_win;
00445 
00446 #ifdef COMPOSITE_DEBUG
00447         printf ("Received CirculateNotify event: 0x%x\n",
00448                 (guint) ev->xcirculate.window);
00449 #endif /* COMPOSITE_DEBUG */
00450         if (ev->xcirculate.window == mag_window) {
00451 #ifdef HAVE_OVERLAY
00452 #ifdef COMPOSITE_DEBUG
00453                 printf ("Overlay window = 0x%x\n",
00454                         (guint) gmag_events_overlay_window);
00455 #endif /* COMPOSITE_DEBUG */
00456 #endif /* HAVE_OVERLAY */
00457                 return;
00458         }
00459         elem = g_queue_find_custom (mag_windows_list,
00460                                     (gconstpointer) ev->xcirculate.window,
00461                                     (GCompareFunc) gmag_events_g_compare_func);
00462         if (elem) {
00463                 pgmag_win = (GmagWinPtr) elem->data;
00464                 g_queue_remove (mag_windows_list, pgmag_win);
00465                 if (ev->xcirculate.place == PlaceOnTop) {
00466                         g_queue_push_tail (mag_windows_list,
00467                                            pgmag_win);
00468                         if (pgmag_win->attr.map_state == IsViewable) {
00469                                 XFixesSubtractRegion (
00470                                         dpy_conn,
00471                                         tmp_region, pgmag_win->win_region,
00472                                         pgmag_win->clip);
00473                                 XFixesUnionRegion (
00474                                         dpy_conn,
00475                                         exp_region, exp_region, tmp_region);
00476                         }
00477                 } else {
00478                         g_queue_push_head (mag_windows_list,
00479                                            pgmag_win);
00480                         if (pgmag_win->attr.map_state == IsViewable)
00481                                 XFixesUnionRegion (
00482                                         dpy_conn,
00483                                         exp_region, exp_region,
00484                                         pgmag_win->clip);
00485                 }
00486         }
00487 }
00488 
00489 static void
00490 gmag_events_configure_notify_handler (XEvent *ev)
00491 {
00492         GList      *elem;
00493         GmagWinPtr  pgmag_win;
00494         
00495 #ifdef COMPOSITE_DEBUG
00496         printf ("Received ConfigureNotify event: 0x%x\n",
00497                 (guint) ev->xconfigure.window);
00498 #endif /* COMPOSITE_DEBUG */
00499         if (ev->xconfigure.window == mag_window) {
00500 #ifdef HAVE_OVERLAY
00501 #ifdef COMPOSITE_DEBUG
00502                 printf ("Overlay window = 0x%x\n",
00503                         (guint) gmag_events_overlay_window);
00504 #endif /* COMPOSITE_DEBUG */
00505 #endif /* HAVE_OVERLAY */
00506                 return;
00507         }
00508         elem = g_queue_find_custom (mag_windows_list,
00509                                     (gconstpointer) ev->xconfigure.window,
00510                                     (GCompareFunc) gmag_events_g_compare_func);
00511         if (elem) {
00512                 pgmag_win = (GmagWinPtr) elem->data;
00513                 if ((pgmag_win->attr.x != ev->xconfigure.x) ||
00514                     (pgmag_win->attr.y != ev->xconfigure.y) ||
00515                     (pgmag_win->attr.width != ev->xconfigure.width) ||
00516                     (pgmag_win->attr.height != ev->xconfigure.height) ||
00517                     (pgmag_win->attr.border_width !=
00518                      ev->xconfigure.border_width)) {
00519                         /* If an attribute of the window has changed we could
00520                          * have an exposed area that is not reported due to the
00521                          * overlay window. So we subtract the new region, from
00522                          * the old one, and we have the value of the exposed
00523                          * region that must be repainted.
00524                          */
00525                         pgmag_win->attr.x = ev->xconfigure.x;
00526                         pgmag_win->attr.y = ev->xconfigure.y;
00527                         pgmag_win->attr.width = ev->xconfigure.width;
00528                         pgmag_win->attr.height = ev->xconfigure.height;
00529                         pgmag_win->attr.border_width =
00530                                 ev->xconfigure.border_width;
00531                               
00532                         if (pgmag_win->attr.map_state == IsViewable) {
00533                                 XFixesCopyRegion (
00534                                         dpy_conn,
00535                                         old_region, pgmag_win->clip);
00536                                 gmag_events_calculate_window_clip (pgmag_win);
00537                                 XFixesCopyRegion (
00538                                         dpy_conn,
00539                                         new_region, pgmag_win->clip);
00540                                 XFixesUnionRegion (
00541                                         dpy_conn,
00542                                         exp_region, exp_region, old_region);
00543                                 XFixesUnionRegion (
00544                                         dpy_conn,
00545                                         exp_region, exp_region, new_region);
00546                         }
00547                 }
00548                 if (!ev->xconfigure.above) {
00549                         g_queue_remove (mag_windows_list, pgmag_win);
00550                         g_queue_push_head (mag_windows_list,
00551                                            pgmag_win);
00552                         if (pgmag_win->attr.map_state == IsViewable) {
00553                                 XFixesUnionRegion (
00554                                         dpy_conn,
00555                                         exp_region, exp_region,
00556                                         pgmag_win->win_region);
00557                         }
00558                 } else {
00559                         elem = g_queue_find_custom (
00560                                 mag_windows_list,
00561                                 (gconstpointer) ev->xconfigure.above,
00562                                 (GCompareFunc) gmag_events_g_compare_func);
00563                         if (elem) {
00564                                 g_queue_remove (mag_windows_list,
00565                                                 pgmag_win);
00566                                 g_queue_insert_after (mag_windows_list,
00567                                                       elem, pgmag_win);
00568                                 if (pgmag_win->attr.map_state == IsViewable) {
00569                                         XFixesUnionRegion (
00570                                                 dpy_conn,
00571                                                 exp_region, exp_region,
00572                                                 pgmag_win->win_region);
00573                                 }
00574                         }
00575                 }
00576         }
00577 }
00578 
00579 static void
00580 gmag_events_create_notify_handler (XEvent *ev)
00581 {
00582         GList      *elem;
00583         GmagWinPtr  pgmag_win;
00584 
00585 #ifdef COMPOSITE_DEBUG
00586         printf ("Received CreateNotify event: 0x%x\n",
00587                 (guint) ev->xcreatewindow.window);
00588 #endif /* COMPOSITE_DEBUG */
00589         if (ev->xcreatewindow.window == mag_window) {
00590 #ifdef HAVE_OVERLAY
00591 #ifdef COMPOSITE_DEBUG
00592                 printf ("Overlay window = 0x%x\n",
00593                         (guint) gmag_events_overlay_window);
00594 #endif /* COMPOSITE_DEBUG */
00595 #endif /* HAVE_OVERLAY */
00596                 return;
00597         }
00598         gmag_events_add_window (ev->xcreatewindow.window);
00599         elem = g_queue_find_custom (mag_windows_list,
00600                                     (gconstpointer) ev->xcreatewindow.window,
00601                                     (GCompareFunc) gmag_events_g_compare_func);
00602         if (elem) {
00603                 pgmag_win = (GmagWinPtr) elem->data;
00604                 if (pgmag_win->attr.map_state == IsViewable) {
00605                         gmag_events_calculate_window_clip (pgmag_win);
00606                         XFixesUnionRegion (dpy_conn,
00607                                            exp_region, exp_region,
00608                                            pgmag_win->clip);
00609                 }
00610         }
00611 }
00612 
00613 static void
00614 gmag_events_destroy_notify_handler (XEvent *ev)
00615 {
00616         GList      *elem;
00617         GmagWinPtr  pgmag_win;
00618 
00619 #ifdef COMPOSITE_DEBUG
00620         printf ("Received DestroyNotify event: 0x%x\n",
00621                 (guint) ev->xdestroywindow.window);
00622 #endif /* COMPOSITE_DEBUG */
00623         if (ev->xdestroywindow.window == mag_window) {
00624 #ifdef HAVE_OVERLAY
00625 #ifdef COMPOSITE_DEBUG
00626                 printf ("Overlay window = 0x%x\n",
00627                         (guint) gmag_events_overlay_window);
00628 #endif /* COMPOSITE_DEBUG */
00629 #endif /* HAVE_OVERLAY */
00630                 return;
00631         }
00632         elem = g_queue_find_custom (mag_windows_list,
00633                                     (gconstpointer) ev->xdestroywindow.window,
00634                                     (GCompareFunc) gmag_events_g_compare_func);
00635         if (elem) {
00636                 pgmag_win = (GmagWinPtr) elem->data;
00637                 if (pgmag_win->attr.map_state == IsViewable)
00638                         XFixesUnionRegion (dpy_conn,
00639                                            exp_region, exp_region,
00640                                            pgmag_win->clip);
00641                 gmag_events_remove_window (ev->xdestroywindow.window);
00642         }
00643 }
00644 
00645 static void
00646 gmag_events_map_notify_handler (XEvent *ev)
00647 {
00648         GList      *elem;
00649         GmagWinPtr  pgmag_win;
00650 
00651 #ifdef COMPOSITE_DEBUG
00652         printf ("Received MapNotify event: 0x%x\n",
00653                 (guint) ev->xmap.window);
00654 #endif /* COMPOSITE_DEBUG */
00655         if (ev->xmap.window == mag_window) {
00656 #ifdef HAVE_OVERLAY
00657 #ifdef COMPOSITE_DEBUG
00658                 printf ("Overlay window = 0x%x\n",
00659                         (guint) gmag_events_overlay_window);
00660 #endif /* COMPOSITE_DEBUG */
00661 #endif /* HAVE_OVERLAY */
00662                 return;
00663         }
00664         elem = g_queue_find_custom (mag_windows_list,
00665                                     (gconstpointer) ev->xmap.window,
00666                                     (GCompareFunc) gmag_events_g_compare_func);
00667         if (elem) {
00668                 pgmag_win = (GmagWinPtr) elem->data;
00669                 pgmag_win->attr.map_state = IsViewable;
00670                 gmag_events_calculate_window_clip (pgmag_win);
00671                 XFixesUnionRegion (dpy_conn, exp_region,
00672                                    exp_region, pgmag_win->clip);
00673         }
00674 }
00675 
00676 static void
00677 gmag_events_unmap_notify_handler (XEvent *ev)
00678 {
00679         GList      *elem;
00680         GmagWinPtr  pgmag_win;
00681 
00682 #ifdef COMPOSITE_DEBUG
00683         printf ("Received UnmapNotify event: 0x%x\n",
00684                 (guint) ev->xunmap.window);
00685 #endif /* COMPOSITE_DEBUG */
00686         if (ev->xunmap.window == mag_window) {
00687 #ifdef HAVE_OVERLAY
00688 #ifdef COMPOSITE_DEBUG
00689                 printf ("Overlay window = 0x%x\n",
00690                         (guint) gmag_events_overlay_window);
00691 #endif /* COMPOSITE_DEBUG */
00692 #endif /* HAVE_OVERLAY */
00693                 return;
00694         }
00695         elem = g_queue_find_custom (mag_windows_list,
00696                                     (gconstpointer) ev->xunmap.window,
00697                                     (GCompareFunc) gmag_events_g_compare_func);
00698         if (elem) {
00699                 pgmag_win = (GmagWinPtr) elem->data;
00700                 pgmag_win->attr.map_state = IsUnmapped;
00701                 XFixesUnionRegion (dpy_conn, exp_region,
00702                                    exp_region, pgmag_win->clip);
00703         }
00704 }
00705 
00706 static void
00707 gmag_events_reparent_notify_handler (XEvent *ev)
00708 {
00709         GList      *elem;
00710         GmagWinPtr  pgmag_win;
00711 
00712 #ifdef COMPOSITE_DEBUG
00713         printf ("Received ReparentNotify event: 0x%x (Window), 0x%x (Parent)\n", (guint) ev->xreparent.window, (guint) ev->xreparent.parent);
00714 #endif /* COMPOSITE_DEBUG */
00715         if  (ev->xreparent.window == mag_window) {
00716 #ifdef HAVE_OVERLAY
00717 #ifdef COMPOSITE_DEBUG
00718                 printf ("Overlay window = 0x%x\n",
00719                         (guint) gmag_events_overlay_window);
00720 #endif /* COMPOSITE_DEBUG */
00721 #endif /* HAVE_OVERLAY */
00722                 return;
00723         }
00724         if (ev->xreparent.parent != root_window) {
00725                 gmag_events_remove_window (ev->xreparent.window);
00726         } else {
00727                 gmag_events_add_window (ev->xreparent.window);
00728                 elem = g_queue_find_custom (
00729                         mag_windows_list,
00730                         (gconstpointer) ev->xreparent.window,
00731                         (GCompareFunc) gmag_events_g_compare_func);
00732                 if (elem) {
00733                         pgmag_win = (GmagWinPtr) elem->data;
00734                         if (pgmag_win->attr.map_state == IsViewable) {
00735                                 gmag_events_calculate_window_clip (pgmag_win);
00736                                 XFixesUnionRegion (
00737                                         dpy_conn,
00738                                         exp_region, exp_region,
00739                                         pgmag_win->clip);
00740                         }
00741                 }
00742         }
00743 }
00744 
00745 #endif /* HAVE_COMPOSITE */
00746 
00747 #ifdef HAVE_DAMAGE
00748 
00749 static void
00750 gmag_events_damage_notify_handler (XEvent *ev)
00751 {
00752         XDamageNotifyEvent *dev = (XDamageNotifyEvent *) ev;
00753 #ifdef DAMAGE_DEBUG
00754         g_message ("Damage area %3d, %3d x %3d, %3d",
00755                    (int) dev->area.x, (int) dev->area.x + dev->area.width,
00756                    (int) dev->area.y, (int) dev->area.y + dev->area.height);
00757         g_message ("Damage geometry %3d, %3d x %3d, %3d",
00758                    (int) dev->geometry.x,
00759                    (int) dev->geometry.x + dev->geometry.width,
00760                    (int) dev->geometry.y,
00761                    (int) dev->geometry.y + dev->geometry.height);
00762 #endif /* DAMAGE_DEBUG */
00763 
00764 #ifdef HAVE_COMPOSITE
00765         if (use_composite) {
00766                 if (dev->damage == off_screen_damage) {
00767 #ifdef DAMAGE_DEBUG
00768                         g_message ("off_screen_damage damaged");
00769 #endif /* DAMAGE_DEBUG */
00770                         XDamageSubtract (dpy_conn, dev->damage, None,
00771                                          gmag_events_tmp_region);
00772                         XFixesUnionRegion (dpy_conn,
00773                                            off_screen_region,
00774                                            off_screen_region,
00775                                            gmag_events_tmp_region);
00776                 } else {
00777 #ifdef DAMAGE_DEBUG
00778                         g_message ("Window with damage: 0x%x", dev->drawable);
00779 #endif /* DAMAGE_DEBUG */
00780                         XDamageSubtract (dpy_conn, dev->damage, None,
00781                                          gmag_events_tmp_region);
00782                         gmag_events_add_win_damaged_region (
00783                                 dev->drawable, gmag_events_tmp_region);
00784                 }
00785         }
00786 #endif /* HAVE_COMPOSITE */
00787 }
00788 
00789 #endif /* HAVE_DAMAGE */
00790 
00791 static void
00792 gmag_events_cursor_convert_to_rgba (Magnifier *magnifier,
00793                                     XFixesCursorImage *cursor_image)
00794 {
00795         int i, count = cursor_image->width * cursor_image->height;
00796         for (i = 0; i < count; ++i) {
00797                 guint32 pixval = GUINT_TO_LE (cursor_image->pixels[i]);
00798                 cursor_image->pixels[i] = pixval;
00799         }
00800 }
00801 
00802 static void
00803 gmag_events_free_cursor_pixels (guchar *pixels, gpointer data)
00804 {
00805     /* XFree (data); FIXME why doesn't this work properly? */
00806 }
00807 
00808 #endif /* HAVE_XFIXES */
00809 
00810 GdkPixbuf *
00811 gmag_events_get_source_pixbuf (Magnifier *magnifier)
00812 {
00813 #ifdef HAVE_XFIXES
00814         XFixesCursorImage *cursor_image = XFixesGetCursorImage (
00815                 dpy_conn);
00816         GdkPixbuf *cursor_pixbuf = NULL;
00817         gchar s[6];
00818         if (cursor_image)
00819         {
00820                 gmag_events_cursor_convert_to_rgba (magnifier, cursor_image);
00821                 cursor_pixbuf = gdk_pixbuf_new_from_data (
00822                         (guchar *) cursor_image->pixels, GDK_COLORSPACE_RGB,
00823                         TRUE, 8, cursor_image->width, cursor_image->height,
00824                         cursor_image->width * 4,
00825                         gmag_events_free_cursor_pixels, cursor_image);
00826                 gdk_pixbuf_set_option (cursor_pixbuf, "x_hot", 
00827                                        g_ascii_dtostr (
00828                                                s, 6,
00829                                                (gdouble) cursor_image->xhot));
00830                 gdk_pixbuf_set_option (cursor_pixbuf, "y_hot", 
00831                                        g_ascii_dtostr (
00832                                                s, 6,
00833                                                (gdouble) cursor_image->yhot));
00834         }
00835         return cursor_pixbuf;
00836 #else
00837         return NULL;
00838 #endif /* HAVE_XFIXES */
00839 }
00840 
00841 gboolean
00842 gmag_events_source_has_damage_extension (Magnifier *magnifier)
00843 {
00844 #ifdef HAVE_DAMAGE
00845         gint event_base, error_base;
00846         Display *dpy;
00847         g_assert (magnifier);
00848         dpy = GDK_DISPLAY_XDISPLAY (magnifier->source_display);
00849         if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
00850                 return FALSE;
00851         if (XDamageQueryExtension (dpy, &event_base, &error_base))
00852                 return TRUE;
00853 #endif /* HAVE_DAMAGE */
00854         return FALSE;
00855 }
00856 
00857 static gboolean
00858 gmag_events_handler (GIOChannel *source, GIOCondition condition, gpointer data)
00859 {
00860 #ifdef HAVE_XFIXES
00861         XEvent                   ev;
00862         XFixesCursorNotifyEvent *cev = NULL;
00863         gboolean                 cursor_changed = FALSE;
00864         Magnifier               *magnifier = (Magnifier *) data;
00865         XRectangle              *rectlist;
00866 #ifdef HAVE_COMPOSITE
00867         gboolean                 calc_clip = FALSE;
00868 #endif /* HAVE_COMPOSITE */
00869 
00870 #ifdef HAVE_OVERLAY
00871         if (magnifier->priv->overlay)
00872                 mag_window = GDK_WINDOW_XID (magnifier->priv->overlay);
00873 #else
00874         if (magnifier->priv->w && magnifier->priv->w->window)
00875                 mag_window = GDK_WINDOW_XID (magnifier->priv->w->window);
00876 #endif /* HAVE_OVERLAY */
00877 
00878         do
00879         {
00880                 XNextEvent(dpy_conn, &ev);
00881 
00882 #ifdef HAVE_COMPOSITE
00883                 if (use_composite) {
00884                         switch (ev.type) {
00885                         case CirculateNotify:
00886                                 gmag_events_circulate_notify_handler (&ev);
00887                                 calc_clip = TRUE;
00888                                 break;
00889                         case ConfigureNotify:
00890                                 gmag_events_configure_notify_handler (&ev);
00891                                 calc_clip = TRUE;
00892                                 break;
00893                         case CreateNotify:
00894                                 gmag_events_create_notify_handler (&ev);
00895                                 calc_clip = TRUE;
00896                                 break;
00897                         case DestroyNotify:
00898                                 gmag_events_destroy_notify_handler (&ev);
00899                                 calc_clip = TRUE;
00900                                 break;
00901                         case MapNotify:
00902                                 gmag_events_map_notify_handler (&ev);
00903                                 calc_clip = TRUE;
00904                                 break;
00905                         case UnmapNotify:
00906                                 gmag_events_unmap_notify_handler (&ev);
00907                                 calc_clip = TRUE;
00908                                 break;
00909                         case ReparentNotify:
00910                                 gmag_events_reparent_notify_handler (&ev);
00911                                 calc_clip = TRUE;
00912                                 break;
00913                         }
00914                 }
00915 #endif /* HAVE_COMPOSITE */
00916 
00917 #ifdef HAVE_DAMAGE
00918                 if (use_damage) {
00919                         if (ev.type == damage_event_base + XDamageNotify) {
00920                                 gmag_events_damage_notify_handler (&ev);
00921                         }
00922                 }
00923 #endif /* HAVE_DAMAGE */
00924 
00925 #ifdef HAVE_XFIXES
00926                 if (ev.type == fixes_event_base + XFixesCursorNotify) {
00927                         cursor_changed = TRUE;
00928                         cev = (XFixesCursorNotifyEvent *) &ev;
00929                 }
00930 #endif /* HAVE_XFIXES */
00931 
00932         } while (XPending (dpy_conn));
00933 
00934 #ifndef HAVE_OVERLAY
00935         if (use_composite && mag_window) {
00936                 XRaiseWindow (dpy_conn, mag_window);
00937         }
00938 #endif /* HAVE_OVERLAY */
00939 
00940 #ifdef HAVE_DAMAGE
00941         if (!use_composite) {
00942                 XDamageSubtract (dpy_conn, root_window_damage, None,
00943                                  gmag_events_tmp_region);
00944         }
00945 
00946         if (use_damage) {
00947                 if (magnifier) {
00948                         int i, howmany;
00949                         /* TODO: maintain this list on the client instead, to
00950                          * avoid the roundtrip below */
00951 #ifdef HAVE_COMPOSITE
00952                         if (use_composite) {
00953                                 rectlist = XFixesFetchRegion (
00954                                         dpy_conn,
00955                                         off_screen_region,
00956                                         &howmany);
00957                         } else {
00958 #endif /* HAVE_COMPOSITE */
00959                                 rectlist = XFixesFetchRegion (
00960                                         dpy_conn, gmag_events_tmp_region,
00961                                         &howmany);
00962 #ifdef HAVE_COMPOSITE
00963                         }
00964 #endif /* HAVE_COMPOSITE */
00965                         if (rectlist == NULL) /* no reply from fetch */
00966                                 return TRUE;
00967                         for (i=0; i < howmany; ++i) {
00968                                 magnifier_notify_damage (magnifier,
00969                                                          &rectlist[i]);
00970                         }
00971                         XFree (rectlist);
00972                 }
00973         }
00974 #endif /* HAVE_DAMAGE */
00975 
00976 #ifdef HAVE_COMPOSITE
00977         if (use_composite) {
00978                 if (calc_clip) {
00979                         gmag_events_calculate_windows_clip ();
00980                         gmag_events_paint_windows (exp_region);
00981                 }
00982                 gmag_events_paint_damaged_windows ();
00983         }
00984 #endif /* HAVE_COMPOSITE */
00985 
00986 #ifdef HAVE_XFIXES
00987         if (cursor_changed) {
00988                 if (magnifier->priv->use_source_cursor) {
00989                         GdkPixbuf *cursor_pixbuf =
00990                                 gmag_events_get_source_pixbuf (magnifier);
00991                         magnifier_set_cursor_from_pixbuf (magnifier,
00992                                                           cursor_pixbuf);
00993                         if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
00994                 } else {
00995                         magnifier_set_cursor_pixmap_by_name (magnifier, cev ? gdk_x11_get_xatom_name (cev->cursor_name) : "default", TRUE);
00996                 }
00997           
00998                 magnifier_transform_cursor (magnifier);
00999 #ifdef CURSOR_DEBUG
01000                 if (cev)
01001                         g_message ("cursor changed: subtype=%d, " \
01002                                    "cursor_serial=%lu, name=[%x] %s\n",
01003                                    (int) cev->subtype, cev->cursor_serial,
01004                                    (int) cev->cursor_name,
01005                                    gdk_x11_get_xatom_name (cev->cursor_name));
01006 #endif /* CURSOR_DEBUG */
01007                 cursor_changed = FALSE;
01008         }
01009 #endif /* HAVE_XFIXES */
01010 
01011 #ifdef HAVE_COMPOSITE
01012         if (use_composite) {
01013                 XFixesSetRegion (dpy_conn, tmp_region, 0, 0);
01014                 XFixesSetRegion (dpy_conn, new_region, 0, 0);
01015                 XFixesSetRegion (dpy_conn, old_region, 0, 0);
01016                 XFixesSetRegion (dpy_conn, exp_region, 0, 0);
01017                 XFixesSetRegion (dpy_conn, off_screen_region, 0, 0);
01018         }
01019 #endif /* HAVE_COMPOSITE */
01020 
01021         XFlush (dpy_conn);
01022 #else
01023         return FALSE;
01024 #endif /* HAVE_XFIXES */
01025         return TRUE;
01026 }
01027 
01028 static gboolean
01029 gmag_events_use_damage ()
01030 {
01031 #ifdef HAVE_DAMAGE
01032         gint major, event, error;
01033         if (XQueryExtension (dpy_conn, "DAMAGE", &major, &event, &error) &&
01034             !g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
01035                 return TRUE;
01036         return FALSE;
01037 #else
01038         return FALSE;
01039 #endif /* HAVE_DAMAGE */
01040 }
01041 
01042 static gboolean
01043 gmag_events_use_composite ()
01044 {
01045         if (!gmag_events_use_damage ()) {
01046                 return FALSE;
01047         }
01048 #ifdef HAVE_COMPOSITE
01049         gint major, event, error;
01050         if (XQueryExtension (dpy_conn, "Composite", &major, &event, &error) &&
01051             !g_getenv ("MAGNIFIER_IGNORE_COMPOSITE"))
01052                 return TRUE;
01053         return FALSE;
01054 #else
01055         return FALSE;
01056 #endif /* HAVE_COMPOSITE */
01057 }
01058 
01059 void
01060 gmag_events_client_init (Magnifier *magnifier)
01061 {
01062         GIOChannel               *ioc;
01063         gint                      fd;
01064         gint                      event_base, error_base;
01065 #ifdef HAVE_COMPOSITE
01066         XRenderPictureAttributes  pic_attr;
01067         XRenderPictFormat        *format;
01068         GdkDisplay               *gdk_display_connection;
01069         GdkScreen                *gdkscr;
01070         gint                      scr = 0, root_w, root_h;
01071 #endif /* HAVE_COMPOSITE */
01072 
01073         if (dpy_conn) {
01074                 /* remove the old watch */
01075                 if (dpy_gsource) 
01076                         g_source_remove (dpy_gsource);
01077                 XCloseDisplay (dpy_conn);
01078         }
01079 
01080         if (magnifier) {
01081                 /* we need our own connection here to keep from gumming up the
01082                  * works */
01083                 dpy_conn = XOpenDisplay (magnifier->source_display_name); 
01084                 root_window = GDK_WINDOW_XWINDOW (magnifier->priv->root);
01085         } else {
01086                 dpy_conn = XOpenDisplay (NULL);
01087                 root_window = RootWindow (dpy_conn, DefaultScreen (dpy_conn));
01088                 g_message ("warning - using DefaultScreen for X connection.");
01089         }
01090 
01091 #ifdef EVENTS_DEBUG
01092         XSynchronize (dpy_conn, True);
01093 #endif /* EVENTS_DEBUG */
01094 
01095         fd = ConnectionNumber (dpy_conn);
01096         ioc = g_io_channel_unix_new (fd);
01097         dpy_gsource = g_io_add_watch (ioc,
01098                                       G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR,
01099                                       gmag_events_handler, magnifier);
01100         g_io_channel_unref (ioc); 
01101 
01102 #ifdef HAVE_XFIXES
01103 
01104         use_damage = gmag_events_use_damage ();
01105         use_composite = gmag_events_use_composite ();
01106 
01107         if (!XFixesQueryExtension (dpy_conn, &fixes_event_base,
01108                                    &fixes_error_base)) {
01109                 g_warning ("XFixes extension not currently active.\n");
01110         } else {
01111                 XFixesSelectCursorInput (dpy_conn, root_window,
01112                                          XFixesDisplayCursorNotifyMask);
01113                 g_message ("added event source to xfixes cursor-notify " \
01114                            "connection");
01115         }
01116 
01117 #ifdef HAVE_DAMAGE
01118         if (!XDamageQueryExtension (dpy_conn, &damage_event_base,
01119                                     &damage_error_base)) {
01120                 g_warning ("Damage extension not currently active.\n");
01121         } else if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE")) {
01122                 g_warning ("Damage extension being ignored at user request.");
01123         } else {
01124                 gmag_events_tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01125                 if (!use_composite) {
01126                         root_window_damage = XDamageCreate (
01127                                 dpy_conn, root_window,
01128                                 XDamageReportDeltaRectangles);
01129                         /* I don't know why, but without this XDamageSubtract
01130                          * call below the damage events aren't hanled normally.
01131                          * They start to be handled normally, without the call
01132                          * below, only after you move your mouse.
01133                          */
01134                         XDamageSubtract (dpy_conn, root_window_damage, None,
01135                                          None);
01136                 }
01137                 g_message ("added event source to damage connection");
01138         }
01139 #else
01140         g_warning ("this copy of gnome-mag was built without damage " \
01141                    "extension support.\n");
01142 #endif /* HAVE_DAMAGE */
01143 
01144 #ifdef HAVE_COMPOSITE
01145         if (!XCompositeQueryExtension (dpy_conn, &event_base, &error_base)) {
01146                 g_warning ("Composite extension not currently active.\n");
01147         } else if (g_getenv ("MAGNIFIER_IGNORE_COMPOSITE")) {
01148                 g_warning ("Composite extension being ignored at user " \
01149                            "request.");
01150         } else if (!use_damage) {
01151                 g_setenv ("MAGNIFIER_IGNORE_COMPOSITE", "1", TRUE);
01152                 g_warning ("Composite extension being ignored due Damage " \
01153                            "is not actived.");
01154         } else {
01155 #ifndef HAVE_OVERLAY
01156                 g_warning ("update composite to version 0.3 or higher to " \
01157                            "have overlay window support.\n");
01158 #endif /* HAVE_OVERLAY */
01159 
01160                 gdk_drawable_get_size (magnifier->priv->root, &root_w,
01161                                        &root_h);
01162                 magnifier->priv->source_drawable = gdk_pixmap_new (
01163                         magnifier->priv->root, root_w, root_h, -1);
01164                 /* GTK+ uses it's own connection with X, so we must flush that
01165                  * to not receive a BadDrawable when creating a picture of this
01166                  * drawable below. */
01167                 gdk_flush ();
01168 
01169                 gdk_display_connection = gdk_drawable_get_display (
01170                         magnifier->priv->root);
01171                 gdkscr = gdk_display_get_default_screen (
01172                         gdk_display_connection);
01173             
01174                 scr = GDK_SCREEN_XNUMBER (gdkscr);
01175 
01176                 XCompositeRedirectSubwindows (dpy_conn, root_window,
01177                                               CompositeRedirectAutomatic);
01178                 off_screen_region = XFixesCreateRegion (
01179                         dpy_conn, 0, 0);
01180                 tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01181                 new_region = XFixesCreateRegion (dpy_conn, 0, 0);
01182                 old_region = XFixesCreateRegion (dpy_conn, 0, 0);
01183                 exp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01184                 off_screen_damage = XDamageCreate (
01185                                 dpy_conn, 
01186                                 GDK_DRAWABLE_XID (
01187                                         magnifier->priv->source_drawable),
01188                                 XDamageReportDeltaRectangles);
01189 
01190                 format = XRenderFindVisualFormat (
01191                         dpy_conn,
01192                         DefaultVisual (dpy_conn, scr));
01193                 pic_attr.subwindow_mode = IncludeInferiors;
01194                 off_screen_picture = XRenderCreatePicture (
01195                         dpy_conn,
01196                         GDK_DRAWABLE_XID (magnifier->priv->source_drawable),
01197                         format, CPSubwindowMode, &pic_attr);
01198 
01199                 gmag_events_create_windows_list (gdk_display_connection,
01200                                                  gdkscr);
01201                 gmag_events_calculate_windows_clip ();
01202                 g_message ("added event source to composite connection");
01203         }
01204 #else
01205         g_warning ("this copy of gnome-mag was built without composite " \
01206                    "extension support.\n");
01207 #endif /* HAVE_COMPOSITE */
01208 
01209 #else
01210         g_warning ("this copy of gnome-mag was built without xfixes " \
01211                    "extension support.\n");     
01212 #endif /* HAVE_XFIXES */
01213         XFlush (dpy_conn);
01214 }

Generated on Thu Jan 25 16:23:22 2007 for gnome-mag by  doxygen 1.4.7