diff --git a/ChangeLog b/ChangeLog index 7b9dc3672..7f305fd82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2002-08-12 Havoc Pennington + + * 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. + 2002-08-11 Havoc Pennington * src/menu.c: don't include nonexistent stock-icons.h file diff --git a/src/Makefile.am b/src/Makefile.am index c04d4807c..d0d234b26 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 7539fe759..ec45e27c2 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 754110b7b..7c56d24fe 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 000000000..8550c50c2 --- /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 000000000..c14dc3097 --- /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 4b8c00ad1..94f1f3af7 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 @@ -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 aff236e9e..b604a612a 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 2ba94d5f1..c45cb707d 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 #define _(x) dgettext (GETTEXT_PACKAGE, x) #define N_(x) x diff --git a/src/window.c b/src/window.c index 0b3e264fc..3d8e06e86 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 @@ -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 f10e632f1..847204c67 100644 --- a/src/window.h +++ b/src/window.h @@ -29,6 +29,8 @@ #include #include +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)