diff options
author | Havoc Pennington <hp@pobox.com> | 2002-06-08 23:55:27 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2002-06-08 23:55:27 +0000 |
commit | 31b211550f557947f67ef42dbdf2875c1622eafa (patch) | |
tree | d3a0e2f2405dfcda146d156fe0a5b2fd3cea08f8 | |
parent | 538a06fd55b969f4649c8c6f003c5ac1b56a7d95 (diff) | |
download | metacity-31b211550f557947f67ef42dbdf2875c1622eafa.tar.gz |
don't die on bad atom name
2002-06-08 Havoc Pennington <hp@pobox.com>
* src/xprops.c (meta_prop_get_utf8_string): don't die on bad atom
name
* src/display.c (meta_display_close): don't unmanage windows here,
do it in screen_free and then closing the display unmanages
windows as a side effect of unmanaging the screen
(meta_display_unmanage_screen): new function
(process_selection_clear, process_selection_request): handle
selection stuff
(meta_spew_event): don't crash on client message containing
invalid atom
(meta_spew_event): don't crash on property notify with invalid
atom
* src/main.c (main): add --replace option to replace existing
window manager.
* src/screen.c: implement holding manager selection.
* src/display.c (meta_display_open): add new selection-related
atoms.
-rw-r--r-- | ChangeLog | 24 | ||||
-rw-r--r-- | src/display.c | 294 | ||||
-rw-r--r-- | src/display.h | 12 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/screen.c | 135 | ||||
-rw-r--r-- | src/screen.h | 4 | ||||
-rw-r--r-- | src/util.c | 13 | ||||
-rw-r--r-- | src/util.h | 3 | ||||
-rw-r--r-- | src/xprops.c | 2 |
9 files changed, 463 insertions, 28 deletions
@@ -1,5 +1,29 @@ 2002-06-08 Havoc Pennington <hp@pobox.com> + * src/xprops.c (meta_prop_get_utf8_string): don't die on bad atom + name + + * src/display.c (meta_display_close): don't unmanage windows here, + do it in screen_free and then closing the display unmanages + windows as a side effect of unmanaging the screen + (meta_display_unmanage_screen): new function + (process_selection_clear, process_selection_request): handle + selection stuff + (meta_spew_event): don't crash on client message containing + invalid atom + (meta_spew_event): don't crash on property notify with invalid + atom + + * src/main.c (main): add --replace option to replace existing + window manager. + + * src/screen.c: implement holding manager selection. + + * src/display.c (meta_display_open): add new selection-related + atoms. + +2002-06-08 Havoc Pennington <hp@pobox.com> + * src/screen.c (meta_screen_new): select keypress/keyrelease events on root window, this may fix the bug where keybindings didn't work if you didn't have a focused window. diff --git a/src/display.c b/src/display.c index 53d9b640..1dcdb948 100644 --- a/src/display.c +++ b/src/display.c @@ -71,7 +71,10 @@ static guint32 event_get_time (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 gint unsigned_long_equal (gconstpointer v1, @@ -217,7 +220,13 @@ meta_display_open (const char *name) "WM_CLIENT_MACHINE", "_NET_WM_WORKAREA", "_NET_SHOW_DESKTOP", - "_NET_DESKTOP_LAYOUT" + "_NET_DESKTOP_LAYOUT", + "MANAGER", + "TARGETS", + "MULTIPLE", + "TIMESTAMP", + "VERSION", + "ATOM_PAIR" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -340,6 +349,12 @@ meta_display_open (const char *name) display->atom_net_wm_workarea = atoms[56]; display->atom_net_show_desktop = atoms[57]; display->atom_net_desktop_layout = atoms[58]; + display->atom_manager = atoms[59]; + display->atom_targets = atoms[60]; + display->atom_multiple = atoms[61]; + display->atom_timestamp = atoms[62]; + display->atom_version = atoms[63]; + display->atom_atom_pair = atoms[64]; /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK, * created in screen_new @@ -529,26 +544,11 @@ meta_display_list_windows (MetaDisplay *display) void meta_display_close (MetaDisplay *display) { - GSList *winlist; GSList *tmp; if (display->error_traps > 0) meta_bug ("Display closed with error traps pending\n"); - winlist = meta_display_list_windows (display); - - /* Unmanage all windows */ - meta_display_grab (display); - tmp = winlist; - while (tmp != NULL) - { - meta_window_free (tmp->data); - - tmp = tmp->next; - } - g_slist_free (winlist); - meta_display_ungrab (display); - if (display->autoraise_timeout_id != 0) { g_source_remove (display->autoraise_timeout_id); @@ -1373,8 +1373,18 @@ event_callback (XEvent *event, } break; case SelectionClear: + /* do this here instead of at end of function + * so we can return + */ + 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; break; case SelectionRequest: + process_selection_request (display, event); break; case SelectionNotify: break; @@ -1899,7 +1909,7 @@ meta_spew_event (MetaDisplay *display, extra = g_strdup_printf ("atom: %s state: %s", str ? str : "(unknown atom)", state); - XFree (str); + meta_XFree (str); } break; case SelectionClear: @@ -1925,7 +1935,7 @@ meta_spew_event (MetaDisplay *display, extra = g_strdup_printf ("type: %s format: %d\n", str ? str : "(unknown atom)", event->xclient.format); - XFree (str); + meta_XFree (str); } break; case MappingNotify: @@ -2989,3 +2999,249 @@ meta_rectangle_intersect (MetaRectangle *src1, return return_val; } +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 Dominik Vogt I assume, but it + * was unmarked. + */ +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 (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 (display); + return FALSE; + } + + if (meta_error_trap_pop (display) != Success) + return FALSE; + + /* Be sure the PropertyNotify has arrived so we + * can send SelectionNotify + */ + XSync (display->xdisplay, False); + + return TRUE; +} + +/* from fvwm2, Copyright Dominik Vogt I assume, but it + * was unmarked. + */ +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); + + 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 (display); + XGetWindowProperty (display->xdisplay, + event->xselectionrequest.requestor, + event->xselectionrequest.property, 0, 256, False, + display->atom_atom_pair, + &type, &format, &num, &rest, &data); + if (meta_error_trap_pop (display) == 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); + 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); + + /* 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); + + 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) +{ + 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); + display->screens = g_slist_remove (display->screens, screen); + + if (display->screens == NULL) + meta_display_close (display); +} + +void +meta_display_unmanage_windows_for_screen (MetaDisplay *display, + MetaScreen *screen) +{ + GSList *tmp; + GSList *winlist; + + winlist = meta_display_list_windows (display); + + /* Unmanage all windows */ + tmp = winlist; + while (tmp != NULL) + { + meta_window_free (tmp->data); + + tmp = tmp->next; + } + g_slist_free (winlist); +} diff --git a/src/display.h b/src/display.h index 92a94a09..52b8292f 100644 --- a/src/display.h +++ b/src/display.h @@ -131,6 +131,12 @@ struct _MetaDisplay Atom atom_net_wm_workarea; Atom atom_net_show_desktop; Atom atom_net_desktop_layout; + Atom atom_manager; + Atom atom_targets; + Atom atom_multiple; + Atom atom_timestamp; + Atom atom_version; + Atom atom_atom_pair; /* This is the actual window from focus events, * not the one we last set @@ -225,6 +231,12 @@ void meta_display_grab (MetaDisplay *display); void meta_display_ungrab (MetaDisplay *display); gboolean meta_display_is_double_click (MetaDisplay *display); +void meta_display_unmanage_screen (MetaDisplay *display, + MetaScreen *screen); + +void meta_display_unmanage_windows_for_screen (MetaDisplay *display, + MetaScreen *screen); + /* A given MetaWindow may have various X windows that "belong" * to it, such as the frame window. */ @@ -127,7 +127,9 @@ main (int argc, char **argv) strcmp (arg, "-?") == 0) usage (); else if (strcmp (arg, "--sm-disable") == 0) - disable_sm = TRUE; + disable_sm = TRUE; + else if (strcmp (arg, "--replace") == 0) + meta_set_replace_current_wm (TRUE); else if (strstr (arg, "--display=") == arg) { const char *disp; diff --git a/src/screen.c b/src/screen.c index 758ddd55..e5b68ca1 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,7 +1,10 @@ /* Metacity X screen handler */ /* - * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2002 Red Hat Inc. + * Some ICCCM manager selection code derived from fvwm2, + * Copyright (C) 2001 Dominik Vogt and fvwm2 team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,6 +41,7 @@ #include <X11/Xatom.h> #include <locale.h> #include <string.h> +#include <stdio.h> static char* get_screen_name (MetaDisplay *display, int number); @@ -168,6 +172,14 @@ meta_screen_new (MetaDisplay *display, Window xroot; Display *xdisplay; XWindowAttributes attr; + Window new_wm_sn_owner; + Window current_wm_sn_owner; + gboolean replace_current_wm; + Atom wm_sn_atom; + char buf[128]; + Time manager_timestamp; + + replace_current_wm = meta_get_replace_current_wm (); /* Only display->name, display->xdisplay, and display->error_traps * can really be used in this function, since normally screens are @@ -191,7 +203,98 @@ meta_screen_new (MetaDisplay *display, return NULL; } - /* Select our root window events */ + sprintf (buf, "WM_S%d", number); + wm_sn_atom = XInternAtom (xdisplay, buf, False); + + current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom); + + if (current_wm_sn_owner != None) + { + XSetWindowAttributes attrs; + + if (!replace_current_wm) + { + meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to override the current window manager.\n"), + number, display->name); + + return NULL; + } + + /* We want to find out when the current selection owner dies */ + meta_error_trap_push (display); + attrs.event_mask = StructureNotifyMask; + XChangeWindowAttributes (xdisplay, + current_wm_sn_owner, CWEventMask, &attrs); + if (meta_error_trap_pop (display) != Success) + current_wm_sn_owner = None; /* don't wait for it to die later on */ + } + + new_wm_sn_owner = XCreateSimpleWindow (xdisplay, xroot, + -100, -100, 1, 1, 0, 0, 0); + + { + /* Generate a timestamp */ + XSetWindowAttributes attrs; + XEvent event; + + attrs.event_mask = PropertyChangeMask; + XChangeWindowAttributes (xdisplay, new_wm_sn_owner, CWEventMask, &attrs); + + XChangeProperty (xdisplay, + new_wm_sn_owner, XA_WM_CLASS, XA_STRING, 8, + PropModeAppend, NULL, 0); + XWindowEvent (xdisplay, new_wm_sn_owner, PropertyChangeMask, &event); + attrs.event_mask = NoEventMask; + XChangeWindowAttributes (display->xdisplay, + new_wm_sn_owner, CWEventMask, &attrs); + + manager_timestamp = event.xproperty.time; + } + + XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner, + manager_timestamp); + + if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner) + { + meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"), + number, display->name); + + XDestroyWindow (xdisplay, new_wm_sn_owner); + + return NULL; + } + + { + /* Send client message indicating that we are now the WM */ + XClientMessageEvent ev; + + ev.type = ClientMessage; + ev.window = xroot; + ev.message_type = display->atom_manager; + ev.format = 32; + ev.data.l[0] = manager_timestamp; + ev.data.l[1] = wm_sn_atom; + + XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev); + } + + /* Wait for old window manager to go away */ + if (current_wm_sn_owner != None) + { + XEvent event; + + /* We sort of block infinitely here which is probably lame. */ + + meta_verbose ("Waiting for old window manager to exit\n"); + do + { + XWindowEvent (xdisplay, current_wm_sn_owner, + StructureNotifyMask, &event); + } + while (event.type != DestroyNotify); + } + + /* select our root window events */ meta_error_trap_push (display); /* We need to or with the existing event mask since @@ -208,13 +311,16 @@ meta_screen_new (MetaDisplay *display, FocusChangeMask | attr.your_event_mask); if (meta_error_trap_pop (display) != Success) { - meta_warning (_("Screen %d on display '%s' already has a window manager\n"), + meta_warning (_("Screen %d on display \"%s\" already has a window manager\n"), number, display->name); + + XDestroyWindow (xdisplay, new_wm_sn_owner); + return NULL; } screen = g_new (MetaScreen, 1); - + screen->display = display; screen->number = number; screen->screen_name = get_screen_name (display, number); @@ -226,6 +332,10 @@ meta_screen_new (MetaDisplay *display, screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen); + screen->wm_sn_selection_window = new_wm_sn_owner; + screen->wm_sn_atom = wm_sn_atom; + screen->wm_sn_timestamp = manager_timestamp; + screen->work_area_idle = 0; screen->rows_of_workspaces = 1; @@ -385,7 +495,15 @@ meta_screen_new (MetaDisplay *display, void meta_screen_free (MetaScreen *screen) -{ +{ + MetaDisplay *display; + + display = screen->display; + + meta_display_grab (display); + + meta_display_unmanage_windows_for_screen (display, screen); + meta_prefs_remove_listener (prefs_changed_callback, screen); meta_screen_ungrab_keys (screen); @@ -397,14 +515,19 @@ meta_screen_free (MetaScreen *screen) meta_error_trap_push (screen->display); XSelectInput (screen->display->xdisplay, screen->xroot, 0); if (meta_error_trap_pop (screen->display) != Success) - meta_warning (_("Could not release screen %d on display '%s'\n"), + meta_warning (_("Could not release screen %d on display \"%s\"\n"), screen->number, screen->display->name); + XDestroyWindow (screen->display->xdisplay, + screen->wm_sn_selection_window); + if (screen->work_area_idle != 0) g_source_remove (screen->work_area_idle); g_free (screen->screen_name); g_free (screen); + + meta_display_ungrab (display); } void diff --git a/src/screen.h b/src/screen.h index f9782037..b76d7ac1 100644 --- a/src/screen.h +++ b/src/screen.h @@ -60,6 +60,10 @@ struct _MetaScreen MetaCursor current_cursor; + Window wm_sn_selection_window; + Atom wm_sn_atom; + Time wm_sn_timestamp; + MetaXineramaScreenInfo *xinerama_infos; int n_xinerama_infos; @@ -31,6 +31,7 @@ static gboolean is_verbose = FALSE; static gboolean is_debugging = FALSE; +static gboolean replace_current = FALSE; static int no_prefix = 0; static FILE* logfile = NULL; @@ -109,6 +110,18 @@ meta_set_debugging (gboolean setting) is_debugging = setting; } +gboolean +meta_get_replace_current_wm (void) +{ + return replace_current; +} + +void +meta_set_replace_current_wm (gboolean setting) +{ + replace_current = setting; +} + void meta_debug_spew (const char *format, ...) { @@ -30,7 +30,8 @@ gboolean meta_is_debugging (void); void meta_set_debugging (gboolean setting); gboolean meta_is_syncing (void); void meta_set_syncing (gboolean setting); - +gboolean meta_get_replace_current_wm (void); +void meta_set_replace_current_wm (gboolean setting); void meta_debug_spew (const char *format, ...) G_GNUC_PRINTF (1, 2); diff --git a/src/xprops.c b/src/xprops.c index f5cd838a..bb539c30 100644 --- a/src/xprops.c +++ b/src/xprops.c @@ -280,7 +280,7 @@ meta_prop_get_utf8_string (MetaDisplay *display, name = XGetAtomName (display->xdisplay, xatom); meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8\n"), name, xwindow); - XFree (name); + meta_XFree (name); XFree (str); return FALSE; |