summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2002-08-12 21:32:13 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-08-12 21:32:13 +0000
commit27e35b8bcde23717494af4f651eedabfae2d6b96 (patch)
treea1905e1484bc72a00e3caa3b76776ee4062ebb75 /src
parent501264647eb4241127f6cee9c9bfc16a6e75d193 (diff)
downloadmetacity-27e35b8bcde23717494af4f651eedabfae2d6b96.tar.gz
metacity-27e35b8bcde23717494af4f651eedabfae2d6b96.tar.bz2
window is in fullscreen layer if any member of its group is fullscreen
2002-08-12 Havoc Pennington <hp@redhat.com> * src/stack.c (compute_layer): window is in fullscreen layer if any member of its group is fullscreen * src/window.c (meta_window_unmake_fullscreen): update layer for whole window group (meta_window_make_fullscreen): ditto * src/util.c (meta_unsigned_long_hash): move hash/equal funcs for Window in here. * src/group.c: track window groups so we can do stuff with them.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/display.c24
-rw-r--r--src/display.h3
-rw-r--r--src/group.c188
-rw-r--r--src/group.h43
-rw-r--r--src/stack.c36
-rw-r--r--src/util.c20
-rw-r--r--src/util.h4
-rw-r--r--src/window.c43
-rw-r--r--src/window.h5
10 files changed, 344 insertions, 24 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c04d480..d0d234b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,8 @@ metacity_SOURCES= \
frames.h \
gradient.c \
gradient.h \
+ group.c \
+ group.h \
iconcache.c \
iconcache.h \
inlinepixbufs.h \
diff --git a/src/display.c b/src/display.c
index 7539fe7..ec45e27 100644
--- a/src/display.c
+++ b/src/display.c
@@ -76,25 +76,6 @@ static void process_selection_request (MetaDisplay *display,
static void process_selection_clear (MetaDisplay *display,
XEvent *event);
-static gint
-unsigned_long_equal (gconstpointer v1,
- gconstpointer v2)
-{
- return *((const gulong*) v1) == *((const gulong*) v2);
-}
-
-static guint
-unsigned_long_hash (gconstpointer v)
-{
- gulong val = * (const gulong *) v;
-
- /* I'm not sure this works so well. */
-#if G_SIZEOF_LONG > 4
- return (guint) (val ^ (val >> 32));
-#else
- return val;
-#endif
-}
static int
set_utf8_string_hint (MetaDisplay *display,
@@ -386,6 +367,8 @@ meta_display_open (const char *name)
display->no_focus_window = None;
display->xinerama_cache_invalidated = TRUE;
+
+ display->groups_by_leader = NULL;
screens = NULL;
@@ -440,7 +423,8 @@ meta_display_open (const char *name)
display);
#endif
- display->window_ids = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
+ display->window_ids = g_hash_table_new (meta_unsigned_long_hash,
+ meta_unsigned_long_equal);
display->double_click_time = 250;
display->last_button_time = 0;
diff --git a/src/display.h b/src/display.h
index 754110b..7c56d24 100644
--- a/src/display.h
+++ b/src/display.h
@@ -244,6 +244,9 @@ struct _MetaDisplay
/* Closing down the display */
int closing;
+
+ /* Managed by group.c */
+ GHashTable *groups_by_leader;
};
gboolean meta_display_open (const char *name);
diff --git a/src/group.c b/src/group.c
new file mode 100644
index 0000000..8550c50
--- /dev/null
+++ b/src/group.c
@@ -0,0 +1,188 @@
+/* Metacity window groups */
+
+/*
+ * 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 "util.h"
+#include "group.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;
+
+ group = g_new0 (MetaGroup, 1);
+
+ group->display = display;
+ group->windows = NULL;
+ group->group_leader = group_leader;
+ group->refcount = 1; /* owned by caller, hash table has only weak ref */
+
+ if (display->groups_by_leader == NULL)
+ display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash,
+ meta_unsigned_long_equal);
+
+ g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL);
+
+ g_hash_table_insert (display->groups_by_leader,
+ &group->group_leader,
+ group);
+
+ return group;
+}
+
+static void
+meta_group_unref (MetaGroup *group)
+{
+ g_return_if_fail (group->refcount > 0);
+
+ group->refcount -= 1;
+ if (group->refcount == 0)
+ {
+ g_assert (group->display->groups_by_leader != NULL);
+
+ g_hash_table_remove (group->display->groups_by_leader,
+ &group->group_leader);
+
+ /* mop up hash table, this is how it gets freed on display close */
+ if (g_hash_table_size (group->display->groups_by_leader) == 0)
+ {
+ g_hash_table_destroy (group->display->groups_by_leader);
+ group->display->groups_by_leader = NULL;
+ }
+
+ g_free (group);
+ }
+}
+
+MetaGroup*
+meta_window_get_group (MetaWindow *window)
+{
+ if (window->cached_group == NULL &&
+ window->xgroup_leader != None) /* some windows have no group */
+ {
+ MetaGroup *group;
+
+ group = NULL;
+
+ if (window->display->groups_by_leader)
+ group = g_hash_table_lookup (window->display->groups_by_leader,
+ &window->xgroup_leader);
+
+ if (group != NULL)
+ {
+ window->cached_group = group;
+ group->refcount += 1;
+ }
+ else
+ {
+ group = meta_group_new (window->display,
+ window->xgroup_leader);
+
+ window->cached_group = group;
+ }
+
+ window->cached_group->windows = g_slist_prepend (window->cached_group->windows,
+ window);
+ }
+
+ return window->cached_group;
+}
+
+void
+meta_window_shutdown_group (MetaWindow *window)
+{
+ if (window->cached_group != NULL)
+ {
+ window->cached_group->windows =
+ g_slist_remove (window->cached_group->windows,
+ window);
+ meta_group_unref (window->cached_group);
+ window->cached_group = NULL;
+ }
+}
+
+MetaGroup*
+meta_display_lookup_group (MetaDisplay *display,
+ Window group_leader)
+{
+ MetaGroup *group;
+
+ group = NULL;
+
+ if (display->groups_by_leader)
+ group = g_hash_table_lookup (display->groups_by_leader,
+ &group_leader);
+
+ return group;
+}
+
+GSList*
+meta_group_list_windows (MetaGroup *group)
+{
+ return g_slist_copy (group->windows);
+}
+
+void
+meta_group_update_layers (MetaGroup *group)
+{
+ GSList *tmp;
+ GSList *frozen_stacks;
+
+ if (group->windows == NULL)
+ return;
+
+ frozen_stacks = NULL;
+ tmp = group->windows;
+ while (tmp != NULL)
+ {
+ MetaWindow *window = tmp->data;
+
+ /* we end up freezing the same stack a lot of times,
+ * but doesn't hurt anything. have to handle
+ * groups that span 2 screens.
+ */
+ meta_stack_freeze (window->screen->stack);
+ frozen_stacks = g_slist_prepend (frozen_stacks, window->screen->stack);
+
+ meta_stack_update_layer (window->screen->stack,
+ window);
+
+ tmp = tmp->next;
+ }
+
+ tmp = frozen_stacks;
+ while (tmp != NULL)
+ {
+ meta_stack_thaw (tmp->data);
+ tmp = tmp->next;
+ }
+
+ g_slist_free (frozen_stacks);
+}
diff --git a/src/group.h b/src/group.h
new file mode 100644
index 0000000..c14dc30
--- /dev/null
+++ b/src/group.h
@@ -0,0 +1,43 @@
+/* Metacity window groups */
+
+/*
+ * 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_H
+#define META_GROUP_H
+
+#include "window.h"
+
+/* note, can return NULL */
+MetaGroup* meta_window_get_group (MetaWindow *window);
+void meta_window_shutdown_group (MetaWindow *window);
+
+/* note, can return NULL */
+MetaGroup* meta_display_lookup_group (MetaDisplay *display,
+ Window group_leader);
+
+GSList* meta_group_list_windows (MetaGroup *group);
+
+void meta_group_update_layers (MetaGroup *group);
+
+#endif
+
+
+
+
diff --git a/src/stack.c b/src/stack.c
index 4b8c00a..94f1f3a 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -23,6 +23,7 @@
#include "window.h"
#include "errors.h"
#include "frame.h"
+#include "group.h"
#include "workspace.h"
#include <X11/Xatom.h>
@@ -256,6 +257,37 @@ meta_stack_thaw (MetaStack *stack)
meta_stack_sync_to_server (stack);
}
+static gboolean
+group_member_is_fullscreen (MetaWindow *window)
+{
+ GSList *members;
+ MetaGroup *group;
+ GSList *tmp;
+ gboolean retval;
+
+ group = meta_window_get_group (window);
+ if (group == NULL)
+ return FALSE;
+
+ retval = FALSE;
+ members = meta_group_list_windows (group);
+ tmp = members;
+ while (tmp != NULL)
+ {
+ MetaWindow *w = tmp->data;
+
+ if (w->fullscreen)
+ {
+ retval = TRUE;
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+
+ return retval;
+}
+
static void
compute_layer (MetaWindow *window)
{
@@ -275,12 +307,12 @@ compute_layer (MetaWindow *window)
break;
default:
- if (window->fullscreen)
+ if (group_member_is_fullscreen (window))
window->layer = META_LAYER_FULLSCREEN;
else
window->layer = META_LAYER_NORMAL;
break;
- }
+ }
meta_topic (META_DEBUG_STACK, "Window %s on layer %d\n",
window->desc, window->layer);
diff --git a/src/util.c b/src/util.c
index aff236e..b604a61 100644
--- a/src/util.c
+++ b/src/util.c
@@ -369,3 +369,23 @@ meta_exit (MetaExitCode code)
exit (code);
}
+
+gint
+meta_unsigned_long_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ return *((const gulong*) v1) == *((const gulong*) v2);
+}
+
+guint
+meta_unsigned_long_hash (gconstpointer v)
+{
+ gulong val = * (const gulong *) v;
+
+ /* I'm not sure this works so well. */
+#if G_SIZEOF_LONG > 4
+ return (guint) (val ^ (val >> 32));
+#else
+ return val;
+#endif
+}
diff --git a/src/util.h b/src/util.h
index 2ba94d5..c45cb70 100644
--- a/src/util.h
+++ b/src/util.h
@@ -69,6 +69,10 @@ void meta_topic (MetaDebugTopic topic,
void meta_push_no_msg_prefix (void);
void meta_pop_no_msg_prefix (void);
+gint meta_unsigned_long_equal (gconstpointer v1,
+ gconstpointer v2);
+guint meta_unsigned_long_hash (gconstpointer v);
+
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
diff --git a/src/window.c b/src/window.c
index 0b3e264..3d8e06e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -34,6 +34,7 @@
#include "prefs.h"
#include "resizepopup.h"
#include "xprops.h"
+#include "group.h"
#include <X11/Xatom.h>
@@ -408,6 +409,8 @@ meta_window_new (MetaDisplay *display, Window xwindow,
window->right_strut = 0;
window->top_strut = 0;
window->bottom_strut = 0;
+
+ window->cached_group = NULL;
window->layer = META_LAYER_NORMAL;
window->stack_op = NULL;
@@ -943,6 +946,8 @@ meta_window_free (MetaWindow *window)
g_object_unref (G_OBJECT (window->mini_icon));
meta_icon_cache_free (&window->icon_cache);
+
+ meta_window_shutdown_group (window);
g_free (window->sm_client_id);
g_free (window->wm_client_machine);
@@ -1646,6 +1651,8 @@ meta_window_make_fullscreen (MetaWindow *window)
{
if (!window->fullscreen)
{
+ MetaGroup *group;
+
meta_topic (META_DEBUG_WINDOW_OPS,
"Fullscreening %s\n", window->desc);
@@ -1654,8 +1661,15 @@ meta_window_make_fullscreen (MetaWindow *window)
window->fullscreen = TRUE;
- meta_stack_update_layer (window->screen->stack, window);
+ meta_stack_freeze (window->screen->stack);
+ group = meta_window_get_group (window);
+ if (group)
+ meta_group_update_layers (group);
+ else
+ meta_stack_update_layer (window->screen->stack, window);
+
meta_window_raise (window);
+ meta_stack_thaw (window->screen->stack);
/* save size/pos as appropriate args for move_resize */
window->saved_rect = window->rect;
@@ -1678,12 +1692,20 @@ meta_window_unmake_fullscreen (MetaWindow *window)
{
if (window->fullscreen)
{
+ MetaGroup *group;
+
meta_topic (META_DEBUG_WINDOW_OPS,
"Unfullscreening %s\n", window->desc);
window->fullscreen = FALSE;
- meta_stack_update_layer (window->screen->stack, window);
+ meta_stack_freeze (window->screen->stack);
+ group = meta_window_get_group (window);
+ if (group)
+ meta_group_update_layers (group);
+ else
+ meta_stack_update_layer (window->screen->stack, window);
+ meta_stack_thaw (window->screen->stack);
meta_window_move_resize (window,
TRUE,
@@ -4197,6 +4219,9 @@ static int
update_wm_hints (MetaWindow *window)
{
XWMHints *hints;
+ Window old_group_leader;
+
+ old_group_leader = window->xgroup_leader;
/* Fill in defaults */
window->input = TRUE;
@@ -4234,6 +4259,20 @@ update_wm_hints (MetaWindow *window)
meta_XFree (hints);
}
+
+ 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);
+ }
return meta_error_trap_pop (window->display);
}
diff --git a/src/window.h b/src/window.h
index f10e632..847204c 100644
--- a/src/window.h
+++ b/src/window.h
@@ -29,6 +29,8 @@
#include <X11/Xutil.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+typedef struct _MetaGroup MetaGroup;
+
typedef void (*MetaWindowForeachFunc) (MetaWindow *window,
void *data);
@@ -252,6 +254,9 @@ struct _MetaWindow
/* Current dialog open for this window */
int dialog_pid;
int dialog_pipe;
+
+ /* maintained by group.c */
+ MetaGroup *cached_group;
};
#define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->maximized && !(w)->fullscreen)