display.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity X display handler */
00004 
00005 /* 
00006  * Copyright (C) 2001 Havoc Pennington
00007  * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
00008  * Copyright (C) 2003, 2004 Rob Adams
00009  * Copyright (C) 2004-2006 Elijah Newren
00010  * 
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License as
00013  * published by the Free Software Foundation; either version 2 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * General Public License for more details.
00020  * 
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00024  * 02111-1307, USA.
00025  */
00026 
00033 #include <config.h>
00034 #include "display-private.h"
00035 #include "util.h"
00036 #include "main.h"
00037 #include "screen-private.h"
00038 #include "window-private.h"
00039 #include "window-props.h"
00040 #include "group-props.h"
00041 #include "frame-private.h"
00042 #include "errors.h"
00043 #include "keybindings.h"
00044 #include "prefs.h"
00045 #include "resizepopup.h"
00046 #include "xprops.h"
00047 #include "workspace.h"
00048 #include "bell.h"
00049 #include "effects.h"
00050 #include "compositor.h"
00051 #include <X11/Xatom.h>
00052 #include <X11/cursorfont.h>
00053 #ifdef HAVE_SOLARIS_XINERAMA
00054 #include <X11/extensions/xinerama.h>
00055 #endif
00056 #ifdef HAVE_XFREE_XINERAMA
00057 #include <X11/extensions/Xinerama.h>
00058 #endif
00059 #ifdef HAVE_RANDR
00060 #include <X11/extensions/Xrandr.h>
00061 #endif
00062 #ifdef HAVE_SHAPE
00063 #include <X11/extensions/shape.h>
00064 #endif
00065 #ifdef HAVE_RENDER
00066 #include <X11/extensions/Xrender.h>
00067 #endif
00068 #ifdef HAVE_XKB
00069 #include <X11/XKBlib.h>
00070 #endif
00071 #ifdef HAVE_XCURSOR
00072 #include <X11/Xcursor/Xcursor.h>
00073 #endif
00074 #ifdef HAVE_COMPOSITE_EXTENSIONS
00075 #include <X11/extensions/Xcomposite.h>
00076 #include <X11/extensions/Xdamage.h>
00077 #include <X11/extensions/Xfixes.h>
00078 #endif
00079 #include <string.h>
00080 
00081 #define GRAB_OP_IS_WINDOW_SWITCH(g)                     \
00082         (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL  ||  \
00083          g == META_GRAB_OP_KEYBOARD_TABBING_DOCK    ||  \
00084          g == META_GRAB_OP_KEYBOARD_TABBING_GROUP   ||  \
00085          g == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL ||  \
00086          g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK   ||  \
00087          g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
00088 
00113 typedef struct 
00114 {
00115   MetaDisplay *display;
00116   Window       xwindow;
00117   guint32      timestamp;
00118   MetaWindowPingFunc ping_reply_func;
00119   MetaWindowPingFunc ping_timeout_func;
00120   void        *user_data;
00121   guint        ping_timeout_id;
00122 } MetaPingData;
00123 
00124 typedef struct 
00125 {
00126   MetaDisplay *display;
00127   Window xwindow;
00128 } MetaAutoRaiseData;
00129 
00136 static MetaDisplay *the_display = NULL;
00137 
00138 static void   meta_spew_event           (MetaDisplay    *display,
00139                                          XEvent         *event);
00140 
00141 static gboolean event_callback          (XEvent         *event,
00142                                          gpointer        data);
00143 static Window event_get_modified_window (MetaDisplay    *display,
00144                                          XEvent         *event);
00145 static guint32 event_get_time           (MetaDisplay    *display,
00146                                          XEvent         *event);
00147 static void    process_request_frame_extents (MetaDisplay    *display,
00148                                               XEvent         *event);
00149 static void    process_pong_message     (MetaDisplay    *display,
00150                                          XEvent         *event);
00151 static void    process_selection_request (MetaDisplay   *display,
00152                                           XEvent        *event);
00153 static void    process_selection_clear   (MetaDisplay   *display,
00154                                           XEvent        *event);
00155 
00156 static void    update_window_grab_modifiers (MetaDisplay *display);
00157 
00158 static void    prefs_changed_callback    (MetaPreference pref,
00159                                           void          *data);
00160 
00161 static void    sanity_check_timestamps   (MetaDisplay *display,
00162                                           guint32      known_good_timestamp);
00163 
00164 MetaGroup*     get_focussed_group (MetaDisplay *display);
00165 
00172 static void
00173 ping_data_free (MetaPingData *ping_data)
00174 {
00175   /* Remove the timeout */
00176   if (ping_data->ping_timeout_id != 0)
00177     g_source_remove (ping_data->ping_timeout_id);
00178 
00179   g_free (ping_data);
00180 }
00181 
00192 static void
00193 remove_pending_pings_for_window (MetaDisplay *display, Window xwindow)
00194 {
00195   GSList *tmp;
00196   GSList *dead;
00197 
00198   /* could obviously be more efficient, don't care */
00199   
00200   /* build list to be removed */
00201   dead = NULL;
00202   for (tmp = display->pending_pings; tmp; tmp = tmp->next)
00203     {
00204       MetaPingData *ping_data = tmp->data;
00205 
00206       if (ping_data->xwindow == xwindow)
00207         dead = g_slist_prepend (dead, ping_data);
00208     }
00209 
00210   /* remove what we found */
00211   for (tmp = dead; tmp; tmp = tmp->next)
00212     {
00213       MetaPingData *ping_data = tmp->data;
00214 
00215       display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
00216       ping_data_free (ping_data);
00217     }
00218 
00219   g_slist_free (dead);
00220 }
00221 
00222 
00223 #ifdef HAVE_STARTUP_NOTIFICATION
00224 static void
00225 sn_error_trap_push (SnDisplay *sn_display,
00226                     Display   *xdisplay)
00227 {
00228   MetaDisplay *display;
00229   display = meta_display_for_x_display (xdisplay);
00230   if (display != NULL)
00231     meta_error_trap_push (display);
00232 }
00233 
00234 static void
00235 sn_error_trap_pop (SnDisplay *sn_display,
00236                    Display   *xdisplay)
00237 {
00238   MetaDisplay *display;
00239   display = meta_display_for_x_display (xdisplay);
00240   if (display != NULL)
00241     meta_error_trap_pop (display, FALSE);
00242 }
00243 #endif
00244 
00245 static void
00246 enable_compositor (MetaDisplay *display,
00247                    gboolean     composite_windows)
00248 {
00249   GSList *list;
00250 
00251   if (!META_DISPLAY_HAS_COMPOSITE (display) ||
00252       !META_DISPLAY_HAS_DAMAGE (display) ||
00253       !META_DISPLAY_HAS_XFIXES (display) ||
00254       !META_DISPLAY_HAS_RENDER (display))
00255     {
00256       meta_warning (_("Missing %s extension required for compositing"),
00257                     !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" :
00258                     !META_DISPLAY_HAS_DAMAGE (display) ? "damage" :
00259                     !META_DISPLAY_HAS_XFIXES (display) ? "xfixes" : "render");
00260       return;
00261     }
00262 
00263   if (!display->compositor)
00264       display->compositor = meta_compositor_new (display);
00265 
00266   if (!display->compositor)
00267     return;
00268   
00269   for (list = display->screens; list != NULL; list = list->next)
00270     {
00271       MetaScreen *screen = list->data;
00272       
00273       meta_compositor_manage_screen (screen->display->compositor,
00274                                      screen);
00275 
00276       if (composite_windows)
00277         meta_screen_composite_all_windows (screen);
00278     }
00279 }
00280 
00281 static void
00282 disable_compositor (MetaDisplay *display)
00283 {
00284   GSList *list;
00285   
00286   if (!display->compositor)
00287     return;
00288   
00289   for (list = display->screens; list != NULL; list = list->next)
00290     {
00291       MetaScreen *screen = list->data;
00292       
00293       meta_compositor_unmanage_screen (screen->display->compositor,
00294                                        screen);
00295     }
00296   
00297   meta_compositor_destroy (display->compositor);
00298   display->compositor = NULL;
00299 }
00300 
00311 gboolean
00312 meta_display_open (void)
00313 {
00314   Display *xdisplay;
00315   GSList *screens;
00316   GSList *tmp;
00317   int i;
00318   guint32 timestamp;
00319 
00320   /* A list of all atom names, so that we can intern them in one go. */
00321   char *atom_names[] = {
00322 #define item(x) #x,
00323 #include "atomnames.h"
00324 #undef item
00325   };
00326   Atom atoms[G_N_ELEMENTS(atom_names)];
00327   
00328   meta_verbose ("Opening display '%s'\n", XDisplayName (NULL));
00329 
00330   xdisplay = meta_ui_get_display ();
00331   
00332   if (xdisplay == NULL)
00333     {
00334       meta_warning (_("Failed to open X Window System display '%s'\n"),
00335                     XDisplayName (NULL));
00336       return FALSE;
00337     }
00338 
00339   if (meta_is_syncing ())
00340     XSynchronize (xdisplay, True);
00341   
00342   g_assert (the_display == NULL);
00343   the_display = g_new (MetaDisplay, 1);
00344 
00345   the_display->closing = 0;
00346   
00347   /* here we use XDisplayName which is what the user
00348    * probably put in, vs. DisplayString(display) which is
00349    * canonicalized by XOpenDisplay()
00350    */
00351   the_display->name = g_strdup (XDisplayName (NULL));
00352   the_display->xdisplay = xdisplay;
00353   the_display->error_trap_synced_at_last_pop = TRUE;
00354   the_display->error_traps = 0;
00355   the_display->error_trap_handler = NULL;
00356   the_display->server_grab_count = 0;
00357   the_display->display_opening = TRUE;
00358 
00359   the_display->pending_pings = NULL;
00360   the_display->autoraise_timeout_id = 0;
00361   the_display->autoraise_window = NULL;
00362   the_display->focus_window = NULL;
00363   the_display->expected_focus_window = NULL;
00364   the_display->grab_old_window_stacking = NULL;
00365 
00366   the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
00367   the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
00368                                                   terminal has the focus */
00369 
00370 #ifdef HAVE_XSYNC
00371   the_display->grab_sync_request_alarm = None;
00372 #endif
00373   
00374   /* FIXME copy the checks from GDK probably */
00375   the_display->static_gravity_works = g_getenv ("METACITY_USE_STATIC_GRAVITY") != NULL;
00376   
00377   meta_bell_init (the_display);
00378 
00379   meta_display_init_keys (the_display);
00380 
00381   update_window_grab_modifiers (the_display);
00382 
00383   meta_prefs_add_listener (prefs_changed_callback, the_display);
00384 
00385   meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
00386   XInternAtoms (the_display->xdisplay, atom_names, G_N_ELEMENTS (atom_names),
00387                 False, atoms);
00388   {
00389     int i = 0;    
00390 #define item(x) the_display->atom_##x = atoms[i++];
00391 #include "atomnames.h"
00392 #undef item
00393   }
00394 
00395   the_display->prop_hooks = NULL;
00396   meta_display_init_window_prop_hooks (the_display);
00397   the_display->group_prop_hooks = NULL;
00398   meta_display_init_group_prop_hooks (the_display);
00399   
00400   /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
00401    * created in screen_new
00402    */
00403   the_display->leader_window = None;
00404   the_display->timestamp_pinging_window = None;
00405 
00406   the_display->xinerama_cache_invalidated = TRUE;
00407 
00408   the_display->groups_by_leader = NULL;
00409 
00410   the_display->window_with_menu = NULL;
00411   the_display->window_menu = NULL;
00412   
00413   the_display->screens = NULL;
00414   the_display->active_screen = NULL;
00415   
00416 #ifdef HAVE_STARTUP_NOTIFICATION
00417   the_display->sn_display = sn_display_new (the_display->xdisplay,
00418                                         sn_error_trap_push,
00419                                         sn_error_trap_pop);
00420 #endif
00421   
00422   the_display->events = NULL;
00423 
00424   /* Get events */
00425   meta_ui_add_event_func (the_display->xdisplay,
00426                           event_callback,
00427                           the_display);
00428   
00429   the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash,
00430                                           meta_unsigned_long_equal);
00431   
00432   i = 0;
00433   while (i < N_IGNORED_SERIALS)
00434     {
00435       the_display->ignored_serials[i] = 0;
00436       ++i;
00437     }
00438   the_display->ungrab_should_not_cause_focus_window = None;
00439   
00440   the_display->current_time = CurrentTime;
00441   the_display->sentinel_counter = 0;
00442 
00443   the_display->grab_resize_timeout_id = 0;
00444   the_display->grab_have_keyboard = FALSE;
00445   
00446 #ifdef HAVE_XKB  
00447   the_display->last_bell_time = 0;
00448 #endif
00449 
00450   the_display->grab_op = META_GRAB_OP_NONE;
00451   the_display->grab_wireframe_active = FALSE;
00452   the_display->grab_window = NULL;
00453   the_display->grab_screen = NULL;
00454   the_display->grab_resize_popup = NULL;
00455 
00456   the_display->grab_edge_resistance_data = NULL;
00457 
00458 #ifdef HAVE_XSYNC
00459   {
00460     int major, minor;
00461 
00462     the_display->have_xsync = FALSE;
00463     
00464     the_display->xsync_error_base = 0;
00465     the_display->xsync_event_base = 0;
00466 
00467     /* I don't think we really have to fill these in */
00468     major = SYNC_MAJOR_VERSION;
00469     minor = SYNC_MINOR_VERSION;
00470     
00471     if (!XSyncQueryExtension (the_display->xdisplay,
00472                               &the_display->xsync_event_base,
00473                               &the_display->xsync_error_base) ||
00474         !XSyncInitialize (the_display->xdisplay,
00475                           &major, &minor))
00476       {
00477         the_display->xsync_error_base = 0;
00478         the_display->xsync_event_base = 0;
00479       }
00480     else
00481       the_display->have_xsync = TRUE;
00482     
00483     meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n",
00484                   major, minor,
00485                   the_display->xsync_error_base,
00486                   the_display->xsync_event_base);
00487   }
00488 #else  /* HAVE_XSYNC */
00489   meta_verbose ("Not compiled with Xsync support\n");
00490 #endif /* !HAVE_XSYNC */
00491 
00492 
00493 #ifdef HAVE_SHAPE
00494   {
00495     the_display->have_shape = FALSE;
00496     
00497     the_display->shape_error_base = 0;
00498     the_display->shape_event_base = 0;
00499     
00500     if (!XShapeQueryExtension (the_display->xdisplay,
00501                                &the_display->shape_event_base,
00502                                &the_display->shape_error_base))
00503       {
00504         the_display->shape_error_base = 0;
00505         the_display->shape_event_base = 0;
00506       }
00507     else
00508       the_display->have_shape = TRUE;
00509     
00510     meta_verbose ("Attempted to init Shape, found error base %d event base %d\n",
00511                   the_display->shape_error_base,
00512                   the_display->shape_event_base);
00513   }
00514 #else  /* HAVE_SHAPE */
00515   meta_verbose ("Not compiled with Shape support\n");
00516 #endif /* !HAVE_SHAPE */
00517 
00518 #ifdef HAVE_RENDER
00519   {
00520     the_display->have_render = FALSE;
00521     
00522     the_display->render_error_base = 0;
00523     the_display->render_event_base = 0;
00524     
00525     if (!XRenderQueryExtension (the_display->xdisplay,
00526                                 &the_display->render_event_base,
00527                                 &the_display->render_error_base))
00528       {
00529         the_display->render_error_base = 0;
00530         the_display->render_event_base = 0;
00531       }
00532     else
00533       the_display->have_render = TRUE;
00534     
00535     meta_verbose ("Attempted to init Render, found error base %d event base %d\n",
00536                   the_display->render_error_base,
00537                   the_display->render_event_base);
00538   }
00539 #else  /* HAVE_RENDER */
00540   meta_verbose ("Not compiled with Render support\n");
00541 #endif /* !HAVE_RENDER */
00542 
00543 #ifdef HAVE_COMPOSITE_EXTENSIONS
00544   {
00545     the_display->have_composite = FALSE;
00546 
00547     the_display->composite_error_base = 0;
00548     the_display->composite_event_base = 0;
00549 
00550     if (!XCompositeQueryExtension (the_display->xdisplay,
00551                                    &the_display->composite_event_base,
00552                                    &the_display->composite_error_base))
00553       {
00554         the_display->composite_error_base = 0;
00555         the_display->composite_event_base = 0;
00556       } 
00557     else
00558       {
00559         the_display->composite_major_version = 0;
00560         the_display->composite_minor_version = 0;
00561         if (XCompositeQueryVersion (the_display->xdisplay,
00562                                     &the_display->composite_major_version,
00563                                     &the_display->composite_minor_version))
00564           {
00565             the_display->have_composite = TRUE;
00566           }
00567         else
00568           {
00569             the_display->composite_major_version = 0;
00570             the_display->composite_minor_version = 0;
00571           }
00572       }
00573 
00574     meta_verbose ("Attempted to init Composite, found error base %d event base %d "
00575                   "extn ver %d %d\n",
00576                   the_display->composite_error_base, 
00577                   the_display->composite_event_base,
00578                   the_display->composite_major_version,
00579                   the_display->composite_minor_version);
00580 
00581     the_display->have_damage = FALSE;
00582 
00583     the_display->damage_error_base = 0;
00584     the_display->damage_event_base = 0;
00585 
00586     if (!XDamageQueryExtension (the_display->xdisplay,
00587                                 &the_display->damage_event_base,
00588                                 &the_display->damage_error_base))
00589       {
00590         the_display->damage_error_base = 0;
00591         the_display->damage_event_base = 0;
00592       } 
00593     else
00594       the_display->have_damage = TRUE;
00595 
00596     meta_verbose ("Attempted to init Damage, found error base %d event base %d\n",
00597                   the_display->damage_error_base, 
00598                   the_display->damage_event_base);
00599 
00600     the_display->have_xfixes = FALSE;
00601 
00602     the_display->xfixes_error_base = 0;
00603     the_display->xfixes_event_base = 0;
00604 
00605     if (!XFixesQueryExtension (the_display->xdisplay,
00606                                &the_display->xfixes_event_base,
00607                                &the_display->xfixes_error_base))
00608       {
00609         the_display->xfixes_error_base = 0;
00610         the_display->xfixes_event_base = 0;
00611       } 
00612     else
00613       the_display->have_xfixes = TRUE;
00614 
00615     meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n",
00616                   the_display->xfixes_error_base, 
00617                   the_display->xfixes_event_base);
00618   }
00619 #else /* HAVE_COMPOSITE_EXTENSIONS */
00620   meta_verbose ("Not compiled with Composite support\n");
00621 #endif /* !HAVE_COMPOSITE_EXTENSIONS */
00622       
00623 #ifdef HAVE_XCURSOR
00624   {
00625     XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ());
00626     XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ());
00627   }
00628 #else /* HAVE_XCURSOR */
00629   meta_verbose ("Not compiled with Xcursor support\n");
00630 #endif /* !HAVE_XCURSOR */
00631 
00632   /* Create the leader window here. Set its properties and
00633    * use the timestamp from one of the PropertyNotify events
00634    * that will follow.
00635    */
00636   {
00637     gulong data[1];
00638     XEvent event;
00639 
00640     /* We only care about the PropertyChangeMask in the next 30 or so lines of
00641      * code.  Note that gdk will at some point unset the PropertyChangeMask for
00642      * this window, so we can't rely on it still being set later.  See bug
00643      * 354213 for details.
00644      */
00645     the_display->leader_window =
00646       meta_create_offscreen_window (the_display->xdisplay,
00647                                     DefaultRootWindow (the_display->xdisplay),
00648                                     PropertyChangeMask);
00649 
00650     meta_prop_set_utf8_string_hint (the_display,
00651                                     the_display->leader_window,
00652                                     the_display->atom__NET_WM_NAME,
00653                                     "Metacity");
00654     
00655     meta_prop_set_utf8_string_hint (the_display,
00656                                     the_display->leader_window,
00657                                     the_display->atom__METACITY_VERSION,
00658                                     VERSION);
00659 
00660     data[0] = the_display->leader_window;
00661     XChangeProperty (the_display->xdisplay,
00662                      the_display->leader_window,
00663                      the_display->atom__NET_SUPPORTING_WM_CHECK,
00664                      XA_WINDOW,
00665                      32, PropModeReplace, (guchar*) data, 1);
00666 
00667     XWindowEvent (the_display->xdisplay,
00668                   the_display->leader_window,
00669                   PropertyChangeMask,
00670                   &event);
00671 
00672     timestamp = event.xproperty.time;
00673 
00674     /* Make it painfully clear that we can't rely on PropertyNotify events on
00675      * this window, as per bug 354213.
00676      */
00677     XSelectInput(the_display->xdisplay,
00678                  the_display->leader_window,
00679                  NoEventMask);
00680   }
00681 
00682   /* Make a little window used only for pinging the server for timestamps; note
00683    * that meta_create_offscreen_window already selects for PropertyChangeMask.
00684    */
00685   the_display->timestamp_pinging_window =
00686     meta_create_offscreen_window (the_display->xdisplay,
00687                                   DefaultRootWindow (the_display->xdisplay),
00688                                   PropertyChangeMask);
00689 
00690   the_display->last_focus_time = timestamp;
00691   the_display->last_user_time = timestamp;
00692   the_display->compositor = NULL;
00693   
00694   screens = NULL;
00695   
00696   i = 0;
00697   while (i < ScreenCount (xdisplay))
00698     {
00699       MetaScreen *screen;
00700 
00701       screen = meta_screen_new (the_display, i, timestamp);
00702 
00703       if (screen)
00704         screens = g_slist_prepend (screens, screen);
00705       ++i;
00706     }
00707   
00708   the_display->screens = screens;
00709   
00710   if (screens == NULL)
00711     {
00712       /* This would typically happen because all the screens already
00713        * have window managers.
00714        */
00715       meta_display_close (the_display, timestamp);
00716       return FALSE;
00717     }
00718 
00719   /* We don't composite the windows here because they will be composited 
00720      faster with the call to meta_screen_manage_all_windows further down 
00721      the code */
00722   if (meta_prefs_get_compositing_manager ())
00723     enable_compositor (the_display, FALSE);
00724    
00725   meta_display_grab (the_display);
00726   
00727   /* Now manage all existing windows */
00728   tmp = the_display->screens;
00729   while (tmp != NULL)
00730     {
00731       MetaScreen *screen = tmp->data;
00732         
00733       meta_screen_manage_all_windows (screen);
00734 
00735       tmp = tmp->next;
00736     }
00737 
00738   {
00739     Window focus;
00740     int ret_to;
00741 
00742     /* kinda bogus because GetInputFocus has no possible errors */
00743     meta_error_trap_push (the_display);
00744 
00745     /* FIXME: This is totally broken; see comment 9 of bug 88194 about this */
00746     focus = None;
00747     ret_to = RevertToPointerRoot;
00748     XGetInputFocus (the_display->xdisplay, &focus, &ret_to);
00749 
00750     /* Force a new FocusIn (does this work?) */
00751 
00752     /* Use the same timestamp that was passed to meta_screen_new(),
00753      * as it is the most recent timestamp.
00754      */
00755     if (focus == None || focus == PointerRoot)
00756       /* Just focus the no_focus_window on the first screen */
00757       meta_display_focus_the_no_focus_window (the_display,
00758                                               the_display->screens->data,
00759                                               timestamp);
00760     else
00761       {
00762         MetaWindow * window;
00763         window  = meta_display_lookup_x_window (the_display, focus);
00764         if (window)
00765           meta_display_set_input_focus_window (the_display, window, FALSE, timestamp);
00766         else
00767           /* Just focus the no_focus_window on the first screen */
00768           meta_display_focus_the_no_focus_window (the_display,
00769                                                   the_display->screens->data,
00770                                                   timestamp);
00771       }
00772 
00773     meta_error_trap_pop (the_display, FALSE);
00774   }
00775   
00776   meta_display_ungrab (the_display);  
00777 
00778   /* Done opening new display */
00779   the_display->display_opening = FALSE;
00780 
00781   return TRUE;
00782 }
00783 
00784 static void
00785 listify_func (gpointer key, gpointer value, gpointer data)
00786 {
00787   GSList **listp;
00788 
00789   listp = data;
00790   *listp = g_slist_prepend (*listp, value);
00791 }
00792 
00793 static gint
00794 ptrcmp (gconstpointer a, gconstpointer b)
00795 {
00796   if (a < b)
00797     return -1;
00798   else if (a > b)
00799     return 1;
00800   else
00801     return 0;
00802 }
00803 
00804 GSList*
00805 meta_display_list_windows (MetaDisplay *display)
00806 {
00807   GSList *winlist;
00808   GSList *tmp;
00809   GSList *prev;
00810   
00811   winlist = NULL;
00812   g_hash_table_foreach (display->window_ids,
00813                         listify_func,
00814                         &winlist);
00815 
00816   /* Uniquify the list, since both frame windows and plain
00817    * windows are in the hash
00818    */
00819   winlist = g_slist_sort (winlist, ptrcmp);
00820 
00821   prev = NULL;
00822   tmp = winlist;
00823   while (tmp != NULL)
00824     {
00825       GSList *next;
00826 
00827       next = tmp->next;
00828       
00829       if (next &&
00830           next->data == tmp->data)
00831         {
00832           /* Delete tmp from list */
00833 
00834           if (prev)
00835             prev->next = next;
00836 
00837           if (tmp == winlist)
00838             winlist = next;
00839           
00840           g_slist_free_1 (tmp);
00841 
00842           /* leave prev unchanged */
00843         }
00844       else
00845         {
00846           prev = tmp;
00847         }
00848       
00849       tmp = next;
00850     }
00851 
00852   return winlist;
00853 }
00854 
00855 void
00856 meta_display_close (MetaDisplay *display,
00857                     guint32      timestamp)
00858 {
00859   GSList *tmp;
00860 
00861   g_assert (display != NULL);
00862 
00863   if (display->closing != 0)
00864     {
00865       /* The display's already been closed. */
00866       return;
00867     }
00868 
00869   if (display->error_traps > 0)
00870     meta_bug ("Display closed with error traps pending\n");
00871 
00872   display->closing += 1;
00873 
00874   meta_prefs_remove_listener (prefs_changed_callback, display);
00875   
00876   meta_display_remove_autoraise_callback (display);
00877 
00878   if (display->grab_old_window_stacking)
00879     g_list_free (display->grab_old_window_stacking);
00880   
00881   /* Stop caring about events */
00882   meta_ui_remove_event_func (display->xdisplay,
00883                              event_callback,
00884                              display);
00885   
00886   /* Free all screens */
00887   tmp = display->screens;
00888   while (tmp != NULL)
00889     {
00890       MetaScreen *screen = tmp->data;
00891       meta_screen_free (screen, timestamp);
00892       tmp = tmp->next;
00893     }
00894 
00895   g_slist_free (display->screens);
00896   display->screens = NULL;
00897 
00898 #ifdef HAVE_STARTUP_NOTIFICATION
00899   if (display->sn_display)
00900     {
00901       sn_display_unref (display->sn_display);
00902       display->sn_display = NULL;
00903     }
00904 #endif
00905   
00906   /* Must be after all calls to meta_window_free() since they
00907    * unregister windows
00908    */
00909   g_hash_table_destroy (display->window_ids);
00910 
00911   if (display->leader_window != None)
00912     XDestroyWindow (display->xdisplay, display->leader_window);
00913 
00914   XFlush (display->xdisplay);
00915 
00916   meta_display_free_window_prop_hooks (display);
00917   meta_display_free_group_prop_hooks (display);
00918   
00919   g_free (display->name);
00920 
00921   meta_display_shutdown_keys (display);
00922 
00923   if (display->compositor)
00924     meta_compositor_destroy (display->compositor);
00925   
00926   g_free (display);
00927   display = NULL;
00928 
00929   meta_quit (META_EXIT_SUCCESS);
00930 }
00931 
00932 MetaScreen*
00933 meta_display_screen_for_root (MetaDisplay *display,
00934                               Window       xroot)
00935 {
00936   GSList *tmp;
00937 
00938   tmp = display->screens;
00939   while (tmp != NULL)
00940     {
00941       MetaScreen *screen = tmp->data;
00942 
00943       if (xroot == screen->xroot)
00944         return screen;
00945 
00946       tmp = tmp->next;
00947     }
00948 
00949   return NULL;
00950 }
00951 
00952 MetaScreen*
00953 meta_display_screen_for_xwindow (MetaDisplay *display,
00954                                  Window       xwindow)
00955 {
00956   XWindowAttributes attr;
00957   int result;
00958   
00959   meta_error_trap_push (display);
00960   attr.screen = NULL;
00961   result = XGetWindowAttributes (display->xdisplay, xwindow, &attr);
00962   meta_error_trap_pop (display, TRUE);
00963 
00964   /* Note, XGetWindowAttributes is on all kinds of crack
00965    * and returns 1 on success 0 on failure, rather than Success
00966    * on success.
00967    */
00968   if (result == 0 || attr.screen == NULL)
00969     return NULL;
00970   
00971   return meta_display_screen_for_x_screen (display, attr.screen);
00972 }
00973 
00974 MetaScreen*
00975 meta_display_screen_for_x_screen (MetaDisplay *display,
00976                                   Screen      *xscreen)
00977 {
00978   GSList *tmp;
00979 
00980   tmp = display->screens;
00981   while (tmp != NULL)
00982     {
00983       MetaScreen *screen = tmp->data;
00984 
00985       if (xscreen == screen->xscreen)
00986         return screen;
00987 
00988       tmp = tmp->next;
00989     }
00990 
00991   return NULL;
00992 }
00993 
00994 /* Grab/ungrab routines taken from fvwm */
00995 void
00996 meta_display_grab (MetaDisplay *display)
00997 {
00998   if (display->server_grab_count == 0)
00999     {
01000       XGrabServer (display->xdisplay);
01001     }
01002   display->server_grab_count += 1;
01003   meta_verbose ("Grabbing display, grab count now %d\n",
01004                 display->server_grab_count);
01005 }
01006 
01007 void
01008 meta_display_ungrab (MetaDisplay *display)
01009 {
01010   if (display->server_grab_count == 0)
01011     meta_bug ("Ungrabbed non-grabbed server\n");
01012   
01013   display->server_grab_count -= 1;
01014   if (display->server_grab_count == 0)
01015     {
01016       /* FIXME we want to purge all pending "queued" stuff
01017        * at this point, such as window hide/show
01018        */
01019       XUngrabServer (display->xdisplay);
01020       XFlush (display->xdisplay);
01021     }
01022 
01023   meta_verbose ("Ungrabbing display, grab count now %d\n",
01024                 display->server_grab_count);
01025 }
01026 
01038 MetaDisplay*
01039 meta_display_for_x_display (Display *xdisplay)
01040 {
01041   if (the_display->xdisplay == xdisplay)
01042     return the_display;
01043 
01044   meta_warning ("Could not find display for X display %p, probably going to crash\n",
01045                 xdisplay);
01046   
01047   return NULL;
01048 }
01049 
01056 MetaDisplay*
01057 meta_get_display (void)
01058 {
01059   return the_display;
01060 }
01061 
01062 #ifdef WITH_VERBOSE_MODE
01063 static gboolean dump_events = TRUE;
01064 #endif
01065 
01066 static gboolean
01067 grab_op_is_mouse_only (MetaGrabOp op)
01068 {
01069   switch (op)
01070     {
01071     case META_GRAB_OP_MOVING:
01072     case META_GRAB_OP_RESIZING_SE:
01073     case META_GRAB_OP_RESIZING_S:      
01074     case META_GRAB_OP_RESIZING_SW:      
01075     case META_GRAB_OP_RESIZING_N:
01076     case META_GRAB_OP_RESIZING_NE:
01077     case META_GRAB_OP_RESIZING_NW:
01078     case META_GRAB_OP_RESIZING_W:
01079     case META_GRAB_OP_RESIZING_E:
01080       return TRUE;
01081 
01082     default:
01083       return FALSE;
01084     }
01085 }
01086 
01087 static gboolean
01088 grab_op_is_mouse (MetaGrabOp op)
01089 {
01090   switch (op)
01091     {
01092     case META_GRAB_OP_MOVING:
01093     case META_GRAB_OP_RESIZING_SE:
01094     case META_GRAB_OP_RESIZING_S:      
01095     case META_GRAB_OP_RESIZING_SW:      
01096     case META_GRAB_OP_RESIZING_N:
01097     case META_GRAB_OP_RESIZING_NE:
01098     case META_GRAB_OP_RESIZING_NW:
01099     case META_GRAB_OP_RESIZING_W:
01100     case META_GRAB_OP_RESIZING_E:
01101     case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
01102     case META_GRAB_OP_KEYBOARD_RESIZING_S:
01103     case META_GRAB_OP_KEYBOARD_RESIZING_N:
01104     case META_GRAB_OP_KEYBOARD_RESIZING_W:
01105     case META_GRAB_OP_KEYBOARD_RESIZING_E:
01106     case META_GRAB_OP_KEYBOARD_RESIZING_SE:
01107     case META_GRAB_OP_KEYBOARD_RESIZING_NE:
01108     case META_GRAB_OP_KEYBOARD_RESIZING_SW:
01109     case META_GRAB_OP_KEYBOARD_RESIZING_NW:
01110     case META_GRAB_OP_KEYBOARD_MOVING:
01111       return TRUE;
01112 
01113     default:
01114       return FALSE;
01115     }
01116 }
01117 
01118 static gboolean
01119 grab_op_is_keyboard (MetaGrabOp op)
01120 {
01121   switch (op)
01122     {
01123     case META_GRAB_OP_KEYBOARD_MOVING:
01124     case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
01125     case META_GRAB_OP_KEYBOARD_RESIZING_S:
01126     case META_GRAB_OP_KEYBOARD_RESIZING_N:
01127     case META_GRAB_OP_KEYBOARD_RESIZING_W:
01128     case META_GRAB_OP_KEYBOARD_RESIZING_E:
01129     case META_GRAB_OP_KEYBOARD_RESIZING_SE:
01130     case META_GRAB_OP_KEYBOARD_RESIZING_NE:
01131     case META_GRAB_OP_KEYBOARD_RESIZING_SW:
01132     case META_GRAB_OP_KEYBOARD_RESIZING_NW:
01133     case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
01134     case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
01135     case META_GRAB_OP_KEYBOARD_TABBING_GROUP:
01136     case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
01137     case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
01138     case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP:
01139     case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
01140       return TRUE;
01141 
01142     default:
01143       return FALSE;
01144     }
01145 }
01146 
01147 gboolean
01148 meta_grab_op_is_resizing (MetaGrabOp op)
01149 {
01150   switch (op)
01151     {
01152     case META_GRAB_OP_RESIZING_SE:
01153     case META_GRAB_OP_RESIZING_S:      
01154     case META_GRAB_OP_RESIZING_SW:      
01155     case META_GRAB_OP_RESIZING_N:
01156     case META_GRAB_OP_RESIZING_NE:
01157     case META_GRAB_OP_RESIZING_NW:
01158     case META_GRAB_OP_RESIZING_W:
01159     case META_GRAB_OP_RESIZING_E:
01160     case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
01161     case META_GRAB_OP_KEYBOARD_RESIZING_S:
01162     case META_GRAB_OP_KEYBOARD_RESIZING_N:
01163     case META_GRAB_OP_KEYBOARD_RESIZING_W:
01164     case META_GRAB_OP_KEYBOARD_RESIZING_E:
01165     case META_GRAB_OP_KEYBOARD_RESIZING_SE:
01166     case META_GRAB_OP_KEYBOARD_RESIZING_NE:
01167     case META_GRAB_OP_KEYBOARD_RESIZING_SW:
01168     case META_GRAB_OP_KEYBOARD_RESIZING_NW:
01169       return TRUE;
01170 
01171     default:
01172       return FALSE;
01173     }
01174 }
01175 
01176 gboolean
01177 meta_grab_op_is_moving (MetaGrabOp op)
01178 {
01179   switch (op)
01180     {
01181     case META_GRAB_OP_MOVING:
01182     case META_GRAB_OP_KEYBOARD_MOVING:
01183       return TRUE;
01184       
01185     default:
01186       return FALSE;
01187     }
01188 }
01189 
01190 /* Get time of current event, or CurrentTime if none. */
01191 guint32
01192 meta_display_get_current_time (MetaDisplay *display)
01193 {
01194   return display->current_time;
01195 }
01196 
01197 /* Get a timestamp, even if it means a roundtrip */
01198 guint32
01199 meta_display_get_current_time_roundtrip (MetaDisplay *display)
01200 {
01201   guint32 timestamp;
01202   
01203   timestamp = meta_display_get_current_time (display);
01204   if (timestamp == CurrentTime)
01205     {
01206       XEvent property_event;
01207 
01208       /* Using the property XA_PRIMARY because it's safe; nothing
01209        * would use it as a property. The type doesn't matter.
01210        */
01211       XChangeProperty (display->xdisplay,
01212                        display->timestamp_pinging_window,
01213                        XA_PRIMARY, XA_STRING, 8,
01214                        PropModeAppend, NULL, 0);
01215       XWindowEvent (display->xdisplay,
01216                     display->timestamp_pinging_window,
01217                     PropertyChangeMask,
01218                     &property_event);
01219       timestamp = property_event.xproperty.time;
01220     }
01221 
01222   sanity_check_timestamps (display, timestamp);
01223 
01224   return timestamp;
01225 }
01226 
01227 static void
01228 add_ignored_serial (MetaDisplay  *display,
01229                     unsigned long serial)
01230 {
01231   int i;
01232 
01233   /* don't add the same serial more than once */
01234   if (display->ignored_serials[N_IGNORED_SERIALS-1] == serial)
01235     return;
01236   
01237   /* shift serials to the left */
01238   i = 0;
01239   while (i < (N_IGNORED_SERIALS - 1))
01240     {
01241       display->ignored_serials[i] = display->ignored_serials[i+1];
01242       ++i;
01243     }
01244   /* put new one on the end */
01245   display->ignored_serials[i] = serial;
01246 }
01247 
01248 static gboolean
01249 serial_is_ignored (MetaDisplay  *display,
01250                    unsigned long serial)
01251 {
01252   int i;
01253 
01254   i = 0;
01255   while (i < N_IGNORED_SERIALS)
01256     {
01257       if (display->ignored_serials[i] == serial)
01258         return TRUE;
01259       ++i;
01260     }
01261   return FALSE;
01262 }
01263 
01264 static void
01265 reset_ignores (MetaDisplay *display)
01266 {
01267   int i;
01268 
01269   i = 0;
01270   while (i < N_IGNORED_SERIALS)
01271     {
01272       display->ignored_serials[i] = 0;
01273       ++i;
01274     }
01275 
01276   display->ungrab_should_not_cause_focus_window = None;
01277 }
01278 
01279 static gboolean 
01280 window_raise_with_delay_callback (void *data)
01281 {
01282   MetaWindow *window;
01283   MetaAutoRaiseData *auto_raise;
01284 
01285   auto_raise = data;
01286 
01287   meta_topic (META_DEBUG_FOCUS, 
01288               "In autoraise callback for window 0x%lx\n", 
01289               auto_raise->xwindow);
01290 
01291   auto_raise->display->autoraise_timeout_id = 0;
01292   auto_raise->display->autoraise_window = NULL;
01293 
01294   window  = meta_display_lookup_x_window (auto_raise->display, 
01295                                           auto_raise->xwindow);
01296   
01297   if (window == NULL) 
01298     return FALSE;
01299 
01300   /* If we aren't already on top, check whether the pointer is inside
01301    * the window and raise the window if so.
01302    */      
01303   if (meta_stack_get_top (window->screen->stack) != window) 
01304     {
01305       int x, y, root_x, root_y;
01306       Window root, child;
01307       unsigned int mask;
01308       gboolean same_screen;
01309       gboolean point_in_window;
01310 
01311       meta_error_trap_push (window->display);
01312       same_screen = XQueryPointer (window->display->xdisplay,
01313                                    window->xwindow,
01314                                    &root, &child,
01315                                    &root_x, &root_y, &x, &y, &mask);
01316       meta_error_trap_pop (window->display, TRUE);
01317 
01318       point_in_window = 
01319         (window->frame && POINT_IN_RECT (root_x, root_y, window->frame->rect)) ||
01320         (window->frame == NULL && POINT_IN_RECT (root_x, root_y, window->rect));
01321       if (same_screen && point_in_window)
01322         meta_window_raise (window);
01323       else
01324         meta_topic (META_DEBUG_FOCUS, 
01325                     "Pointer not inside window, not raising %s\n", 
01326                     window->desc);
01327     }
01328 
01329   return FALSE;
01330 }
01331 
01332 void
01333 meta_display_queue_autoraise_callback (MetaDisplay *display,
01334                                        MetaWindow  *window)
01335 {
01336   MetaAutoRaiseData *auto_raise_data;
01337 
01338   meta_topic (META_DEBUG_FOCUS, 
01339               "Queuing an autoraise timeout for %s with delay %d\n", 
01340               window->desc, 
01341               meta_prefs_get_auto_raise_delay ());
01342   
01343   auto_raise_data = g_new (MetaAutoRaiseData, 1);
01344   auto_raise_data->display = window->display;
01345   auto_raise_data->xwindow = window->xwindow;
01346   
01347   if (display->autoraise_timeout_id != 0)
01348     g_source_remove (display->autoraise_timeout_id);
01349 
01350   display->autoraise_timeout_id = 
01351     g_timeout_add_full (G_PRIORITY_DEFAULT,
01352                         meta_prefs_get_auto_raise_delay (),
01353                         window_raise_with_delay_callback,
01354                         auto_raise_data,
01355                         g_free);
01356   display->autoraise_window = window;
01357 }
01358 
01359 #if 0
01360 static void
01361 handle_net_restack_window (MetaDisplay* display,
01362                            XEvent *event)
01363 {
01364   MetaWindow *window;
01365 
01366   window = meta_display_lookup_x_window (display,
01367                                          event->xclient.window);
01368 
01369   if (window)
01370     {
01371       /* FIXME: The EWMH includes a sibling for the restack request, but we
01372        * (stupidly) don't currently support these types of raises.
01373        *
01374        * Also, unconditionally following these is REALLY stupid--we should
01375        * combine this code with the stuff in
01376        * meta_window_configure_request() which is smart about whether to
01377        * follow the request or do something else (though not smart enough
01378        * and is also too stupid to handle the sibling stuff).
01379        */
01380       switch (event->xclient.data.l[2])
01381         {
01382         case Above:
01383           meta_window_raise (window);
01384           break;
01385         case Below:
01386           meta_window_lower (window);
01387           break;
01388         case TopIf:
01389         case BottomIf:
01390         case Opposite:
01391           break;          
01392         }
01393     }
01394 }
01395 #endif
01396 
01412 static gboolean
01413 event_callback (XEvent   *event,
01414                 gpointer  data)
01415 {
01416   MetaWindow *window;
01417   MetaWindow *property_for_window;
01418   MetaDisplay *display;
01419   Window modified;
01420   gboolean frame_was_receiver;
01421   gboolean filter_out_event;
01422 
01423   display = data;
01424   
01425 #ifdef WITH_VERBOSE_MODE
01426   if (dump_events)
01427     meta_spew_event (display, event);
01428 #endif
01429 
01430 #ifdef HAVE_STARTUP_NOTIFICATION
01431   sn_display_process_event (display->sn_display, event);
01432 #endif
01433   
01434   filter_out_event = FALSE;
01435   display->current_time = event_get_time (display, event);
01436   display->xinerama_cache_invalidated = TRUE;
01437   
01438   modified = event_get_modified_window (display, event);
01439   
01440   if (event->type == ButtonPress)
01441     {
01442       /* filter out scrollwheel */
01443       if (event->xbutton.button == 4 ||
01444           event->xbutton.button == 5)
01445         return FALSE;
01446     }
01447   else if (event->type == UnmapNotify)
01448     {
01449       if (meta_ui_window_should_not_cause_focus (display->xdisplay,
01450                                                  modified))
01451         {
01452           add_ignored_serial (display, event->xany.serial);
01453           meta_topic (META_DEBUG_FOCUS,
01454                       "Adding EnterNotify serial %lu to ignored focus serials\n",
01455                       event->xany.serial);
01456         }
01457     }
01458   else if (event->type == LeaveNotify &&
01459            event->xcrossing.mode == NotifyUngrab &&
01460            modified == display->ungrab_should_not_cause_focus_window)
01461     {
01462       add_ignored_serial (display, event->xany.serial);
01463       meta_topic (META_DEBUG_FOCUS,
01464                   "Adding LeaveNotify serial %lu to ignored focus serials\n",
01465                   event->xany.serial);
01466     }
01467 
01468   if (modified != None)
01469     window = meta_display_lookup_x_window (display, modified);
01470   else
01471     window = NULL;
01472 
01473   /* We only want to respond to _NET_WM_USER_TIME property notify
01474    * events on _NET_WM_USER_TIME_WINDOW windows; in particular,
01475    * responding to UnmapNotify events is kind of bad.
01476    */
01477   property_for_window = NULL;
01478   if (window && modified == window->user_time_window)
01479     {
01480       property_for_window = window;
01481       window = NULL;
01482     }
01483     
01484 
01485   frame_was_receiver = FALSE;
01486   if (window &&
01487       window->frame &&
01488       modified == window->frame->xwindow)
01489     {
01490       /* Note that if the frame and the client both have an
01491        * XGrabButton (as is normal with our setup), the event
01492        * goes to the frame.
01493        */
01494       frame_was_receiver = TRUE;
01495       meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n",
01496                   window->desc);
01497     }
01498 
01499 #ifdef HAVE_XSYNC
01500   if (META_DISPLAY_HAS_XSYNC (display) && 
01501       event->type == (display->xsync_event_base + XSyncAlarmNotify) &&
01502       ((XSyncAlarmNotifyEvent*)event)->alarm == display->grab_sync_request_alarm)
01503     {
01504       filter_out_event = TRUE; /* GTK doesn't want to see this really */
01505       
01506       if (display->grab_op != META_GRAB_OP_NONE &&
01507           display->grab_window != NULL &&
01508           grab_op_is_mouse (display->grab_op))
01509         meta_window_handle_mouse_grab_op_event (display->grab_window, event);
01510     }
01511 #endif /* HAVE_XSYNC */
01512 
01513 #ifdef HAVE_SHAPE
01514   if (META_DISPLAY_HAS_SHAPE (display) && 
01515       event->type == (display->shape_event_base + ShapeNotify))
01516     {
01517       filter_out_event = TRUE; /* GTK doesn't want to see this really */
01518       
01519       if (window && !frame_was_receiver)
01520         {
01521           XShapeEvent *sev = (XShapeEvent*) event;
01522 
01523           if (sev->kind == ShapeBounding)
01524             {
01525               if (sev->shaped && !window->has_shape)
01526                 {
01527                   window->has_shape = TRUE;                  
01528                   meta_topic (META_DEBUG_SHAPES,
01529                               "Window %s now has a shape\n",
01530                               window->desc);
01531                 }
01532               else if (!sev->shaped && window->has_shape)
01533                 {
01534                   window->has_shape = FALSE;
01535                   meta_topic (META_DEBUG_SHAPES,
01536                               "Window %s no longer has a shape\n",
01537                               window->desc);
01538                 }
01539               else
01540                 {
01541                   meta_topic (META_DEBUG_SHAPES,
01542                               "Window %s shape changed\n",
01543                               window->desc);
01544                 }
01545 
01546               if (window->frame)
01547                 {
01548                   window->frame->need_reapply_frame_shape = TRUE;
01549                   meta_warning("from event callback\n");                  
01550                   meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
01551                 }
01552             }
01553         }
01554       else
01555         {
01556           meta_topic (META_DEBUG_SHAPES,
01557                       "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n",
01558                       window ? window->desc : "(none)",
01559                       frame_was_receiver);
01560         }
01561     }
01562 #endif /* HAVE_SHAPE */
01563 
01564   if (window && ((event->type == KeyPress) || (event->type == ButtonPress)))
01565     {
01566       if (CurrentTime == display->current_time)
01567         {
01568           /* We can't use missing (i.e. invalid) timestamps to set user time,
01569            * nor do we want to use them to sanity check other timestamps.
01570            * See bug 313490 for more details.
01571            */
01572           meta_warning ("Event has no timestamp! You may be using a broken "
01573                         "program such as xse.  Please ask the authors of that "
01574                         "program to fix it.\n");
01575         }
01576       else
01577         {
01578           meta_window_set_user_time (window, display->current_time);
01579           sanity_check_timestamps (display, display->current_time);
01580         }
01581     }
01582   
01583   switch (event->type)
01584     {
01585     case KeyPress:
01586     case KeyRelease:
01587       meta_display_process_key_event (display, window, event);
01588       break;
01589     case ButtonPress:
01590       if ((window &&
01591            grab_op_is_mouse (display->grab_op) &&
01592            display->grab_button != (int) event->xbutton.button &&
01593            display->grab_window == window) ||
01594           grab_op_is_keyboard (display->grab_op))
01595         {
01596           meta_topic (META_DEBUG_WINDOW_OPS,
01597                       "Ending grab op %u on window %s due to button press\n",
01598                       display->grab_op,
01599                       (display->grab_window ?
01600                        display->grab_window->desc : 
01601                        "none"));
01602           if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
01603             {
01604               MetaScreen *screen;
01605               meta_topic (META_DEBUG_WINDOW_OPS, 
01606                           "Syncing to old stack positions.\n");
01607               screen = 
01608                 meta_display_screen_for_root (display, event->xany.window);
01609 
01610               if (screen!=NULL)
01611                 meta_stack_set_positions (screen->stack,
01612                                           display->grab_old_window_stacking);
01613             }
01614           meta_display_end_grab_op (display,
01615                                     event->xbutton.time);
01616         }
01617       else if (window && display->grab_op == META_GRAB_OP_NONE)
01618         {
01619           gboolean begin_move = FALSE;
01620           unsigned int grab_mask;
01621           gboolean unmodified;
01622 
01623           grab_mask = display->window_grab_modifiers;
01624           if (g_getenv ("METACITY_DEBUG_BUTTON_GRABS"))
01625             grab_mask |= ControlMask;
01626 
01627           /* Two possible sources of an unmodified event; one is a
01628            * client that's letting button presses pass through to the
01629            * frame, the other is our focus_window_grab on unmodified
01630            * button 1.  So for all such events we focus the window.
01631            */
01632           unmodified = (event->xbutton.state & grab_mask) == 0;
01633           
01634           if (unmodified ||
01635               event->xbutton.button == 1)
01636             {
01637               /* don't focus if frame received, will be lowered in
01638                * frames.c or special-cased if the click was on a
01639                * minimize/close button.
01640                */
01641               if (!frame_was_receiver)
01642                 {
01643                   if (meta_prefs_get_raise_on_click ()) 
01644                     meta_window_raise (window);
01645                   else
01646                     meta_topic (META_DEBUG_FOCUS,
01647                                 "Not raising window on click due to don't-raise-on-click option\n");
01648 
01649                   /* Don't focus panels--they must explicitly request focus.
01650                    * See bug 160470
01651                    */
01652                   if (window->type != META_WINDOW_DOCK)
01653                     {
01654                       meta_topic (META_DEBUG_FOCUS,
01655                                   "Focusing %s due to unmodified button %u press (display.c)\n",
01656                                   window->desc, event->xbutton.button);
01657                       meta_window_focus (window, event->xbutton.time);
01658                     }
01659                   else
01660                     /* However, do allow terminals to lose focus due to new
01661                      * window mappings after the user clicks on a panel.
01662                      */
01663                     display->allow_terminal_deactivation = TRUE;
01664                 }
01665               
01666               /* you can move on alt-click but not on
01667                * the click-to-focus
01668                */
01669               if (!unmodified)
01670                 begin_move = TRUE;
01671             }
01672           else if (!unmodified && event->xbutton.button == 2)
01673             {
01674               if (window->has_resize_func)
01675                 {
01676                   gboolean north, south;
01677                   gboolean west, east;
01678                   int root_x, root_y;
01679                   MetaGrabOp op;
01680 
01681                   meta_window_get_position (window, &root_x, &root_y);
01682 
01683                   west = event->xbutton.x_root <  (root_x + 1 * window->rect.width  / 3);
01684                   east = event->xbutton.x_root >  (root_x + 2 * window->rect.width  / 3);
01685                   north = event->xbutton.y_root < (root_y + 1 * window->rect.height / 3);
01686                   south = event->xbutton.y_root > (root_y + 2 * window->rect.height / 3);
01687 
01688                   if (north && west)
01689                     op = META_GRAB_OP_RESIZING_NW;
01690                   else if (north && east)
01691                     op = META_GRAB_OP_RESIZING_NE;
01692                   else if (south && west)
01693                     op = META_GRAB_OP_RESIZING_SW;
01694                   else if (south && east)
01695                     op = META_GRAB_OP_RESIZING_SE;
01696                   else if (north)
01697                     op = META_GRAB_OP_RESIZING_N;
01698                   else if (west)
01699                     op = META_GRAB_OP_RESIZING_W;
01700                   else if (east)
01701                     op = META_GRAB_OP_RESIZING_E;
01702                   else if (south)
01703                     op = META_GRAB_OP_RESIZING_S;
01704                   else /* Middle region is no-op to avoid user triggering wrong action */
01705                     op = META_GRAB_OP_NONE;
01706                   
01707                   if (op != META_GRAB_OP_NONE)
01708                     meta_display_begin_grab_op (display,
01709                                                 window->screen,
01710                                                 window,
01711                                                 op,
01712                                                 TRUE,
01713                                                 FALSE,
01714                                                 event->xbutton.button,
01715                                                 0,
01716                                                 event->xbutton.time,
01717                                                 event->xbutton.x_root,
01718                                                 event->xbutton.y_root);
01719                 }
01720             }
01721           else if (event->xbutton.button == 3)
01722             {
01723               if (meta_prefs_get_raise_on_click ())
01724                 meta_window_raise (window);
01725               meta_window_show_menu (window,
01726                                      event->xbutton.x_root,
01727                                      event->xbutton.y_root,
01728                                      event->xbutton.button,
01729                                      event->xbutton.time);
01730             }
01731 
01732           if (!frame_was_receiver && unmodified)
01733             {
01734               /* This is from our synchronous grab since
01735                * it has no modifiers and was on the client window
01736                */
01737               int mode;
01738               
01739               /* When clicking a different app in click-to-focus
01740                * in application-based mode, and the different
01741                * app is not a dock or desktop, eat the focus click.
01742                */
01743               if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK &&
01744                   meta_prefs_get_application_based () &&
01745                   !window->has_focus &&
01746                   window->type != META_WINDOW_DOCK &&
01747                   window->type != META_WINDOW_DESKTOP &&
01748                   (display->focus_window == NULL ||
01749                    !meta_window_same_application (window,
01750                                                   display->focus_window)))
01751                 mode = AsyncPointer; /* eat focus click */
01752               else
01753                 mode = ReplayPointer; /* give event back */
01754 
01755               meta_verbose ("Allowing events mode %s time %u\n",
01756                             mode == AsyncPointer ? "AsyncPointer" : "ReplayPointer",
01757                             (unsigned int)event->xbutton.time);
01758               
01759               XAllowEvents (display->xdisplay,
01760                             mode, event->xbutton.time);
01761             }
01762 
01763           if (begin_move && window->has_move_func)
01764             {
01765               meta_display_begin_grab_op (display,
01766                                           window->screen,
01767                                           window,
01768                                           META_GRAB_OP_MOVING,
01769                                           TRUE,
01770                                           FALSE,
01771                                           event->xbutton.button,
01772                                           0,
01773                                           event->xbutton.time,
01774                                           event->xbutton.x_root,
01775                                           event->xbutton.y_root);
01776             }
01777         }
01778       break;
01779     case ButtonRelease:
01780       if (display->grab_window == window &&
01781           grab_op_is_mouse (display->grab_op))
01782         meta_window_handle_mouse_grab_op_event (window, event);
01783       break;
01784     case MotionNotify:
01785       if (display->grab_window == window &&
01786           grab_op_is_mouse (display->grab_op))
01787         meta_window_handle_mouse_grab_op_event (window, event);
01788       break;
01789     case EnterNotify:
01790       if (display->grab_window == window &&
01791           grab_op_is_mouse (display->grab_op))
01792         {
01793           meta_window_handle_mouse_grab_op_event (window, event);
01794           break;
01795         }
01796 
01797       /* If the mouse switches screens, active the default window on the new
01798        * screen; this will make keybindings and workspace-launched items
01799        * actually appear on the right screen.
01800        */
01801       {
01802         MetaScreen *new_screen = 
01803           meta_display_screen_for_root (display, event->xcrossing.root);
01804 
01805         if (new_screen != NULL && display->active_screen != new_screen)
01806           meta_workspace_focus_default_window (new_screen->active_workspace, 
01807                                                NULL,
01808                                                event->xcrossing.time);
01809       }
01810 
01811       /* Check if we've entered a window; do this even if window->has_focus to
01812        * avoid races.
01813        */
01814       if (window && !serial_is_ignored (display, event->xany.serial) &&
01815                event->xcrossing.mode != NotifyGrab && 
01816                event->xcrossing.mode != NotifyUngrab &&
01817                event->xcrossing.detail != NotifyInferior &&
01818                meta_display_focus_sentinel_clear (display))
01819         {
01820           switch (meta_prefs_get_focus_mode ())
01821             {
01822             case META_FOCUS_MODE_SLOPPY:
01823             case META_FOCUS_MODE_MOUSE:
01824               display->mouse_mode = TRUE;
01825               if (window->type != META_WINDOW_DOCK &&
01826                   window->type != META_WINDOW_DESKTOP)
01827                 {
01828                   meta_topic (META_DEBUG_FOCUS,
01829                               "Focusing %s due to enter notify with serial %lu "
01830                               "at time %lu, and setting display->mouse_mode to "
01831                               "TRUE.\n",
01832                               window->desc, 
01833                               event->xany.serial,
01834                               event->xcrossing.time);
01835 
01836                   meta_window_focus (window, event->xcrossing.time);
01837 
01838                   /* stop ignoring stuff */
01839                   reset_ignores (display);
01840                   
01841                   if (meta_prefs_get_auto_raise ()) 
01842                     {
01843                       meta_display_queue_autoraise_callback (display, window);
01844                     }
01845                   else
01846                     {
01847                       meta_topic (META_DEBUG_FOCUS,
01848                                   "Auto raise is disabled\n");                
01849                     }
01850                 }
01851               /* In mouse focus mode, we defocus when the mouse *enters*
01852                * the DESKTOP window, instead of defocusing on LeaveNotify.
01853                * This is because having the mouse enter override-redirect
01854                * child windows unfortunately causes LeaveNotify events that
01855                * we can't distinguish from the mouse actually leaving the
01856                * toplevel window as we expect.  But, since we filter out
01857                * EnterNotify events on override-redirect windows, this
01858                * alternative mechanism works great.
01859                */
01860               if (window->type == META_WINDOW_DESKTOP &&
01861                   meta_prefs_get_focus_mode() == META_FOCUS_MODE_MOUSE &&
01862                   display->expected_focus_window != NULL)
01863                 {
01864                   meta_topic (META_DEBUG_FOCUS,
01865                               "Unsetting focus from %s due to mouse entering "
01866                               "the DESKTOP window\n",
01867                               display->expected_focus_window->desc);
01868                   meta_display_focus_the_no_focus_window (display, 
01869                                                           window->screen,
01870                                                           event->xcrossing.time);
01871                 }
01872               break;
01873             case META_FOCUS_MODE_CLICK:
01874               break;
01875             }
01876           
01877           if (window->type == META_WINDOW_DOCK)
01878             meta_window_raise (window);
01879         }
01880       break;
01881     case LeaveNotify:
01882       if (display->grab_window == window &&
01883           grab_op_is_mouse (display->grab_op))
01884         meta_window_handle_mouse_grab_op_event (window, event);
01885       else if (window != NULL)
01886         {
01887           if (window->type == META_WINDOW_DOCK &&
01888               event->xcrossing.mode != NotifyGrab &&
01889               event->xcrossing.mode != NotifyUngrab &&
01890               !window->has_focus)
01891             meta_window_lower (window);
01892         }
01893       break;
01894     case FocusIn:
01895     case FocusOut:
01896       if (window)
01897         {
01898           meta_window_notify_focus (window, event);
01899         }
01900       else if (meta_display_xwindow_is_a_no_focus_window (display,
01901                                                           event->xany.window))
01902         {
01903           meta_topic (META_DEBUG_FOCUS,
01904                       "Focus %s event received on no_focus_window 0x%lx "
01905                       "mode %s detail %s\n",
01906                       event->type == FocusIn ? "in" :
01907                       event->type == FocusOut ? "out" :
01908                       "???",
01909                       event->xany.window,
01910                       meta_event_mode_to_string (event->xfocus.mode),
01911                       meta_event_detail_to_string (event->xfocus.detail));
01912         }
01913       else
01914         {
01915           MetaScreen *screen =
01916                 meta_display_screen_for_root(display,
01917                                              event->xany.window);
01918           if (screen == NULL)
01919             break;
01920 
01921           meta_topic (META_DEBUG_FOCUS,
01922                       "Focus %s event received on root window 0x%lx "
01923                       "mode %s detail %s\n",
01924                       event->type == FocusIn ? "in" :
01925                       event->type == FocusOut ? "out" :
01926                       "???",
01927                       event->xany.window,
01928                       meta_event_mode_to_string (event->xfocus.mode),
01929                       meta_event_detail_to_string (event->xfocus.detail));
01930           
01931           if (event->type == FocusIn &&
01932               event->xfocus.detail == NotifyDetailNone)
01933             {
01934               meta_topic (META_DEBUG_FOCUS, 
01935                           "Focus got set to None, probably due to "
01936                           "brain-damage in the X protocol (see bug "
01937                           "125492).  Setting the default focus window.\n");
01938               meta_workspace_focus_default_window (screen->active_workspace,
01939                                                    NULL,
01940                                                    meta_display_get_current_time_roundtrip (display));
01941             }
01942           else if (event->type == FocusIn &&
01943               event->xfocus.mode == NotifyNormal &&
01944               event->xfocus.detail == NotifyInferior)
01945             {
01946               meta_topic (META_DEBUG_FOCUS,
01947                           "Focus got set to root window, probably due to "
01948                           "gnome-session logout dialog usage (see bug "
01949                           "153220).  Setting the default focus window.\n");
01950               meta_workspace_focus_default_window (screen->active_workspace,
01951                                                    NULL,
01952                                                    meta_display_get_current_time_roundtrip (display));
01953             }
01954 
01955         }
01956       break;
01957     case KeymapNotify:
01958       break;
01959     case Expose:
01960       break;
01961     case GraphicsExpose:
01962       break;
01963     case NoExpose:
01964       break;
01965     case VisibilityNotify:
01966       break;
01967     case CreateNotify:
01968       break;
01969       
01970     case DestroyNotify:
01971       if (window)
01972         {
01973           /* FIXME: It sucks that DestroyNotify events don't come with
01974            * a timestamp; could we do something better here?  Maybe X
01975            * will change one day?
01976            */
01977           guint32 timestamp;
01978           timestamp = meta_display_get_current_time_roundtrip (display);
01979 
01980           if (display->grab_op != META_GRAB_OP_NONE &&
01981               display->grab_window == window)
01982             meta_display_end_grab_op (display, timestamp);
01983           
01984           if (frame_was_receiver)
01985             {
01986               meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n",
01987                             window->frame->xwindow);
01988               meta_error_trap_push (display);
01989               meta_window_destroy_frame (window->frame->window);
01990               meta_error_trap_pop (display, FALSE);
01991             }
01992           else
01993             {
01994               /* Unmanage destroyed window */
01995               meta_window_free (window, timestamp);
01996               window = NULL;
01997             }
01998         }
01999       break;
02000     case UnmapNotify:
02001       if (window)
02002         {
02003           /* FIXME: It sucks that UnmapNotify events don't come with
02004            * a timestamp; could we do something better here?  Maybe X
02005            * will change one day?
02006            */
02007           guint32 timestamp;
02008           timestamp = meta_display_get_current_time_roundtrip (display);
02009 
02010           if (display->grab_op != META_GRAB_OP_NONE &&
02011               display->grab_window == window &&
02012               ((window->frame == NULL) || !window->frame->mapped))
02013             meta_display_end_grab_op (display, timestamp);
02014       
02015           if (!frame_was_receiver)
02016             {
02017               if (window->unmaps_pending == 0)
02018                 {
02019                   meta_topic (META_DEBUG_WINDOW_STATE,
02020                               "Window %s withdrawn\n",
02021                               window->desc);
02022 
02023                   meta_effect_run_close (window, NULL, NULL);
02024 
02025                   /* Unmanage withdrawn window */                 
02026                   window->withdrawn = TRUE;
02027                   meta_window_free (window, timestamp);
02028                   window = NULL;
02029                 }
02030               else
02031                 {
02032                   window->unmaps_pending -= 1;
02033                   meta_topic (META_DEBUG_WINDOW_STATE,
02034                               "Received pending unmap, %d now pending\n",
02035                               window->unmaps_pending);
02036                 }
02037             }
02038 
02039           /* Unfocus on UnmapNotify, do this after the possible
02040            * window_free above so that window_free can see if window->has_focus
02041            * and move focus to another window
02042            */
02043           if (window)
02044             meta_window_notify_focus (window, event);
02045         }
02046       break;
02047     case MapNotify:
02048       break;
02049     case MapRequest:
02050       if (window == NULL)
02051         {
02052           window = meta_window_new (display, event->xmaprequest.window,
02053                                     FALSE);
02054         }
02055       /* if frame was receiver it's some malicious send event or something */
02056       else if (!frame_was_receiver && window)        
02057         {
02058           meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n",
02059                         window->desc, window->mapped, window->minimized);
02060           if (window->minimized)
02061             {
02062               meta_window_unminimize (window);
02063               if (window->workspace != window->screen->active_workspace)
02064                 {
02065                   meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n",
02066                                 window->mapped, window->minimized);
02067                   meta_window_change_workspace (window,
02068                                                 window->screen->active_workspace);
02069                 }
02070             }
02071         }
02072       break;
02073     case ReparentNotify:
02074       break;
02075     case ConfigureNotify:
02076       /* Handle screen resize */
02077       {
02078         MetaScreen *screen;
02079 
02080         screen = meta_display_screen_for_root (display,
02081                                                event->xconfigure.window);
02082 
02083         if (screen != NULL)
02084           {
02085 #ifdef HAVE_RANDR
02086             /* do the resize the official way */
02087             XRRUpdateConfiguration (event);
02088 #else
02089             /* poke around in Xlib */
02090             screen->xscreen->width   = event->xconfigure.width;
02091             screen->xscreen->height  = event->xconfigure.height;
02092 #endif
02093             
02094             meta_screen_resize (screen, 
02095                                 event->xconfigure.width,
02096                                 event->xconfigure.height);
02097           }
02098       }
02099       break;
02100     case ConfigureRequest:
02101       /* This comment and code is found in both twm and fvwm */
02102       /*
02103        * According to the July 27, 1988 ICCCM draft, we should ignore size and
02104        * position fields in the WM_NORMAL_HINTS property when we map a window.
02105        * Instead, we'll read the current geometry.  Therefore, we should respond
02106        * to configuration requests for windows which have never been mapped.
02107        */
02108       if (window == NULL)
02109         {
02110           unsigned int xwcm;
02111           XWindowChanges xwc;
02112           
02113           xwcm = event->xconfigurerequest.value_mask &
02114             (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
02115 
02116           xwc.x = event->xconfigurerequest.x;
02117           xwc.y = event->xconfigurerequest.y;
02118           xwc.width = event->xconfigurerequest.width;
02119           xwc.height = event->xconfigurerequest.height;
02120           xwc.border_width = event->xconfigurerequest.border_width;
02121 
02122           meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n",
02123                         xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
02124           meta_error_trap_push (display);
02125           XConfigureWindow (display->xdisplay, event->xconfigurerequest.window,
02126                             xwcm, &xwc);
02127           meta_error_trap_pop (display, FALSE);
02128         }
02129       else
02130         {
02131           if (!frame_was_receiver)
02132             meta_window_configure_request (window, event);
02133         }
02134       break;
02135     case GravityNotify:
02136       break;
02137     case ResizeRequest:
02138       break;
02139     case CirculateNotify:
02140       break;
02141     case CirculateRequest:
02142       break;
02143     case PropertyNotify:
02144       {
02145         MetaGroup *group;
02146         MetaScreen *screen;
02147         
02148         if (window && !frame_was_receiver)
02149           meta_window_property_notify (window, event);
02150         else if (property_for_window && !frame_was_receiver)
02151           meta_window_property_notify (property_for_window, event);
02152 
02153         group = meta_display_lookup_group (display,
02154                                            event->xproperty.window);
02155         if (group != NULL)
02156           meta_group_property_notify (group, event);
02157         
02158         screen = NULL;
02159         if (window == NULL &&
02160             group == NULL) /* window/group != NULL means it wasn't a root window */
02161           screen = meta_display_screen_for_root (display,
02162                                                  event->xproperty.window);
02163             
02164         if (screen != NULL)
02165           {
02166             if (event->xproperty.atom ==
02167                 display->atom__NET_DESKTOP_LAYOUT)
02168               meta_screen_update_workspace_layout (screen);
02169             else if (event->xproperty.atom ==
02170                      display->atom__NET_DESKTOP_NAMES)
02171               meta_screen_update_workspace_names (screen);
02172 #if 0
02173             else if (event->xproperty.atom ==
02174                      display->atom__NET_RESTACK_WINDOW)
02175               handle_net_restack_window (display, event);
02176 #endif
02177 
02178             /* we just use this property as a sentinel to avoid
02179              * certain race conditions.  See the comment for the
02180              * sentinel_counter variable declaration in display.h
02181              */
02182             if (event->xproperty.atom ==
02183                 display->atom__METACITY_SENTINEL)
02184               {
02185                 meta_display_decrement_focus_sentinel (display);
02186               }
02187           }
02188       }
02189       break;
02190     case SelectionClear:
02191       /* do this here instead of at end of function
02192        * so we can return
02193        */
02194 
02195       /* FIXME: Clearing display->current_time here makes no sense to
02196        * me; who put this here and why?
02197        */
02198       display->current_time = CurrentTime;
02199 
02200       process_selection_clear (display, event);
02201       /* Note that processing that may have resulted in
02202        * closing the display... so return right away.
02203        */
02204       return FALSE;
02205     case SelectionRequest:
02206       process_selection_request (display, event);
02207       break;
02208     case SelectionNotify:
02209       break;
02210     case ColormapNotify:
02211       if (window && !frame_was_receiver)
02212         window->colormap = event->xcolormap.colormap;
02213       break;
02214     case ClientMessage:
02215       if (window)
02216         {
02217           if (!frame_was_receiver)
02218             meta_window_client_message (window, event);
02219         }
02220       else
02221         {
02222           MetaScreen *screen;
02223 
02224           screen = meta_display_screen_for_root (display,
02225                                                  event->xclient.window);
02226           
02227           if (screen)
02228             {
02229               if (event->xclient.message_type ==
02230                   display->atom__NET_CURRENT_DESKTOP)
02231                 {
02232                   int space;
02233                   MetaWorkspace *workspace;
02234                   guint32 time;
02235               
02236                   space = event->xclient.data.l[0];
02237                   time = event->xclient.data.l[1];
02238               
02239                   meta_verbose ("Request to change current workspace to %d with "
02240                                 "specified timestamp of %u\n",
02241                                 space, time);
02242 
02243                   workspace =
02244                     meta_screen_get_workspace_by_index (screen,
02245                                                         space);
02246 
02247                   /* Handle clients using the older version of the spec... */
02248                   if (time == 0 && workspace)
02249                     {
02250                       meta_warning ("Received a NET_CURRENT_DESKTOP message "
02251                                     "from a broken (outdated) client who sent "
02252                                     "a 0 timestamp\n");
02253                       time = meta_display_get_current_time_roundtrip (display);
02254                     }
02255 
02256                   if (workspace)
02257                     meta_workspace_activate (workspace, time);
02258                   else
02259                     meta_verbose ("Don't know about workspace %d\n", space);
02260                 }
02261               else if (event->xclient.message_type ==
02262                        display->atom__NET_NUMBER_OF_DESKTOPS)
02263                 {
02264                   int num_spaces;
02265               
02266                   num_spaces = event->xclient.data.l[0];
02267               
02268                   meta_verbose ("Request to set number of workspaces to %d\n",
02269                                 num_spaces);
02270 
02271                   meta_prefs_set_num_workspaces (num_spaces);
02272                 }
02273               else if (event->xclient.message_type ==
02274                        display->atom__NET_SHOWING_DESKTOP)
02275                 {
02276                   gboolean showing_desktop;
02277                   guint32  timestamp;
02278                   
02279                   showing_desktop = event->xclient.data.l[0] != 0;
02280                   /* FIXME: Braindead protocol doesn't have a timestamp */
02281                   timestamp = meta_display_get_current_time_roundtrip (display);
02282                   meta_verbose ("Request to %s desktop\n",
02283                                 showing_desktop ? "show" : "hide");
02284                   
02285                   if (showing_desktop)
02286                     meta_screen_show_desktop (screen, timestamp);
02287                   else
02288                     {
02289                       meta_screen_unshow_desktop (screen);
02290                       meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp);
02291                     }
02292                 }
02293               else if (event->xclient.message_type ==
02294                        display->atom__METACITY_RESTART_MESSAGE)
02295                 {
02296                   meta_verbose ("Received restart request\n");
02297                   meta_restart ();
02298                 }
02299               else if (event->xclient.message_type ==
02300                        display->atom__METACITY_RELOAD_THEME_MESSAGE)
02301                 {
02302                   meta_verbose ("Received reload theme request\n");
02303                   meta_ui_set_current_theme (meta_prefs_get_theme (),
02304                                              TRUE);
02305                   meta_display_retheme_all ();
02306                 }
02307               else if (event->xclient.message_type ==
02308                        display->atom__METACITY_SET_KEYBINDINGS_MESSAGE)
02309                 {
02310                   meta_verbose ("Received set keybindings request = %d\n",
02311                                 (int) event->xclient.data.l[0]);
02312                   meta_set_keybindings_disabled (!event->xclient.data.l[0]);
02313                 }
02314               else if (event->xclient.message_type ==
02315                        display->atom__METACITY_TOGGLE_VERBOSE)
02316                 {
02317                   meta_verbose ("Received toggle verbose message\n");
02318                   meta_set_verbose (!meta_is_verbose ());
02319                 }
02320               else if (event->xclient.message_type ==
02321                        display->atom_WM_PROTOCOLS) 
02322                 {
02323                   meta_verbose ("Received WM_PROTOCOLS message\n");
02324                   
02325                   if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING)
02326                     {
02327                       process_pong_message (display, event);
02328 
02329                       /* We don't want ping reply events going into
02330                        * the GTK+ event loop because gtk+ will treat
02331                        * them as ping requests and send more replies.
02332                        */
02333                       filter_out_event = TRUE;
02334                     }
02335                 }
02336             }
02337 
02338           if (event->xclient.message_type ==
02339               display->atom__NET_REQUEST_FRAME_EXTENTS)
02340             {
02341               meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n");
02342               process_request_frame_extents (display, event);
02343             }
02344         }
02345       break;
02346     case MappingNotify:
02347       {
02348         gboolean ignore_current;
02349 
02350         ignore_current = FALSE;
02351         
02352         /* Check whether the next event is an identical MappingNotify
02353          * event.  If it is, ignore the current event, we'll update
02354          * when we get the next one.
02355          */
02356         if (XPending (display->xdisplay))
02357           {
02358             XEvent next_event;
02359             
02360             XPeekEvent (display->xdisplay, &next_event);
02361             
02362             if (next_event.type == MappingNotify &&
02363                 next_event.xmapping.request == event->xmapping.request)
02364               ignore_current = TRUE;
02365           }
02366 
02367         if (!ignore_current)
02368           {
02369             /* Let XLib know that there is a new keyboard mapping.
02370              */
02371             XRefreshKeyboardMapping (&event->xmapping);
02372             meta_display_process_mapping_event (display, event);
02373           }
02374       }
02375       break;
02376     default:
02377 #ifdef HAVE_XKB
02378       if (event->type == display->xkb_base_event_type) 
02379         {
02380           XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
02381           
02382           switch (xkb_ev->xkb_type)
02383             {
02384             case XkbBellNotify:
02385               if (XSERVER_TIME_IS_BEFORE(display->last_bell_time,
02386                                          xkb_ev->time - 1000))
02387                 {
02388                   display->last_bell_time = xkb_ev->time;
02389                   meta_bell_notify (display, xkb_ev);
02390                 }
02391               break;
02392             }
02393         }
02394 #endif
02395       break;
02396     }
02397 
02398   if (display->compositor)
02399     {
02400       meta_compositor_process_event (display->compositor,
02401                                      event,
02402                                      window);
02403     }
02404   
02405   display->current_time = CurrentTime;
02406   return filter_out_event;
02407 }
02408 
02409 /* Return the window this has to do with, if any, rather
02410  * than the frame or root window that was selecting
02411  * for substructure
02412  */
02413 static Window
02414 event_get_modified_window (MetaDisplay *display,
02415                            XEvent *event)
02416 {
02417   switch (event->type)
02418     {
02419     case KeyPress:
02420     case KeyRelease:
02421     case ButtonPress:
02422     case ButtonRelease:
02423     case MotionNotify:
02424     case FocusIn:
02425     case FocusOut:
02426     case KeymapNotify:
02427     case Expose:
02428     case GraphicsExpose:
02429     case NoExpose:
02430     case VisibilityNotify:
02431     case ResizeRequest:
02432     case PropertyNotify:
02433     case SelectionClear:
02434     case SelectionRequest:
02435     case SelectionNotify:
02436     case ColormapNotify:
02437     case ClientMessage:
02438     case EnterNotify:
02439     case LeaveNotify:
02440       return event->xany.window;
02441       
02442     case CreateNotify:
02443       return event->xcreatewindow.window;
02444       
02445     case DestroyNotify:
02446       return event->xdestroywindow.window;
02447 
02448     case UnmapNotify:
02449       return event->xunmap.window;
02450 
02451     case MapNotify:
02452       return event->xmap.window;
02453 
02454     case MapRequest:
02455       return event->xmaprequest.window;
02456 
02457     case ReparentNotify:
02458      return event->xreparent.window;
02459       
02460     case ConfigureNotify:
02461       return event->xconfigure.window;
02462       
02463     case ConfigureRequest:
02464       return event->xconfigurerequest.window;
02465 
02466     case GravityNotify:
02467       return event->xgravity.window;
02468 
02469     case CirculateNotify:
02470       return event->xcirculate.window;
02471 
02472     case CirculateRequest:
02473       return event->xcirculaterequest.window;
02474 
02475     case MappingNotify:
02476       return None;
02477 
02478     default:
02479 #ifdef HAVE_SHAPE
02480       if (META_DISPLAY_HAS_SHAPE (display) && 
02481           event->type == (display->shape_event_base + ShapeNotify))
02482         {
02483           XShapeEvent *sev = (XShapeEvent*) event;
02484           return sev->window;
02485         }
02486 #endif
02487 
02488       return None;
02489     }
02490 }
02491 
02492 static guint32
02493 event_get_time (MetaDisplay *display,
02494                 XEvent      *event)
02495 {
02496   switch (event->type)
02497     {
02498     case KeyPress:
02499     case KeyRelease:
02500       return event->xkey.time;
02501       
02502     case ButtonPress:
02503     case ButtonRelease:
02504       return event->xbutton.time;
02505       
02506     case MotionNotify:
02507       return event->xmotion.time;
02508 
02509     case PropertyNotify:
02510       return event->xproperty.time;
02511 
02512     case SelectionClear:
02513     case SelectionRequest:
02514     case SelectionNotify:
02515       return event->xselection.time;
02516 
02517     case EnterNotify:
02518     case LeaveNotify:
02519       return event->xcrossing.time;
02520 
02521     case FocusIn:
02522     case FocusOut:
02523     case KeymapNotify:      
02524     case Expose:
02525     case GraphicsExpose:
02526     case NoExpose:
02527     case MapNotify:
02528     case UnmapNotify:
02529     case VisibilityNotify:
02530     case ResizeRequest:
02531     case ColormapNotify:
02532     case ClientMessage:
02533     case CreateNotify:
02534     case DestroyNotify:
02535     case MapRequest:
02536     case ReparentNotify:
02537     case ConfigureNotify:
02538     case ConfigureRequest:
02539     case GravityNotify:
02540     case CirculateNotify:
02541     case CirculateRequest:
02542     case MappingNotify:
02543     default:
02544       return CurrentTime;
02545     }
02546 }
02547 
02548 #ifdef WITH_VERBOSE_MODE
02549 const char*
02550 meta_event_detail_to_string (int d)
02551 {
02552   const char *detail = "???";
02553   switch (d)
02554     {
02555       /* We are an ancestor in the A<->B focus change relationship */
02556     case NotifyAncestor:
02557       detail = "NotifyAncestor";
02558       break;
02559     case NotifyDetailNone:
02560       detail = "NotifyDetailNone";
02561       break;
02562       /* We are a descendant in the A<->B focus change relationship */
02563     case NotifyInferior:
02564       detail = "NotifyInferior";
02565       break;
02566     case NotifyNonlinear:
02567       detail = "NotifyNonlinear";
02568       break;
02569     case NotifyNonlinearVirtual:
02570       detail = "NotifyNonlinearVirtual";
02571       break;
02572     case NotifyPointer:
02573       detail = "NotifyPointer";
02574       break;
02575     case NotifyPointerRoot:
02576       detail = "NotifyPointerRoot";
02577       break;
02578     case NotifyVirtual:
02579       detail = "NotifyVirtual";
02580       break;
02581     }
02582 
02583   return detail;
02584 }
02585 #endif /* WITH_VERBOSE_MODE */
02586 
02587 #ifdef WITH_VERBOSE_MODE
02588 const char*
02589 meta_event_mode_to_string (int m)
02590 {
02591   const char *mode = "???";
02592   switch (m)
02593     {
02594     case NotifyNormal:
02595       mode = "NotifyNormal";
02596       break;
02597     case NotifyGrab:
02598       mode = "NotifyGrab";
02599       break;
02600     case NotifyUngrab:
02601       mode = "NotifyUngrab";
02602       break;
02603       /* not sure any X implementations are missing this, but
02604        * it seems to be absent from some docs.
02605        */
02606 #ifdef NotifyWhileGrabbed
02607     case NotifyWhileGrabbed:
02608       mode = "NotifyWhileGrabbed";
02609       break;
02610 #endif
02611     }
02612 
02613   return mode;
02614 }
02615 #endif /* WITH_VERBOSE_MODE */
02616 
02617 #ifdef WITH_VERBOSE_MODE
02618 static const char*
02619 stack_mode_to_string (int mode)
02620 {
02621   switch (mode)
02622     {
02623     case Above:
02624       return "Above";
02625     case Below:
02626       return "Below";
02627     case TopIf:
02628       return "TopIf";
02629     case BottomIf:
02630       return "BottomIf";
02631     case Opposite:
02632       return "Opposite";      
02633     }
02634 
02635   return "Unknown";
02636 }
02637 #endif /* WITH_VERBOSE_MODE */
02638 
02639 #ifdef WITH_VERBOSE_MODE
02640 static char*
02641 key_event_description (Display *xdisplay,
02642                        XEvent  *event)
02643 {
02644   KeySym keysym;
02645   const char *str;
02646   
02647   keysym = XKeycodeToKeysym (xdisplay, event->xkey.keycode, 0);  
02648 
02649   str = XKeysymToString (keysym);
02650   
02651   return g_strdup_printf ("Key '%s' state 0x%x", 
02652                           str ? str : "none", event->xkey.state);
02653 }
02654 #endif /* WITH_VERBOSE_MODE */
02655 
02656 #ifdef HAVE_XSYNC
02657 #ifdef WITH_VERBOSE_MODE
02658 static gint64
02659 sync_value_to_64 (const XSyncValue *value)
02660 {
02661   gint64 v;
02662 
02663   v = XSyncValueLow32 (*value);
02664   v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
02665   
02666   return v;
02667 }
02668 #endif /* WITH_VERBOSE_MODE */
02669 
02670 #ifdef WITH_VERBOSE_MODE
02671 static const char*
02672 alarm_state_to_string (XSyncAlarmState state)
02673 {
02674   switch (state)
02675     {
02676     case XSyncAlarmActive:
02677       return "Active";
02678     case XSyncAlarmInactive:
02679       return "Inactive";
02680     case XSyncAlarmDestroyed:
02681       return "Destroyed";
02682     default:
02683       return "(unknown)";
02684     }
02685 }
02686 #endif /* WITH_VERBOSE_MODE */
02687 
02688 #endif /* HAVE_XSYNC */
02689 
02690 #ifdef WITH_VERBOSE_MODE
02691 static void
02692 meta_spew_event (MetaDisplay *display,
02693                  XEvent      *event)
02694 {
02695   const char *name = NULL;
02696   char *extra = NULL;
02697   char *winname;
02698   MetaScreen *screen;
02699 
02700   if (!meta_is_verbose())
02701     return;
02702   
02703   /* filter overnumerous events */
02704   if (event->type == Expose || event->type == MotionNotify ||
02705       event->type == NoExpose)
02706     return;
02707       
02708   switch (event->type)
02709     {
02710     case KeyPress:
02711       name = "KeyPress";
02712       extra = key_event_description (display->xdisplay, event);
02713       break;
02714     case KeyRelease:
02715       name = "KeyRelease";
02716       extra = key_event_description (display->xdisplay, event);
02717       break;
02718     case ButtonPress:
02719       name = "ButtonPress";
02720       extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d",
02721                                event->xbutton.button,
02722                                event->xbutton.state,
02723                                event->xbutton.x,
02724                                event->xbutton.y,
02725                                event->xbutton.root,
02726                                event->xbutton.same_screen);
02727       break;
02728     case ButtonRelease:
02729       name = "ButtonRelease";
02730       extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d",
02731                                event->xbutton.button,
02732                                event->xbutton.state,
02733                                event->xbutton.x,
02734                                event->xbutton.y,
02735                                event->xbutton.root,
02736                                event->xbutton.same_screen);
02737       break;
02738     case MotionNotify:
02739       name = "MotionNotify";
02740       extra = g_strdup_printf ("win: 0x%lx x: %d y: %d",
02741                                event->xmotion.window,
02742                                event->xmotion.x,
02743                                event->xmotion.y);
02744       break;
02745     case EnterNotify:
02746       name = "EnterNotify";
02747       extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d",
02748                                event->xcrossing.window,
02749                                event->xcrossing.root,
02750                                event->xcrossing.subwindow,
02751                                meta_event_mode_to_string (event->xcrossing.mode),
02752                                meta_event_detail_to_string (event->xcrossing.detail),
02753                                event->xcrossing.focus,
02754                                event->xcrossing.x,
02755                                event->xcrossing.y);
02756       break;
02757     case LeaveNotify:
02758       name = "LeaveNotify";
02759       extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d",
02760                                event->xcrossing.window,
02761                                event->xcrossing.root,
02762                                event->xcrossing.subwindow,
02763                                meta_event_mode_to_string (event->xcrossing.mode),
02764                                meta_event_detail_to_string (event->xcrossing.detail),
02765                                event->xcrossing.focus,
02766                                event->xcrossing.x,
02767                                event->xcrossing.y);
02768       break;
02769     case FocusIn:
02770       name = "FocusIn";
02771       extra = g_strdup_printf ("detail: %s mode: %s\n",
02772                                meta_event_detail_to_string (event->xfocus.detail),
02773                                meta_event_mode_to_string (event->xfocus.mode));
02774       break;
02775     case FocusOut:
02776       name = "FocusOut";
02777       extra = g_strdup_printf ("detail: %s mode: %s\n",
02778                                meta_event_detail_to_string (event->xfocus.detail),
02779                                meta_event_mode_to_string (event->xfocus.mode));
02780       break;
02781     case KeymapNotify:
02782       name = "KeymapNotify";
02783       break;
02784     case Expose:
02785       name = "Expose";
02786       break;
02787     case GraphicsExpose:
02788       name = "GraphicsExpose";
02789       break;
02790     case NoExpose:
02791       name = "NoExpose";
02792       break;
02793     case VisibilityNotify:
02794       name = "VisibilityNotify";
02795       break;
02796     case CreateNotify:
02797       name = "CreateNotify";
02798       extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
02799                                event->xcreatewindow.parent,
02800                                event->xcreatewindow.window);
02801       break;
02802     case DestroyNotify:
02803       name = "DestroyNotify";
02804       extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
02805                                event->xdestroywindow.event,
02806                                event->xdestroywindow.window);
02807       break;
02808     case UnmapNotify:
02809       name = "UnmapNotify";
02810       extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d",
02811                                event->xunmap.event,
02812                                event->xunmap.window,
02813                                event->xunmap.from_configure);
02814       break;
02815     case MapNotify:
02816       name = "MapNotify";
02817       extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d",
02818                                event->xmap.event,
02819                                event->xmap.window,
02820                                event->xmap.override_redirect);
02821       break;
02822     case MapRequest:
02823       name = "MapRequest";
02824       extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
02825                                event->xmaprequest.window,
02826                                event->xmaprequest.parent);
02827       break;
02828     case ReparentNotify:
02829       name = "ReparentNotify";
02830       extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n",
02831                                event->xreparent.window,
02832                                event->xreparent.parent,
02833                                event->xreparent.event);
02834       break;
02835     case ConfigureNotify:
02836       name = "ConfigureNotify";
02837       extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d",
02838                                event->xconfigure.x,
02839                                event->xconfigure.y,
02840                                event->xconfigure.width,
02841                                event->xconfigure.height,
02842                                event->xconfigure.above,
02843                                event->xconfigure.override_redirect);
02844       break;
02845     case ConfigureRequest:
02846       name = "ConfigureRequest";
02847       extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s",
02848                                event->xconfigurerequest.parent,
02849                                event->xconfigurerequest.window,
02850                                event->xconfigurerequest.x,
02851                                event->xconfigurerequest.value_mask &
02852                                CWX ? "" : "(unset) ",
02853                                event->xconfigurerequest.y,
02854                                event->xconfigurerequest.value_mask &
02855                                CWY ? "" : "(unset) ",
02856                                event->xconfigurerequest.width,
02857                                event->xconfigurerequest.value_mask &
02858                                CWWidth ? "" : "(unset) ",
02859                                event->xconfigurerequest.height,
02860                                event->xconfigurerequest.value_mask &
02861                                CWHeight ? "" : "(unset) ",
02862                                event->xconfigurerequest.border_width,
02863                                event->xconfigurerequest.value_mask &
02864                                CWBorderWidth ? "" : "(unset)",
02865                                event->xconfigurerequest.above,
02866                                event->xconfigurerequest.value_mask &
02867                                CWSibling ? "" : "(unset)",
02868                                stack_mode_to_string (event->xconfigurerequest.detail),
02869                                event->xconfigurerequest.value_mask &
02870                                CWStackMode ? "" : "(unset)");
02871       break;
02872     case GravityNotify:
02873       name = "GravityNotify";
02874       break;
02875     case ResizeRequest:
02876       name = "ResizeRequest";
02877       extra = g_strdup_printf ("width = %d height = %d",
02878                                event->xresizerequest.width,
02879                                event->xresizerequest.height);
02880       break;
02881     case CirculateNotify:
02882       name = "CirculateNotify";
02883       break;
02884     case CirculateRequest:
02885       name = "CirculateRequest";
02886       break;
02887     case PropertyNotify:
02888       {
02889         char *str;
02890         const char *state;
02891             
02892         name = "PropertyNotify";
02893             
02894         meta_error_trap_push (display);
02895         str = XGetAtomName (display->xdisplay,
02896                             event->xproperty.atom);
02897         meta_error_trap_pop (display, TRUE);
02898 
02899         if (event->xproperty.state == PropertyNewValue)
02900           state = "PropertyNewValue";
02901         else if (event->xproperty.state == PropertyDelete)
02902           state = "PropertyDelete";
02903         else
02904           state = "???";
02905             
02906         extra = g_strdup_printf ("atom: %s state: %s",
02907                                  str ? str : "(unknown atom)",
02908                                  state);
02909         meta_XFree (str);
02910       }
02911       break;
02912     case SelectionClear:
02913       name = "SelectionClear";
02914       break;
02915     case SelectionRequest:
02916       name = "SelectionRequest";
02917       break;
02918     case SelectionNotify:
02919       name = "SelectionNotify";
02920       break;
02921     case ColormapNotify:
02922       name = "ColormapNotify";
02923       break;
02924     case ClientMessage:
02925       {
02926         char *str;
02927         name = "ClientMessage";
02928         meta_error_trap_push (display);
02929         str = XGetAtomName (display->xdisplay,
02930                             event->xclient.message_type);
02931         meta_error_trap_pop (display, TRUE);
02932         extra = g_strdup_printf ("type: %s format: %d\n",
02933                                  str ? str : "(unknown atom)",
02934                                  event->xclient.format);
02935         meta_XFree (str);
02936       }
02937       break;
02938     case MappingNotify:
02939       name = "MappingNotify";
02940       break;
02941     default:
02942 #ifdef HAVE_XSYNC
02943       if (META_DISPLAY_HAS_XSYNC (display) && 
02944           event->type == (display->xsync_event_base + XSyncAlarmNotify))
02945         {
02946           XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
02947           
02948           name = "XSyncAlarmNotify";
02949           extra =
02950             g_strdup_printf ("alarm: 0x%lx"
02951                              " counter_value: %" G_GINT64_FORMAT
02952                              " alarm_value: %" G_GINT64_FORMAT
02953                              " time: %u alarm state: %s",
02954                              aevent->alarm,
02955                              (gint64) sync_value_to_64 (&aevent->counter_value),
02956                              (gint64) sync_value_to_64 (&aevent->alarm_value),
02957                              (unsigned int)aevent->time,
02958                              alarm_state_to_string (aevent->state));
02959         }
02960       else
02961 #endif /* HAVE_XSYNC */
02962 #ifdef HAVE_SHAPE
02963         if (META_DISPLAY_HAS_SHAPE (display) && 
02964             event->type == (display->shape_event_base + ShapeNotify))
02965           {
02966             XShapeEvent *sev = (XShapeEvent*) event;
02967 
02968             name = "ShapeNotify";
02969 
02970             extra =
02971               g_strdup_printf ("kind: %s "
02972                                "x: %d y: %d w: %u h: %u "
02973                                "shaped: %d",
02974                                sev->kind == ShapeBounding ?
02975                                "ShapeBounding" :
02976                                (sev->kind == ShapeClip ?
02977                                "ShapeClip" : "(unknown)"),
02978                                sev->x, sev->y, sev->width, sev->height,
02979                                sev->shaped);
02980           }
02981         else
02982 #endif /* HAVE_SHAPE */      
02983         {
02984           name = "(Unknown event)";
02985           extra = g_strdup_printf ("type: %d", event->xany.type);
02986         }
02987       break;
02988     }
02989 
02990   screen = meta_display_screen_for_root (display, event->xany.window);
02991       
02992   if (screen)
02993     winname = g_strdup_printf ("root %d", screen->number);
02994   else
02995     winname = g_strdup_printf ("0x%lx", event->xany.window);
02996       
02997   meta_topic (META_DEBUG_EVENTS,
02998               "%s on %s%s %s %sserial %lu\n", name, winname,
02999               extra ? ":" : "", extra ? extra : "",
03000               event->xany.send_event ? "SEND " : "",
03001               event->xany.serial);
03002 
03003   g_free (winname);
03004 
03005   if (extra)
03006     g_free (extra);
03007 }
03008 #endif /* WITH_VERBOSE_MODE */
03009 
03010 MetaWindow*
03011 meta_display_lookup_x_window (MetaDisplay *display,
03012                               Window       xwindow)
03013 {
03014   return g_hash_table_lookup (display->window_ids, &xwindow);
03015 }
03016 
03017 void
03018 meta_display_register_x_window (MetaDisplay *display,
03019                                 Window      *xwindowp,
03020                                 MetaWindow  *window)
03021 {
03022   g_return_if_fail (g_hash_table_lookup (display->window_ids, xwindowp) == NULL);
03023   
03024   g_hash_table_insert (display->window_ids, xwindowp, window);
03025 }
03026 
03027 void
03028 meta_display_unregister_x_window (MetaDisplay *display,
03029                                   Window       xwindow)
03030 {
03031   g_return_if_fail (g_hash_table_lookup (display->window_ids, &xwindow) != NULL);
03032 
03033   g_hash_table_remove (display->window_ids, &xwindow);
03034 
03035   /* Remove any pending pings */
03036   remove_pending_pings_for_window (display, xwindow);
03037 }
03038 
03039 gboolean
03040 meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
03041                                            Window xwindow)
03042 {
03043   gboolean is_a_no_focus_window = FALSE;
03044   GSList *temp = display->screens;
03045   while (temp != NULL) {
03046     MetaScreen *screen = temp->data;
03047     if (screen->no_focus_window == xwindow) {
03048       is_a_no_focus_window = TRUE;
03049       break;
03050     }
03051     temp = temp->next;
03052   }
03053 
03054   return is_a_no_focus_window;
03055 }
03056 
03057 Cursor
03058 meta_display_create_x_cursor (MetaDisplay *display,
03059                               MetaCursor cursor)
03060 {
03061   Cursor xcursor;
03062   guint glyph;
03063 
03064   switch (cursor)
03065     {
03066     case META_CURSOR_DEFAULT:
03067       glyph = XC_left_ptr;
03068       break;
03069     case META_CURSOR_NORTH_RESIZE:
03070       glyph = XC_top_side;
03071       break;
03072     case META_CURSOR_SOUTH_RESIZE:
03073       glyph = XC_bottom_side;
03074       break;
03075     case META_CURSOR_WEST_RESIZE:
03076       glyph = XC_left_side;
03077       break;
03078     case META_CURSOR_EAST_RESIZE:
03079       glyph = XC_right_side;
03080       break;
03081     case META_CURSOR_SE_RESIZE:
03082       glyph = XC_bottom_right_corner;
03083       break;
03084     case META_CURSOR_SW_RESIZE:
03085       glyph = XC_bottom_left_corner;
03086       break;
03087     case META_CURSOR_NE_RESIZE:
03088       glyph = XC_top_right_corner;
03089       break;
03090     case META_CURSOR_NW_RESIZE:
03091       glyph = XC_top_left_corner;
03092       break;
03093     case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
03094       glyph = XC_fleur;
03095       break;
03096     case META_CURSOR_BUSY:
03097       glyph = XC_watch;
03098       break;
03099       
03100     default:
03101       g_assert_not_reached ();
03102       glyph = 0; /* silence compiler */
03103       break;
03104     }
03105   
03106   xcursor = XCreateFontCursor (display->xdisplay, glyph);
03107 
03108   return xcursor;
03109 }
03110 
03111 static Cursor
03112 xcursor_for_op (MetaDisplay *display,
03113                 MetaGrabOp   op)
03114 {
03115   MetaCursor cursor = META_CURSOR_DEFAULT;
03116   
03117   switch (op)
03118     {
03119     case META_GRAB_OP_RESIZING_SE:
03120     case META_GRAB_OP_KEYBOARD_RESIZING_SE:
03121       cursor = META_CURSOR_SE_RESIZE;
03122       break;
03123     case META_GRAB_OP_RESIZING_S:
03124     case META_GRAB_OP_KEYBOARD_RESIZING_S:
03125       cursor = META_CURSOR_SOUTH_RESIZE;
03126       break;
03127     case META_GRAB_OP_RESIZING_SW:
03128     case META_GRAB_OP_KEYBOARD_RESIZING_SW:
03129       cursor = META_CURSOR_SW_RESIZE;
03130       break;
03131     case META_GRAB_OP_RESIZING_N:
03132     case META_GRAB_OP_KEYBOARD_RESIZING_N:
03133       cursor = META_CURSOR_NORTH_RESIZE;
03134       break;
03135     case META_GRAB_OP_RESIZING_NE:
03136     case META_GRAB_OP_KEYBOARD_RESIZING_NE:
03137       cursor = META_CURSOR_NE_RESIZE;
03138       break;
03139     case META_GRAB_OP_RESIZING_NW:
03140     case META_GRAB_OP_KEYBOARD_RESIZING_NW:
03141       cursor = META_CURSOR_NW_RESIZE;
03142       break;
03143     case META_GRAB_OP_RESIZING_W:
03144     case META_GRAB_OP_KEYBOARD_RESIZING_W:
03145       cursor = META_CURSOR_WEST_RESIZE;
03146       break;
03147     case META_GRAB_OP_RESIZING_E:
03148     case META_GRAB_OP_KEYBOARD_RESIZING_E:
03149       cursor = META_CURSOR_EAST_RESIZE;
03150       break;
03151     case META_GRAB_OP_MOVING:
03152     case META_GRAB_OP_KEYBOARD_MOVING:
03153     case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
03154       cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW;
03155       break;
03156       
03157     default:
03158       break;
03159     }
03160 
03161   if (cursor == META_CURSOR_DEFAULT)
03162     return None;
03163   return meta_display_create_x_cursor (display, cursor);
03164 }
03165 
03166 void
03167 meta_display_set_grab_op_cursor (MetaDisplay *display,
03168                                  MetaScreen  *screen,
03169                                  MetaGrabOp   op,
03170                                  gboolean     change_pointer,
03171                                  Window       grab_xwindow,
03172                                  guint32      timestamp)
03173 {
03174   Cursor cursor;
03175 
03176   cursor = xcursor_for_op (display, op);
03177 
03178 #define GRAB_MASK (PointerMotionMask |                          \
03179                    ButtonPressMask | ButtonReleaseMask |        \
03180                    EnterWindowMask | LeaveWindowMask)
03181 
03182   if (change_pointer)
03183     {
03184       meta_error_trap_push_with_return (display);
03185       XChangeActivePointerGrab (display->xdisplay,
03186                                 GRAB_MASK,
03187                                 cursor,
03188                                 timestamp);
03189 
03190       meta_topic (META_DEBUG_WINDOW_OPS,
03191                   "Changed pointer with XChangeActivePointerGrab()\n");
03192 
03193       if (meta_error_trap_pop_with_return (display, FALSE) != Success)
03194         {
03195           meta_topic (META_DEBUG_WINDOW_OPS,
03196                       "Error trapped from XChangeActivePointerGrab()\n");
03197           if (display->grab_have_pointer)
03198             display->grab_have_pointer = FALSE;
03199         }
03200     }
03201   else
03202     {
03203       g_assert (screen != NULL);
03204 
03205       meta_error_trap_push (display);
03206       if (XGrabPointer (display->xdisplay,
03207                         grab_xwindow,
03208                         False,
03209                         GRAB_MASK,
03210                         GrabModeAsync, GrabModeAsync,
03211                         screen->xroot,
03212                         cursor,
03213                         timestamp) == GrabSuccess)
03214         {
03215           display->grab_have_pointer = TRUE;
03216           meta_topic (META_DEBUG_WINDOW_OPS,
03217                       "XGrabPointer() returned GrabSuccess time %u\n",
03218                       timestamp);
03219         }
03220       else
03221         {
03222           meta_topic (META_DEBUG_WINDOW_OPS,
03223                       "XGrabPointer() failed time %u\n",
03224                       timestamp);
03225         }
03226       meta_error_trap_pop (display, TRUE);
03227     }
03228 
03229 #undef GRAB_MASK
03230   
03231   if (cursor != None)
03232     XFreeCursor (display->xdisplay, cursor);
03233 }
03234 
03235 gboolean
03236 meta_display_begin_grab_op (MetaDisplay *display,
03237                             MetaScreen  *screen,
03238                             MetaWindow  *window,
03239                             MetaGrabOp   op,
03240                             gboolean     pointer_already_grabbed,
03241                             gboolean     frame_action,
03242                             int          button,
03243                             gulong       modmask,
03244                             guint32      timestamp,
03245                             int          root_x,
03246                             int          root_y)
03247 {
03248   Window grab_xwindow;
03249   
03250   if (grab_op_is_mouse (op) && meta_grab_op_is_moving (op))
03251     {
03252       if (display->compositor)
03253         {
03254           meta_compositor_begin_move (display->compositor,
03255                                       window, &window->rect,
03256                                       root_x, root_y);
03257         }
03258     }
03259   
03260   meta_topic (META_DEBUG_WINDOW_OPS,
03261               "Doing grab op %u on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n",
03262               op, window ? window->desc : "none", button, pointer_already_grabbed,
03263               root_x, root_y);
03264   
03265   if (display->grab_op != META_GRAB_OP_NONE)
03266     {
03267       meta_warning ("Attempt to perform window operation %u on window %s when operation %u on %s already in effect\n",
03268                     op, window ? window->desc : "none", display->grab_op,
03269                     display->grab_window ? display->grab_window->desc : "none");
03270       return FALSE;
03271     }
03272 
03273   if (window &&
03274       (meta_grab_op_is_moving (op) || meta_grab_op_is_resizing (op)))
03275     {
03276       if (meta_prefs_get_raise_on_click ())
03277         meta_window_raise (window);
03278       else
03279         {
03280           display->grab_initial_x = root_x;
03281           display->grab_initial_y = root_y;
03282           display->grab_threshold_movement_reached = FALSE;
03283         }
03284     }
03285 
03286   /* FIXME:
03287    *   If we have no MetaWindow we do our best
03288    *   and try to do the grab on the RootWindow.
03289    *   This will fail if anyone else has any
03290    *   key grab on the RootWindow.
03291    */
03292   if (window)
03293     grab_xwindow = window->frame ? window->frame->xwindow : window->xwindow;
03294   else
03295     grab_xwindow = screen->xroot;
03296 
03297   display->grab_have_pointer = FALSE;
03298   
03299   if (pointer_already_grabbed)
03300     display->grab_have_pointer = TRUE;
03301   
03302   meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow,
03303                                    timestamp);
03304 
03305   if (!display->grab_have_pointer)
03306     {
03307       meta_topic (META_DEBUG_WINDOW_OPS,
03308                   "XGrabPointer() failed\n");
03309       return FALSE;
03310     }
03311 
03312   /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */
03313   if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op))
03314     {
03315       if (window)
03316         display->grab_have_keyboard =
03317                      meta_window_grab_all_keys (window, timestamp);
03318 
03319       else
03320         display->grab_have_keyboard =
03321                      meta_screen_grab_all_keys (screen, timestamp);
03322       
03323       if (!display->grab_have_keyboard)
03324         {
03325           meta_topic (META_DEBUG_WINDOW_OPS,
03326                       "grabbing all keys failed, ungrabbing pointer\n");
03327           XUngrabPointer (display->xdisplay, timestamp);
03328           display->grab_have_pointer = FALSE;
03329           return FALSE;
03330         }
03331     }
03332   
03333   display->grab_op = op;
03334   display->grab_window = window;
03335   display->grab_screen = screen;
03336   display->grab_xwindow = grab_xwindow;
03337   display->grab_button = button;
03338   display->grab_mask = modmask;
03339   display->grab_anchor_root_x = root_x;
03340   display->grab_anchor_root_y = root_y;
03341   display->grab_latest_motion_x = root_x;
03342   display->grab_latest_motion_y = root_y;
03343   display->grab_last_moveresize_time.tv_sec = 0;
03344   display->grab_last_moveresize_time.tv_usec = 0;
03345   display->grab_motion_notify_time = 0;
03346   display->grab_old_window_stacking = NULL;
03347 #ifdef HAVE_XSYNC
03348   display->grab_sync_request_alarm = None;
03349   display->grab_last_user_action_was_snap = FALSE;
03350 #endif
03351   display->grab_was_cancelled = FALSE;
03352   display->grab_frame_action = frame_action;
03353 
03354   if (display->grab_resize_timeout_id)
03355     {
03356       g_source_remove (display->grab_resize_timeout_id);
03357       display->grab_resize_timeout_id = 0;
03358     }
03359         
03360   if (display->grab_window)
03361     {
03362       meta_window_get_client_root_coords (display->grab_window,
03363                                           &display->grab_initial_window_pos);
03364       display->grab_anchor_window_pos = display->grab_initial_window_pos;
03365 
03366       display->grab_wireframe_active =
03367         (meta_prefs_get_reduced_resources () && !meta_prefs_get_gnome_accessibility ())  && 
03368         (meta_grab_op_is_resizing (display->grab_op) ||
03369          meta_grab_op_is_moving (display->grab_op));
03370       
03371       if (display->grab_wireframe_active)
03372         {
03373           meta_window_calc_showing (display->grab_window);
03374           meta_window_begin_wireframe (window);
03375         }
03376       
03377 #ifdef HAVE_XSYNC
03378       if (!display->grab_wireframe_active &&
03379           meta_grab_op_is_resizing (display->grab_op) &&
03380           display->grab_window->sync_request_counter != None)
03381         {
03382           XSyncAlarmAttributes values;
03383           XSyncValue init;
03384 
03385           meta_error_trap_push_with_return (display);
03386 
03387           /* Set the counter to 0, so we know that the application's
03388            * responses to the client messages will always trigger
03389            * a PositiveTransition
03390            */
03391           
03392           XSyncIntToValue (&init, 0);
03393           XSyncSetCounter (display->xdisplay,
03394                            display->grab_window->sync_request_counter, init);
03395           
03396           display->grab_window->sync_request_serial = 0;
03397           display->grab_window->sync_request_time.tv_sec = 0;
03398           display->grab_window->sync_request_time.tv_usec = 0;
03399           
03400           values.trigger.counter = display->grab_window->sync_request_counter;
03401           values.trigger.value_type = XSyncAbsolute;
03402           values.trigger.test_type = XSyncPositiveTransition;
03403           XSyncIntToValue (&values.trigger.wait_value,
03404                            display->grab_window->sync_request_serial + 1);
03405           
03406           /* After triggering, increment test_value by this.
03407            * (NOT wait_value above)
03408            */
03409           XSyncIntToValue (&values.delta, 1);
03410           
03411           /* we want events (on by default anyway) */
03412           values.events = True;
03413           
03414           display->grab_sync_request_alarm = XSyncCreateAlarm (display->xdisplay,
03415                                                          XSyncCACounter |
03416                                                          XSyncCAValueType |
03417                                                          XSyncCAValue |
03418                                                          XSyncCATestType |
03419                                                          XSyncCADelta |
03420                                                          XSyncCAEvents,
03421                                                          &values);
03422 
03423           if (meta_error_trap_pop_with_return (display, FALSE) != Success)
03424             display->grab_sync_request_alarm = None;
03425 
03426           meta_topic (META_DEBUG_RESIZING,
03427                       "Created update alarm 0x%lx\n",
03428                       display->grab_sync_request_alarm);
03429         }
03430 #endif
03431     }
03432   
03433   meta_topic (META_DEBUG_WINDOW_OPS,
03434               "Grab op %u on window %s successful\n",
03435               display->grab_op, window ? window->desc : "(null)");
03436 
03437   g_assert (display->grab_window != NULL || display->grab_screen != NULL);
03438   g_assert (display->grab_op != META_GRAB_OP_NONE);
03439 
03440   /* If this is a move or resize, cache the window edges for
03441    * resistance/snapping
03442    */
03443   if (meta_grab_op_is_resizing (display->grab_op) || 
03444       meta_grab_op_is_moving (display->grab_op))
03445     {
03446       meta_topic (META_DEBUG_WINDOW_OPS,
03447                   "Computing edges to resist-movement or snap-to for %s.\n",
03448                   window->desc);
03449       meta_display_compute_resistance_and_snapping_edges (display);
03450     }
03451 
03452   /* Save the old stacking */
03453   if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
03454     {
03455       meta_topic (META_DEBUG_WINDOW_OPS,
03456                   "Saving old stack positions; old pointer was %p.\n",
03457                   display->grab_old_window_stacking);
03458       display->grab_old_window_stacking = 
03459         meta_stack_get_positions (screen->stack);
03460     }
03461 
03462   /* Do this last, after everything is set up. */
03463   switch (op)
03464     {
03465     case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
03466       meta_screen_ensure_tab_popup (screen,
03467                                     META_TAB_LIST_NORMAL,
03468                                     META_TAB_SHOW_ICON);
03469       break;
03470     case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
03471       meta_screen_ensure_tab_popup (screen,
03472                                     META_TAB_LIST_NORMAL,
03473                                     META_TAB_SHOW_INSTANTLY);
03474       break;
03475 
03476     case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
03477       meta_screen_ensure_tab_popup (screen,
03478                                     META_TAB_LIST_DOCKS,
03479                                     META_TAB_SHOW_ICON);
03480       break;
03481     case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
03482       meta_screen_ensure_tab_popup (screen,
03483                                     META_TAB_LIST_DOCKS,
03484                                     META_TAB_SHOW_INSTANTLY);
03485       break;
03486     case META_GRAB_OP_KEYBOARD_TABBING_GROUP:
03487       meta_screen_ensure_tab_popup (screen,
03488                                     META_TAB_LIST_GROUP,
03489                                     META_TAB_SHOW_ICON);
03490       break;
03491      case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP:
03492       meta_screen_ensure_tab_popup (screen,
03493                                     META_TAB_LIST_GROUP,
03494                                     META_TAB_SHOW_INSTANTLY);
03495       
03496     case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
03497       meta_screen_ensure_workspace_popup (screen);
03498       break;
03499 
03500     default:
03501       break;
03502     }
03503 
03504   if (display->grab_window)
03505     {
03506       meta_window_refresh_resize_popup (display->grab_window);
03507     }
03508   
03509   return TRUE;
03510 }
03511 
03512 void
03513 meta_display_end_grab_op (MetaDisplay *display,
03514                           guint32      timestamp)
03515 {
03516   meta_topic (META_DEBUG_WINDOW_OPS,
03517               "Ending grab op %u at time %u\n", display->grab_op, timestamp);
03518   
03519   if (display->grab_op == META_GRAB_OP_NONE)
03520     return;
03521 
03522   if (display->grab_window != NULL)
03523     display->grab_window->shaken_loose = FALSE;
03524   
03525   if (display->grab_window != NULL &&
03526       !meta_prefs_get_raise_on_click () &&
03527       (meta_grab_op_is_moving (display->grab_op) ||
03528        meta_grab_op_is_resizing (display->grab_op)))
03529     {
03530       /* Only raise the window in orthogonal raise
03531        * ('do-not-raise-on-click') mode if the user didn't try to move
03532        * or resize the given window by at least a threshold amount.
03533        * For raise on click mode, the window was raised at the
03534        * beginning of the grab_op.
03535        */
03536       if (!display->grab_threshold_movement_reached)
03537         meta_window_raise (display->grab_window);
03538     }
03539 
03540   if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op) ||
03541       display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING)
03542     {
03543       meta_ui_tab_popup_free (display->grab_screen->tab_popup);
03544       display->grab_screen->tab_popup = NULL;
03545 
03546       /* If the ungrab here causes an EnterNotify, ignore it for
03547        * sloppy focus
03548        */
03549       display->ungrab_should_not_cause_focus_window = display->grab_xwindow;
03550     }
03551   
03552   /* If this was a move or resize clear out the edge cache */
03553   if (meta_grab_op_is_resizing (display->grab_op) || 
03554       meta_grab_op_is_moving (display->grab_op))
03555     {
03556       meta_topic (META_DEBUG_WINDOW_OPS,
03557                   "Clearing out the edges for resistance/snapping");
03558       meta_display_cleanup_edges (display);
03559     }
03560 
03561   if (display->grab_old_window_stacking != NULL)
03562     {
03563       meta_topic (META_DEBUG_WINDOW_OPS,
03564                   "Clearing out the old stack position, which was %p.\n",
03565                   display->grab_old_window_stacking);
03566       g_list_free (display->grab_old_window_stacking);
03567       display->grab_old_window_stacking = NULL;
03568     }
03569 
03570   if (display->grab_wireframe_active)
03571     {
03572       display->grab_wireframe_active = FALSE;
03573       meta_window_end_wireframe (display->grab_window);
03574 
03575       if (!display->grab_was_cancelled)
03576         {
03577           if (meta_grab_op_is_moving (display->grab_op))
03578             meta_window_move (display->grab_window,
03579                               TRUE,
03580                               display->grab_wireframe_rect.x,
03581                               display->grab_wireframe_rect.y);
03582           if (meta_grab_op_is_resizing (display->grab_op))
03583             meta_window_resize_with_gravity (display->grab_window,
03584                                              TRUE,
03585                                              display->grab_wireframe_rect.width,
03586                                              display->grab_wireframe_rect.height,
03587                                              meta_resize_gravity_from_grab_op (display->grab_op));
03588         }
03589       meta_window_calc_showing (display->grab_window);
03590     }
03591 
03592   if (display->compositor &&
03593       display->grab_window &&
03594       grab_op_is_mouse (display->grab_op) && 
03595       meta_grab_op_is_moving (display->grab_op))
03596     {
03597       meta_compositor_end_move (display->compositor,
03598                                 display->grab_window);
03599     }
03600   
03601   if (display->grab_have_pointer)
03602     {
03603       meta_topic (META_DEBUG_WINDOW_OPS,
03604                   "Ungrabbing pointer with timestamp %u\n", timestamp);
03605       XUngrabPointer (display->xdisplay, timestamp);
03606     }
03607 
03608   if (display->grab_have_keyboard)
03609     {
03610       meta_topic (META_DEBUG_WINDOW_OPS,
03611                   "Ungrabbing all keys timestamp %u\n", timestamp);
03612       if (display->grab_window)
03613         meta_window_ungrab_all_keys (display->grab_window, timestamp);
03614       else
03615         meta_screen_ungrab_all_keys (display->grab_screen, timestamp);
03616     }
03617 
03618 #ifdef HAVE_XSYNC
03619   if (display->grab_sync_request_alarm != None)
03620     {
03621       XSyncDestroyAlarm (display->xdisplay,
03622                          display->grab_sync_request_alarm);
03623       display->grab_sync_request_alarm = None;
03624     }
03625 #endif /* HAVE_XSYNC */
03626   
03627   display->grab_window = NULL;
03628   display->grab_screen = NULL;
03629   display->grab_xwindow = None;
03630   display->grab_op = META_GRAB_OP_NONE;
03631 
03632   if (display->grab_resize_popup)
03633     {
03634       meta_ui_resize_popup_free (display->grab_resize_popup);
03635       display->grab_resize_popup = NULL;
03636     }
03637 
03638   if (display->grab_resize_timeout_id)
03639     {
03640       g_source_remove (display->grab_resize_timeout_id);
03641       display->grab_resize_timeout_id = 0;
03642     }
03643 }
03644 
03645 void
03646 meta_display_check_threshold_reached (MetaDisplay *display,
03647                                       int          x,
03648                                       int          y)
03649 {
03650   /* Don't bother doing the check again if we've already reached the threshold */
03651   if (meta_prefs_get_raise_on_click () ||
03652       display->grab_threshold_movement_reached)
03653     return;
03654 
03655   if (ABS (display->grab_initial_x - x) >= 8 ||
03656       ABS (display->grab_initial_y - y) >= 8)
03657     display->grab_threshold_movement_reached = TRUE;
03658 }
03659 
03660 static void
03661 meta_change_button_grab (MetaDisplay *display,
03662                          Window       xwindow,
03663                          gboolean     grab,
03664                          gboolean     sync,
03665                          int          button,
03666                          int          modmask)
03667 {
03668   unsigned int ignored_mask;
03669 
03670   meta_verbose ("%s 0x%lx sync = %d button = %d modmask 0x%x\n",
03671                 grab ? "Grabbing" : "Ungrabbing",
03672                 xwindow,
03673                 sync, button, modmask);
03674   
03675   meta_error_trap_push (display);
03676   
03677   ignored_mask = 0;
03678   while (ignored_mask <= display->ignored_modifier_mask)
03679     {
03680       if (ignored_mask & ~(display->ignored_modifier_mask))
03681         {
03682           /* Not a combination of ignored modifiers
03683            * (it contains some non-ignored modifiers)
03684            */
03685           ++ignored_mask;
03686           continue;
03687         }
03688 
03689       if (meta_is_debugging ())
03690         meta_error_trap_push_with_return (display);
03691 
03692       /* GrabModeSync means freeze until XAllowEvents */
03693       
03694       if (grab)
03695         XGrabButton (display->xdisplay, button, modmask | ignored_mask,
03696                      xwindow, False,
03697                      ButtonPressMask | ButtonReleaseMask |    
03698                      PointerMotionMask | PointerMotionHintMask,
03699                      sync ? GrabModeSync : GrabModeAsync,
03700                      GrabModeAsync,
03701                      False, None);
03702       else
03703         XUngrabButton (display->xdisplay, button, modmask | ignored_mask,
03704                        xwindow);
03705 
03706       if (meta_is_debugging ())
03707         {
03708           int result;
03709           
03710           result = meta_error_trap_pop_with_return (display, FALSE);
03711           
03712           if (result != Success)
03713             meta_verbose ("Failed to %s button %d with mask 0x%x for window 0x%lx error code %d\n",
03714                           grab ? "grab" : "ungrab",
03715                           button, modmask | ignored_mask, xwindow, result);
03716         }
03717       
03718       ++ignored_mask;
03719     }
03720 
03721   meta_error_trap_pop (display, FALSE);
03722 }
03723 
03724 void
03725 meta_display_grab_window_buttons (MetaDisplay *display,
03726                                   Window       xwindow)
03727 {  
03728   /* Grab Alt + button1 for moving window.
03729    * Grab Alt + button2 for resizing window.
03730    * Grab Alt + button3 for popping up window menu.
03731    * Grab Alt + Shift + button1 for snap-moving window.
03732    */
03733   meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow);
03734   
03735   /* FIXME If we ignored errors here instead of spewing, we could
03736    * put one big error trap around the loop and avoid a bunch of
03737    * XSync()
03738    */
03739 
03740   if (display->window_grab_modifiers != 0)
03741     {
03742       gboolean debug = g_getenv ("METACITY_DEBUG_BUTTON_GRABS") != NULL;
03743       int i;
03744       for (i = 1; i < 4; i++)
03745         {
03746           meta_change_button_grab (display, xwindow,
03747                                    TRUE,
03748                                    FALSE,
03749                                    i, display->window_grab_modifiers);  
03750           
03751           /* This is for debugging, since I end up moving the Xnest
03752            * otherwise ;-)
03753            */
03754           if (debug)
03755             meta_change_button_grab (display, xwindow,
03756                                      TRUE,
03757                                      FALSE,
03758                                      i, ControlMask);
03759         }
03760 
03761       /* In addition to grabbing Alt+Button1 for moving the window,
03762        * grab Alt+Shift+Button1 for snap-moving the window.  See bug
03763        * 112478.  Unfortunately, this doesn't work with
03764        * Shift+Alt+Button1 for some reason; so at least part of the
03765        * order still matters, which sucks (please FIXME).
03766        */
03767       meta_change_button_grab (display, xwindow,
03768                                TRUE,
03769                                FALSE,
03770                                1, display->window_grab_modifiers | ShiftMask);
03771     }
03772 }
03773 
03774 void
03775 meta_display_ungrab_window_buttons  (MetaDisplay *display,
03776                                      Window       xwindow)
03777 {
03778   gboolean debug;
03779   int i;
03780 
03781   if (display->window_grab_modifiers == 0)
03782     return;
03783   
03784   debug = g_getenv ("METACITY_DEBUG_BUTTON_GRABS") != NULL;
03785   i = 1;
03786   while (i < 4)
03787     {
03788       meta_change_button_grab (display, xwindow,
03789                                FALSE, FALSE, i,
03790                                display->window_grab_modifiers);
03791       
03792       if (debug)
03793         meta_change_button_grab (display, xwindow,
03794                                  FALSE, FALSE, i, ControlMask);
03795       
03796       ++i;
03797     }
03798 }
03799 
03800 /* Grab buttons we only grab while unfocused in click-to-focus mode */
03801 #define MAX_FOCUS_BUTTON 4
03802 void
03803 meta_display_grab_focus_window_button (MetaDisplay *display,
03804                                        MetaWindow  *window)
03805 {
03806   /* Grab button 1 for activating unfocused windows */
03807   meta_verbose ("Grabbing unfocused window buttons for %s\n", window->desc);
03808 
03809 #if 0
03810   /* FIXME:115072 */
03811   /* Don't grab at all unless in click to focus mode. In click to
03812    * focus, we may sometimes be clever about intercepting and eating
03813    * the focus click. But in mouse focus, we never do that since the
03814    * focus window may not be raised, and who wants to think about
03815    * mouse focus anyway.
03816    */
03817   if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK)
03818     {
03819       meta_verbose (" (well, not grabbing since not in click to focus mode)\n");
03820       return;
03821     }
03822 #endif
03823   
03824   if (window->have_focus_click_grab)
03825     {
03826       meta_verbose (" (well, not grabbing since we already have the grab)\n");
03827       return;
03828     }
03829   
03830   /* FIXME If we ignored errors here instead of spewing, we could
03831    * put one big error trap around the loop and avoid a bunch of
03832    * XSync()
03833    */
03834   
03835   {
03836     int i = 1;
03837     while (i < MAX_FOCUS_BUTTON)
03838       {
03839         meta_change_button_grab (display,
03840                                  window->xwindow,
03841                                  TRUE, TRUE,
03842                                  i, 0);
03843         
03844         ++i;
03845       }
03846 
03847     window->have_focus_click_grab = TRUE;
03848   }
03849 }
03850 
03851 void
03852 meta_display_ungrab_focus_window_button (MetaDisplay *display,
03853                                          MetaWindow  *window)
03854 {
03855   meta_verbose ("Ungrabbing unfocused window buttons for %s\n", window->desc);
03856 
03857   if (!window->have_focus_click_grab)
03858     return;
03859   
03860   {
03861     int i = 1;
03862     while (i < MAX_FOCUS_BUTTON)
03863       {
03864         meta_change_button_grab (display, window->xwindow,
03865                                  FALSE, FALSE, i, 0);
03866         
03867         ++i;
03868       }
03869 
03870     window->have_focus_click_grab = FALSE;
03871   }
03872 }
03873 
03874 void
03875 meta_display_increment_event_serial (MetaDisplay *display)
03876 {
03877   /* We just make some random X request */
03878   XDeleteProperty (display->xdisplay, display->leader_window,
03879                    display->atom__MOTIF_WM_HINTS);
03880 }
03881 
03882 void
03883 meta_display_update_active_window_hint (MetaDisplay *display)
03884 {
03885   GSList *tmp;
03886   
03887   gulong data[1];
03888 
03889   if (display->focus_window)
03890     data[0] = display->focus_window->xwindow;
03891   else
03892     data[0] = None;
03893   
03894   tmp = display->screens;
03895   while (tmp != NULL)
03896     {
03897       MetaScreen *screen = tmp->data;
03898       
03899       meta_error_trap_push (display);
03900       XChangeProperty (display->xdisplay, screen->xroot,
03901                        display->atom__NET_ACTIVE_WINDOW,
03902                        XA_WINDOW,
03903                        32, PropModeReplace, (guchar*) data, 1);
03904 
03905       meta_error_trap_pop (display, FALSE);
03906 
03907       tmp = tmp->next;
03908     }
03909 }
03910 
03911 void
03912 meta_display_queue_retheme_all_windows (MetaDisplay *display)
03913 {
03914   GSList* windows;
03915   GSList *tmp;
03916 
03917   windows = meta_display_list_windows (display);
03918   tmp = windows;
03919   while (tmp != NULL)
03920     {
03921       MetaWindow *window = tmp->data;
03922       
03923       meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
03924       if (window->frame)
03925         {
03926           window->frame->need_reapply_frame_shape = TRUE;
03927           
03928           meta_frame_queue_draw (window->frame);
03929         }
03930       
03931       tmp = tmp->next;
03932     }
03933 
03934   g_slist_free (windows);
03935 }
03936 
03937 void
03938 meta_display_retheme_all (void)
03939 {
03940   meta_display_queue_retheme_all_windows (meta_get_display ());
03941 }
03942 
03943 void 
03944 meta_display_set_cursor_theme (const char *theme, 
03945                                int         size)
03946 {
03947 #ifdef HAVE_XCURSOR     
03948   GSList *tmp;
03949 
03950   MetaDisplay *display = meta_get_display ();
03951 
03952   XcursorSetTheme (display->xdisplay, theme);
03953   XcursorSetDefaultSize (display->xdisplay, size);
03954 
03955   tmp = display->screens;
03956   while (tmp != NULL)
03957     {
03958       MetaScreen *screen = tmp->data;
03959                   
03960       meta_screen_update_cursor (screen);
03961 
03962       tmp = tmp->next;
03963     }
03964 
03965 #endif
03966 }
03967 
03971 static gboolean is_syncing = FALSE;
03972 
03984 gboolean
03985 meta_is_syncing (void)
03986 {
03987   return is_syncing;
03988 }
03989 
03996 void
03997 meta_set_syncing (gboolean setting)
03998 {
03999   if (setting != is_syncing)
04000     {
04001       is_syncing = setting;
04002 
04003       XSynchronize (meta_get_display ()->xdisplay, is_syncing);
04004     }
04005 }
04006 
04011 #define PING_TIMEOUT_DELAY 2250
04012 
04028 static gboolean
04029 meta_display_ping_timeout (gpointer data)
04030 {
04031   MetaPingData *ping_data;
04032 
04033   ping_data = data;
04034 
04035   ping_data->ping_timeout_id = 0;
04036 
04037   meta_topic (META_DEBUG_PING,
04038               "Ping %u on window %lx timed out\n",
04039               ping_data->timestamp, ping_data->xwindow);
04040   
04041   (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow,
04042                                     ping_data->timestamp, ping_data->user_data);
04043 
04044   ping_data->display->pending_pings =
04045     g_slist_remove (ping_data->display->pending_pings,
04046                     ping_data);
04047   ping_data_free (ping_data);
04048   
04049   return FALSE;
04050 }
04051 
04077 void
04078 meta_display_ping_window (MetaDisplay       *display,
04079                           MetaWindow        *window,
04080                           guint32            timestamp,
04081                           MetaWindowPingFunc ping_reply_func,
04082                           MetaWindowPingFunc ping_timeout_func,
04083                           gpointer           user_data)
04084 {
04085   MetaPingData *ping_data;
04086 
04087   if (timestamp == CurrentTime)
04088     {
04089       meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
04090       return;
04091     }
04092 
04093   if (!window->net_wm_ping)
04094     {
04095       if (ping_reply_func)
04096         (* ping_reply_func) (display, window->xwindow, timestamp, user_data);
04097 
04098       return;
04099     }
04100   
04101   ping_data = g_new (MetaPingData, 1);
04102   ping_data->display = display;
04103   ping_data->xwindow = window->xwindow;
04104   ping_data->timestamp = timestamp;
04105   ping_data->ping_reply_func = ping_reply_func;
04106   ping_data->ping_timeout_func = ping_timeout_func;
04107   ping_data->user_data = user_data;
04108   ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY,
04109                                               meta_display_ping_timeout,
04110                                               ping_data);
04111   
04112   display->pending_pings = g_slist_prepend (display->pending_pings, ping_data);
04113 
04114   meta_topic (META_DEBUG_PING,
04115               "Sending ping with timestamp %u to window %s\n",
04116               timestamp, window->desc);
04117   meta_window_send_icccm_message (window,
04118                                   display->atom__NET_WM_PING,
04119                                   timestamp);
04120 }
04121 
04122 static void
04123 process_request_frame_extents (MetaDisplay    *display,
04124                                XEvent         *event)
04125 {
04126   /* The X window whose frame extents will be set. */
04127   Window xwindow = event->xclient.window;
04128   unsigned long data[4] = { 0, 0, 0, 0 };
04129 
04130   MotifWmHints *hints = NULL;
04131   gboolean hints_set = FALSE;
04132 
04133   meta_verbose ("Setting frame extents for 0x%lx\n", xwindow);
04134 
04135   /* See if the window is decorated. */
04136   hints_set = meta_prop_get_motif_hints (display,
04137                                          xwindow,
04138                                          display->atom__MOTIF_WM_HINTS,
04139                                          &hints);
04140   if ((hints_set && hints->decorations) || !hints_set)
04141     {
04142       int top = 0;
04143       int bottom = 0;
04144       int left = 0;
04145       int right = 0;
04146 
04147       MetaScreen *screen;
04148 
04149       screen = meta_display_screen_for_xwindow (display,
04150                                                 event->xclient.window);
04151       if (screen == NULL)
04152         {
04153           meta_warning ("Received request to set _NET_FRAME_EXTENTS "
04154                         "on 0x%lx which is on a screen we are not managing\n",
04155                         event->xclient.window);
04156           meta_XFree (hints);
04157           return;
04158         }
04159 
04160       /* Return estimated frame extents for a normal window. */
04161       meta_ui_theme_get_frame_borders (screen->ui,
04162                                        META_FRAME_TYPE_NORMAL,
04163                                        0,
04164                                        &top,
04165                                        &bottom,
04166                                        &left,
04167                                        &right);
04168 
04169       data[0] = left;
04170       data[1] = right;
04171       data[2] = top;
04172       data[3] = bottom;
04173     }
04174 
04175   meta_topic (META_DEBUG_GEOMETRY,
04176               "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx "
04177               "to top = %lu, left = %lu, bottom = %lu, right = %lu\n",
04178               xwindow, data[0], data[1], data[2], data[3]);
04179 
04180   meta_error_trap_push (display);
04181   XChangeProperty (display->xdisplay, xwindow,
04182                    display->atom__NET_FRAME_EXTENTS,
04183                    XA_CARDINAL,
04184                    32, PropModeReplace, (guchar*) data, 4);
04185   meta_error_trap_pop (display, FALSE);
04186 
04187   meta_XFree (hints);
04188 }
04189 
04202 static void
04203 process_pong_message (MetaDisplay    *display,
04204                       XEvent         *event)
04205 {
04206   GSList *tmp;
04207   guint32 timestamp = event->xclient.data.l[1];
04208 
04209   meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n",
04210               timestamp);
04211   
04212   for (tmp = display->pending_pings; tmp; tmp = tmp->next)
04213     {
04214       MetaPingData *ping_data = tmp->data;
04215                           
04216       if (timestamp == ping_data->timestamp)
04217         {
04218           meta_topic (META_DEBUG_PING,
04219                       "Matching ping found for pong %u\n", 
04220                       ping_data->timestamp);
04221 
04222           /* Remove the ping data from the list */
04223           display->pending_pings = g_slist_remove (display->pending_pings,
04224                                                    ping_data);
04225 
04226           /* Remove the timeout */
04227           if (ping_data->ping_timeout_id != 0)
04228             {
04229               g_source_remove (ping_data->ping_timeout_id);
04230               ping_data->ping_timeout_id = 0;
04231             }
04232           
04233           /* Call callback */
04234           (* ping_data->ping_reply_func) (display, 
04235                                           ping_data->xwindow,
04236                                           ping_data->timestamp, 
04237                                           ping_data->user_data);
04238                               
04239           ping_data_free (ping_data);
04240 
04241           break;
04242         }
04243     }
04244 }
04245 
04260 gboolean
04261 meta_display_window_has_pending_pings (MetaDisplay *display,
04262                                        MetaWindow  *window)
04263 {
04264   GSList *tmp;
04265 
04266   for (tmp = display->pending_pings; tmp; tmp = tmp->next)
04267     {
04268       MetaPingData *ping_data = tmp->data;
04269 
04270       if (ping_data->xwindow == window->xwindow) 
04271         return TRUE;
04272     }
04273 
04274   return FALSE;
04275 }
04276 
04277 MetaGroup*
04278 get_focussed_group (MetaDisplay *display)
04279 {
04280   if (display->focus_window)
04281     return display->focus_window->group;
04282   else
04283     return NULL;
04284 }
04285 
04286 #define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \
04287     || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \
04288     || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))))
04289 
04290 static MetaWindow*
04291 find_tab_forward (MetaDisplay   *display,
04292                   MetaTabList    type,
04293                   MetaScreen    *screen, 
04294                   MetaWorkspace *workspace,
04295                   GList         *start,
04296                   gboolean       skip_first)
04297 {
04298   GList *tmp;
04299 
04300   g_return_val_if_fail (start != NULL, NULL);
04301   g_return_val_if_fail (workspace != NULL, NULL);
04302 
04303   tmp = start;
04304   if (skip_first)
04305     tmp = tmp->next;
04306 
04307   while (tmp != NULL)
04308     {
04309       MetaWindow *window = tmp->data;
04310 
04311       if (window->screen == screen &&
04312           IN_TAB_CHAIN (window, type))
04313         return window;
04314 
04315       tmp = tmp->next;
04316     }
04317 
04318   tmp = workspace->mru_list;
04319   while (tmp != start)
04320     {
04321       MetaWindow *window = tmp->data;
04322 
04323       if (IN_TAB_CHAIN (window, type))
04324         return window;
04325 
04326       tmp = tmp->next;
04327     }  
04328 
04329   return NULL;
04330 }
04331 
04332 static MetaWindow*
04333 find_tab_backward (MetaDisplay   *display,
04334                    MetaTabList    type,
04335                    MetaScreen    *screen, 
04336                    MetaWorkspace *workspace,
04337                    GList         *start,
04338                    gboolean       skip_last)
04339 {
04340   GList *tmp;
04341 
04342   g_return_val_if_fail (start != NULL, NULL);
04343   g_return_val_if_fail (workspace != NULL, NULL);
04344 
04345   tmp = start;
04346   if (skip_last)  
04347     tmp = tmp->prev;
04348   while (tmp != NULL)
04349     {
04350       MetaWindow *window = tmp->data;
04351 
04352       if (window->screen == screen &&
04353           IN_TAB_CHAIN (window, type))
04354         return window;
04355 
04356       tmp = tmp->prev;
04357     }
04358 
04359   tmp = g_list_last (workspace->mru_list);
04360   while (tmp != start)
04361     {
04362       MetaWindow *window = tmp->data;
04363 
04364       if (IN_TAB_CHAIN (window, type))
04365         return window;
04366 
04367       tmp = tmp->prev;
04368     }
04369 
04370   return NULL;
04371 }
04372 
04373 GList*
04374 meta_display_get_tab_list (MetaDisplay   *display,
04375                            MetaTabList    type,
04376                            MetaScreen    *screen,
04377                            MetaWorkspace *workspace)
04378 {
04379   GList *tab_list;
04380 
04381   g_return_val_if_fail (workspace != NULL, NULL);
04382 
04383   /* Windows sellout mode - MRU order. Collect unminimized windows
04384    * then minimized so minimized windows aren't in the way so much.
04385    */
04386   {
04387     GList *tmp;
04388     
04389     tab_list = NULL;
04390     tmp = workspace->mru_list;
04391     while (tmp != NULL)
04392       {
04393         MetaWindow *window = tmp->data;
04394         
04395         if (!window->minimized &&
04396             window->screen == screen &&
04397             IN_TAB_CHAIN (window, type))
04398           tab_list = g_list_prepend (tab_list, window);
04399         
04400         tmp = tmp->next;
04401       }
04402   }
04403 
04404   {
04405     GList *tmp;
04406     
04407     tmp = workspace->mru_list;
04408     while (tmp != NULL)
04409       {
04410         MetaWindow *window = tmp->data;
04411         
04412         if (window->minimized &&
04413             window->screen == screen &&
04414             IN_TAB_CHAIN (window, type))
04415           tab_list = g_list_prepend (tab_list, window);
04416         
04417         tmp = tmp->next;
04418       }
04419   }
04420 
04421   tab_list = g_list_reverse (tab_list);
04422 
04423   {
04424     GSList *tmp;
04425     MetaWindow *l_window;
04426 
04427     tmp = meta_display_list_windows (display);
04428 
04429     /* Go through all windows */
04430     while (tmp != NULL)
04431       {
04432         l_window=tmp->data;
04433 
04434         /* Check to see if it demands attention */
04435         if (l_window->wm_state_demands_attention && 
04436             l_window->workspace!=workspace) 
04437           {
04438             /* if it does, add it to the popup */
04439             tab_list = g_list_prepend (tab_list, l_window);
04440           }
04441 
04442         tmp = tmp->next;
04443       } /* End while tmp!=NULL */
04444   }
04445   
04446   return tab_list;
04447 }
04448 
04449 MetaWindow*
04450 meta_display_get_tab_next (MetaDisplay   *display,
04451                            MetaTabList    type,
04452                            MetaScreen    *screen,
04453                            MetaWorkspace *workspace,
04454                            MetaWindow    *window,
04455                            gboolean       backward)
04456 {
04457   gboolean skip;
04458   GList *tab_list;
04459   MetaWindow *ret;
04460   tab_list = meta_display_get_tab_list(display,
04461                                        type,
04462                                        screen,
04463                                        workspace);
04464 
04465   if (tab_list == NULL)
04466     return NULL;
04467   
04468   if (window != NULL)
04469     {
04470       g_assert (window->display == display);
04471       
04472       if (backward)
04473         ret = find_tab_backward (display, type, screen, workspace,
04474                                  g_list_find (tab_list,
04475                                               window),
04476                                  TRUE);
04477       else
04478         ret = find_tab_forward (display, type, screen, workspace,
04479                                 g_list_find (tab_list,
04480                                              window),
04481                                 TRUE);
04482     }
04483   else
04484     {
04485       skip = display->focus_window != NULL && 
04486              IN_TAB_CHAIN (display->focus_window, type);
04487       if (backward)
04488         ret = find_tab_backward (display, type, screen, workspace,
04489                                  tab_list, skip);
04490       else
04491         ret = find_tab_forward (display, type, screen, workspace,
04492                                 tab_list, skip);
04493     }
04494 
04495   g_list_free (tab_list);
04496   return ret;
04497 }
04498 
04499 MetaWindow*
04500 meta_display_get_tab_current (MetaDisplay   *display,
04501                               MetaTabList    type,
04502                               MetaScreen    *screen,
04503                               MetaWorkspace *workspace)
04504 {
04505   MetaWindow *window;
04506 
04507   window = display->focus_window;
04508   
04509   if (window != NULL &&
04510       window->screen == screen &&
04511       IN_TAB_CHAIN (window, type) &&
04512       (workspace == NULL ||
04513        meta_window_located_on_workspace (window, workspace)))
04514     return window;
04515   else
04516     return NULL;
04517 }
04518 
04519 int
04520 meta_resize_gravity_from_grab_op (MetaGrabOp op)
04521 {
04522   int gravity;
04523   
04524   gravity = -1;
04525   switch (op)
04526     {
04527     case META_GRAB_OP_RESIZING_SE:
04528     case META_GRAB_OP_KEYBOARD_RESIZING_SE:
04529       gravity = NorthWestGravity;
04530       break;
04531     case META_GRAB_OP_KEYBOARD_RESIZING_S:
04532     case META_GRAB_OP_RESIZING_S:
04533       gravity = NorthGravity;
04534       break;
04535     case META_GRAB_OP_KEYBOARD_RESIZING_SW:
04536     case META_GRAB_OP_RESIZING_SW:
04537       gravity = NorthEastGravity;
04538       break;
04539     case META_GRAB_OP_KEYBOARD_RESIZING_N:
04540     case META_GRAB_OP_RESIZING_N:
04541       gravity = SouthGravity;
04542       break;
04543     case META_GRAB_OP_KEYBOARD_RESIZING_NE:
04544     case META_GRAB_OP_RESIZING_NE:
04545       gravity = SouthWestGravity;
04546       break;
04547     case META_GRAB_OP_KEYBOARD_RESIZING_NW:
04548     case META_GRAB_OP_RESIZING_NW:
04549       gravity = SouthEastGravity;
04550       break;
04551     case META_GRAB_OP_KEYBOARD_RESIZING_E:
04552     case META_GRAB_OP_RESIZING_E:
04553       gravity = WestGravity;
04554       break;
04555     case META_GRAB_OP_KEYBOARD_RESIZING_W:
04556     case META_GRAB_OP_RESIZING_W:
04557       gravity = EastGravity;
04558       break;
04559     case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
04560       gravity = CenterGravity;
04561       break;
04562     default:
04563       break;
04564     }
04565 
04566   return gravity;
04567 }
04568 
04569 static MetaScreen*
04570 find_screen_for_selection (MetaDisplay *display,
04571                            Window       owner,
04572                            Atom         selection)
04573 {  
04574   GSList *tmp;  
04575   
04576   tmp = display->screens;
04577   while (tmp != NULL)
04578     {
04579       MetaScreen *screen = tmp->data;
04580       
04581       if (screen->wm_sn_selection_window == owner &&
04582           screen->wm_sn_atom == selection)
04583         return screen;
04584   
04585       tmp = tmp->next;
04586     }
04587 
04588   return NULL;
04589 }
04590 
04591 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
04592 static gboolean
04593 convert_property (MetaDisplay *display,
04594                   MetaScreen  *screen,
04595                   Window       w,
04596                   Atom         target,
04597                   Atom         property)
04598 {
04599 #define N_TARGETS 4
04600   Atom conversion_targets[N_TARGETS];
04601   long icccm_version[] = { 2, 0 };
04602 
04603   conversion_targets[0] = display->atom_TARGETS;
04604   conversion_targets[1] = display->atom_MULTIPLE;
04605   conversion_targets[2] = display->atom_TIMESTAMP;
04606   conversion_targets[3] = display->atom_VERSION;
04607 
04608   meta_error_trap_push_with_return (display);
04609   if (target == display->atom_TARGETS)
04610     XChangeProperty (display->xdisplay, w, property,
04611                      XA_ATOM, 32, PropModeReplace,
04612                      (unsigned char *)conversion_targets, N_TARGETS);
04613   else if (target == display->atom_TIMESTAMP)
04614     XChangeProperty (display->xdisplay, w, property,
04615                      XA_INTEGER, 32, PropModeReplace,
04616                      (unsigned char *)&screen->wm_sn_timestamp, 1);
04617   else if (target == display->atom_VERSION)
04618     XChangeProperty (display->xdisplay, w, property,
04619                      XA_INTEGER, 32, PropModeReplace,
04620                      (unsigned char *)icccm_version, 2);
04621   else
04622     {
04623       meta_error_trap_pop_with_return (display, FALSE);
04624       return FALSE;
04625     }
04626   
04627   if (meta_error_trap_pop_with_return (display, FALSE) != Success)
04628     return FALSE;
04629 
04630   /* Be sure the PropertyNotify has arrived so we
04631    * can send SelectionNotify
04632    */
04633   /* FIXME the error trap pop synced anyway, right? */
04634   meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC);
04635   XSync (display->xdisplay, False);
04636 
04637   return TRUE;
04638 }
04639 
04640 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
04641 static void
04642 process_selection_request (MetaDisplay   *display,
04643                            XEvent        *event)
04644 {
04645   XSelectionEvent reply;
04646   MetaScreen *screen;
04647 
04648   screen = find_screen_for_selection (display,
04649                                       event->xselectionrequest.owner,
04650                                       event->xselectionrequest.selection);
04651 
04652   if (screen == NULL)
04653     {
04654       char *str;
04655       
04656       meta_error_trap_push (display);
04657       str = XGetAtomName (display->xdisplay,
04658                           event->xselectionrequest.selection);
04659       meta_error_trap_pop (display, TRUE);
04660       
04661       meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
04662                     str ? str : "(bad atom)", event->xselectionrequest.owner);
04663       
04664       meta_XFree (str);
04665 
04666       return;
04667     }
04668   
04669   reply.type = SelectionNotify;
04670   reply.display = display->xdisplay;
04671   reply.requestor = event->xselectionrequest.requestor;
04672   reply.selection = event->xselectionrequest.selection;
04673   reply.target = event->xselectionrequest.target;
04674   reply.property = None;
04675   reply.time = event->xselectionrequest.time;
04676 
04677   if (event->xselectionrequest.target == display->atom_MULTIPLE)
04678     {
04679       if (event->xselectionrequest.property != None)
04680         {
04681           Atom type, *adata;
04682           int i, format;
04683           unsigned long num, rest;
04684           unsigned char *data;
04685 
04686           meta_error_trap_push_with_return (display);
04687           if (XGetWindowProperty (display->xdisplay,
04688                                   event->xselectionrequest.requestor,
04689                                   event->xselectionrequest.property, 0, 256, False,
04690                                   display->atom_ATOM_PAIR,
04691                                   &type, &format, &num, &rest, &data) != Success)
04692             {
04693               meta_error_trap_pop_with_return (display, TRUE);
04694               return;
04695             }
04696           
04697           if (meta_error_trap_pop_with_return (display, TRUE) == Success)
04698             {              
04699               /* FIXME: to be 100% correct, should deal with rest > 0,
04700                * but since we have 4 possible targets, we will hardly ever
04701                * meet multiple requests with a length > 8
04702                */
04703               adata = (Atom*)data;
04704               i = 0;
04705               while (i < (int) num)
04706                 {
04707                   if (!convert_property (display, screen,
04708                                          event->xselectionrequest.requestor,
04709                                          adata[i], adata[i+1]))
04710                     adata[i+1] = None;
04711                   i += 2;
04712                 }
04713 
04714               meta_error_trap_push (display);
04715               XChangeProperty (display->xdisplay,
04716                                event->xselectionrequest.requestor,
04717                                event->xselectionrequest.property,
04718                                display->atom_ATOM_PAIR,
04719                                32, PropModeReplace, data, num);
04720               meta_error_trap_pop (display, FALSE);
04721               meta_XFree (data);
04722             }
04723         }
04724     }
04725   else
04726     {
04727       if (event->xselectionrequest.property == None)
04728         event->xselectionrequest.property = event->xselectionrequest.target;
04729       
04730       if (convert_property (display, screen,
04731                             event->xselectionrequest.requestor,
04732                             event->xselectionrequest.target,
04733                             event->xselectionrequest.property))
04734         reply.property = event->xselectionrequest.property;
04735     }
04736 
04737   XSendEvent (display->xdisplay,
04738               event->xselectionrequest.requestor,
04739               False, 0L, (XEvent*)&reply);
04740 
04741   meta_verbose ("Handled selection request\n");
04742 }
04743 
04744 static void
04745 process_selection_clear (MetaDisplay   *display,
04746                          XEvent        *event)
04747 {
04748   /* We need to unmanage the screen on which we lost the selection */
04749   MetaScreen *screen;
04750 
04751   screen = find_screen_for_selection (display,
04752                                       event->xselectionclear.window,
04753                                       event->xselectionclear.selection);
04754   
04755 
04756   if (screen != NULL)
04757     {
04758       meta_verbose ("Got selection clear for screen %d on display %s\n",
04759                     screen->number, display->name);
04760       
04761       meta_display_unmanage_screen (display, 
04762                                     screen,
04763                                     event->xselectionclear.time);
04764 
04765       /* display and screen may both be invalid memory... */
04766       
04767       return;
04768     }
04769 
04770   {
04771     char *str;
04772             
04773     meta_error_trap_push (display);
04774     str = XGetAtomName (display->xdisplay,
04775                         event->xselectionclear.selection);
04776     meta_error_trap_pop (display, TRUE);
04777 
04778     meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
04779                   str ? str : "(bad atom)", event->xselectionclear.window);
04780 
04781     meta_XFree (str);
04782   }
04783 }
04784 
04785 void
04786 meta_display_unmanage_screen (MetaDisplay *display,
04787                               MetaScreen  *screen,
04788                               guint32      timestamp)
04789 {
04790   meta_verbose ("Unmanaging screen %d on display %s\n",
04791                 screen->number, display->name);
04792   
04793   g_return_if_fail (g_slist_find (display->screens, screen) != NULL);
04794   
04795   meta_screen_free (screen, timestamp);
04796   display->screens = g_slist_remove (display->screens, screen);
04797 
04798   if (display->screens == NULL)
04799     meta_display_close (display, timestamp);
04800 }
04801 
04802 void
04803 meta_display_unmanage_windows_for_screen (MetaDisplay *display,
04804                                           MetaScreen  *screen,
04805                                           guint32      timestamp)
04806 {
04807   GSList *tmp;
04808   GSList *winlist;
04809 
04810   winlist = meta_display_list_windows (display);
04811   winlist = g_slist_sort (winlist, meta_display_stack_cmp);
04812 
04813   /* Unmanage all windows */
04814   tmp = winlist;
04815   while (tmp != NULL)
04816     {
04817       meta_window_free (tmp->data, timestamp);
04818       
04819       tmp = tmp->next;
04820     }
04821   g_slist_free (winlist);
04822 }
04823 
04824 int
04825 meta_display_stack_cmp (const void *a,
04826                         const void *b)
04827 {
04828   MetaWindow *aw = (void*) a;
04829   MetaWindow *bw = (void*) b;
04830 
04831   if (aw->screen == bw->screen)
04832     return meta_stack_windows_cmp (aw->screen->stack, aw, bw);
04833   /* Then assume screens are stacked by number */
04834   else if (aw->screen->number < bw->screen->number)
04835     return -1;
04836   else if (aw->screen->number > bw->screen->number)
04837     return 1;
04838   else
04839     return 0; /* not reached in theory, if windows on same display */
04840 }
04841 
04842 void
04843 meta_display_devirtualize_modifiers (MetaDisplay        *display,
04844                                      MetaVirtualModifier modifiers,
04845                                      unsigned int       *mask)
04846 {
04847   *mask = 0;
04848   
04849   if (modifiers & META_VIRTUAL_SHIFT_MASK)
04850     *mask |= ShiftMask;
04851   if (modifiers & META_VIRTUAL_CONTROL_MASK)
04852     *mask |= ControlMask;
04853   if (modifiers & META_VIRTUAL_ALT_MASK)
04854     *mask |= Mod1Mask;
04855   if (modifiers & META_VIRTUAL_META_MASK)
04856     *mask |= display->meta_mask;
04857   if (modifiers & META_VIRTUAL_HYPER_MASK)
04858     *mask |= display->hyper_mask;
04859   if (modifiers & META_VIRTUAL_SUPER_MASK)
04860     *mask |= display->super_mask;
04861   if (modifiers & META_VIRTUAL_MOD2_MASK)
04862     *mask |= Mod2Mask;
04863   if (modifiers & META_VIRTUAL_MOD3_MASK)
04864     *mask |= Mod3Mask;
04865   if (modifiers & META_VIRTUAL_MOD4_MASK)
04866     *mask |= Mod4Mask;
04867   if (modifiers & META_VIRTUAL_MOD5_MASK)
04868     *mask |= Mod5Mask;  
04869 }
04870 
04871 static void
04872 update_window_grab_modifiers (MetaDisplay *display)
04873      
04874 {
04875   MetaVirtualModifier virtual_mods;
04876   unsigned int mods;
04877     
04878   virtual_mods = meta_prefs_get_mouse_button_mods ();
04879   meta_display_devirtualize_modifiers (display, virtual_mods,
04880                                        &mods);
04881     
04882   display->window_grab_modifiers = mods;
04883 }
04884 
04885 static void
04886 prefs_changed_callback (MetaPreference pref,
04887                         void          *data)
04888 {
04889   MetaDisplay *display = data;
04890   
04891   /* It may not be obvious why we regrab on focus mode
04892    * change; it's because we handle focus clicks a
04893    * bit differently for the different focus modes.
04894    */
04895   if (pref == META_PREF_MOUSE_BUTTON_MODS ||
04896       pref == META_PREF_FOCUS_MODE)
04897     {
04898       MetaDisplay *display = data;
04899       GSList *windows;
04900       GSList *tmp;
04901       
04902       windows = meta_display_list_windows (display);
04903       
04904       /* Ungrab all */
04905       tmp = windows;
04906       while (tmp != NULL)
04907         {
04908           MetaWindow *w = tmp->data;
04909           meta_display_ungrab_window_buttons (display, w->xwindow);
04910           meta_display_ungrab_focus_window_button (display, w);
04911           tmp = tmp->next;
04912         }
04913 
04914       /* change our modifier */
04915       if (pref == META_PREF_MOUSE_BUTTON_MODS)
04916         update_window_grab_modifiers (display);
04917 
04918       /* Grab all */
04919       tmp = windows;
04920       while (tmp != NULL)
04921         {
04922           MetaWindow *w = tmp->data;
04923           meta_display_grab_focus_window_button (display, w);
04924           meta_display_grab_window_buttons (display, w->xwindow);
04925           tmp = tmp->next;
04926         }
04927 
04928       g_slist_free (windows);
04929     }
04930   else if (pref == META_PREF_AUDIBLE_BELL)
04931     {
04932       meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
04933     }
04934   else if (pref == META_PREF_COMPOSITING_MANAGER)
04935     {
04936       gboolean cm = meta_prefs_get_compositing_manager ();
04937 
04938       if (cm)
04939         enable_compositor (display, TRUE);
04940       else
04941         disable_compositor (display);
04942     }
04943 }
04944 
04945 void
04946 meta_display_increment_focus_sentinel (MetaDisplay *display)
04947 {
04948   unsigned long data[1];
04949 
04950   data[0] = meta_display_get_current_time (display);
04951   
04952   XChangeProperty (display->xdisplay,
04953                    ((MetaScreen*) display->screens->data)->xroot,
04954                    display->atom__METACITY_SENTINEL,
04955                    XA_CARDINAL,
04956                    32, PropModeReplace, (guchar*) data, 1);
04957   
04958   display->sentinel_counter += 1;
04959 }
04960 
04961 void
04962 meta_display_decrement_focus_sentinel (MetaDisplay *display)
04963 {
04964   display->sentinel_counter -= 1;
04965 
04966   if (display->sentinel_counter < 0)
04967     display->sentinel_counter = 0;
04968 }
04969 
04970 gboolean
04971 meta_display_focus_sentinel_clear (MetaDisplay *display)
04972 {
04973   return (display->sentinel_counter == 0);
04974 }
04975 
04976 static void
04977 sanity_check_timestamps (MetaDisplay *display,
04978                          guint32      timestamp)
04979 {
04980   if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time))
04981     {
04982       meta_warning ("last_focus_time (%u) is greater than comparison "
04983                     "timestamp (%u).  This most likely represents a buggy "
04984                     "client sending inaccurate timestamps in messages such as "
04985                     "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
04986                     display->last_focus_time, timestamp);
04987       display->last_focus_time = timestamp;
04988     }
04989   if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time))
04990     {
04991       GSList *windows;
04992       GSList *tmp;
04993 
04994       meta_warning ("last_user_time (%u) is greater than comparison "
04995                     "timestamp (%u).  This most likely represents a buggy "
04996                     "client sending inaccurate timestamps in messages such as "
04997                     "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
04998                     display->last_user_time, timestamp);
04999       display->last_user_time = timestamp;
05000 
05001       windows = meta_display_list_windows (display);
05002       tmp = windows;
05003       while (tmp != NULL)
05004         {
05005           MetaWindow *window = tmp->data;
05006           
05007           if (XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time))
05008             {
05009               meta_warning ("%s appears to be one of the offending windows "
05010                             "with a timestamp of %u.  Working around...\n",
05011                             window->desc, window->net_wm_user_time);
05012               window->net_wm_user_time = timestamp;
05013             }
05014           
05015           tmp = tmp->next;
05016         }
05017 
05018       g_slist_free (windows);
05019     }
05020 }
05021 
05022 static gboolean
05023 timestamp_too_old (MetaDisplay *display,
05024                    MetaWindow  *window,
05025                    guint32     *timestamp)
05026 {
05027   /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow
05028    * us to sanity check the timestamp here and ensure it doesn't correspond to
05029    * a future time (though we would want to rename to 
05030    * timestamp_too_old_or_in_future).
05031    */
05032 
05033   if (*timestamp == CurrentTime)
05034     {
05035       meta_warning ("Got a request to focus %s with a timestamp of 0.  This "
05036                     "shouldn't happen!\n",
05037                     window ? window->desc : "the no_focus_window");
05038       meta_print_backtrace ();
05039       *timestamp = meta_display_get_current_time_roundtrip (display);
05040       return FALSE;
05041     }
05042   else if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_focus_time))
05043     {
05044       if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time))
05045         {
05046           meta_topic (META_DEBUG_FOCUS,
05047                       "Ignoring focus request for %s since %u "
05048                       "is less than %u and %u.\n",
05049                       window ? window->desc : "the no_focus_window",
05050                       *timestamp,
05051                       display->last_user_time,
05052                       display->last_focus_time);
05053           return TRUE;
05054         }
05055       else
05056         {
05057           meta_topic (META_DEBUG_FOCUS,
05058                       "Received focus request for %s which is newer than most "
05059                       "recent user_time, but less recent than "
05060                       "last_focus_time (%u < %u < %u); adjusting "
05061                       "accordingly.  (See bug 167358)\n",
05062                       window ? window->desc : "the no_focus_window",
05063                       display->last_user_time,
05064                       *timestamp,
05065                       display->last_focus_time);
05066           *timestamp = display->last_focus_time;
05067           return FALSE;
05068         }
05069     }
05070 
05071   return FALSE;
05072 }
05073 
05074 void
05075 meta_display_set_input_focus_window (MetaDisplay *display, 
05076                                      MetaWindow  *window,
05077                                      gboolean     focus_frame,
05078                                      guint32      timestamp)
05079 {
05080   if (timestamp_too_old (display, window, &timestamp))
05081     return;
05082 
05083   meta_error_trap_push (display);
05084   XSetInputFocus (display->xdisplay,
05085                   focus_frame ? window->frame->xwindow : window->xwindow,
05086                   RevertToPointerRoot,
05087                   timestamp);
05088   meta_error_trap_pop (display, FALSE);
05089 
05090   display->expected_focus_window = window;
05091   display->last_focus_time = timestamp;
05092   display->active_screen = window->screen;
05093 
05094   if (window != display->autoraise_window)
05095     meta_display_remove_autoraise_callback (window->display);
05096 }
05097 
05098 void
05099 meta_display_focus_the_no_focus_window (MetaDisplay *display, 
05100                                         MetaScreen  *screen,
05101                                         guint32      timestamp)
05102 {
05103   if (timestamp_too_old (display, NULL, &timestamp))
05104     return;
05105 
05106   XSetInputFocus (display->xdisplay,
05107                   screen->no_focus_window,
05108                   RevertToPointerRoot,
05109                   timestamp);
05110   display->expected_focus_window = NULL;
05111   display->last_focus_time = timestamp;
05112   display->active_screen = screen;
05113 
05114   meta_display_remove_autoraise_callback (display);
05115 }
05116 
05117 void
05118 meta_display_remove_autoraise_callback (MetaDisplay *display)
05119 {
05120   if (display->autoraise_timeout_id != 0)
05121     {
05122       g_source_remove (display->autoraise_timeout_id);
05123       display->autoraise_timeout_id = 0;
05124       display->autoraise_window = NULL;
05125     }
05126 }
05127 
05128 #ifdef HAVE_COMPOSITE_EXTENSIONS
05129 void
05130 meta_display_get_compositor_version (MetaDisplay *display,
05131                                      int         *major,
05132                                      int         *minor)
05133 {
05134   *major = display->composite_major_version;
05135   *minor = display->composite_minor_version;
05136 }
05137 #endif
05138 
05139 Display *
05140 meta_display_get_xdisplay (MetaDisplay *display)
05141 {
05142   return display->xdisplay;
05143 }
05144 
05145 MetaCompositor *
05146 meta_display_get_compositor (MetaDisplay *display)
05147 {
05148   return display->compositor;
05149 }
05150 
05151 GSList *
05152 meta_display_get_screens (MetaDisplay *display)
05153 {
05154   return display->screens;
05155 }
05156 
05157 gboolean
05158 meta_display_has_shape (MetaDisplay *display)
05159 {
05160   return META_DISPLAY_HAS_SHAPE (display);
05161 }
05162 
05163 MetaWindow *
05164 meta_display_get_focus_window (MetaDisplay *display)
05165 {
05166   return display->focus_window;
05167 }
05168 
05169 #ifdef HAVE_COMPOSITE_EXTENSIONS
05170 int 
05171 meta_display_get_damage_event_base (MetaDisplay *display)
05172 {
05173   return display->damage_event_base;
05174 }
05175 #endif
05176 
05177 #ifdef HAVE_COMPOSITE_EXTENSIONS
05178 #ifdef HAVE_SHAPE
05179 int
05180 meta_display_get_shape_event_base (MetaDisplay *display)
05181 {
05182   return display->shape_event_base;
05183 }
05184 #endif
05185 #endif

Generated on Sat Aug 23 22:04:16 2008 for metacity by  doxygen 1.5.5