summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-12-01 03:58:04 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-12-01 03:58:04 +0000
commit5e1439f89e7acd7d57c4027eea2160953fb323f1 (patch)
tree43c90978783096f9858b781cc18b172d8f56192a
parenteb40c5c2cfed8f4dae46fe865526cf880feec7ba (diff)
downloadmetacity-5e1439f89e7acd7d57c4027eea2160953fb323f1.tar.gz
lengthen to 15 seconds
2002-11-30 Havoc Pennington <hp@pobox.com> * 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.
-rw-r--r--ChangeLog52
-rw-r--r--configure.in2
-rw-r--r--src/Makefile.am3
-rw-r--r--src/display.c55
-rw-r--r--src/display.h7
-rw-r--r--src/group-private.h41
-rw-r--r--src/group-props.c230
-rw-r--r--src/group-props.h35
-rw-r--r--src/group.c104
-rw-r--r--src/group.h7
-rw-r--r--src/screen.c79
-rw-r--r--src/screen.h3
-rw-r--r--src/util.c11
-rw-r--r--src/util.h3
-rw-r--r--src/window-props.c42
-rw-r--r--src/window.c64
-rw-r--r--src/window.h3
-rw-r--r--src/xprops.c21
18 files changed, 684 insertions, 78 deletions
diff --git a/ChangeLog b/ChangeLog
index c3529936..28e81aa2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2002-11-30 Havoc Pennington <hp@pobox.com>
+
+ * 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 <calum.benson@sun.com>
* src/themes/Crux :
diff --git a/configure.in b/configure.in
index aa9d3123..b305f181 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 73a7512d..ab173bd8 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 8198276e..4c880191 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 d4055943..4aa3ffd9 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 00000000..1ec7a249
--- /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 00000000..707b2912
--- /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 <config.h>
+#include "group-props.h"
+#include "group-private.h"
+#include "xprops.h"
+#include <X11/Xatom.h>
+
+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 00000000..727c636a
--- /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 9deb9bfa..ab35cd26 100644
--- a/src/group.c
+++ b/src/group.c
@@ -21,23 +21,21 @@
#include <config.h>
#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 c14dc309..6639839a 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 76740bdf..ef062703 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 04de75cf..351f6b92 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 8d5a57e3..92b96f8e 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 7ade91b7..a339352a 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 9bcfb1c3..f1d19ce6 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 0f2d63db..dbfcd843 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 09d58033..c94173bc 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 a5bae985..4f92e2d4 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;