diff --git a/ChangeLog b/ChangeLog index c35299365..28e81aa27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +2002-11-30 Havoc Pennington + + * src/screen.c (STARTUP_TIMEOUT): lengthen to 15 seconds + + * src/util.c (utf8_fputs): hmm, return a value + + * src/screen.c (meta_screen_apply_startup_properties): new + function to apply initial workspace based on startup sequence. + + * src/window.c (meta_window_new): load _NET_STARTUP_ID + (meta_window_get_startup_id): new function + + * src/window-props.c (meta_display_init_window_prop_hooks): add + hooks for _NET_STARTUP_ID + + * src/display.c (event_callback): send property events to + groups. + + * src/xprops.c (meta_prop_get_values): make a type of INVALID + mean to ignore that property (don't fetch its value). + + * src/group.c (meta_group_property_notify): new function + + * src/screen.c (set_supported_hint): support _NET_STARTUP_ID + + * src/display.c (meta_display_open): add _NET_STARTUP_ID to atoms + we initialize + + * src/group-private.h: private header shared between + group-props.c, group.c + + * src/group-props.h, src/group-props.c: new files to contain + functions for retrieving group properties + + * src/window.c (meta_window_same_application): change this a bit + to work with new definition of group + + * src/group.c (meta_window_get_group): always create a group for + every window, using the window's own ID as group leader if + required. + + * src/window.c (update_wm_hints): handle changes to group leader + + * src/group.c (meta_window_group_leader_changed): new function + + * src/display.h (struct _MetaDisplay): _NET_WM_WINDOW_TYPE_SPLASH, + not SPLASHSCREEN. Reported by Gregory Merchan and Matthias Clasen. + + * src/screen.c (startup_sequence_timeout): when timing out a + startup sequence, send a remove message, don't just time it out + locally. + 2002-11-26 Calum Benson * src/themes/Crux : diff --git a/configure.in b/configure.in index aa9d3123b..b305f1818 100644 --- a/configure.in +++ b/configure.in @@ -96,7 +96,7 @@ PKG_CHECK_MODULES(METACITY_MESSAGE, gtk+-2.0 >= 2.0.0) PKG_CHECK_MODULES(METACITY_WINDOW_DEMO, gtk+-2.0 >= 2.0.0) PKG_CHECK_MODULES(METACITY_PROPS, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9 libglade-2.0) -STARTUP_NOTIFICATION_VERSION=0.2 +STARTUP_NOTIFICATION_VERSION=0.4 if $PKG_CONFIG --atleast-version $STARTUP_NOTIFICATION_VERSION libstartup-notification-1.0; then echo "Building with libstartup-notification" PKG_CHECK_MODULES(METACITY, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9 libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_VERSION) diff --git a/src/Makefile.am b/src/Makefile.am index 73a7512d5..ab173bd84 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,6 +35,9 @@ metacity_SOURCES= \ gradient.h \ group.c \ group.h \ + group-private.h \ + group-props.c \ + group-props.h \ iconcache.c \ iconcache.h \ inlinepixbufs.h \ diff --git a/src/display.c b/src/display.c index 8198276e4..4c8801914 100644 --- a/src/display.c +++ b/src/display.c @@ -26,6 +26,7 @@ #include "screen.h" #include "window.h" #include "window-props.h" +#include "group-props.h" #include "frame.h" #include "errors.h" #include "keybindings.h" @@ -225,7 +226,7 @@ meta_display_open (const char *name) "_METACITY_SET_KEYBINDINGS_MESSAGE", "_NET_WM_STATE_HIDDEN", "_NET_WM_WINDOW_TYPE_UTILITY", - "_NET_WM_WINDOW_TYPE_SPLASHSCREEN", + "_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_PING", "_NET_WM_PID", @@ -250,7 +251,8 @@ meta_display_open (const char *name) "_NET_WM_ACTION_CHANGE_DESKTOP", "_NET_WM_ACTION_CLOSE", "_NET_WM_STATE_ABOVE", - "_NET_WM_STATE_BELOW" + "_NET_WM_STATE_BELOW", + "_NET_STARTUP_ID" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -358,7 +360,7 @@ meta_display_open (const char *name) display->atom_metacity_set_keybindings_message = atoms[48]; display->atom_net_wm_state_hidden = atoms[49]; display->atom_net_wm_window_type_utility = atoms[50]; - display->atom_net_wm_window_type_splashscreen = atoms[51]; + display->atom_net_wm_window_type_splash = atoms[51]; display->atom_net_wm_state_fullscreen = atoms[52]; display->atom_net_wm_ping = atoms[53]; display->atom_net_wm_pid = atoms[54]; @@ -384,9 +386,12 @@ meta_display_open (const char *name) display->atom_net_wm_action_close = atoms[74]; display->atom_net_wm_state_above = atoms[75]; display->atom_net_wm_state_below = atoms[76]; - + display->atom_net_startup_id = atoms[77]; + display->prop_hooks = NULL; meta_display_init_window_prop_hooks (display); + display->group_prop_hooks = NULL; + meta_display_init_group_prop_hooks (display); /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK, * created in screen_new @@ -669,6 +674,7 @@ meta_display_close (MetaDisplay *display) XFlush (display->xdisplay); meta_display_free_window_prop_hooks (display); + meta_display_free_group_prop_hooks (display); #ifndef USE_GDK_DISPLAY meta_event_queue_free (display->events); @@ -1525,25 +1531,34 @@ event_callback (XEvent *event, case CirculateRequest: break; case PropertyNotify: - if (window && !frame_was_receiver) - meta_window_property_notify (window, event); - else - { - MetaScreen *screen; + { + MetaGroup *group; + MetaScreen *screen; + + if (window && !frame_was_receiver) + meta_window_property_notify (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) - { - 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 (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); + } + } break; case SelectionClear: /* do this here instead of at end of function diff --git a/src/display.h b/src/display.h index d40559430..4aa3ffd99 100644 --- a/src/display.h +++ b/src/display.h @@ -58,6 +58,7 @@ typedef struct _MetaWindow MetaWindow; typedef struct _MetaWorkspace MetaWorkspace; typedef struct _MetaWindowPropHooks MetaWindowPropHooks; +typedef struct _MetaGroupPropHooks MetaGroupPropHooks; typedef void (* MetaWindowPingFunc) (MetaDisplay *display, Window xwindow, @@ -133,7 +134,7 @@ struct _MetaDisplay Atom atom_metacity_set_keybindings_message; Atom atom_net_wm_state_hidden; Atom atom_net_wm_window_type_utility; - Atom atom_net_wm_window_type_splashscreen; + Atom atom_net_wm_window_type_splash; Atom atom_net_wm_ping; Atom atom_net_wm_pid; Atom atom_wm_client_machine; @@ -159,6 +160,7 @@ struct _MetaDisplay Atom atom_net_wm_action_close; Atom atom_net_wm_state_above; Atom atom_net_wm_state_below; + Atom atom_net_startup_id; /* This is the actual window from focus events, * not the one we last set @@ -267,6 +269,9 @@ struct _MetaDisplay /* Managed by window-props.c */ MetaWindowPropHooks *prop_hooks; + + /* Managed by group-props.c */ + MetaGroupPropHooks *group_prop_hooks; #ifdef HAVE_STARTUP_NOTIFICATION /* This is at the end in case someone doesn't include config.h before this file diff --git a/src/group-private.h b/src/group-private.h new file mode 100644 index 000000000..1ec7a249d --- /dev/null +++ b/src/group-private.h @@ -0,0 +1,41 @@ +/* Metacity window group private header */ + +/* + * Copyright (C) 2002 Red Hat Inc. + * + * 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. + */ + +#ifndef META_GROUP_PRIVATE_H +#define META_GROUP_PRIVATE_H + +#include "group.h" + +struct _MetaGroup +{ + int refcount; + MetaDisplay *display; + GSList *windows; + Window group_leader; + char *startup_id; + char *wm_client_machine; +}; + +#endif + + + + diff --git a/src/group-props.c b/src/group-props.c new file mode 100644 index 000000000..707b29128 --- /dev/null +++ b/src/group-props.c @@ -0,0 +1,230 @@ +/* MetaGroup property handling */ + +/* + * Copyright (C) 2002 Red Hat, Inc. + * + * 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. + */ + +#include +#include "group-props.h" +#include "group-private.h" +#include "xprops.h" +#include + +typedef void (* InitValueFunc) (MetaDisplay *display, + Atom property, + MetaPropValue *value); +typedef void (* ReloadValueFunc) (MetaGroup *group, + MetaPropValue *value); + +struct _MetaGroupPropHooks +{ + Atom property; + InitValueFunc init_func; + ReloadValueFunc reload_func; +}; + +static void init_prop_value (MetaDisplay *display, + Atom property, + MetaPropValue *value); +static void reload_prop_value (MetaGroup *group, + MetaPropValue *value); +static MetaGroupPropHooks* find_hooks (MetaDisplay *display, + Atom property); + + + +void +meta_group_reload_property (MetaGroup *group, + Atom property) +{ + meta_group_reload_properties (group, &property, 1); +} + +void +meta_group_reload_properties (MetaGroup *group, + const Atom *properties, + int n_properties) +{ + int i; + MetaPropValue *values; + + g_return_if_fail (properties != NULL); + g_return_if_fail (n_properties > 0); + + values = g_new0 (MetaPropValue, n_properties); + + i = 0; + while (i < n_properties) + { + init_prop_value (group->display, properties[i], &values[i]); + ++i; + } + + meta_prop_get_values (group->display, group->group_leader, + values, n_properties); + + i = 0; + while (i < n_properties) + { + reload_prop_value (group, &values[i]); + + ++i; + } + + meta_prop_free_values (values, n_properties); + + g_free (values); +} + +/* Fill in the MetaPropValue used to get the value of "property" */ +static void +init_prop_value (MetaDisplay *display, + Atom property, + MetaPropValue *value) +{ + MetaGroupPropHooks *hooks; + + value->type = META_PROP_VALUE_INVALID; + value->atom = None; + + hooks = find_hooks (display, property); + if (hooks && hooks->init_func != NULL) + (* hooks->init_func) (display, property, value); +} + +static void +reload_prop_value (MetaGroup *group, + MetaPropValue *value) +{ + MetaGroupPropHooks *hooks; + + hooks = find_hooks (group->display, value->atom); + if (hooks && hooks->reload_func != NULL) + (* hooks->reload_func) (group, value); +} + +static void +init_wm_client_machine (MetaDisplay *display, + Atom property, + MetaPropValue *value) +{ + value->type = META_PROP_VALUE_STRING; + value->atom = display->atom_wm_client_machine; +} + +static void +reload_wm_client_machine (MetaGroup *group, + MetaPropValue *value) +{ + g_free (group->wm_client_machine); + group->wm_client_machine = NULL; + + if (value->type != META_PROP_VALUE_INVALID) + group->wm_client_machine = g_strdup (value->v.str); + + meta_verbose ("Group has client machine \"%s\"\n", + group->wm_client_machine ? group->wm_client_machine : "unset"); +} + +static void +init_net_startup_id (MetaDisplay *display, + Atom property, + MetaPropValue *value) +{ + value->type = META_PROP_VALUE_UTF8; + value->atom = display->atom_net_startup_id; +} + +static void +reload_net_startup_id (MetaGroup *group, + MetaPropValue *value) +{ + g_free (group->startup_id); + group->startup_id = NULL; + + if (value->type != META_PROP_VALUE_INVALID) + group->startup_id = g_strdup (value->v.str); + + meta_verbose ("Group has startup id \"%s\"\n", + group->startup_id ? group->startup_id : "unset"); +} + +#define N_HOOKS 3 + +void +meta_display_init_group_prop_hooks (MetaDisplay *display) +{ + int i; + MetaGroupPropHooks *hooks; + + g_assert (display->group_prop_hooks == NULL); + + display->group_prop_hooks = g_new0 (MetaGroupPropHooks, N_HOOKS); + hooks = display->group_prop_hooks; + + i = 0; + + hooks[i].property = display->atom_wm_client_machine; + hooks[i].init_func = init_wm_client_machine; + hooks[i].reload_func = reload_wm_client_machine; + ++i; + + hooks[i].property = display->atom_net_wm_pid; + hooks[i].init_func = NULL; + hooks[i].reload_func = NULL; + ++i; + + hooks[i].property = display->atom_net_startup_id; + hooks[i].init_func = init_net_startup_id; + hooks[i].reload_func = reload_net_startup_id; + ++i; + + if (i != N_HOOKS) + g_error ("Initialized %d group hooks should have been %d\n", i, N_HOOKS); +} + +void +meta_display_free_group_prop_hooks (MetaDisplay *display) +{ + g_assert (display->group_prop_hooks != NULL); + + g_free (display->group_prop_hooks); + display->group_prop_hooks = NULL; +} + +static MetaGroupPropHooks* +find_hooks (MetaDisplay *display, + Atom property) +{ + int i; + + /* FIXME we could sort the array and do binary search or + * something + */ + + i = 0; + while (i < N_HOOKS) + { + if (display->group_prop_hooks[i].property == property) + return &display->group_prop_hooks[i]; + + ++i; + } + + return NULL; +} diff --git a/src/group-props.h b/src/group-props.h new file mode 100644 index 000000000..727c636a4 --- /dev/null +++ b/src/group-props.h @@ -0,0 +1,35 @@ +/* MetaGroup property handling */ + +/* + * Copyright (C) 2002 Red Hat, Inc. + * + * 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. + */ + +#ifndef META_GROUP_PROPS_H +#define META_GROUP_PROPS_H + +#include "group.h" + +void meta_group_reload_property (MetaGroup *group, + Atom property); +void meta_group_reload_properties (MetaGroup *group, + const Atom *properties, + int n_properties); +void meta_display_init_group_prop_hooks (MetaDisplay *display); +void meta_display_free_group_prop_hooks (MetaDisplay *display); + +#endif /* META_GROUP_PROPS_H */ diff --git a/src/group.c b/src/group.c index 9deb9bfa0..ab35cd262 100644 --- a/src/group.c +++ b/src/group.c @@ -21,23 +21,21 @@ #include #include "util.h" -#include "group.h" +#include "group-private.h" +#include "group-props.h" #include "window.h" -struct _MetaGroup -{ - MetaDisplay *display; - GSList *windows; - Window group_leader; - int refcount; -}; - static MetaGroup* meta_group_new (MetaDisplay *display, Window group_leader) { MetaGroup *group; - +#define N_INITIAL_PROPS 3 + Atom initial_props[N_INITIAL_PROPS]; + int i; + + g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props)); + group = g_new0 (MetaGroup, 1); group->display = display; @@ -54,6 +52,19 @@ meta_group_new (MetaDisplay *display, g_hash_table_insert (display->groups_by_leader, &group->group_leader, group); + + /* Fill these in the order we want them to be gotten */ + i = 0; + initial_props[i++] = display->atom_wm_client_machine; + initial_props[i++] = display->atom_net_wm_pid; + initial_props[i++] = display->atom_net_startup_id; + g_assert (N_INITIAL_PROPS == i); + + meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS); + + meta_topic (META_DEBUG_GROUPS, + "Created new group with leader 0x%lx\n", + group->group_leader); return group; } @@ -66,6 +77,10 @@ meta_group_unref (MetaGroup *group) group->refcount -= 1; if (group->refcount == 0) { + meta_topic (META_DEBUG_GROUPS, + "Destroying group with leader 0x%lx\n", + group->group_leader); + g_assert (group->display->groups_by_leader != NULL); g_hash_table_remove (group->display->groups_by_leader, @@ -78,6 +93,9 @@ meta_group_unref (MetaGroup *group) group->display->groups_by_leader = NULL; } + g_free (group->wm_client_machine); + g_free (group->startup_id); + g_free (group); } } @@ -88,16 +106,23 @@ meta_window_get_group (MetaWindow *window) if (window->unmanaging) return NULL; - if (window->cached_group == NULL && - window->xgroup_leader != None) /* some windows have no group */ + if (window->cached_group == NULL) { MetaGroup *group; + /* use window->xwindow if no window->xgroup_leader */ + group = NULL; if (window->display->groups_by_leader) - group = g_hash_table_lookup (window->display->groups_by_leader, - &window->xgroup_leader); + { + if (window->xgroup_leader != None) + group = g_hash_table_lookup (window->display->groups_by_leader, + &window->xgroup_leader); + else + group = g_hash_table_lookup (window->display->groups_by_leader, + &window->xwindow); + } if (group != NULL) { @@ -106,24 +131,36 @@ meta_window_get_group (MetaWindow *window) } else { - group = meta_group_new (window->display, - window->xgroup_leader); - + if (window->xgroup_leader != None) + group = meta_group_new (window->display, + window->xgroup_leader); + else + group = meta_group_new (window->display, + window->xwindow); + window->cached_group = group; } window->cached_group->windows = g_slist_prepend (window->cached_group->windows, window); + + meta_topic (META_DEBUG_GROUPS, + "Adding %s to group with leader 0x%lx\n", + window->desc, group->group_leader); } return window->cached_group; } -void -meta_window_shutdown_group (MetaWindow *window) +static void +remove_window_from_group (MetaWindow *window) { if (window->cached_group != NULL) { + meta_topic (META_DEBUG_GROUPS, + "Removing %s from group with leader 0x%lx\n", + window->desc, window->cached_group->group_leader); + window->cached_group->windows = g_slist_remove (window->cached_group->windows, window); @@ -132,6 +169,19 @@ meta_window_shutdown_group (MetaWindow *window) } } +void +meta_window_group_leader_changed (MetaWindow *window) +{ + remove_window_from_group (window); + meta_window_get_group (window); +} + +void +meta_window_shutdown_group (MetaWindow *window) +{ + remove_window_from_group (window); +} + MetaGroup* meta_display_lookup_group (MetaDisplay *display, Window group_leader) @@ -190,3 +240,19 @@ meta_group_update_layers (MetaGroup *group) g_slist_free (frozen_stacks); } + +const char* +meta_group_get_startup_id (MetaGroup *group) +{ + return group->startup_id; +} + +gboolean +meta_group_property_notify (MetaGroup *group, + XEvent *event) +{ + meta_group_reload_property (group, + event->xproperty.atom); + + return TRUE; +} diff --git a/src/group.h b/src/group.h index c14dc3097..6639839a9 100644 --- a/src/group.h +++ b/src/group.h @@ -28,6 +28,8 @@ MetaGroup* meta_window_get_group (MetaWindow *window); void meta_window_shutdown_group (MetaWindow *window); +void meta_window_group_leader_changed (MetaWindow *window); + /* note, can return NULL */ MetaGroup* meta_display_lookup_group (MetaDisplay *display, Window group_leader); @@ -36,6 +38,11 @@ GSList* meta_group_list_windows (MetaGroup *group); void meta_group_update_layers (MetaGroup *group); +const char* meta_group_get_startup_id (MetaGroup *group); + +gboolean meta_group_property_notify (MetaGroup *group, + XEvent *event); + #endif diff --git a/src/screen.c b/src/screen.c index 76740bdfd..ef0627036 100644 --- a/src/screen.c +++ b/src/screen.c @@ -90,7 +90,7 @@ set_wm_check_hint (MetaScreen *screen) static int set_supported_hint (MetaScreen *screen) { -#define N_SUPPORTED 44 +#define N_SUPPORTED 45 #define N_WIN_SUPPORTED 1 Atom atoms[N_SUPPORTED]; @@ -119,7 +119,7 @@ set_supported_hint (MetaScreen *screen) atoms[22] = screen->display->atom_net_wm_moveresize; atoms[23] = screen->display->atom_net_wm_state_hidden; atoms[24] = screen->display->atom_net_wm_window_type_utility; - atoms[25] = screen->display->atom_net_wm_window_type_splashscreen; + atoms[25] = screen->display->atom_net_wm_window_type_splash; atoms[26] = screen->display->atom_net_wm_state_fullscreen; atoms[27] = screen->display->atom_net_wm_ping; atoms[28] = screen->display->atom_net_active_window; @@ -138,6 +138,7 @@ set_supported_hint (MetaScreen *screen) atoms[41] = screen->display->atom_net_wm_action_close; atoms[42] = screen->display->atom_net_wm_state_above; atoms[43] = screen->display->atom_net_wm_state_below; + atoms[44] = screen->display->atom_net_startup_id; XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom_net_supported, @@ -1800,7 +1801,12 @@ typedef struct GTimeVal now; } CollectTimedOutData; -#define STARTUP_TIMEOUT 5000 +/* This should be fairly long, as it should never be required unless + * apps or .desktop files are buggy, and it's confusing if + * OpenOffice or whatever seems to stop launching - people + * might decide they need to launch it again. + */ +#define STARTUP_TIMEOUT 15000 static void collect_timed_out_foreach (void *element, @@ -1848,7 +1854,7 @@ startup_sequence_timeout (void *data) "Timed out sequence %s\n", sn_startup_sequence_get_id (sequence)); - remove_sequence (screen, sequence); + sn_startup_sequence_complete (sequence); tmp = tmp->next; } @@ -1913,3 +1919,68 @@ meta_screen_sn_event (SnMonitorEvent *event, } } #endif + +void +meta_screen_apply_startup_properties (MetaScreen *screen, + MetaWindow *window) +{ +#ifdef HAVE_STARTUP_NOTIFICATION + const char *startup_id; + GSList *tmp; + SnStartupSequence *sequence; + + startup_id = meta_window_get_startup_id (window); + if (startup_id == NULL) + return; + + sequence = NULL; + tmp = screen->startup_sequences; + while (tmp != NULL) + { + const char *id; + + id = sn_startup_sequence_get_id (tmp->data); + + if (strcmp (id, startup_id) == 0) + { + sequence = tmp->data; + break; + } + + tmp = tmp->next; + } + + if (sequence != NULL) + { + int space; + + meta_topic (META_DEBUG_STARTUP, + "Found startup sequence for window %s ID \"%s\"\n", + window->desc, startup_id); + + if (!window->initial_workspace_set) + { + space = sn_startup_sequence_get_workspace (sequence); + if (space >= 0) + { + meta_topic (META_DEBUG_STARTUP, + "Setting initial window workspace to %d based on startup info\n", + space); + + window->initial_workspace_set = TRUE; + window->initial_workspace = space; + } + } + + return; + } + else + { + meta_topic (META_DEBUG_STARTUP, + "Did not find startup sequence for window %s ID \"%s\"\n", + window->desc, startup_id); + } + +#endif /* HAVE_STARTUP_NOTIFICATION */ +} + diff --git a/src/screen.h b/src/screen.h index 04de75cfb..351f6b92a 100644 --- a/src/screen.h +++ b/src/screen.h @@ -152,5 +152,8 @@ void meta_screen_resize (MetaScreen *screen, void meta_screen_show_desktop (MetaScreen *screen); void meta_screen_unshow_desktop (MetaScreen *screen); +void meta_screen_apply_startup_properties (MetaScreen *screen, + MetaWindow *window); + #endif diff --git a/src/util.c b/src/util.c index 8d5a57e33..92b96f8ed 100644 --- a/src/util.c +++ b/src/util.c @@ -158,15 +158,18 @@ utf8_fputs (const char *str, FILE *f) { char *l; - + int retval; + l = g_locale_from_utf8 (str, -1, NULL, NULL, NULL); if (l == NULL) - fputs (str, f); /* just print it anyway, better than nothing */ + retval = fputs (str, f); /* just print it anyway, better than nothing */ else - fputs (l, f); + retval = fputs (l, f); g_free (l); + + return retval; } void @@ -262,6 +265,8 @@ topic_name (MetaDebugTopic topic) return "STARTUP"; case META_DEBUG_PREFS: return "PREFS"; + case META_DEBUG_GROUPS: + return "GROUPS"; } return "Window manager"; diff --git a/src/util.h b/src/util.h index 7ade91b7a..a339352a2 100644 --- a/src/util.h +++ b/src/util.h @@ -62,7 +62,8 @@ typedef enum META_DEBUG_SYNC = 1 << 13, META_DEBUG_ERRORS = 1 << 14, META_DEBUG_STARTUP = 1 << 15, - META_DEBUG_PREFS = 1 << 16 + META_DEBUG_PREFS = 1 << 16, + META_DEBUG_GROUPS = 1 << 17 } MetaDebugTopic; diff --git a/src/window-props.c b/src/window-props.c index 9bcfb1c33..f1d19ce68 100644 --- a/src/window-props.c +++ b/src/window-props.c @@ -97,10 +97,12 @@ init_prop_value (MetaDisplay *display, MetaPropValue *value) { MetaWindowPropHooks *hooks; + + value->type = META_PROP_VALUE_INVALID; + value->atom = None; hooks = find_hooks (display, property); - g_assert (hooks != NULL); - if (hooks->init_func != NULL) + if (hooks && hooks->init_func != NULL) (* hooks->init_func) (display, property, value); } @@ -111,8 +113,7 @@ reload_prop_value (MetaWindow *window, MetaWindowPropHooks *hooks; hooks = find_hooks (window->display, value->atom); - g_assert (hooks != NULL); - if (hooks->reload_func != NULL) + if (hooks && hooks->reload_func != NULL) (* hooks->reload_func) (window, value); } @@ -385,7 +386,33 @@ reload_win_workspace (MetaWindow *window, } } -#define N_HOOKS 22 + +static void +init_net_startup_id (MetaDisplay *display, + Atom property, + MetaPropValue *value) +{ + value->type = META_PROP_VALUE_UTF8; + value->atom = display->atom_net_startup_id; +} + +static void +reload_net_startup_id (MetaWindow *window, + MetaPropValue *value) +{ + g_free (window->startup_id); + + if (value->type != META_PROP_VALUE_INVALID) + window->startup_id = g_strdup (value->v.str); + else + window->startup_id = NULL; + + meta_verbose ("New _NET_STARTUP_ID \"%s\" for %s\n", + window->startup_id ? window->startup_id : "unset", + window->desc); +} + +#define N_HOOKS 23 void meta_display_init_window_prop_hooks (MetaDisplay *display) @@ -509,6 +536,11 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) hooks[i].init_func = NULL; hooks[i].reload_func = NULL; ++i; + + hooks[i].property = display->atom_net_startup_id; + hooks[i].init_func = init_net_startup_id; + hooks[i].reload_func = reload_net_startup_id; + ++i; if (i != N_HOOKS) g_error ("Initialized %d hooks should have been %d\n", i, N_HOOKS); diff --git a/src/window.c b/src/window.c index 0f2d63dbf..dbfcd8431 100644 --- a/src/window.c +++ b/src/window.c @@ -157,7 +157,7 @@ meta_window_new (MetaDisplay *display, GSList *tmp; MetaWorkspace *space; gulong existing_wm_state; -#define N_INITIAL_PROPS 8 +#define N_INITIAL_PROPS 9 Atom initial_props[N_INITIAL_PROPS]; int i; @@ -401,7 +401,8 @@ meta_window_new (MetaDisplay *display, window->role = NULL; window->sm_client_id = NULL; window->wm_client_machine = NULL; - + window->startup_id = NULL; + window->net_wm_pid = -1; window->xtransient_for = None; @@ -439,6 +440,7 @@ meta_window_new (MetaDisplay *display, initial_props[i++] = XA_WM_ICON_NAME; initial_props[i++] = display->atom_net_wm_desktop; initial_props[i++] = display->atom_win_workspace; + initial_props[i++] = display->atom_net_startup_id; g_assert (N_INITIAL_PROPS == i); meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS); @@ -477,6 +479,11 @@ meta_window_new (MetaDisplay *display, */ window->placed = TRUE; } + + /* Apply any window attributes such as initial workspace + * based on startup notification + */ + meta_screen_apply_startup_properties (window->screen, window); /* FIXME we have a tendency to set this then immediately * change it again. @@ -972,6 +979,7 @@ meta_window_free (MetaWindow *window) g_free (window->sm_client_id); g_free (window->wm_client_machine); + g_free (window->startup_id); g_free (window->role); g_free (window->res_class); g_free (window->res_name); @@ -2881,6 +2889,22 @@ meta_window_get_outer_rect (MetaWindow *window, *rect = window->rect; } +const char* +meta_window_get_startup_id (MetaWindow *window) +{ + if (window->startup_id == NULL) + { + MetaGroup *group; + + group = meta_window_get_group (window); + + if (group != NULL) + return meta_group_get_startup_id (group); + } + + return window->startup_id; +} + void meta_window_focus (MetaWindow *window, Time timestamp) @@ -3873,6 +3897,11 @@ static gboolean process_property_notify (MetaWindow *window, XPropertyEvent *event) { + /* FIXME once we move entirely to the window-props.h framework, we + * can just call reload on the property in the event and get rid of + * this if-else chain. + */ + if (event->atom == XA_WM_NAME) { meta_verbose ("Property notify on %s for WM_NAME\n", window->desc); @@ -4018,6 +4047,13 @@ process_property_notify (MetaWindow *window, meta_verbose ("Property notify on %s for _WIN_HINTS\n", window->desc); update_struts (window); } + else if (event->atom == window->display->atom_net_startup_id) + { + meta_verbose ("Property notify on %s for _NET_STARTUP_ID\n", window->desc); + + meta_window_reload_property (window, + window->display->atom_net_startup_id); + } return TRUE; } @@ -4400,16 +4436,10 @@ update_wm_hints (MetaWindow *window) if (window->xgroup_leader != old_group_leader) { - if (old_group_leader != None) - { - meta_warning ("Window %s changed its group leader, not handled right now.\n", - window->desc); - /* ignore the change */ - window->xgroup_leader = old_group_leader; - } - - /* ensure this window is listed in the group for this group leader */ - meta_window_get_group (window); + meta_verbose ("Window %s changed its group leader to 0x%lx\n", + window->desc, window->xgroup_leader); + + meta_window_group_leader_changed (window); } } @@ -4865,7 +4895,7 @@ update_net_wm_type (MetaWindow *window) atoms[i] == window->display->atom_net_wm_window_type_dialog || atoms[i] == window->display->atom_net_wm_window_type_normal || atoms[i] == window->display->atom_net_wm_window_type_utility || - atoms[i] == window->display->atom_net_wm_window_type_splashscreen) + atoms[i] == window->display->atom_net_wm_window_type_splash) { window->type_atom = atoms[i]; break; @@ -5152,7 +5182,7 @@ recalc_window_type (MetaWindow *window) window->type = META_WINDOW_NORMAL; else if (window->type_atom == window->display->atom_net_wm_window_type_utility) window->type = META_WINDOW_UTILITY; - else if (window->type_atom == window->display->atom_net_wm_window_type_splashscreen) + else if (window->type_atom == window->display->atom_net_wm_window_type_splash) window->type = META_WINDOW_SPLASHSCREEN; else meta_bug ("Set a type atom for %s that wasn't handled in recalc_window_type\n", @@ -6321,9 +6351,9 @@ gboolean meta_window_same_application (MetaWindow *window, MetaWindow *other_window) { - return (window->xgroup_leader != None && - other_window->xgroup_leader != None && - window->xgroup_leader == other_window->xgroup_leader); + return + meta_window_get_group (window) == + meta_window_get_group (other_window); } void diff --git a/src/window.h b/src/window.h index 09d580334..c94173bcd 100644 --- a/src/window.h +++ b/src/window.h @@ -79,6 +79,7 @@ struct _MetaWindow char *role; char *sm_client_id; char *wm_client_machine; + char *startup_id; int net_wm_pid; @@ -437,4 +438,6 @@ void meta_window_update_layer (MetaWindow *window); gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect); +const char* meta_window_get_startup_id (MetaWindow *window); + #endif diff --git a/src/xprops.c b/src/xprops.c index a5bae985a..4f92e2d48 100644 --- a/src/xprops.c +++ b/src/xprops.c @@ -866,7 +866,9 @@ meta_prop_get_values (MetaDisplay *display, tasks = g_new0 (AgGetPropertyTask*, n_values); - /* Start up tasks */ + /* Start up tasks. The "values" array can have values + * with atom == None, which means to ignore that element. + */ i = 0; while (i < n_values) { @@ -875,7 +877,11 @@ meta_prop_get_values (MetaDisplay *display, switch (values[i].type) { case META_PROP_VALUE_INVALID: - meta_bug ("META_PROP_VALUE_INVALID requested in %s\n", G_GNUC_FUNCTION); + /* This means we don't really want a value, e.g. got + * property notify on an atom we don't care about. + */ + if (values[i].atom != None) + meta_bug ("META_PROP_VALUE_INVALID requested in %s\n", G_GNUC_FUNCTION); break; case META_PROP_VALUE_UTF8_LIST: case META_PROP_VALUE_UTF8: @@ -911,10 +917,11 @@ meta_prop_get_values (MetaDisplay *display, break; } } - - tasks[i] = get_task (display, xwindow, - values[i].atom, values[i].required_type); + if (values[i].atom != None) + tasks[i] = get_task (display, xwindow, + values[i].atom, values[i].required_type); + ++i; } @@ -932,8 +939,8 @@ meta_prop_get_values (MetaDisplay *display, if (tasks[i] == NULL) { - /* task creation failed for this property - * (doesn't actually happen I guess) + /* Probably values[i].type was None, or ag_task_create() + * returned NULL. */ values[i].type = META_PROP_VALUE_INVALID; goto next;