diff options
Diffstat (limited to 'src/core/display.c')
-rw-r--r-- | src/core/display.c | 5185 |
1 files changed, 0 insertions, 5185 deletions
diff --git a/src/core/display.c b/src/core/display.c deleted file mode 100644 index d6c44d10..00000000 --- a/src/core/display.c +++ /dev/null @@ -1,5185 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity X display handler */ - -/* - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. - * Copyright (C) 2003, 2004 Rob Adams - * Copyright (C) 2004-2006 Elijah Newren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -/** - * \file display.c Handles operations on an X display. - * - * The display is represented as a MetaDisplay struct. - */ - -#include <config.h> -#include "display-private.h" -#include "util.h" -#include "main.h" -#include "screen-private.h" -#include "window-private.h" -#include "window-props.h" -#include "group-props.h" -#include "frame-private.h" -#include "errors.h" -#include "keybindings.h" -#include "prefs.h" -#include "resizepopup.h" -#include "xprops.h" -#include "workspace.h" -#include "bell.h" -#include "effects.h" -#include "compositor.h" -#include <X11/Xatom.h> -#include <X11/cursorfont.h> -#ifdef HAVE_SOLARIS_XINERAMA -#include <X11/extensions/xinerama.h> -#endif -#ifdef HAVE_XFREE_XINERAMA -#include <X11/extensions/Xinerama.h> -#endif -#ifdef HAVE_RANDR -#include <X11/extensions/Xrandr.h> -#endif -#ifdef HAVE_SHAPE -#include <X11/extensions/shape.h> -#endif -#ifdef HAVE_RENDER -#include <X11/extensions/Xrender.h> -#endif -#ifdef HAVE_XKB -#include <X11/XKBlib.h> -#endif -#ifdef HAVE_XCURSOR -#include <X11/Xcursor/Xcursor.h> -#endif -#ifdef HAVE_COMPOSITE_EXTENSIONS -#include <X11/extensions/Xcomposite.h> -#include <X11/extensions/Xdamage.h> -#include <X11/extensions/Xfixes.h> -#endif -#include <string.h> - -#define GRAB_OP_IS_WINDOW_SWITCH(g) \ - (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \ - g == META_GRAB_OP_KEYBOARD_TABBING_DOCK || \ - g == META_GRAB_OP_KEYBOARD_TABBING_GROUP || \ - g == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL || \ - g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK || \ - g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP) - -/** - * \defgroup pings Pings - * - * Sometimes we want to see whether a window is responding, - * so we send it a "ping" message and see whether it sends us back a "pong" - * message within a reasonable time. Here we have a system which lets us - * nominate one function to be called if we get the pong in time and another - * function if we don't. The system is rather more complicated than it needs - * to be, since we only ever use it to destroy windows which are asked to - * close themselves and don't do so within a reasonable amount of time, and - * therefore we always use the same callbacks. It's possible that we might - * use it for other things in future, or on the other hand we might decide - * that we're never going to do so and simplify it a bit. - */ - -/** - * Describes a ping on a window. When we send a ping to a window, we build - * one of these structs, and it eventually gets passed to the timeout function - * or to the function which handles the response from the window. If the window - * does or doesn't respond to the ping, we use this information to deal with - * these facts; we have a handler function for each. - * - * \ingroup pings - */ -typedef struct -{ - MetaDisplay *display; - Window xwindow; - guint32 timestamp; - MetaWindowPingFunc ping_reply_func; - MetaWindowPingFunc ping_timeout_func; - void *user_data; - guint ping_timeout_id; -} MetaPingData; - -typedef struct -{ - MetaDisplay *display; - Window xwindow; -} MetaAutoRaiseData; - -/** - * The display we're managing. This is a singleton object. (Historically, - * this was a list of displays, but there was never any way to add more - * than one element to it.) The goofy name is because we don't want it - * to shadow the parameter in its object methods. - */ -static MetaDisplay *the_display = NULL; - -static void meta_spew_event (MetaDisplay *display, - XEvent *event); - -static gboolean event_callback (XEvent *event, - gpointer data); -static Window event_get_modified_window (MetaDisplay *display, - XEvent *event); -static guint32 event_get_time (MetaDisplay *display, - XEvent *event); -static void process_request_frame_extents (MetaDisplay *display, - XEvent *event); -static void process_pong_message (MetaDisplay *display, - XEvent *event); -static void process_selection_request (MetaDisplay *display, - XEvent *event); -static void process_selection_clear (MetaDisplay *display, - XEvent *event); - -static void update_window_grab_modifiers (MetaDisplay *display); - -static void prefs_changed_callback (MetaPreference pref, - void *data); - -static void sanity_check_timestamps (MetaDisplay *display, - guint32 known_good_timestamp); - -MetaGroup* get_focussed_group (MetaDisplay *display); - -/** - * Destructor for MetaPingData structs. Will destroy the - * event source for the struct as well. - * - * \ingroup pings - */ -static void -ping_data_free (MetaPingData *ping_data) -{ - /* Remove the timeout */ - if (ping_data->ping_timeout_id != 0) - g_source_remove (ping_data->ping_timeout_id); - - g_free (ping_data); -} - -/** - * Frees every pending ping structure for the given X window on the - * given display. This means that we also destroy the timeouts. - * - * \param display The display the window appears on - * \param xwindow The X ID of the window whose pings we should remove - * - * \ingroup pings - * - */ -static void -remove_pending_pings_for_window (MetaDisplay *display, Window xwindow) -{ - GSList *tmp; - GSList *dead; - - /* could obviously be more efficient, don't care */ - - /* build list to be removed */ - dead = NULL; - for (tmp = display->pending_pings; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - if (ping_data->xwindow == xwindow) - dead = g_slist_prepend (dead, ping_data); - } - - /* remove what we found */ - for (tmp = dead; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - display->pending_pings = g_slist_remove (display->pending_pings, ping_data); - ping_data_free (ping_data); - } - - g_slist_free (dead); -} - - -#ifdef HAVE_STARTUP_NOTIFICATION -static void -sn_error_trap_push (SnDisplay *sn_display, - Display *xdisplay) -{ - MetaDisplay *display; - display = meta_display_for_x_display (xdisplay); - if (display != NULL) - meta_error_trap_push (display); -} - -static void -sn_error_trap_pop (SnDisplay *sn_display, - Display *xdisplay) -{ - MetaDisplay *display; - display = meta_display_for_x_display (xdisplay); - if (display != NULL) - meta_error_trap_pop (display, FALSE); -} -#endif - -static void -enable_compositor (MetaDisplay *display, - gboolean composite_windows) -{ - GSList *list; - - if (!META_DISPLAY_HAS_COMPOSITE (display) || - !META_DISPLAY_HAS_DAMAGE (display) || - !META_DISPLAY_HAS_XFIXES (display) || - !META_DISPLAY_HAS_RENDER (display)) - { - meta_warning (_("Missing %s extension required for compositing"), - !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : - !META_DISPLAY_HAS_DAMAGE (display) ? "damage" : - !META_DISPLAY_HAS_XFIXES (display) ? "xfixes" : "render"); - return; - } - - if (!display->compositor) - display->compositor = meta_compositor_new (display); - - if (!display->compositor) - return; - - for (list = display->screens; list != NULL; list = list->next) - { - MetaScreen *screen = list->data; - - meta_compositor_manage_screen (screen->display->compositor, - screen); - - if (composite_windows) - meta_screen_composite_all_windows (screen); - } -} - -static void -disable_compositor (MetaDisplay *display) -{ - GSList *list; - - if (!display->compositor) - return; - - for (list = display->screens; list != NULL; list = list->next) - { - MetaScreen *screen = list->data; - - meta_compositor_unmanage_screen (screen->display->compositor, - screen); - } - - meta_compositor_destroy (display->compositor); - display->compositor = NULL; -} - -/** - * Opens a new display, sets it up, initialises all the X extensions - * we will need, and adds it to the list of displays. - * - * \return True if the display was opened successfully, and False - * otherwise-- that is, if the display doesn't exist or it already - * has a window manager. - * - * \ingroup main - */ -gboolean -meta_display_open (void) -{ - Display *xdisplay; - GSList *screens; - GSList *tmp; - int i; - guint32 timestamp; - - /* A list of all atom names, so that we can intern them in one go. */ - char *atom_names[] = { -#define item(x) #x, -#include "atomnames.h" -#undef item - }; - Atom atoms[G_N_ELEMENTS(atom_names)]; - - meta_verbose ("Opening display '%s'\n", XDisplayName (NULL)); - - xdisplay = meta_ui_get_display (); - - if (xdisplay == NULL) - { - meta_warning (_("Failed to open X Window System display '%s'\n"), - XDisplayName (NULL)); - return FALSE; - } - - if (meta_is_syncing ()) - XSynchronize (xdisplay, True); - - g_assert (the_display == NULL); - the_display = g_new (MetaDisplay, 1); - - the_display->closing = 0; - - /* here we use XDisplayName which is what the user - * probably put in, vs. DisplayString(display) which is - * canonicalized by XOpenDisplay() - */ - the_display->name = g_strdup (XDisplayName (NULL)); - the_display->xdisplay = xdisplay; - the_display->error_trap_synced_at_last_pop = TRUE; - the_display->error_traps = 0; - the_display->error_trap_handler = NULL; - the_display->server_grab_count = 0; - the_display->display_opening = TRUE; - - the_display->pending_pings = NULL; - the_display->autoraise_timeout_id = 0; - the_display->autoraise_window = NULL; - the_display->focus_window = NULL; - the_display->expected_focus_window = NULL; - the_display->grab_old_window_stacking = NULL; - - the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */ - the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a - terminal has the focus */ - -#ifdef HAVE_XSYNC - the_display->grab_sync_request_alarm = None; -#endif - - /* FIXME copy the checks from GDK probably */ - the_display->static_gravity_works = g_getenv ("METACITY_USE_STATIC_GRAVITY") != NULL; - - meta_bell_init (the_display); - - meta_display_init_keys (the_display); - - update_window_grab_modifiers (the_display); - - meta_prefs_add_listener (prefs_changed_callback, the_display); - - meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names)); - XInternAtoms (the_display->xdisplay, atom_names, G_N_ELEMENTS (atom_names), - False, atoms); - { - int i = 0; -#define item(x) the_display->atom_##x = atoms[i++]; -#include "atomnames.h" -#undef item - } - - the_display->prop_hooks = NULL; - meta_display_init_window_prop_hooks (the_display); - the_display->group_prop_hooks = NULL; - meta_display_init_group_prop_hooks (the_display); - - /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK, - * created in screen_new - */ - the_display->leader_window = None; - the_display->timestamp_pinging_window = None; - - the_display->xinerama_cache_invalidated = TRUE; - - the_display->groups_by_leader = NULL; - - the_display->window_with_menu = NULL; - the_display->window_menu = NULL; - - the_display->screens = NULL; - the_display->active_screen = NULL; - -#ifdef HAVE_STARTUP_NOTIFICATION - the_display->sn_display = sn_display_new (the_display->xdisplay, - sn_error_trap_push, - sn_error_trap_pop); -#endif - - the_display->events = NULL; - - /* Get events */ - meta_ui_add_event_func (the_display->xdisplay, - event_callback, - the_display); - - the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash, - meta_unsigned_long_equal); - - i = 0; - while (i < N_IGNORED_SERIALS) - { - the_display->ignored_serials[i] = 0; - ++i; - } - the_display->ungrab_should_not_cause_focus_window = None; - - the_display->current_time = CurrentTime; - the_display->sentinel_counter = 0; - - the_display->grab_resize_timeout_id = 0; - the_display->grab_have_keyboard = FALSE; - -#ifdef HAVE_XKB - the_display->last_bell_time = 0; -#endif - - the_display->grab_op = META_GRAB_OP_NONE; - the_display->grab_wireframe_active = FALSE; - the_display->grab_window = NULL; - the_display->grab_screen = NULL; - the_display->grab_resize_popup = NULL; - - the_display->grab_edge_resistance_data = NULL; - -#ifdef HAVE_XSYNC - { - int major, minor; - - the_display->have_xsync = FALSE; - - the_display->xsync_error_base = 0; - the_display->xsync_event_base = 0; - - /* I don't think we really have to fill these in */ - major = SYNC_MAJOR_VERSION; - minor = SYNC_MINOR_VERSION; - - if (!XSyncQueryExtension (the_display->xdisplay, - &the_display->xsync_event_base, - &the_display->xsync_error_base) || - !XSyncInitialize (the_display->xdisplay, - &major, &minor)) - { - the_display->xsync_error_base = 0; - the_display->xsync_event_base = 0; - } - else - the_display->have_xsync = TRUE; - - meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n", - major, minor, - the_display->xsync_error_base, - the_display->xsync_event_base); - } -#else /* HAVE_XSYNC */ - meta_verbose ("Not compiled with Xsync support\n"); -#endif /* !HAVE_XSYNC */ - - -#ifdef HAVE_SHAPE - { - the_display->have_shape = FALSE; - - the_display->shape_error_base = 0; - the_display->shape_event_base = 0; - - if (!XShapeQueryExtension (the_display->xdisplay, - &the_display->shape_event_base, - &the_display->shape_error_base)) - { - the_display->shape_error_base = 0; - the_display->shape_event_base = 0; - } - else - the_display->have_shape = TRUE; - - meta_verbose ("Attempted to init Shape, found error base %d event base %d\n", - the_display->shape_error_base, - the_display->shape_event_base); - } -#else /* HAVE_SHAPE */ - meta_verbose ("Not compiled with Shape support\n"); -#endif /* !HAVE_SHAPE */ - -#ifdef HAVE_RENDER - { - the_display->have_render = FALSE; - - the_display->render_error_base = 0; - the_display->render_event_base = 0; - - if (!XRenderQueryExtension (the_display->xdisplay, - &the_display->render_event_base, - &the_display->render_error_base)) - { - the_display->render_error_base = 0; - the_display->render_event_base = 0; - } - else - the_display->have_render = TRUE; - - meta_verbose ("Attempted to init Render, found error base %d event base %d\n", - the_display->render_error_base, - the_display->render_event_base); - } -#else /* HAVE_RENDER */ - meta_verbose ("Not compiled with Render support\n"); -#endif /* !HAVE_RENDER */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS - { - the_display->have_composite = FALSE; - - the_display->composite_error_base = 0; - the_display->composite_event_base = 0; - - if (!XCompositeQueryExtension (the_display->xdisplay, - &the_display->composite_event_base, - &the_display->composite_error_base)) - { - the_display->composite_error_base = 0; - the_display->composite_event_base = 0; - } - else - { - the_display->composite_major_version = 0; - the_display->composite_minor_version = 0; - if (XCompositeQueryVersion (the_display->xdisplay, - &the_display->composite_major_version, - &the_display->composite_minor_version)) - { - the_display->have_composite = TRUE; - } - else - { - the_display->composite_major_version = 0; - the_display->composite_minor_version = 0; - } - } - - meta_verbose ("Attempted to init Composite, found error base %d event base %d " - "extn ver %d %d\n", - the_display->composite_error_base, - the_display->composite_event_base, - the_display->composite_major_version, - the_display->composite_minor_version); - - the_display->have_damage = FALSE; - - the_display->damage_error_base = 0; - the_display->damage_event_base = 0; - - if (!XDamageQueryExtension (the_display->xdisplay, - &the_display->damage_event_base, - &the_display->damage_error_base)) - { - the_display->damage_error_base = 0; - the_display->damage_event_base = 0; - } - else - the_display->have_damage = TRUE; - - meta_verbose ("Attempted to init Damage, found error base %d event base %d\n", - the_display->damage_error_base, - the_display->damage_event_base); - - the_display->have_xfixes = FALSE; - - the_display->xfixes_error_base = 0; - the_display->xfixes_event_base = 0; - - if (!XFixesQueryExtension (the_display->xdisplay, - &the_display->xfixes_event_base, - &the_display->xfixes_error_base)) - { - the_display->xfixes_error_base = 0; - the_display->xfixes_event_base = 0; - } - else - the_display->have_xfixes = TRUE; - - meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n", - the_display->xfixes_error_base, - the_display->xfixes_event_base); - } -#else /* HAVE_COMPOSITE_EXTENSIONS */ - meta_verbose ("Not compiled with Composite support\n"); -#endif /* !HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_XCURSOR - { - XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ()); - XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ()); - } -#else /* HAVE_XCURSOR */ - meta_verbose ("Not compiled with Xcursor support\n"); -#endif /* !HAVE_XCURSOR */ - - /* Create the leader window here. Set its properties and - * use the timestamp from one of the PropertyNotify events - * that will follow. - */ - { - gulong data[1]; - XEvent event; - - /* We only care about the PropertyChangeMask in the next 30 or so lines of - * code. Note that gdk will at some point unset the PropertyChangeMask for - * this window, so we can't rely on it still being set later. See bug - * 354213 for details. - */ - the_display->leader_window = - meta_create_offscreen_window (the_display->xdisplay, - DefaultRootWindow (the_display->xdisplay), - PropertyChangeMask); - - meta_prop_set_utf8_string_hint (the_display, - the_display->leader_window, - the_display->atom__NET_WM_NAME, - "Metacity"); - - meta_prop_set_utf8_string_hint (the_display, - the_display->leader_window, - the_display->atom__METACITY_VERSION, - VERSION); - - data[0] = the_display->leader_window; - XChangeProperty (the_display->xdisplay, - the_display->leader_window, - the_display->atom__NET_SUPPORTING_WM_CHECK, - XA_WINDOW, - 32, PropModeReplace, (guchar*) data, 1); - - XWindowEvent (the_display->xdisplay, - the_display->leader_window, - PropertyChangeMask, - &event); - - timestamp = event.xproperty.time; - - /* Make it painfully clear that we can't rely on PropertyNotify events on - * this window, as per bug 354213. - */ - XSelectInput(the_display->xdisplay, - the_display->leader_window, - NoEventMask); - } - - /* Make a little window used only for pinging the server for timestamps; note - * that meta_create_offscreen_window already selects for PropertyChangeMask. - */ - the_display->timestamp_pinging_window = - meta_create_offscreen_window (the_display->xdisplay, - DefaultRootWindow (the_display->xdisplay), - PropertyChangeMask); - - the_display->last_focus_time = timestamp; - the_display->last_user_time = timestamp; - the_display->compositor = NULL; - - screens = NULL; - - i = 0; - while (i < ScreenCount (xdisplay)) - { - MetaScreen *screen; - - screen = meta_screen_new (the_display, i, timestamp); - - if (screen) - screens = g_slist_prepend (screens, screen); - ++i; - } - - the_display->screens = screens; - - if (screens == NULL) - { - /* This would typically happen because all the screens already - * have window managers. - */ - meta_display_close (the_display, timestamp); - return FALSE; - } - - /* We don't composite the windows here because they will be composited - faster with the call to meta_screen_manage_all_windows further down - the code */ - if (meta_prefs_get_compositing_manager ()) - enable_compositor (the_display, FALSE); - - meta_display_grab (the_display); - - /* Now manage all existing windows */ - tmp = the_display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_manage_all_windows (screen); - - tmp = tmp->next; - } - - { - Window focus; - int ret_to; - - /* kinda bogus because GetInputFocus has no possible errors */ - meta_error_trap_push (the_display); - - /* FIXME: This is totally broken; see comment 9 of bug 88194 about this */ - focus = None; - ret_to = RevertToPointerRoot; - XGetInputFocus (the_display->xdisplay, &focus, &ret_to); - - /* Force a new FocusIn (does this work?) */ - - /* Use the same timestamp that was passed to meta_screen_new(), - * as it is the most recent timestamp. - */ - if (focus == None || focus == PointerRoot) - /* Just focus the no_focus_window on the first screen */ - meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, - timestamp); - else - { - MetaWindow * window; - window = meta_display_lookup_x_window (the_display, focus); - if (window) - meta_display_set_input_focus_window (the_display, window, FALSE, timestamp); - else - /* Just focus the no_focus_window on the first screen */ - meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, - timestamp); - } - - meta_error_trap_pop (the_display, FALSE); - } - - meta_display_ungrab (the_display); - - /* Done opening new display */ - the_display->display_opening = FALSE; - - return TRUE; -} - -static void -listify_func (gpointer key, gpointer value, gpointer data) -{ - GSList **listp; - - listp = data; - *listp = g_slist_prepend (*listp, value); -} - -static gint -ptrcmp (gconstpointer a, gconstpointer b) -{ - if (a < b) - return -1; - else if (a > b) - return 1; - else - return 0; -} - -GSList* -meta_display_list_windows (MetaDisplay *display) -{ - GSList *winlist; - GSList *tmp; - GSList *prev; - - winlist = NULL; - g_hash_table_foreach (display->window_ids, - listify_func, - &winlist); - - /* Uniquify the list, since both frame windows and plain - * windows are in the hash - */ - winlist = g_slist_sort (winlist, ptrcmp); - - prev = NULL; - tmp = winlist; - while (tmp != NULL) - { - GSList *next; - - next = tmp->next; - - if (next && - next->data == tmp->data) - { - /* Delete tmp from list */ - - if (prev) - prev->next = next; - - if (tmp == winlist) - winlist = next; - - g_slist_free_1 (tmp); - - /* leave prev unchanged */ - } - else - { - prev = tmp; - } - - tmp = next; - } - - return winlist; -} - -void -meta_display_close (MetaDisplay *display, - guint32 timestamp) -{ - GSList *tmp; - - g_assert (display != NULL); - - if (display->closing != 0) - { - /* The display's already been closed. */ - return; - } - - if (display->error_traps > 0) - meta_bug ("Display closed with error traps pending\n"); - - display->closing += 1; - - meta_prefs_remove_listener (prefs_changed_callback, display); - - meta_display_remove_autoraise_callback (display); - - if (display->grab_old_window_stacking) - g_list_free (display->grab_old_window_stacking); - - /* Stop caring about events */ - meta_ui_remove_event_func (display->xdisplay, - event_callback, - display); - - /* Free all screens */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - meta_screen_free (screen, timestamp); - tmp = tmp->next; - } - - g_slist_free (display->screens); - display->screens = NULL; - -#ifdef HAVE_STARTUP_NOTIFICATION - if (display->sn_display) - { - sn_display_unref (display->sn_display); - display->sn_display = NULL; - } -#endif - - /* Must be after all calls to meta_window_free() since they - * unregister windows - */ - g_hash_table_destroy (display->window_ids); - - if (display->leader_window != None) - XDestroyWindow (display->xdisplay, display->leader_window); - - XFlush (display->xdisplay); - - meta_display_free_window_prop_hooks (display); - meta_display_free_group_prop_hooks (display); - - g_free (display->name); - - meta_display_shutdown_keys (display); - - if (display->compositor) - meta_compositor_destroy (display->compositor); - - g_free (display); - display = NULL; - - meta_quit (META_EXIT_SUCCESS); -} - -MetaScreen* -meta_display_screen_for_root (MetaDisplay *display, - Window xroot) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xroot == screen->xroot) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -MetaScreen* -meta_display_screen_for_xwindow (MetaDisplay *display, - Window xwindow) -{ - XWindowAttributes attr; - int result; - - meta_error_trap_push (display); - attr.screen = NULL; - result = XGetWindowAttributes (display->xdisplay, xwindow, &attr); - meta_error_trap_pop (display, TRUE); - - /* Note, XGetWindowAttributes is on all kinds of crack - * and returns 1 on success 0 on failure, rather than Success - * on success. - */ - if (result == 0 || attr.screen == NULL) - return NULL; - - return meta_display_screen_for_x_screen (display, attr.screen); -} - -MetaScreen* -meta_display_screen_for_x_screen (MetaDisplay *display, - Screen *xscreen) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xscreen == screen->xscreen) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -/* Grab/ungrab routines taken from fvwm */ -void -meta_display_grab (MetaDisplay *display) -{ - if (display->server_grab_count == 0) - { - XGrabServer (display->xdisplay); - } - display->server_grab_count += 1; - meta_verbose ("Grabbing display, grab count now %d\n", - display->server_grab_count); -} - -void -meta_display_ungrab (MetaDisplay *display) -{ - if (display->server_grab_count == 0) - meta_bug ("Ungrabbed non-grabbed server\n"); - - display->server_grab_count -= 1; - if (display->server_grab_count == 0) - { - /* FIXME we want to purge all pending "queued" stuff - * at this point, such as window hide/show - */ - XUngrabServer (display->xdisplay); - XFlush (display->xdisplay); - } - - meta_verbose ("Ungrabbing display, grab count now %d\n", - display->server_grab_count); -} - -/** - * Returns the singleton MetaDisplay if "xdisplay" matches the X display it's - * managing; otherwise gives a warning and returns NULL. When we were claiming - * to be able to manage multiple displays, this was supposed to find the - * display out of the list which matched that display. Now it's merely an - * extra sanity check. - * - * \param xdisplay An X display - * \return The singleton X display, or NULL if "xdisplay" isn't the one - * we're managing. - */ -MetaDisplay* -meta_display_for_x_display (Display *xdisplay) -{ - if (the_display->xdisplay == xdisplay) - return the_display; - - meta_warning ("Could not find display for X display %p, probably going to crash\n", - xdisplay); - - return NULL; -} - -/** - * Accessor for the singleton MetaDisplay. - * - * \return The only MetaDisplay there is. This can be NULL, but only - * during startup. - */ -MetaDisplay* -meta_get_display (void) -{ - return the_display; -} - -#ifdef WITH_VERBOSE_MODE -static gboolean dump_events = TRUE; -#endif - -static gboolean -grab_op_is_mouse_only (MetaGrabOp op) -{ - switch (op) - { - case META_GRAB_OP_MOVING: - case META_GRAB_OP_RESIZING_SE: - case META_GRAB_OP_RESIZING_S: - case META_GRAB_OP_RESIZING_SW: - case META_GRAB_OP_RESIZING_N: - case META_GRAB_OP_RESIZING_NE: - case META_GRAB_OP_RESIZING_NW: - case META_GRAB_OP_RESIZING_W: - case META_GRAB_OP_RESIZING_E: - return TRUE; - - default: - return FALSE; - } -} - -static gboolean -grab_op_is_mouse (MetaGrabOp op) -{ - switch (op) - { - case META_GRAB_OP_MOVING: - case META_GRAB_OP_RESIZING_SE: - case META_GRAB_OP_RESIZING_S: - case META_GRAB_OP_RESIZING_SW: - case META_GRAB_OP_RESIZING_N: - case META_GRAB_OP_RESIZING_NE: - case META_GRAB_OP_RESIZING_NW: - case META_GRAB_OP_RESIZING_W: - case META_GRAB_OP_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - case META_GRAB_OP_KEYBOARD_RESIZING_S: - case META_GRAB_OP_KEYBOARD_RESIZING_N: - case META_GRAB_OP_KEYBOARD_RESIZING_W: - case META_GRAB_OP_KEYBOARD_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_SE: - case META_GRAB_OP_KEYBOARD_RESIZING_NE: - case META_GRAB_OP_KEYBOARD_RESIZING_SW: - case META_GRAB_OP_KEYBOARD_RESIZING_NW: - case META_GRAB_OP_KEYBOARD_MOVING: - return TRUE; - - default: - return FALSE; - } -} - -static gboolean -grab_op_is_keyboard (MetaGrabOp op) -{ - switch (op) - { - case META_GRAB_OP_KEYBOARD_MOVING: - case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - case META_GRAB_OP_KEYBOARD_RESIZING_S: - case META_GRAB_OP_KEYBOARD_RESIZING_N: - case META_GRAB_OP_KEYBOARD_RESIZING_W: - case META_GRAB_OP_KEYBOARD_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_SE: - case META_GRAB_OP_KEYBOARD_RESIZING_NE: - case META_GRAB_OP_KEYBOARD_RESIZING_SW: - case META_GRAB_OP_KEYBOARD_RESIZING_NW: - case META_GRAB_OP_KEYBOARD_TABBING_NORMAL: - case META_GRAB_OP_KEYBOARD_TABBING_DOCK: - case META_GRAB_OP_KEYBOARD_TABBING_GROUP: - case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: - case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: - case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: - case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: - return TRUE; - - default: - return FALSE; - } -} - -gboolean -meta_grab_op_is_resizing (MetaGrabOp op) -{ - switch (op) - { - case META_GRAB_OP_RESIZING_SE: - case META_GRAB_OP_RESIZING_S: - case META_GRAB_OP_RESIZING_SW: - case META_GRAB_OP_RESIZING_N: - case META_GRAB_OP_RESIZING_NE: - case META_GRAB_OP_RESIZING_NW: - case META_GRAB_OP_RESIZING_W: - case META_GRAB_OP_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - case META_GRAB_OP_KEYBOARD_RESIZING_S: - case META_GRAB_OP_KEYBOARD_RESIZING_N: - case META_GRAB_OP_KEYBOARD_RESIZING_W: - case META_GRAB_OP_KEYBOARD_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_SE: - case META_GRAB_OP_KEYBOARD_RESIZING_NE: - case META_GRAB_OP_KEYBOARD_RESIZING_SW: - case META_GRAB_OP_KEYBOARD_RESIZING_NW: - return TRUE; - - default: - return FALSE; - } -} - -gboolean -meta_grab_op_is_moving (MetaGrabOp op) -{ - switch (op) - { - case META_GRAB_OP_MOVING: - case META_GRAB_OP_KEYBOARD_MOVING: - return TRUE; - - default: - return FALSE; - } -} - -/* Get time of current event, or CurrentTime if none. */ -guint32 -meta_display_get_current_time (MetaDisplay *display) -{ - return display->current_time; -} - -/* Get a timestamp, even if it means a roundtrip */ -guint32 -meta_display_get_current_time_roundtrip (MetaDisplay *display) -{ - guint32 timestamp; - - timestamp = meta_display_get_current_time (display); - if (timestamp == CurrentTime) - { - XEvent property_event; - - /* Using the property XA_PRIMARY because it's safe; nothing - * would use it as a property. The type doesn't matter. - */ - XChangeProperty (display->xdisplay, - display->timestamp_pinging_window, - XA_PRIMARY, XA_STRING, 8, - PropModeAppend, NULL, 0); - XWindowEvent (display->xdisplay, - display->timestamp_pinging_window, - PropertyChangeMask, - &property_event); - timestamp = property_event.xproperty.time; - } - - sanity_check_timestamps (display, timestamp); - - return timestamp; -} - -static void -add_ignored_serial (MetaDisplay *display, - unsigned long serial) -{ - int i; - - /* don't add the same serial more than once */ - if (display->ignored_serials[N_IGNORED_SERIALS-1] == serial) - return; - - /* shift serials to the left */ - i = 0; - while (i < (N_IGNORED_SERIALS - 1)) - { - display->ignored_serials[i] = display->ignored_serials[i+1]; - ++i; - } - /* put new one on the end */ - display->ignored_serials[i] = serial; -} - -static gboolean -serial_is_ignored (MetaDisplay *display, - unsigned long serial) -{ - int i; - - i = 0; - while (i < N_IGNORED_SERIALS) - { - if (display->ignored_serials[i] == serial) - return TRUE; - ++i; - } - return FALSE; -} - -static void -reset_ignores (MetaDisplay *display) -{ - int i; - - i = 0; - while (i < N_IGNORED_SERIALS) - { - display->ignored_serials[i] = 0; - ++i; - } - - display->ungrab_should_not_cause_focus_window = None; -} - -static gboolean -window_raise_with_delay_callback (void *data) -{ - MetaWindow *window; - MetaAutoRaiseData *auto_raise; - - auto_raise = data; - - meta_topic (META_DEBUG_FOCUS, - "In autoraise callback for window 0x%lx\n", - auto_raise->xwindow); - - auto_raise->display->autoraise_timeout_id = 0; - auto_raise->display->autoraise_window = NULL; - - window = meta_display_lookup_x_window (auto_raise->display, - auto_raise->xwindow); - - if (window == NULL) - return FALSE; - - /* If we aren't already on top, check whether the pointer is inside - * the window and raise the window if so. - */ - if (meta_stack_get_top (window->screen->stack) != window) - { - int x, y, root_x, root_y; - Window root, child; - unsigned int mask; - gboolean same_screen; - gboolean point_in_window; - - meta_error_trap_push (window->display); - same_screen = XQueryPointer (window->display->xdisplay, - window->xwindow, - &root, &child, - &root_x, &root_y, &x, &y, &mask); - meta_error_trap_pop (window->display, TRUE); - - point_in_window = - (window->frame && POINT_IN_RECT (root_x, root_y, window->frame->rect)) || - (window->frame == NULL && POINT_IN_RECT (root_x, root_y, window->rect)); - if (same_screen && point_in_window) - meta_window_raise (window); - else - meta_topic (META_DEBUG_FOCUS, - "Pointer not inside window, not raising %s\n", - window->desc); - } - - return FALSE; -} - -void -meta_display_queue_autoraise_callback (MetaDisplay *display, - MetaWindow *window) -{ - MetaAutoRaiseData *auto_raise_data; - - meta_topic (META_DEBUG_FOCUS, - "Queuing an autoraise timeout for %s with delay %d\n", - window->desc, - meta_prefs_get_auto_raise_delay ()); - - auto_raise_data = g_new (MetaAutoRaiseData, 1); - auto_raise_data->display = window->display; - auto_raise_data->xwindow = window->xwindow; - - if (display->autoraise_timeout_id != 0) - g_source_remove (display->autoraise_timeout_id); - - display->autoraise_timeout_id = - g_timeout_add_full (G_PRIORITY_DEFAULT, - meta_prefs_get_auto_raise_delay (), - window_raise_with_delay_callback, - auto_raise_data, - g_free); - display->autoraise_window = window; -} - -#if 0 -static void -handle_net_restack_window (MetaDisplay* display, - XEvent *event) -{ - MetaWindow *window; - - window = meta_display_lookup_x_window (display, - event->xclient.window); - - if (window) - { - /* FIXME: The EWMH includes a sibling for the restack request, but we - * (stupidly) don't currently support these types of raises. - * - * Also, unconditionally following these is REALLY stupid--we should - * combine this code with the stuff in - * meta_window_configure_request() which is smart about whether to - * follow the request or do something else (though not smart enough - * and is also too stupid to handle the sibling stuff). - */ - switch (event->xclient.data.l[2]) - { - case Above: - meta_window_raise (window); - break; - case Below: - meta_window_lower (window); - break; - case TopIf: - case BottomIf: - case Opposite: - break; - } - } -} -#endif - -/** - * This is the most important function in the whole program. It is the heart, - * it is the nexus, it is the Grand Central Station of Metacity's world. - * When we create a MetaDisplay, we ask GDK to pass *all* events for *all* - * windows to this function. So every time anything happens that we might - * want to know about, this function gets called. You see why it gets a bit - * busy around here. Most of this function is a ginormous switch statement - * dealing with all the kinds of events that might turn up. - * - * \param event The event that just happened - * \param data The MetaDisplay that events are coming from, cast to a gpointer - * so that it can be sent to a callback - * - * \ingroup main - */ -static gboolean -event_callback (XEvent *event, - gpointer data) -{ - MetaWindow *window; - MetaWindow *property_for_window; - MetaDisplay *display; - Window modified; - gboolean frame_was_receiver; - gboolean filter_out_event; - - display = data; - -#ifdef WITH_VERBOSE_MODE - if (dump_events) - meta_spew_event (display, event); -#endif - -#ifdef HAVE_STARTUP_NOTIFICATION - sn_display_process_event (display->sn_display, event); -#endif - - filter_out_event = FALSE; - display->current_time = event_get_time (display, event); - display->xinerama_cache_invalidated = TRUE; - - modified = event_get_modified_window (display, event); - - if (event->type == ButtonPress) - { - /* filter out scrollwheel */ - if (event->xbutton.button == 4 || - event->xbutton.button == 5) - return FALSE; - } - else if (event->type == UnmapNotify) - { - if (meta_ui_window_should_not_cause_focus (display->xdisplay, - modified)) - { - add_ignored_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding EnterNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - } - else if (event->type == LeaveNotify && - event->xcrossing.mode == NotifyUngrab && - modified == display->ungrab_should_not_cause_focus_window) - { - add_ignored_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding LeaveNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - - if (modified != None) - window = meta_display_lookup_x_window (display, modified); - else - window = NULL; - - /* We only want to respond to _NET_WM_USER_TIME property notify - * events on _NET_WM_USER_TIME_WINDOW windows; in particular, - * responding to UnmapNotify events is kind of bad. - */ - property_for_window = NULL; - if (window && modified == window->user_time_window) - { - property_for_window = window; - window = NULL; - } - - - frame_was_receiver = FALSE; - if (window && - window->frame && - modified == window->frame->xwindow) - { - /* Note that if the frame and the client both have an - * XGrabButton (as is normal with our setup), the event - * goes to the frame. - */ - frame_was_receiver = TRUE; - meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n", - window->desc); - } - -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify) && - ((XSyncAlarmNotifyEvent*)event)->alarm == display->grab_sync_request_alarm) - { - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window != NULL && - grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (display->grab_window, event); - } -#endif /* HAVE_XSYNC */ - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - - if (window && !frame_was_receiver) - { - XShapeEvent *sev = (XShapeEvent*) event; - - if (sev->kind == ShapeBounding) - { - if (sev->shaped && !window->has_shape) - { - window->has_shape = TRUE; - meta_topic (META_DEBUG_SHAPES, - "Window %s now has a shape\n", - window->desc); - } - else if (!sev->shaped && window->has_shape) - { - window->has_shape = FALSE; - meta_topic (META_DEBUG_SHAPES, - "Window %s no longer has a shape\n", - window->desc); - } - else - { - meta_topic (META_DEBUG_SHAPES, - "Window %s shape changed\n", - window->desc); - } - - if (window->frame) - { - window->frame->need_reapply_frame_shape = TRUE; - meta_warning("from event callback\n"); - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - } - } - } - else - { - meta_topic (META_DEBUG_SHAPES, - "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", - window ? window->desc : "(none)", - frame_was_receiver); - } - } -#endif /* HAVE_SHAPE */ - - if (window && ((event->type == KeyPress) || (event->type == ButtonPress))) - { - if (CurrentTime == display->current_time) - { - /* We can't use missing (i.e. invalid) timestamps to set user time, - * nor do we want to use them to sanity check other timestamps. - * See bug 313490 for more details. - */ - meta_warning ("Event has no timestamp! You may be using a broken " - "program such as xse. Please ask the authors of that " - "program to fix it.\n"); - } - else - { - meta_window_set_user_time (window, display->current_time); - sanity_check_timestamps (display, display->current_time); - } - } - - switch (event->type) - { - case KeyPress: - case KeyRelease: - meta_display_process_key_event (display, window, event); - break; - case ButtonPress: - if ((window && - grab_op_is_mouse (display->grab_op) && - display->grab_button != (int) event->xbutton.button && - display->grab_window == window) || - grab_op_is_keyboard (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Ending grab op %u on window %s due to button press\n", - display->grab_op, - (display->grab_window ? - display->grab_window->desc : - "none")); - if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op)) - { - MetaScreen *screen; - meta_topic (META_DEBUG_WINDOW_OPS, - "Syncing to old stack positions.\n"); - screen = - meta_display_screen_for_root (display, event->xany.window); - - if (screen!=NULL) - meta_stack_set_positions (screen->stack, - display->grab_old_window_stacking); - } - meta_display_end_grab_op (display, - event->xbutton.time); - } - else if (window && display->grab_op == META_GRAB_OP_NONE) - { - gboolean begin_move = FALSE; - unsigned int grab_mask; - gboolean unmodified; - - grab_mask = display->window_grab_modifiers; - if (g_getenv ("METACITY_DEBUG_BUTTON_GRABS")) - grab_mask |= ControlMask; - - /* Two possible sources of an unmodified event; one is a - * client that's letting button presses pass through to the - * frame, the other is our focus_window_grab on unmodified - * button 1. So for all such events we focus the window. - */ - unmodified = (event->xbutton.state & grab_mask) == 0; - - if (unmodified || - event->xbutton.button == 1) - { - /* don't focus if frame received, will be lowered in - * frames.c or special-cased if the click was on a - * minimize/close button. - */ - if (!frame_was_receiver) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - else - meta_topic (META_DEBUG_FOCUS, - "Not raising window on click due to don't-raise-on-click option\n"); - - /* Don't focus panels--they must explicitly request focus. - * See bug 160470 - */ - if (window->type != META_WINDOW_DOCK) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s due to unmodified button %u press (display.c)\n", - window->desc, event->xbutton.button); - meta_window_focus (window, event->xbutton.time); - } - else - /* However, do allow terminals to lose focus due to new - * window mappings after the user clicks on a panel. - */ - display->allow_terminal_deactivation = TRUE; - } - - /* you can move on alt-click but not on - * the click-to-focus - */ - if (!unmodified) - begin_move = TRUE; - } - else if (!unmodified && event->xbutton.button == 2) - { - if (window->has_resize_func) - { - gboolean north, south; - gboolean west, east; - int root_x, root_y; - MetaGrabOp op; - - meta_window_get_position (window, &root_x, &root_y); - - west = event->xbutton.x_root < (root_x + 1 * window->rect.width / 3); - east = event->xbutton.x_root > (root_x + 2 * window->rect.width / 3); - north = event->xbutton.y_root < (root_y + 1 * window->rect.height / 3); - south = event->xbutton.y_root > (root_y + 2 * window->rect.height / 3); - - if (north && west) - op = META_GRAB_OP_RESIZING_NW; - else if (north && east) - op = META_GRAB_OP_RESIZING_NE; - else if (south && west) - op = META_GRAB_OP_RESIZING_SW; - else if (south && east) - op = META_GRAB_OP_RESIZING_SE; - else if (north) - op = META_GRAB_OP_RESIZING_N; - else if (west) - op = META_GRAB_OP_RESIZING_W; - else if (east) - op = META_GRAB_OP_RESIZING_E; - else if (south) - op = META_GRAB_OP_RESIZING_S; - else /* Middle region is no-op to avoid user triggering wrong action */ - op = META_GRAB_OP_NONE; - - if (op != META_GRAB_OP_NONE) - meta_display_begin_grab_op (display, - window->screen, - window, - op, - TRUE, - FALSE, - event->xbutton.button, - 0, - event->xbutton.time, - event->xbutton.x_root, - event->xbutton.y_root); - } - } - else if (event->xbutton.button == 3) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_show_menu (window, - event->xbutton.x_root, - event->xbutton.y_root, - event->xbutton.button, - event->xbutton.time); - } - - if (!frame_was_receiver && unmodified) - { - /* This is from our synchronous grab since - * it has no modifiers and was on the client window - */ - int mode; - - /* When clicking a different app in click-to-focus - * in application-based mode, and the different - * app is not a dock or desktop, eat the focus click. - */ - if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK && - meta_prefs_get_application_based () && - !window->has_focus && - window->type != META_WINDOW_DOCK && - window->type != META_WINDOW_DESKTOP && - (display->focus_window == NULL || - !meta_window_same_application (window, - display->focus_window))) - mode = AsyncPointer; /* eat focus click */ - else - mode = ReplayPointer; /* give event back */ - - meta_verbose ("Allowing events mode %s time %u\n", - mode == AsyncPointer ? "AsyncPointer" : "ReplayPointer", - (unsigned int)event->xbutton.time); - - XAllowEvents (display->xdisplay, - mode, event->xbutton.time); - } - - if (begin_move && window->has_move_func) - { - meta_display_begin_grab_op (display, - window->screen, - window, - META_GRAB_OP_MOVING, - TRUE, - FALSE, - event->xbutton.button, - 0, - event->xbutton.time, - event->xbutton.x_root, - event->xbutton.y_root); - } - } - break; - case ButtonRelease: - if (display->grab_window == window && - grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, event); - break; - case MotionNotify: - if (display->grab_window == window && - grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, event); - break; - case EnterNotify: - if (display->grab_window == window && - grab_op_is_mouse (display->grab_op)) - { - meta_window_handle_mouse_grab_op_event (window, event); - break; - } - - /* If the mouse switches screens, active the default window on the new - * screen; this will make keybindings and workspace-launched items - * actually appear on the right screen. - */ - { - MetaScreen *new_screen = - meta_display_screen_for_root (display, event->xcrossing.root); - - if (new_screen != NULL && display->active_screen != new_screen) - meta_workspace_focus_default_window (new_screen->active_workspace, - NULL, - event->xcrossing.time); - } - - /* Check if we've entered a window; do this even if window->has_focus to - * avoid races. - */ - if (window && !serial_is_ignored (display, event->xany.serial) && - event->xcrossing.mode != NotifyGrab && - event->xcrossing.mode != NotifyUngrab && - event->xcrossing.detail != NotifyInferior && - meta_display_focus_sentinel_clear (display)) - { - switch (meta_prefs_get_focus_mode ()) - { - case META_FOCUS_MODE_SLOPPY: - case META_FOCUS_MODE_MOUSE: - display->mouse_mode = TRUE; - if (window->type != META_WINDOW_DOCK && - window->type != META_WINDOW_DESKTOP) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s due to enter notify with serial %lu " - "at time %lu, and setting display->mouse_mode to " - "TRUE.\n", - window->desc, - event->xany.serial, - event->xcrossing.time); - - meta_window_focus (window, event->xcrossing.time); - - /* stop ignoring stuff */ - reset_ignores (display); - - if (meta_prefs_get_auto_raise ()) - { - meta_display_queue_autoraise_callback (display, window); - } - else - { - meta_topic (META_DEBUG_FOCUS, - "Auto raise is disabled\n"); - } - } - /* In mouse focus mode, we defocus when the mouse *enters* - * the DESKTOP window, instead of defocusing on LeaveNotify. - * This is because having the mouse enter override-redirect - * child windows unfortunately causes LeaveNotify events that - * we can't distinguish from the mouse actually leaving the - * toplevel window as we expect. But, since we filter out - * EnterNotify events on override-redirect windows, this - * alternative mechanism works great. - */ - if (window->type == META_WINDOW_DESKTOP && - meta_prefs_get_focus_mode() == META_FOCUS_MODE_MOUSE && - display->expected_focus_window != NULL) - { - meta_topic (META_DEBUG_FOCUS, - "Unsetting focus from %s due to mouse entering " - "the DESKTOP window\n", - display->expected_focus_window->desc); - meta_display_focus_the_no_focus_window (display, - window->screen, - event->xcrossing.time); - } - break; - case META_FOCUS_MODE_CLICK: - break; - } - - if (window->type == META_WINDOW_DOCK) - meta_window_raise (window); - } - break; - case LeaveNotify: - if (display->grab_window == window && - grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, event); - else if (window != NULL) - { - if (window->type == META_WINDOW_DOCK && - event->xcrossing.mode != NotifyGrab && - event->xcrossing.mode != NotifyUngrab && - !window->has_focus) - meta_window_lower (window); - } - break; - case FocusIn: - case FocusOut: - if (window) - { - meta_window_notify_focus (window, event); - } - else if (meta_display_xwindow_is_a_no_focus_window (display, - event->xany.window)) - { - meta_topic (META_DEBUG_FOCUS, - "Focus %s event received on no_focus_window 0x%lx " - "mode %s detail %s\n", - event->type == FocusIn ? "in" : - event->type == FocusOut ? "out" : - "???", - event->xany.window, - meta_event_mode_to_string (event->xfocus.mode), - meta_event_detail_to_string (event->xfocus.detail)); - } - else - { - MetaScreen *screen = - meta_display_screen_for_root(display, - event->xany.window); - if (screen == NULL) - break; - - meta_topic (META_DEBUG_FOCUS, - "Focus %s event received on root window 0x%lx " - "mode %s detail %s\n", - event->type == FocusIn ? "in" : - event->type == FocusOut ? "out" : - "???", - event->xany.window, - meta_event_mode_to_string (event->xfocus.mode), - meta_event_detail_to_string (event->xfocus.detail)); - - if (event->type == FocusIn && - event->xfocus.detail == NotifyDetailNone) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to None, probably due to " - "brain-damage in the X protocol (see bug " - "125492). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - else if (event->type == FocusIn && - event->xfocus.mode == NotifyNormal && - event->xfocus.detail == NotifyInferior) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to root window, probably due to " - "gnome-session logout dialog usage (see bug " - "153220). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - - } - break; - case KeymapNotify: - break; - case Expose: - break; - case GraphicsExpose: - break; - case NoExpose: - break; - case VisibilityNotify: - break; - case CreateNotify: - break; - - case DestroyNotify: - if (window) - { - /* FIXME: It sucks that DestroyNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window) - meta_display_end_grab_op (display, timestamp); - - if (frame_was_receiver) - { - meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", - window->frame->xwindow); - meta_error_trap_push (display); - meta_window_destroy_frame (window->frame->window); - meta_error_trap_pop (display, FALSE); - } - else - { - /* Unmanage destroyed window */ - meta_window_free (window, timestamp); - window = NULL; - } - } - break; - case UnmapNotify: - if (window) - { - /* FIXME: It sucks that UnmapNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window && - ((window->frame == NULL) || !window->frame->mapped)) - meta_display_end_grab_op (display, timestamp); - - if (!frame_was_receiver) - { - if (window->unmaps_pending == 0) - { - meta_topic (META_DEBUG_WINDOW_STATE, - "Window %s withdrawn\n", - window->desc); - - meta_effect_run_close (window, NULL, NULL); - - /* Unmanage withdrawn window */ - window->withdrawn = TRUE; - meta_window_free (window, timestamp); - window = NULL; - } - else - { - window->unmaps_pending -= 1; - meta_topic (META_DEBUG_WINDOW_STATE, - "Received pending unmap, %d now pending\n", - window->unmaps_pending); - } - } - - /* Unfocus on UnmapNotify, do this after the possible - * window_free above so that window_free can see if window->has_focus - * and move focus to another window - */ - if (window) - meta_window_notify_focus (window, event); - } - break; - case MapNotify: - break; - case MapRequest: - if (window == NULL) - { - window = meta_window_new (display, event->xmaprequest.window, - FALSE); - } - /* if frame was receiver it's some malicious send event or something */ - else if (!frame_was_receiver && window) - { - meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", - window->desc, window->mapped, window->minimized); - if (window->minimized) - { - meta_window_unminimize (window); - if (window->workspace != window->screen->active_workspace) - { - meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", - window->mapped, window->minimized); - meta_window_change_workspace (window, - window->screen->active_workspace); - } - } - } - break; - case ReparentNotify: - break; - case ConfigureNotify: - /* Handle screen resize */ - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xconfigure.window); - - if (screen != NULL) - { -#ifdef HAVE_RANDR - /* do the resize the official way */ - XRRUpdateConfiguration (event); -#else - /* poke around in Xlib */ - screen->xscreen->width = event->xconfigure.width; - screen->xscreen->height = event->xconfigure.height; -#endif - - meta_screen_resize (screen, - event->xconfigure.width, - event->xconfigure.height); - } - } - break; - case ConfigureRequest: - /* This comment and code is found in both twm and fvwm */ - /* - * According to the July 27, 1988 ICCCM draft, we should ignore size and - * position fields in the WM_NORMAL_HINTS property when we map a window. - * Instead, we'll read the current geometry. Therefore, we should respond - * to configuration requests for windows which have never been mapped. - */ - if (window == NULL) - { - unsigned int xwcm; - XWindowChanges xwc; - - xwcm = event->xconfigurerequest.value_mask & - (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); - - xwc.x = event->xconfigurerequest.x; - xwc.y = event->xconfigurerequest.y; - xwc.width = event->xconfigurerequest.width; - xwc.height = event->xconfigurerequest.height; - xwc.border_width = event->xconfigurerequest.border_width; - - meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", - xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); - meta_error_trap_push (display); - XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, - xwcm, &xwc); - meta_error_trap_pop (display, FALSE); - } - else - { - if (!frame_was_receiver) - meta_window_configure_request (window, event); - } - break; - case GravityNotify: - break; - case ResizeRequest: - break; - case CirculateNotify: - break; - case CirculateRequest: - break; - case PropertyNotify: - { - MetaGroup *group; - MetaScreen *screen; - - if (window && !frame_was_receiver) - meta_window_property_notify (window, event); - else if (property_for_window && !frame_was_receiver) - meta_window_property_notify (property_for_window, event); - - group = meta_display_lookup_group (display, - event->xproperty.window); - if (group != NULL) - meta_group_property_notify (group, event); - - screen = NULL; - if (window == NULL && - group == NULL) /* window/group != NULL means it wasn't a root window */ - screen = meta_display_screen_for_root (display, - event->xproperty.window); - - if (screen != NULL) - { - if (event->xproperty.atom == - display->atom__NET_DESKTOP_LAYOUT) - meta_screen_update_workspace_layout (screen); - else if (event->xproperty.atom == - display->atom__NET_DESKTOP_NAMES) - meta_screen_update_workspace_names (screen); -#if 0 - else if (event->xproperty.atom == - display->atom__NET_RESTACK_WINDOW) - handle_net_restack_window (display, event); -#endif - - /* we just use this property as a sentinel to avoid - * certain race conditions. See the comment for the - * sentinel_counter variable declaration in display.h - */ - if (event->xproperty.atom == - display->atom__METACITY_SENTINEL) - { - meta_display_decrement_focus_sentinel (display); - } - } - } - break; - case SelectionClear: - /* do this here instead of at end of function - * so we can return - */ - - /* FIXME: Clearing display->current_time here makes no sense to - * me; who put this here and why? - */ - display->current_time = CurrentTime; - - process_selection_clear (display, event); - /* Note that processing that may have resulted in - * closing the display... so return right away. - */ - return FALSE; - case SelectionRequest: - process_selection_request (display, event); - break; - case SelectionNotify: - break; - case ColormapNotify: - if (window && !frame_was_receiver) - window->colormap = event->xcolormap.colormap; - break; - case ClientMessage: - if (window) - { - if (!frame_was_receiver) - meta_window_client_message (window, event); - } - else - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xclient.window); - - if (screen) - { - if (event->xclient.message_type == - display->atom__NET_CURRENT_DESKTOP) - { - int space; - MetaWorkspace *workspace; - guint32 time; - - space = event->xclient.data.l[0]; - time = event->xclient.data.l[1]; - - meta_verbose ("Request to change current workspace to %d with " - "specified timestamp of %u\n", - space, time); - - workspace = - meta_screen_get_workspace_by_index (screen, - space); - - /* Handle clients using the older version of the spec... */ - if (time == 0 && workspace) - { - meta_warning ("Received a NET_CURRENT_DESKTOP message " - "from a broken (outdated) client who sent " - "a 0 timestamp\n"); - time = meta_display_get_current_time_roundtrip (display); - } - - if (workspace) - meta_workspace_activate (workspace, time); - else - meta_verbose ("Don't know about workspace %d\n", space); - } - else if (event->xclient.message_type == - display->atom__NET_NUMBER_OF_DESKTOPS) - { - int num_spaces; - - num_spaces = event->xclient.data.l[0]; - - meta_verbose ("Request to set number of workspaces to %d\n", - num_spaces); - - meta_prefs_set_num_workspaces (num_spaces); - } - else if (event->xclient.message_type == - display->atom__NET_SHOWING_DESKTOP) - { - gboolean showing_desktop; - guint32 timestamp; - - showing_desktop = event->xclient.data.l[0] != 0; - /* FIXME: Braindead protocol doesn't have a timestamp */ - timestamp = meta_display_get_current_time_roundtrip (display); - meta_verbose ("Request to %s desktop\n", - showing_desktop ? "show" : "hide"); - - if (showing_desktop) - meta_screen_show_desktop (screen, timestamp); - else - { - meta_screen_unshow_desktop (screen); - meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp); - } - } - else if (event->xclient.message_type == - display->atom__METACITY_RESTART_MESSAGE) - { - meta_verbose ("Received restart request\n"); - meta_restart (); - } - else if (event->xclient.message_type == - display->atom__METACITY_RELOAD_THEME_MESSAGE) - { - meta_verbose ("Received reload theme request\n"); - meta_ui_set_current_theme (meta_prefs_get_theme (), - TRUE); - meta_display_retheme_all (); - } - else if (event->xclient.message_type == - display->atom__METACITY_SET_KEYBINDINGS_MESSAGE) - { - meta_verbose ("Received set keybindings request = %d\n", - (int) event->xclient.data.l[0]); - meta_set_keybindings_disabled (!event->xclient.data.l[0]); - } - else if (event->xclient.message_type == - display->atom__METACITY_TOGGLE_VERBOSE) - { - meta_verbose ("Received toggle verbose message\n"); - meta_set_verbose (!meta_is_verbose ()); - } - else if (event->xclient.message_type == - display->atom_WM_PROTOCOLS) - { - meta_verbose ("Received WM_PROTOCOLS message\n"); - - if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) - { - process_pong_message (display, event); - - /* We don't want ping reply events going into - * the GTK+ event loop because gtk+ will treat - * them as ping requests and send more replies. - */ - filter_out_event = TRUE; - } - } - } - - if (event->xclient.message_type == - display->atom__NET_REQUEST_FRAME_EXTENTS) - { - meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); - process_request_frame_extents (display, event); - } - } - break; - case MappingNotify: - { - gboolean ignore_current; - - ignore_current = FALSE; - - /* Check whether the next event is an identical MappingNotify - * event. If it is, ignore the current event, we'll update - * when we get the next one. - */ - if (XPending (display->xdisplay)) - { - XEvent next_event; - - XPeekEvent (display->xdisplay, &next_event); - - if (next_event.type == MappingNotify && - next_event.xmapping.request == event->xmapping.request) - ignore_current = TRUE; - } - - if (!ignore_current) - { - /* Let XLib know that there is a new keyboard mapping. - */ - XRefreshKeyboardMapping (&event->xmapping); - meta_display_process_mapping_event (display, event); - } - } - break; - default: -#ifdef HAVE_XKB - if (event->type == display->xkb_base_event_type) - { - XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; - - switch (xkb_ev->xkb_type) - { - case XkbBellNotify: - if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, - xkb_ev->time - 1000)) - { - display->last_bell_time = xkb_ev->time; - meta_bell_notify (display, xkb_ev); - } - break; - } - } -#endif - break; - } - - if (display->compositor) - { - meta_compositor_process_event (display->compositor, - event, - window); - } - - display->current_time = CurrentTime; - return filter_out_event; -} - -/* Return the window this has to do with, if any, rather - * than the frame or root window that was selecting - * for substructure - */ -static Window -event_get_modified_window (MetaDisplay *display, - XEvent *event) -{ - switch (event->type) - { - case KeyPress: - case KeyRelease: - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case FocusIn: - case FocusOut: - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case VisibilityNotify: - case ResizeRequest: - case PropertyNotify: - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - case ColormapNotify: - case ClientMessage: - case EnterNotify: - case LeaveNotify: - return event->xany.window; - - case CreateNotify: - return event->xcreatewindow.window; - - case DestroyNotify: - return event->xdestroywindow.window; - - case UnmapNotify: - return event->xunmap.window; - - case MapNotify: - return event->xmap.window; - - case MapRequest: - return event->xmaprequest.window; - - case ReparentNotify: - return event->xreparent.window; - - case ConfigureNotify: - return event->xconfigure.window; - - case ConfigureRequest: - return event->xconfigurerequest.window; - - case GravityNotify: - return event->xgravity.window; - - case CirculateNotify: - return event->xcirculate.window; - - case CirculateRequest: - return event->xcirculaterequest.window; - - case MappingNotify: - return None; - - default: -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - return sev->window; - } -#endif - - return None; - } -} - -static guint32 -event_get_time (MetaDisplay *display, - XEvent *event) -{ - switch (event->type) - { - case KeyPress: - case KeyRelease: - return event->xkey.time; - - case ButtonPress: - case ButtonRelease: - return event->xbutton.time; - - case MotionNotify: - return event->xmotion.time; - - case PropertyNotify: - return event->xproperty.time; - - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - return event->xselection.time; - - case EnterNotify: - case LeaveNotify: - return event->xcrossing.time; - - case FocusIn: - case FocusOut: - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case MapNotify: - case UnmapNotify: - case VisibilityNotify: - case ResizeRequest: - case ColormapNotify: - case ClientMessage: - case CreateNotify: - case DestroyNotify: - case MapRequest: - case ReparentNotify: - case ConfigureNotify: - case ConfigureRequest: - case GravityNotify: - case CirculateNotify: - case CirculateRequest: - case MappingNotify: - default: - return CurrentTime; - } -} - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_detail_to_string (int d) -{ - const char *detail = "???"; - switch (d) - { - /* We are an ancestor in the A<->B focus change relationship */ - case NotifyAncestor: - detail = "NotifyAncestor"; - break; - case NotifyDetailNone: - detail = "NotifyDetailNone"; - break; - /* We are a descendant in the A<->B focus change relationship */ - case NotifyInferior: - detail = "NotifyInferior"; - break; - case NotifyNonlinear: - detail = "NotifyNonlinear"; - break; - case NotifyNonlinearVirtual: - detail = "NotifyNonlinearVirtual"; - break; - case NotifyPointer: - detail = "NotifyPointer"; - break; - case NotifyPointerRoot: - detail = "NotifyPointerRoot"; - break; - case NotifyVirtual: - detail = "NotifyVirtual"; - break; - } - - return detail; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_mode_to_string (int m) -{ - const char *mode = "???"; - switch (m) - { - case NotifyNormal: - mode = "NotifyNormal"; - break; - case NotifyGrab: - mode = "NotifyGrab"; - break; - case NotifyUngrab: - mode = "NotifyUngrab"; - break; - /* not sure any X implementations are missing this, but - * it seems to be absent from some docs. - */ -#ifdef NotifyWhileGrabbed - case NotifyWhileGrabbed: - mode = "NotifyWhileGrabbed"; - break; -#endif - } - - return mode; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -stack_mode_to_string (int mode) -{ - switch (mode) - { - case Above: - return "Above"; - case Below: - return "Below"; - case TopIf: - return "TopIf"; - case BottomIf: - return "BottomIf"; - case Opposite: - return "Opposite"; - } - - return "Unknown"; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static char* -key_event_description (Display *xdisplay, - XEvent *event) -{ - KeySym keysym; - const char *str; - - keysym = XKeycodeToKeysym (xdisplay, event->xkey.keycode, 0); - - str = XKeysymToString (keysym); - - return g_strdup_printf ("Key '%s' state 0x%x", - str ? str : "none", event->xkey.state); -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef HAVE_XSYNC -#ifdef WITH_VERBOSE_MODE -static gint64 -sync_value_to_64 (const XSyncValue *value) -{ - gint64 v; - - v = XSyncValueLow32 (*value); - v |= (((gint64)XSyncValueHigh32 (*value)) << 32); - - return v; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -alarm_state_to_string (XSyncAlarmState state) -{ - switch (state) - { - case XSyncAlarmActive: - return "Active"; - case XSyncAlarmInactive: - return "Inactive"; - case XSyncAlarmDestroyed: - return "Destroyed"; - default: - return "(unknown)"; - } -} -#endif /* WITH_VERBOSE_MODE */ - -#endif /* HAVE_XSYNC */ - -#ifdef WITH_VERBOSE_MODE -static void -meta_spew_event (MetaDisplay *display, - XEvent *event) -{ - const char *name = NULL; - char *extra = NULL; - char *winname; - MetaScreen *screen; - - if (!meta_is_verbose()) - return; - - /* filter overnumerous events */ - if (event->type == Expose || event->type == MotionNotify || - event->type == NoExpose) - return; - - switch (event->type) - { - case KeyPress: - name = "KeyPress"; - extra = key_event_description (display->xdisplay, event); - break; - case KeyRelease: - name = "KeyRelease"; - extra = key_event_description (display->xdisplay, event); - break; - case ButtonPress: - name = "ButtonPress"; - extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d", - event->xbutton.button, - event->xbutton.state, - event->xbutton.x, - event->xbutton.y, - event->xbutton.root, - event->xbutton.same_screen); - break; - case ButtonRelease: - name = "ButtonRelease"; - extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d", - event->xbutton.button, - event->xbutton.state, - event->xbutton.x, - event->xbutton.y, - event->xbutton.root, - event->xbutton.same_screen); - break; - case MotionNotify: - name = "MotionNotify"; - extra = g_strdup_printf ("win: 0x%lx x: %d y: %d", - event->xmotion.window, - event->xmotion.x, - event->xmotion.y); - break; - case EnterNotify: - name = "EnterNotify"; - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d", - event->xcrossing.window, - event->xcrossing.root, - event->xcrossing.subwindow, - meta_event_mode_to_string (event->xcrossing.mode), - meta_event_detail_to_string (event->xcrossing.detail), - event->xcrossing.focus, - event->xcrossing.x, - event->xcrossing.y); - break; - case LeaveNotify: - name = "LeaveNotify"; - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d", - event->xcrossing.window, - event->xcrossing.root, - event->xcrossing.subwindow, - meta_event_mode_to_string (event->xcrossing.mode), - meta_event_detail_to_string (event->xcrossing.detail), - event->xcrossing.focus, - event->xcrossing.x, - event->xcrossing.y); - break; - case FocusIn: - name = "FocusIn"; - extra = g_strdup_printf ("detail: %s mode: %s\n", - meta_event_detail_to_string (event->xfocus.detail), - meta_event_mode_to_string (event->xfocus.mode)); - break; - case FocusOut: - name = "FocusOut"; - extra = g_strdup_printf ("detail: %s mode: %s\n", - meta_event_detail_to_string (event->xfocus.detail), - meta_event_mode_to_string (event->xfocus.mode)); - break; - case KeymapNotify: - name = "KeymapNotify"; - break; - case Expose: - name = "Expose"; - break; - case GraphicsExpose: - name = "GraphicsExpose"; - break; - case NoExpose: - name = "NoExpose"; - break; - case VisibilityNotify: - name = "VisibilityNotify"; - break; - case CreateNotify: - name = "CreateNotify"; - extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", - event->xcreatewindow.parent, - event->xcreatewindow.window); - break; - case DestroyNotify: - name = "DestroyNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", - event->xdestroywindow.event, - event->xdestroywindow.window); - break; - case UnmapNotify: - name = "UnmapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", - event->xunmap.event, - event->xunmap.window, - event->xunmap.from_configure); - break; - case MapNotify: - name = "MapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", - event->xmap.event, - event->xmap.window, - event->xmap.override_redirect); - break; - case MapRequest: - name = "MapRequest"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", - event->xmaprequest.window, - event->xmaprequest.parent); - break; - case ReparentNotify: - name = "ReparentNotify"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", - event->xreparent.window, - event->xreparent.parent, - event->xreparent.event); - break; - case ConfigureNotify: - name = "ConfigureNotify"; - extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", - event->xconfigure.x, - event->xconfigure.y, - event->xconfigure.width, - event->xconfigure.height, - event->xconfigure.above, - event->xconfigure.override_redirect); - break; - case ConfigureRequest: - name = "ConfigureRequest"; - 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", - event->xconfigurerequest.parent, - event->xconfigurerequest.window, - event->xconfigurerequest.x, - event->xconfigurerequest.value_mask & - CWX ? "" : "(unset) ", - event->xconfigurerequest.y, - event->xconfigurerequest.value_mask & - CWY ? "" : "(unset) ", - event->xconfigurerequest.width, - event->xconfigurerequest.value_mask & - CWWidth ? "" : "(unset) ", - event->xconfigurerequest.height, - event->xconfigurerequest.value_mask & - CWHeight ? "" : "(unset) ", - event->xconfigurerequest.border_width, - event->xconfigurerequest.value_mask & - CWBorderWidth ? "" : "(unset)", - event->xconfigurerequest.above, - event->xconfigurerequest.value_mask & - CWSibling ? "" : "(unset)", - stack_mode_to_string (event->xconfigurerequest.detail), - event->xconfigurerequest.value_mask & - CWStackMode ? "" : "(unset)"); - break; - case GravityNotify: - name = "GravityNotify"; - break; - case ResizeRequest: - name = "ResizeRequest"; - extra = g_strdup_printf ("width = %d height = %d", - event->xresizerequest.width, - event->xresizerequest.height); - break; - case CirculateNotify: - name = "CirculateNotify"; - break; - case CirculateRequest: - name = "CirculateRequest"; - break; - case PropertyNotify: - { - char *str; - const char *state; - - name = "PropertyNotify"; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xproperty.atom); - meta_error_trap_pop (display, TRUE); - - if (event->xproperty.state == PropertyNewValue) - state = "PropertyNewValue"; - else if (event->xproperty.state == PropertyDelete) - state = "PropertyDelete"; - else - state = "???"; - - extra = g_strdup_printf ("atom: %s state: %s", - str ? str : "(unknown atom)", - state); - meta_XFree (str); - } - break; - case SelectionClear: - name = "SelectionClear"; - break; - case SelectionRequest: - name = "SelectionRequest"; - break; - case SelectionNotify: - name = "SelectionNotify"; - break; - case ColormapNotify: - name = "ColormapNotify"; - break; - case ClientMessage: - { - char *str; - name = "ClientMessage"; - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xclient.message_type); - meta_error_trap_pop (display, TRUE); - extra = g_strdup_printf ("type: %s format: %d\n", - str ? str : "(unknown atom)", - event->xclient.format); - meta_XFree (str); - } - break; - case MappingNotify: - name = "MappingNotify"; - break; - default: -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify)) - { - XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; - - name = "XSyncAlarmNotify"; - extra = - g_strdup_printf ("alarm: 0x%lx" - " counter_value: %" G_GINT64_FORMAT - " alarm_value: %" G_GINT64_FORMAT - " time: %u alarm state: %s", - aevent->alarm, - (gint64) sync_value_to_64 (&aevent->counter_value), - (gint64) sync_value_to_64 (&aevent->alarm_value), - (unsigned int)aevent->time, - alarm_state_to_string (aevent->state)); - } - else -#endif /* HAVE_XSYNC */ -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - - name = "ShapeNotify"; - - extra = - g_strdup_printf ("kind: %s " - "x: %d y: %d w: %u h: %u " - "shaped: %d", - sev->kind == ShapeBounding ? - "ShapeBounding" : - (sev->kind == ShapeClip ? - "ShapeClip" : "(unknown)"), - sev->x, sev->y, sev->width, sev->height, - sev->shaped); - } - else -#endif /* HAVE_SHAPE */ - { - name = "(Unknown event)"; - extra = g_strdup_printf ("type: %d", event->xany.type); - } - break; - } - - screen = meta_display_screen_for_root (display, event->xany.window); - - if (screen) - winname = g_strdup_printf ("root %d", screen->number); - else - winname = g_strdup_printf ("0x%lx", event->xany.window); - - meta_topic (META_DEBUG_EVENTS, - "%s on %s%s %s %sserial %lu\n", name, winname, - extra ? ":" : "", extra ? extra : "", - event->xany.send_event ? "SEND " : "", - event->xany.serial); - - g_free (winname); - - if (extra) - g_free (extra); -} -#endif /* WITH_VERBOSE_MODE */ - -MetaWindow* -meta_display_lookup_x_window (MetaDisplay *display, - Window xwindow) -{ - return g_hash_table_lookup (display->window_ids, &xwindow); -} - -void -meta_display_register_x_window (MetaDisplay *display, - Window *xwindowp, - MetaWindow *window) -{ - g_return_if_fail (g_hash_table_lookup (display->window_ids, xwindowp) == NULL); - - g_hash_table_insert (display->window_ids, xwindowp, window); -} - -void -meta_display_unregister_x_window (MetaDisplay *display, - Window xwindow) -{ - g_return_if_fail (g_hash_table_lookup (display->window_ids, &xwindow) != NULL); - - g_hash_table_remove (display->window_ids, &xwindow); - - /* Remove any pending pings */ - remove_pending_pings_for_window (display, xwindow); -} - -gboolean -meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, - Window xwindow) -{ - gboolean is_a_no_focus_window = FALSE; - GSList *temp = display->screens; - while (temp != NULL) { - MetaScreen *screen = temp->data; - if (screen->no_focus_window == xwindow) { - is_a_no_focus_window = TRUE; - break; - } - temp = temp->next; - } - - return is_a_no_focus_window; -} - -Cursor -meta_display_create_x_cursor (MetaDisplay *display, - MetaCursor cursor) -{ - Cursor xcursor; - guint glyph; - - switch (cursor) - { - case META_CURSOR_DEFAULT: - glyph = XC_left_ptr; - break; - case META_CURSOR_NORTH_RESIZE: - glyph = XC_top_side; - break; - case META_CURSOR_SOUTH_RESIZE: - glyph = XC_bottom_side; - break; - case META_CURSOR_WEST_RESIZE: - glyph = XC_left_side; - break; - case META_CURSOR_EAST_RESIZE: - glyph = XC_right_side; - break; - case META_CURSOR_SE_RESIZE: - glyph = XC_bottom_right_corner; - break; - case META_CURSOR_SW_RESIZE: - glyph = XC_bottom_left_corner; - break; - case META_CURSOR_NE_RESIZE: - glyph = XC_top_right_corner; - break; - case META_CURSOR_NW_RESIZE: - glyph = XC_top_left_corner; - break; - case META_CURSOR_MOVE_OR_RESIZE_WINDOW: - glyph = XC_fleur; - break; - case META_CURSOR_BUSY: - glyph = XC_watch; - break; - - default: - g_assert_not_reached (); - glyph = 0; /* silence compiler */ - break; - } - - xcursor = XCreateFontCursor (display->xdisplay, glyph); - - return xcursor; -} - -static Cursor -xcursor_for_op (MetaDisplay *display, - MetaGrabOp op) -{ - MetaCursor cursor = META_CURSOR_DEFAULT; - - switch (op) - { - case META_GRAB_OP_RESIZING_SE: - case META_GRAB_OP_KEYBOARD_RESIZING_SE: - cursor = META_CURSOR_SE_RESIZE; - break; - case META_GRAB_OP_RESIZING_S: - case META_GRAB_OP_KEYBOARD_RESIZING_S: - cursor = META_CURSOR_SOUTH_RESIZE; - break; - case META_GRAB_OP_RESIZING_SW: - case META_GRAB_OP_KEYBOARD_RESIZING_SW: - cursor = META_CURSOR_SW_RESIZE; - break; - case META_GRAB_OP_RESIZING_N: - case META_GRAB_OP_KEYBOARD_RESIZING_N: - cursor = META_CURSOR_NORTH_RESIZE; - break; - case META_GRAB_OP_RESIZING_NE: - case META_GRAB_OP_KEYBOARD_RESIZING_NE: - cursor = META_CURSOR_NE_RESIZE; - break; - case META_GRAB_OP_RESIZING_NW: - case META_GRAB_OP_KEYBOARD_RESIZING_NW: - cursor = META_CURSOR_NW_RESIZE; - break; - case META_GRAB_OP_RESIZING_W: - case META_GRAB_OP_KEYBOARD_RESIZING_W: - cursor = META_CURSOR_WEST_RESIZE; - break; - case META_GRAB_OP_RESIZING_E: - case META_GRAB_OP_KEYBOARD_RESIZING_E: - cursor = META_CURSOR_EAST_RESIZE; - break; - case META_GRAB_OP_MOVING: - case META_GRAB_OP_KEYBOARD_MOVING: - case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW; - break; - - default: - break; - } - - if (cursor == META_CURSOR_DEFAULT) - return None; - return meta_display_create_x_cursor (display, cursor); -} - -void -meta_display_set_grab_op_cursor (MetaDisplay *display, - MetaScreen *screen, - MetaGrabOp op, - gboolean change_pointer, - Window grab_xwindow, - guint32 timestamp) -{ - Cursor cursor; - - cursor = xcursor_for_op (display, op); - -#define GRAB_MASK (PointerMotionMask | \ - ButtonPressMask | ButtonReleaseMask | \ - EnterWindowMask | LeaveWindowMask) - - if (change_pointer) - { - meta_error_trap_push_with_return (display); - XChangeActivePointerGrab (display->xdisplay, - GRAB_MASK, - cursor, - timestamp); - - meta_topic (META_DEBUG_WINDOW_OPS, - "Changed pointer with XChangeActivePointerGrab()\n"); - - if (meta_error_trap_pop_with_return (display, FALSE) != Success) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Error trapped from XChangeActivePointerGrab()\n"); - if (display->grab_have_pointer) - display->grab_have_pointer = FALSE; - } - } - else - { - g_assert (screen != NULL); - - meta_error_trap_push (display); - if (XGrabPointer (display->xdisplay, - grab_xwindow, - False, - GRAB_MASK, - GrabModeAsync, GrabModeAsync, - screen->xroot, - cursor, - timestamp) == GrabSuccess) - { - display->grab_have_pointer = TRUE; - meta_topic (META_DEBUG_WINDOW_OPS, - "XGrabPointer() returned GrabSuccess time %u\n", - timestamp); - } - else - { - meta_topic (META_DEBUG_WINDOW_OPS, - "XGrabPointer() failed time %u\n", - timestamp); - } - meta_error_trap_pop (display, TRUE); - } - -#undef GRAB_MASK - - if (cursor != None) - XFreeCursor (display->xdisplay, cursor); -} - -gboolean -meta_display_begin_grab_op (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - MetaGrabOp op, - gboolean pointer_already_grabbed, - gboolean frame_action, - int button, - gulong modmask, - guint32 timestamp, - int root_x, - int root_y) -{ - Window grab_xwindow; - - if (grab_op_is_mouse (op) && meta_grab_op_is_moving (op)) - { - if (display->compositor) - { - meta_compositor_begin_move (display->compositor, - window, &window->rect, - root_x, root_y); - } - } - - meta_topic (META_DEBUG_WINDOW_OPS, - "Doing grab op %u on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n", - op, window ? window->desc : "none", button, pointer_already_grabbed, - root_x, root_y); - - if (display->grab_op != META_GRAB_OP_NONE) - { - meta_warning ("Attempt to perform window operation %u on window %s when operation %u on %s already in effect\n", - op, window ? window->desc : "none", display->grab_op, - display->grab_window ? display->grab_window->desc : "none"); - return FALSE; - } - - if (window && - (meta_grab_op_is_moving (op) || meta_grab_op_is_resizing (op))) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - else - { - display->grab_initial_x = root_x; - display->grab_initial_y = root_y; - display->grab_threshold_movement_reached = FALSE; - } - } - - /* FIXME: - * If we have no MetaWindow we do our best - * and try to do the grab on the RootWindow. - * This will fail if anyone else has any - * key grab on the RootWindow. - */ - if (window) - grab_xwindow = window->frame ? window->frame->xwindow : window->xwindow; - else - grab_xwindow = screen->xroot; - - display->grab_have_pointer = FALSE; - - if (pointer_already_grabbed) - display->grab_have_pointer = TRUE; - - meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow, - timestamp); - - if (!display->grab_have_pointer) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "XGrabPointer() failed\n"); - return FALSE; - } - - /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */ - if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) - { - if (window) - display->grab_have_keyboard = - meta_window_grab_all_keys (window, timestamp); - - else - display->grab_have_keyboard = - meta_screen_grab_all_keys (screen, timestamp); - - if (!display->grab_have_keyboard) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "grabbing all keys failed, ungrabbing pointer\n"); - XUngrabPointer (display->xdisplay, timestamp); - display->grab_have_pointer = FALSE; - return FALSE; - } - } - - display->grab_op = op; - display->grab_window = window; - display->grab_screen = screen; - display->grab_xwindow = grab_xwindow; - display->grab_button = button; - display->grab_mask = modmask; - display->grab_anchor_root_x = root_x; - display->grab_anchor_root_y = root_y; - display->grab_latest_motion_x = root_x; - display->grab_latest_motion_y = root_y; - display->grab_last_moveresize_time.tv_sec = 0; - display->grab_last_moveresize_time.tv_usec = 0; - display->grab_motion_notify_time = 0; - display->grab_old_window_stacking = NULL; -#ifdef HAVE_XSYNC - display->grab_sync_request_alarm = None; - display->grab_last_user_action_was_snap = FALSE; -#endif - display->grab_was_cancelled = FALSE; - display->grab_frame_action = frame_action; - - if (display->grab_resize_timeout_id) - { - g_source_remove (display->grab_resize_timeout_id); - display->grab_resize_timeout_id = 0; - } - - if (display->grab_window) - { - meta_window_get_client_root_coords (display->grab_window, - &display->grab_initial_window_pos); - display->grab_anchor_window_pos = display->grab_initial_window_pos; - - display->grab_wireframe_active = - (meta_prefs_get_reduced_resources () && !meta_prefs_get_gnome_accessibility ()) && - (meta_grab_op_is_resizing (display->grab_op) || - meta_grab_op_is_moving (display->grab_op)); - - if (display->grab_wireframe_active) - { - meta_window_calc_showing (display->grab_window); - meta_window_begin_wireframe (window); - } - -#ifdef HAVE_XSYNC - if (!display->grab_wireframe_active && - meta_grab_op_is_resizing (display->grab_op) && - display->grab_window->sync_request_counter != None) - { - XSyncAlarmAttributes values; - XSyncValue init; - - meta_error_trap_push_with_return (display); - - /* Set the counter to 0, so we know that the application's - * responses to the client messages will always trigger - * a PositiveTransition - */ - - XSyncIntToValue (&init, 0); - XSyncSetCounter (display->xdisplay, - display->grab_window->sync_request_counter, init); - - display->grab_window->sync_request_serial = 0; - display->grab_window->sync_request_time.tv_sec = 0; - display->grab_window->sync_request_time.tv_usec = 0; - - values.trigger.counter = display->grab_window->sync_request_counter; - values.trigger.value_type = XSyncAbsolute; - values.trigger.test_type = XSyncPositiveTransition; - XSyncIntToValue (&values.trigger.wait_value, - display->grab_window->sync_request_serial + 1); - - /* After triggering, increment test_value by this. - * (NOT wait_value above) - */ - XSyncIntToValue (&values.delta, 1); - - /* we want events (on by default anyway) */ - values.events = True; - - display->grab_sync_request_alarm = XSyncCreateAlarm (display->xdisplay, - XSyncCACounter | - XSyncCAValueType | - XSyncCAValue | - XSyncCATestType | - XSyncCADelta | - XSyncCAEvents, - &values); - - if (meta_error_trap_pop_with_return (display, FALSE) != Success) - display->grab_sync_request_alarm = None; - - meta_topic (META_DEBUG_RESIZING, - "Created update alarm 0x%lx\n", - display->grab_sync_request_alarm); - } -#endif - } - - meta_topic (META_DEBUG_WINDOW_OPS, - "Grab op %u on window %s successful\n", - display->grab_op, window ? window->desc : "(null)"); - - g_assert (display->grab_window != NULL || display->grab_screen != NULL); - g_assert (display->grab_op != META_GRAB_OP_NONE); - - /* If this is a move or resize, cache the window edges for - * resistance/snapping - */ - if (meta_grab_op_is_resizing (display->grab_op) || - meta_grab_op_is_moving (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Computing edges to resist-movement or snap-to for %s.\n", - window->desc); - meta_display_compute_resistance_and_snapping_edges (display); - } - - /* Save the old stacking */ - if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Saving old stack positions; old pointer was %p.\n", - display->grab_old_window_stacking); - display->grab_old_window_stacking = - meta_stack_get_positions (screen->stack); - } - - /* Do this last, after everything is set up. */ - switch (op) - { - case META_GRAB_OP_KEYBOARD_TABBING_NORMAL: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_NORMAL, - META_TAB_SHOW_ICON); - break; - case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_NORMAL, - META_TAB_SHOW_INSTANTLY); - break; - - case META_GRAB_OP_KEYBOARD_TABBING_DOCK: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_DOCKS, - META_TAB_SHOW_ICON); - break; - case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_DOCKS, - META_TAB_SHOW_INSTANTLY); - break; - case META_GRAB_OP_KEYBOARD_TABBING_GROUP: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_GROUP, - META_TAB_SHOW_ICON); - break; - case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: - meta_screen_ensure_tab_popup (screen, - META_TAB_LIST_GROUP, - META_TAB_SHOW_INSTANTLY); - - case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: - meta_screen_ensure_workspace_popup (screen); - break; - - default: - break; - } - - if (display->grab_window) - { - meta_window_refresh_resize_popup (display->grab_window); - } - - return TRUE; -} - -void -meta_display_end_grab_op (MetaDisplay *display, - guint32 timestamp) -{ - meta_topic (META_DEBUG_WINDOW_OPS, - "Ending grab op %u at time %u\n", display->grab_op, timestamp); - - if (display->grab_op == META_GRAB_OP_NONE) - return; - - if (display->grab_window != NULL) - display->grab_window->shaken_loose = FALSE; - - if (display->grab_window != NULL && - !meta_prefs_get_raise_on_click () && - (meta_grab_op_is_moving (display->grab_op) || - meta_grab_op_is_resizing (display->grab_op))) - { - /* Only raise the window in orthogonal raise - * ('do-not-raise-on-click') mode if the user didn't try to move - * or resize the given window by at least a threshold amount. - * For raise on click mode, the window was raised at the - * beginning of the grab_op. - */ - if (!display->grab_threshold_movement_reached) - meta_window_raise (display->grab_window); - } - - if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op) || - display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING) - { - meta_ui_tab_popup_free (display->grab_screen->tab_popup); - display->grab_screen->tab_popup = NULL; - - /* If the ungrab here causes an EnterNotify, ignore it for - * sloppy focus - */ - display->ungrab_should_not_cause_focus_window = display->grab_xwindow; - } - - /* If this was a move or resize clear out the edge cache */ - if (meta_grab_op_is_resizing (display->grab_op) || - meta_grab_op_is_moving (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Clearing out the edges for resistance/snapping"); - meta_display_cleanup_edges (display); - } - - if (display->grab_old_window_stacking != NULL) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Clearing out the old stack position, which was %p.\n", - display->grab_old_window_stacking); - g_list_free (display->grab_old_window_stacking); - display->grab_old_window_stacking = NULL; - } - - if (display->grab_wireframe_active) - { - display->grab_wireframe_active = FALSE; - meta_window_end_wireframe (display->grab_window); - - if (!display->grab_was_cancelled) - { - if (meta_grab_op_is_moving (display->grab_op)) - meta_window_move (display->grab_window, - TRUE, - display->grab_wireframe_rect.x, - display->grab_wireframe_rect.y); - if (meta_grab_op_is_resizing (display->grab_op)) - meta_window_resize_with_gravity (display->grab_window, - TRUE, - display->grab_wireframe_rect.width, - display->grab_wireframe_rect.height, - meta_resize_gravity_from_grab_op (display->grab_op)); - } - meta_window_calc_showing (display->grab_window); - } - - if (display->compositor && - display->grab_window && - grab_op_is_mouse (display->grab_op) && - meta_grab_op_is_moving (display->grab_op)) - { - meta_compositor_end_move (display->compositor, - display->grab_window); - } - - if (display->grab_have_pointer) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Ungrabbing pointer with timestamp %u\n", timestamp); - XUngrabPointer (display->xdisplay, timestamp); - } - - if (display->grab_have_keyboard) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Ungrabbing all keys timestamp %u\n", timestamp); - if (display->grab_window) - meta_window_ungrab_all_keys (display->grab_window, timestamp); - else - meta_screen_ungrab_all_keys (display->grab_screen, timestamp); - } - -#ifdef HAVE_XSYNC - if (display->grab_sync_request_alarm != None) - { - XSyncDestroyAlarm (display->xdisplay, - display->grab_sync_request_alarm); - display->grab_sync_request_alarm = None; - } -#endif /* HAVE_XSYNC */ - - display->grab_window = NULL; - display->grab_screen = NULL; - display->grab_xwindow = None; - display->grab_op = META_GRAB_OP_NONE; - - if (display->grab_resize_popup) - { - meta_ui_resize_popup_free (display->grab_resize_popup); - display->grab_resize_popup = NULL; - } - - if (display->grab_resize_timeout_id) - { - g_source_remove (display->grab_resize_timeout_id); - display->grab_resize_timeout_id = 0; - } -} - -void -meta_display_check_threshold_reached (MetaDisplay *display, - int x, - int y) -{ - /* Don't bother doing the check again if we've already reached the threshold */ - if (meta_prefs_get_raise_on_click () || - display->grab_threshold_movement_reached) - return; - - if (ABS (display->grab_initial_x - x) >= 8 || - ABS (display->grab_initial_y - y) >= 8) - display->grab_threshold_movement_reached = TRUE; -} - -static void -meta_change_button_grab (MetaDisplay *display, - Window xwindow, - gboolean grab, - gboolean sync, - int button, - int modmask) -{ - unsigned int ignored_mask; - - meta_verbose ("%s 0x%lx sync = %d button = %d modmask 0x%x\n", - grab ? "Grabbing" : "Ungrabbing", - xwindow, - sync, button, modmask); - - meta_error_trap_push (display); - - ignored_mask = 0; - while (ignored_mask <= display->ignored_modifier_mask) - { - if (ignored_mask & ~(display->ignored_modifier_mask)) - { - /* Not a combination of ignored modifiers - * (it contains some non-ignored modifiers) - */ - ++ignored_mask; - continue; - } - - if (meta_is_debugging ()) - meta_error_trap_push_with_return (display); - - /* GrabModeSync means freeze until XAllowEvents */ - - if (grab) - XGrabButton (display->xdisplay, button, modmask | ignored_mask, - xwindow, False, - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | PointerMotionHintMask, - sync ? GrabModeSync : GrabModeAsync, - GrabModeAsync, - False, None); - else - XUngrabButton (display->xdisplay, button, modmask | ignored_mask, - xwindow); - - if (meta_is_debugging ()) - { - int result; - - result = meta_error_trap_pop_with_return (display, FALSE); - - if (result != Success) - meta_verbose ("Failed to %s button %d with mask 0x%x for window 0x%lx error code %d\n", - grab ? "grab" : "ungrab", - button, modmask | ignored_mask, xwindow, result); - } - - ++ignored_mask; - } - - meta_error_trap_pop (display, FALSE); -} - -void -meta_display_grab_window_buttons (MetaDisplay *display, - Window xwindow) -{ - /* Grab Alt + button1 for moving window. - * Grab Alt + button2 for resizing window. - * Grab Alt + button3 for popping up window menu. - * Grab Alt + Shift + button1 for snap-moving window. - */ - meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow); - - /* FIXME If we ignored errors here instead of spewing, we could - * put one big error trap around the loop and avoid a bunch of - * XSync() - */ - - if (display->window_grab_modifiers != 0) - { - gboolean debug = g_getenv ("METACITY_DEBUG_BUTTON_GRABS") != NULL; - int i; - for (i = 1; i < 4; i++) - { - meta_change_button_grab (display, xwindow, - TRUE, - FALSE, - i, display->window_grab_modifiers); - - /* This is for debugging, since I end up moving the Xnest - * otherwise ;-) - */ - if (debug) - meta_change_button_grab (display, xwindow, - TRUE, - FALSE, - i, ControlMask); - } - - /* In addition to grabbing Alt+Button1 for moving the window, - * grab Alt+Shift+Button1 for snap-moving the window. See bug - * 112478. Unfortunately, this doesn't work with - * Shift+Alt+Button1 for some reason; so at least part of the - * order still matters, which sucks (please FIXME). - */ - meta_change_button_grab (display, xwindow, - TRUE, - FALSE, - 1, display->window_grab_modifiers | ShiftMask); - } -} - -void -meta_display_ungrab_window_buttons (MetaDisplay *display, - Window xwindow) -{ - gboolean debug; - int i; - - if (display->window_grab_modifiers == 0) - return; - - debug = g_getenv ("METACITY_DEBUG_BUTTON_GRABS") != NULL; - i = 1; - while (i < 4) - { - meta_change_button_grab (display, xwindow, - FALSE, FALSE, i, - display->window_grab_modifiers); - - if (debug) - meta_change_button_grab (display, xwindow, - FALSE, FALSE, i, ControlMask); - - ++i; - } -} - -/* Grab buttons we only grab while unfocused in click-to-focus mode */ -#define MAX_FOCUS_BUTTON 4 -void -meta_display_grab_focus_window_button (MetaDisplay *display, - MetaWindow *window) -{ - /* Grab button 1 for activating unfocused windows */ - meta_verbose ("Grabbing unfocused window buttons for %s\n", window->desc); - -#if 0 - /* FIXME:115072 */ - /* Don't grab at all unless in click to focus mode. In click to - * focus, we may sometimes be clever about intercepting and eating - * the focus click. But in mouse focus, we never do that since the - * focus window may not be raised, and who wants to think about - * mouse focus anyway. - */ - if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK) - { - meta_verbose (" (well, not grabbing since not in click to focus mode)\n"); - return; - } -#endif - - if (window->have_focus_click_grab) - { - meta_verbose (" (well, not grabbing since we already have the grab)\n"); - return; - } - - /* FIXME If we ignored errors here instead of spewing, we could - * put one big error trap around the loop and avoid a bunch of - * XSync() - */ - - { - int i = 1; - while (i < MAX_FOCUS_BUTTON) - { - meta_change_button_grab (display, - window->xwindow, - TRUE, TRUE, - i, 0); - - ++i; - } - - window->have_focus_click_grab = TRUE; - } -} - -void -meta_display_ungrab_focus_window_button (MetaDisplay *display, - MetaWindow *window) -{ - meta_verbose ("Ungrabbing unfocused window buttons for %s\n", window->desc); - - if (!window->have_focus_click_grab) - return; - - { - int i = 1; - while (i < MAX_FOCUS_BUTTON) - { - meta_change_button_grab (display, window->xwindow, - FALSE, FALSE, i, 0); - - ++i; - } - - window->have_focus_click_grab = FALSE; - } -} - -void -meta_display_increment_event_serial (MetaDisplay *display) -{ - /* We just make some random X request */ - XDeleteProperty (display->xdisplay, display->leader_window, - display->atom__MOTIF_WM_HINTS); -} - -void -meta_display_update_active_window_hint (MetaDisplay *display) -{ - GSList *tmp; - - gulong data[1]; - - if (display->focus_window) - data[0] = display->focus_window->xwindow; - else - data[0] = None; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, screen->xroot, - display->atom__NET_ACTIVE_WINDOW, - XA_WINDOW, - 32, PropModeReplace, (guchar*) data, 1); - - meta_error_trap_pop (display, FALSE); - - tmp = tmp->next; - } -} - -void -meta_display_queue_retheme_all_windows (MetaDisplay *display) -{ - GSList* windows; - GSList *tmp; - - windows = meta_display_list_windows (display); - tmp = windows; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - if (window->frame) - { - window->frame->need_reapply_frame_shape = TRUE; - - meta_frame_queue_draw (window->frame); - } - - tmp = tmp->next; - } - - g_slist_free (windows); -} - -void -meta_display_retheme_all (void) -{ - meta_display_queue_retheme_all_windows (meta_get_display ()); -} - -void -meta_display_set_cursor_theme (const char *theme, - int size) -{ -#ifdef HAVE_XCURSOR - GSList *tmp; - - MetaDisplay *display = meta_get_display (); - - XcursorSetTheme (display->xdisplay, theme); - XcursorSetDefaultSize (display->xdisplay, size); - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_update_cursor (screen); - - tmp = tmp->next; - } - -#endif -} - -/** - * Stores whether syncing is currently enabled. - */ -static gboolean is_syncing = FALSE; - -/** - * Returns whether X synchronisation is currently enabled. - * - * \return true if we must wait for events whenever we send X requests; - * false otherwise. - * - * \bug This is *only* called by meta_display_open, but by that time - * we have already turned syncing on or off on startup, and we don't - * have any way to do so while Metacity is running, so it's rather - * pointless. - */ -gboolean -meta_is_syncing (void) -{ - return is_syncing; -} - -/** - * A handy way to turn on synchronisation on or off for every display. - * - * \bug Of course there is only one display ever anyway, so this can - * be rather hugely simplified. - */ -void -meta_set_syncing (gboolean setting) -{ - if (setting != is_syncing) - { - is_syncing = setting; - - XSynchronize (meta_get_display ()->xdisplay, is_syncing); - } -} - -/** - * How long, in milliseconds, we should wait after pinging a window - * before deciding it's not going to get back to us. - */ -#define PING_TIMEOUT_DELAY 2250 - -/** - * Does whatever it is we decided to do when a window didn't respond - * to a ping. We also remove the ping from the display's list of - * pending pings. This function is called by the event loop when the timeout - * times out which we created at the start of the ping. - * - * \param data All the information about this ping. It is a MetaPingData - * cast to a void* in order to be passable to a timeout function. - * This function will also free this parameter. - * - * \return Always returns false, because this function is called as a - * timeout and we don't want to run the timer again. - * - * \ingroup pings - */ -static gboolean -meta_display_ping_timeout (gpointer data) -{ - MetaPingData *ping_data; - - ping_data = data; - - ping_data->ping_timeout_id = 0; - - meta_topic (META_DEBUG_PING, - "Ping %u on window %lx timed out\n", - ping_data->timestamp, ping_data->xwindow); - - (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow, - ping_data->timestamp, ping_data->user_data); - - ping_data->display->pending_pings = - g_slist_remove (ping_data->display->pending_pings, - ping_data); - ping_data_free (ping_data); - - return FALSE; -} - -/** - * Sends a ping request to a window. The window must respond to - * the request within a certain amount of time. If it does, we - * will call one callback; if the time passes and we haven't had - * a response, we call a different callback. The window must have - * the hint showing that it can respond to a ping; if it doesn't, - * we call the "got a response" callback immediately and return. - * This function returns straight away after setting things up; - * the callbacks will be called from the event loop. - * - * \param display The MetaDisplay that the window is on - * \param window The MetaWindow to send the ping to - * \param timestamp The timestamp of the ping. Used for uniqueness. - * Cannot be CurrentTime; use a real timestamp! - * \param ping_reply_func The callback to call if we get a response. - * \param ping_timeout_func The callback to call if we don't get a response. - * \param user_data Arbitrary data that will be passed to the callback - * function. (In practice it's often a pointer to - * the window.) - * - * \bug This should probably be a method on windows, rather than displays - * for one of their windows. - * - * \ingroup pings - */ -void -meta_display_ping_window (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp, - MetaWindowPingFunc ping_reply_func, - MetaWindowPingFunc ping_timeout_func, - gpointer user_data) -{ - MetaPingData *ping_data; - - if (timestamp == CurrentTime) - { - meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n"); - return; - } - - if (!window->net_wm_ping) - { - if (ping_reply_func) - (* ping_reply_func) (display, window->xwindow, timestamp, user_data); - - return; - } - - ping_data = g_new (MetaPingData, 1); - ping_data->display = display; - ping_data->xwindow = window->xwindow; - ping_data->timestamp = timestamp; - ping_data->ping_reply_func = ping_reply_func; - ping_data->ping_timeout_func = ping_timeout_func; - ping_data->user_data = user_data; - ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, - meta_display_ping_timeout, - ping_data); - - display->pending_pings = g_slist_prepend (display->pending_pings, ping_data); - - meta_topic (META_DEBUG_PING, - "Sending ping with timestamp %u to window %s\n", - timestamp, window->desc); - meta_window_send_icccm_message (window, - display->atom__NET_WM_PING, - timestamp); -} - -static void -process_request_frame_extents (MetaDisplay *display, - XEvent *event) -{ - /* The X window whose frame extents will be set. */ - Window xwindow = event->xclient.window; - unsigned long data[4] = { 0, 0, 0, 0 }; - - MotifWmHints *hints = NULL; - gboolean hints_set = FALSE; - - meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); - - /* See if the window is decorated. */ - hints_set = meta_prop_get_motif_hints (display, - xwindow, - display->atom__MOTIF_WM_HINTS, - &hints); - if ((hints_set && hints->decorations) || !hints_set) - { - int top = 0; - int bottom = 0; - int left = 0; - int right = 0; - - MetaScreen *screen; - - screen = meta_display_screen_for_xwindow (display, - event->xclient.window); - if (screen == NULL) - { - meta_warning ("Received request to set _NET_FRAME_EXTENTS " - "on 0x%lx which is on a screen we are not managing\n", - event->xclient.window); - meta_XFree (hints); - return; - } - - /* Return estimated frame extents for a normal window. */ - meta_ui_theme_get_frame_borders (screen->ui, - META_FRAME_TYPE_NORMAL, - 0, - &top, - &bottom, - &left, - &right); - - data[0] = left; - data[1] = right; - data[2] = top; - data[3] = bottom; - } - - meta_topic (META_DEBUG_GEOMETRY, - "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " - "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", - xwindow, data[0], data[1], data[2], data[3]); - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, xwindow, - display->atom__NET_FRAME_EXTENTS, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 4); - meta_error_trap_pop (display, FALSE); - - meta_XFree (hints); -} - -/** - * Process the pong (the response message) from the ping we sent - * to the window. This involves removing the timeout, calling the - * reply handler function, and freeing memory. - * - * \param display the display we got the pong from - * \param event the XEvent which is a pong; we can tell which - * ping it corresponds to because it bears the - * same timestamp. - * - * \ingroup pings - */ -static void -process_pong_message (MetaDisplay *display, - XEvent *event) -{ - GSList *tmp; - guint32 timestamp = event->xclient.data.l[1]; - - meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n", - timestamp); - - for (tmp = display->pending_pings; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - if (timestamp == ping_data->timestamp) - { - meta_topic (META_DEBUG_PING, - "Matching ping found for pong %u\n", - ping_data->timestamp); - - /* Remove the ping data from the list */ - display->pending_pings = g_slist_remove (display->pending_pings, - ping_data); - - /* Remove the timeout */ - if (ping_data->ping_timeout_id != 0) - { - g_source_remove (ping_data->ping_timeout_id); - ping_data->ping_timeout_id = 0; - } - - /* Call callback */ - (* ping_data->ping_reply_func) (display, - ping_data->xwindow, - ping_data->timestamp, - ping_data->user_data); - - ping_data_free (ping_data); - - break; - } - } -} - -/** - * Finds whether a window has any pings waiting on it. - * - * \param display The MetaDisplay of the window. - * \param window The MetaWindow whose pings we want to know about. - * - * \return True if there is at least one ping which has been sent - * to the window without getting a response; false otherwise. - * - * \bug This should probably be a method on windows, rather than displays - * for one of their windows. - * - * \ingroup pings - */ -gboolean -meta_display_window_has_pending_pings (MetaDisplay *display, - MetaWindow *window) -{ - GSList *tmp; - - for (tmp = display->pending_pings; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - if (ping_data->xwindow == window->xwindow) - return TRUE; - } - - return FALSE; -} - -MetaGroup* -get_focussed_group (MetaDisplay *display) -{ - if (display->focus_window) - return display->focus_window->group; - else - return NULL; -} - -#define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \ - || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \ - || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display)))) - -static MetaWindow* -find_tab_forward (MetaDisplay *display, - MetaTabList type, - MetaScreen *screen, - MetaWorkspace *workspace, - GList *start, - gboolean skip_first) -{ - GList *tmp; - - g_return_val_if_fail (start != NULL, NULL); - g_return_val_if_fail (workspace != NULL, NULL); - - tmp = start; - if (skip_first) - tmp = tmp->next; - - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) - return window; - - tmp = tmp->next; - } - - tmp = workspace->mru_list; - while (tmp != start) - { - MetaWindow *window = tmp->data; - - if (IN_TAB_CHAIN (window, type)) - return window; - - tmp = tmp->next; - } - - return NULL; -} - -static MetaWindow* -find_tab_backward (MetaDisplay *display, - MetaTabList type, - MetaScreen *screen, - MetaWorkspace *workspace, - GList *start, - gboolean skip_last) -{ - GList *tmp; - - g_return_val_if_fail (start != NULL, NULL); - g_return_val_if_fail (workspace != NULL, NULL); - - tmp = start; - if (skip_last) - tmp = tmp->prev; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) - return window; - - tmp = tmp->prev; - } - - tmp = g_list_last (workspace->mru_list); - while (tmp != start) - { - MetaWindow *window = tmp->data; - - if (IN_TAB_CHAIN (window, type)) - return window; - - tmp = tmp->prev; - } - - return NULL; -} - -GList* -meta_display_get_tab_list (MetaDisplay *display, - MetaTabList type, - MetaScreen *screen, - MetaWorkspace *workspace) -{ - GList *tab_list; - - g_return_val_if_fail (workspace != NULL, NULL); - - /* Windows sellout mode - MRU order. Collect unminimized windows - * then minimized so minimized windows aren't in the way so much. - */ - { - GList *tmp; - - tab_list = NULL; - tmp = workspace->mru_list; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - if (!window->minimized && - window->screen == screen && - IN_TAB_CHAIN (window, type)) - tab_list = g_list_prepend (tab_list, window); - - tmp = tmp->next; - } - } - - { - GList *tmp; - - tmp = workspace->mru_list; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - if (window->minimized && - window->screen == screen && - IN_TAB_CHAIN (window, type)) - tab_list = g_list_prepend (tab_list, window); - - tmp = tmp->next; - } - } - - tab_list = g_list_reverse (tab_list); - - { - GSList *tmp; - MetaWindow *l_window; - - tmp = meta_display_list_windows (display); - - /* Go through all windows */ - while (tmp != NULL) - { - l_window=tmp->data; - - /* Check to see if it demands attention */ - if (l_window->wm_state_demands_attention && - l_window->workspace!=workspace) - { - /* if it does, add it to the popup */ - tab_list = g_list_prepend (tab_list, l_window); - } - - tmp = tmp->next; - } /* End while tmp!=NULL */ - } - - return tab_list; -} - -MetaWindow* -meta_display_get_tab_next (MetaDisplay *display, - MetaTabList type, - MetaScreen *screen, - MetaWorkspace *workspace, - MetaWindow *window, - gboolean backward) -{ - gboolean skip; - GList *tab_list; - MetaWindow *ret; - tab_list = meta_display_get_tab_list(display, - type, - screen, - workspace); - - if (tab_list == NULL) - return NULL; - - if (window != NULL) - { - g_assert (window->display == display); - - if (backward) - ret = find_tab_backward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); - else - ret = find_tab_forward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); - } - else - { - skip = display->focus_window != NULL && - IN_TAB_CHAIN (display->focus_window, type); - if (backward) - ret = find_tab_backward (display, type, screen, workspace, - tab_list, skip); - else - ret = find_tab_forward (display, type, screen, workspace, - tab_list, skip); - } - - g_list_free (tab_list); - return ret; -} - -MetaWindow* -meta_display_get_tab_current (MetaDisplay *display, - MetaTabList type, - MetaScreen *screen, - MetaWorkspace *workspace) -{ - MetaWindow *window; - - window = display->focus_window; - - if (window != NULL && - window->screen == screen && - IN_TAB_CHAIN (window, type) && - (workspace == NULL || - meta_window_located_on_workspace (window, workspace))) - return window; - else - return NULL; -} - -int -meta_resize_gravity_from_grab_op (MetaGrabOp op) -{ - int gravity; - - gravity = -1; - switch (op) - { - case META_GRAB_OP_RESIZING_SE: - case META_GRAB_OP_KEYBOARD_RESIZING_SE: - gravity = NorthWestGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_S: - case META_GRAB_OP_RESIZING_S: - gravity = NorthGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_SW: - case META_GRAB_OP_RESIZING_SW: - gravity = NorthEastGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_N: - case META_GRAB_OP_RESIZING_N: - gravity = SouthGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_NE: - case META_GRAB_OP_RESIZING_NE: - gravity = SouthWestGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_NW: - case META_GRAB_OP_RESIZING_NW: - gravity = SouthEastGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_E: - case META_GRAB_OP_RESIZING_E: - gravity = WestGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_W: - case META_GRAB_OP_RESIZING_W: - gravity = EastGravity; - break; - case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - gravity = CenterGravity; - break; - default: - break; - } - - return gravity; -} - -static MetaScreen* -find_screen_for_selection (MetaDisplay *display, - Window owner, - Atom selection) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (screen->wm_sn_selection_window == owner && - screen->wm_sn_atom == selection) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static gboolean -convert_property (MetaDisplay *display, - MetaScreen *screen, - Window w, - Atom target, - Atom property) -{ -#define N_TARGETS 4 - Atom conversion_targets[N_TARGETS]; - long icccm_version[] = { 2, 0 }; - - conversion_targets[0] = display->atom_TARGETS; - conversion_targets[1] = display->atom_MULTIPLE; - conversion_targets[2] = display->atom_TIMESTAMP; - conversion_targets[3] = display->atom_VERSION; - - meta_error_trap_push_with_return (display); - if (target == display->atom_TARGETS) - XChangeProperty (display->xdisplay, w, property, - XA_ATOM, 32, PropModeReplace, - (unsigned char *)conversion_targets, N_TARGETS); - else if (target == display->atom_TIMESTAMP) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)&screen->wm_sn_timestamp, 1); - else if (target == display->atom_VERSION) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)icccm_version, 2); - else - { - meta_error_trap_pop_with_return (display, FALSE); - return FALSE; - } - - if (meta_error_trap_pop_with_return (display, FALSE) != Success) - return FALSE; - - /* Be sure the PropertyNotify has arrived so we - * can send SelectionNotify - */ - /* FIXME the error trap pop synced anyway, right? */ - meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); - XSync (display->xdisplay, False); - - return TRUE; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static void -process_selection_request (MetaDisplay *display, - XEvent *event) -{ - XSelectionEvent reply; - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionrequest.owner, - event->xselectionrequest.selection); - - if (screen == NULL) - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionrequest.selection); - meta_error_trap_pop (display, TRUE); - - meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionrequest.owner); - - meta_XFree (str); - - return; - } - - reply.type = SelectionNotify; - reply.display = display->xdisplay; - reply.requestor = event->xselectionrequest.requestor; - reply.selection = event->xselectionrequest.selection; - reply.target = event->xselectionrequest.target; - reply.property = None; - reply.time = event->xselectionrequest.time; - - if (event->xselectionrequest.target == display->atom_MULTIPLE) - { - if (event->xselectionrequest.property != None) - { - Atom type, *adata; - int i, format; - unsigned long num, rest; - unsigned char *data; - - meta_error_trap_push_with_return (display); - if (XGetWindowProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, 0, 256, False, - display->atom_ATOM_PAIR, - &type, &format, &num, &rest, &data) != Success) - { - meta_error_trap_pop_with_return (display, TRUE); - return; - } - - if (meta_error_trap_pop_with_return (display, TRUE) == Success) - { - /* FIXME: to be 100% correct, should deal with rest > 0, - * but since we have 4 possible targets, we will hardly ever - * meet multiple requests with a length > 8 - */ - adata = (Atom*)data; - i = 0; - while (i < (int) num) - { - if (!convert_property (display, screen, - event->xselectionrequest.requestor, - adata[i], adata[i+1])) - adata[i+1] = None; - i += 2; - } - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, - display->atom_ATOM_PAIR, - 32, PropModeReplace, data, num); - meta_error_trap_pop (display, FALSE); - meta_XFree (data); - } - } - } - else - { - if (event->xselectionrequest.property == None) - event->xselectionrequest.property = event->xselectionrequest.target; - - if (convert_property (display, screen, - event->xselectionrequest.requestor, - event->xselectionrequest.target, - event->xselectionrequest.property)) - reply.property = event->xselectionrequest.property; - } - - XSendEvent (display->xdisplay, - event->xselectionrequest.requestor, - False, 0L, (XEvent*)&reply); - - meta_verbose ("Handled selection request\n"); -} - -static void -process_selection_clear (MetaDisplay *display, - XEvent *event) -{ - /* We need to unmanage the screen on which we lost the selection */ - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionclear.window, - event->xselectionclear.selection); - - - if (screen != NULL) - { - meta_verbose ("Got selection clear for screen %d on display %s\n", - screen->number, display->name); - - meta_display_unmanage_screen (display, - screen, - event->xselectionclear.time); - - /* display and screen may both be invalid memory... */ - - return; - } - - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionclear.selection); - meta_error_trap_pop (display, TRUE); - - meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionclear.window); - - meta_XFree (str); - } -} - -void -meta_display_unmanage_screen (MetaDisplay *display, - MetaScreen *screen, - guint32 timestamp) -{ - meta_verbose ("Unmanaging screen %d on display %s\n", - screen->number, display->name); - - g_return_if_fail (g_slist_find (display->screens, screen) != NULL); - - meta_screen_free (screen, timestamp); - display->screens = g_slist_remove (display->screens, screen); - - if (display->screens == NULL) - meta_display_close (display, timestamp); -} - -void -meta_display_unmanage_windows_for_screen (MetaDisplay *display, - MetaScreen *screen, - guint32 timestamp) -{ - GSList *tmp; - GSList *winlist; - - winlist = meta_display_list_windows (display); - winlist = g_slist_sort (winlist, meta_display_stack_cmp); - - /* Unmanage all windows */ - tmp = winlist; - while (tmp != NULL) - { - meta_window_free (tmp->data, timestamp); - - tmp = tmp->next; - } - g_slist_free (winlist); -} - -int -meta_display_stack_cmp (const void *a, - const void *b) -{ - MetaWindow *aw = (void*) a; - MetaWindow *bw = (void*) b; - - if (aw->screen == bw->screen) - return meta_stack_windows_cmp (aw->screen->stack, aw, bw); - /* Then assume screens are stacked by number */ - else if (aw->screen->number < bw->screen->number) - return -1; - else if (aw->screen->number > bw->screen->number) - return 1; - else - return 0; /* not reached in theory, if windows on same display */ -} - -void -meta_display_devirtualize_modifiers (MetaDisplay *display, - MetaVirtualModifier modifiers, - unsigned int *mask) -{ - *mask = 0; - - if (modifiers & META_VIRTUAL_SHIFT_MASK) - *mask |= ShiftMask; - if (modifiers & META_VIRTUAL_CONTROL_MASK) - *mask |= ControlMask; - if (modifiers & META_VIRTUAL_ALT_MASK) - *mask |= Mod1Mask; - if (modifiers & META_VIRTUAL_META_MASK) - *mask |= display->meta_mask; - if (modifiers & META_VIRTUAL_HYPER_MASK) - *mask |= display->hyper_mask; - if (modifiers & META_VIRTUAL_SUPER_MASK) - *mask |= display->super_mask; - if (modifiers & META_VIRTUAL_MOD2_MASK) - *mask |= Mod2Mask; - if (modifiers & META_VIRTUAL_MOD3_MASK) - *mask |= Mod3Mask; - if (modifiers & META_VIRTUAL_MOD4_MASK) - *mask |= Mod4Mask; - if (modifiers & META_VIRTUAL_MOD5_MASK) - *mask |= Mod5Mask; -} - -static void -update_window_grab_modifiers (MetaDisplay *display) - -{ - MetaVirtualModifier virtual_mods; - unsigned int mods; - - virtual_mods = meta_prefs_get_mouse_button_mods (); - meta_display_devirtualize_modifiers (display, virtual_mods, - &mods); - - display->window_grab_modifiers = mods; -} - -static void -prefs_changed_callback (MetaPreference pref, - void *data) -{ - MetaDisplay *display = data; - - /* It may not be obvious why we regrab on focus mode - * change; it's because we handle focus clicks a - * bit differently for the different focus modes. - */ - if (pref == META_PREF_MOUSE_BUTTON_MODS || - pref == META_PREF_FOCUS_MODE) - { - MetaDisplay *display = data; - GSList *windows; - GSList *tmp; - - windows = meta_display_list_windows (display); - - /* Ungrab all */ - tmp = windows; - while (tmp != NULL) - { - MetaWindow *w = tmp->data; - meta_display_ungrab_window_buttons (display, w->xwindow); - meta_display_ungrab_focus_window_button (display, w); - tmp = tmp->next; - } - - /* change our modifier */ - if (pref == META_PREF_MOUSE_BUTTON_MODS) - update_window_grab_modifiers (display); - - /* Grab all */ - tmp = windows; - while (tmp != NULL) - { - MetaWindow *w = tmp->data; - meta_display_grab_focus_window_button (display, w); - meta_display_grab_window_buttons (display, w->xwindow); - tmp = tmp->next; - } - - g_slist_free (windows); - } - else if (pref == META_PREF_AUDIBLE_BELL) - { - meta_bell_set_audible (display, meta_prefs_bell_is_audible ()); - } - else if (pref == META_PREF_COMPOSITING_MANAGER) - { - gboolean cm = meta_prefs_get_compositing_manager (); - - if (cm) - enable_compositor (display, TRUE); - else - disable_compositor (display); - } -} - -void -meta_display_increment_focus_sentinel (MetaDisplay *display) -{ - unsigned long data[1]; - - data[0] = meta_display_get_current_time (display); - - XChangeProperty (display->xdisplay, - ((MetaScreen*) display->screens->data)->xroot, - display->atom__METACITY_SENTINEL, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 1); - - display->sentinel_counter += 1; -} - -void -meta_display_decrement_focus_sentinel (MetaDisplay *display) -{ - display->sentinel_counter -= 1; - - if (display->sentinel_counter < 0) - display->sentinel_counter = 0; -} - -gboolean -meta_display_focus_sentinel_clear (MetaDisplay *display) -{ - return (display->sentinel_counter == 0); -} - -static void -sanity_check_timestamps (MetaDisplay *display, - guint32 timestamp) -{ - if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time)) - { - meta_warning ("last_focus_time (%u) is greater than comparison " - "timestamp (%u). This most likely represents a buggy " - "client sending inaccurate timestamps in messages such as " - "_NET_ACTIVE_WINDOW. Trying to work around...\n", - display->last_focus_time, timestamp); - display->last_focus_time = timestamp; - } - if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time)) - { - GSList *windows; - GSList *tmp; - - meta_warning ("last_user_time (%u) is greater than comparison " - "timestamp (%u). This most likely represents a buggy " - "client sending inaccurate timestamps in messages such as " - "_NET_ACTIVE_WINDOW. Trying to work around...\n", - display->last_user_time, timestamp); - display->last_user_time = timestamp; - - windows = meta_display_list_windows (display); - tmp = windows; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - - if (XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time)) - { - meta_warning ("%s appears to be one of the offending windows " - "with a timestamp of %u. Working around...\n", - window->desc, window->net_wm_user_time); - window->net_wm_user_time = timestamp; - } - - tmp = tmp->next; - } - - g_slist_free (windows); - } -} - -static gboolean -timestamp_too_old (MetaDisplay *display, - MetaWindow *window, - guint32 *timestamp) -{ - /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow - * us to sanity check the timestamp here and ensure it doesn't correspond to - * a future time (though we would want to rename to - * timestamp_too_old_or_in_future). - */ - - if (*timestamp == CurrentTime) - { - meta_warning ("Got a request to focus %s with a timestamp of 0. This " - "shouldn't happen!\n", - window ? window->desc : "the no_focus_window"); - meta_print_backtrace (); - *timestamp = meta_display_get_current_time_roundtrip (display); - return FALSE; - } - else if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_focus_time)) - { - if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time)) - { - meta_topic (META_DEBUG_FOCUS, - "Ignoring focus request for %s since %u " - "is less than %u and %u.\n", - window ? window->desc : "the no_focus_window", - *timestamp, - display->last_user_time, - display->last_focus_time); - return TRUE; - } - else - { - meta_topic (META_DEBUG_FOCUS, - "Received focus request for %s which is newer than most " - "recent user_time, but less recent than " - "last_focus_time (%u < %u < %u); adjusting " - "accordingly. (See bug 167358)\n", - window ? window->desc : "the no_focus_window", - display->last_user_time, - *timestamp, - display->last_focus_time); - *timestamp = display->last_focus_time; - return FALSE; - } - } - - return FALSE; -} - -void -meta_display_set_input_focus_window (MetaDisplay *display, - MetaWindow *window, - gboolean focus_frame, - guint32 timestamp) -{ - if (timestamp_too_old (display, window, ×tamp)) - return; - - meta_error_trap_push (display); - XSetInputFocus (display->xdisplay, - focus_frame ? window->frame->xwindow : window->xwindow, - RevertToPointerRoot, - timestamp); - meta_error_trap_pop (display, FALSE); - - display->expected_focus_window = window; - display->last_focus_time = timestamp; - display->active_screen = window->screen; - - if (window != display->autoraise_window) - meta_display_remove_autoraise_callback (window->display); -} - -void -meta_display_focus_the_no_focus_window (MetaDisplay *display, - MetaScreen *screen, - guint32 timestamp) -{ - if (timestamp_too_old (display, NULL, ×tamp)) - return; - - XSetInputFocus (display->xdisplay, - screen->no_focus_window, - RevertToPointerRoot, - timestamp); - display->expected_focus_window = NULL; - display->last_focus_time = timestamp; - display->active_screen = screen; - - meta_display_remove_autoraise_callback (display); -} - -void -meta_display_remove_autoraise_callback (MetaDisplay *display) -{ - if (display->autoraise_timeout_id != 0) - { - g_source_remove (display->autoraise_timeout_id); - display->autoraise_timeout_id = 0; - display->autoraise_window = NULL; - } -} - -#ifdef HAVE_COMPOSITE_EXTENSIONS -void -meta_display_get_compositor_version (MetaDisplay *display, - int *major, - int *minor) -{ - *major = display->composite_major_version; - *minor = display->composite_minor_version; -} -#endif - -Display * -meta_display_get_xdisplay (MetaDisplay *display) -{ - return display->xdisplay; -} - -MetaCompositor * -meta_display_get_compositor (MetaDisplay *display) -{ - return display->compositor; -} - -GSList * -meta_display_get_screens (MetaDisplay *display) -{ - return display->screens; -} - -gboolean -meta_display_has_shape (MetaDisplay *display) -{ - return META_DISPLAY_HAS_SHAPE (display); -} - -MetaWindow * -meta_display_get_focus_window (MetaDisplay *display) -{ - return display->focus_window; -} - -#ifdef HAVE_COMPOSITE_EXTENSIONS -int -meta_display_get_damage_event_base (MetaDisplay *display) -{ - return display->damage_event_base; -} -#endif - -#ifdef HAVE_COMPOSITE_EXTENSIONS -#ifdef HAVE_SHAPE -int -meta_display_get_shape_event_base (MetaDisplay *display) -{ - return display->shape_event_base; -} -#endif -#endif |