diff options
author | Perberos <[email protected]> | 2011-12-01 23:52:01 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-12-01 23:52:01 -0300 |
commit | 28a029a4990d2a84f9d6a0b890eba812ea503998 (patch) | |
tree | 7a69477d0dd6bf351801fa9698d95224e4fe47b6 /src/core/group.c | |
download | marco-28a029a4990d2a84f9d6a0b890eba812ea503998.tar.bz2 marco-28a029a4990d2a84f9d6a0b890eba812ea503998.tar.xz |
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'src/core/group.c')
-rw-r--r-- | src/core/group.c | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/core/group.c b/src/core/group.c new file mode 100644 index 00000000..35db53c7 --- /dev/null +++ b/src/core/group.c @@ -0,0 +1,274 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* Marco window groups */ + +/* + * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2003 Rob Adams + * + * 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 "util.h" +#include "group-private.h" +#include "group-props.h" +#include "window.h" + +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; + 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); + + /* 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; +} + +static void +meta_group_unref (MetaGroup *group) +{ + g_return_if_fail (group->refcount > 0); + + 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, + &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->wm_client_machine); + g_free (group->startup_id); + + g_free (group); + } +} + +MetaGroup* +meta_window_get_group (MetaWindow *window) +{ + if (window->unmanaging) + return NULL; + + return window->group; +} + +void +meta_window_compute_group (MetaWindow* window) +{ + MetaGroup *group; + MetaWindow *ancestor; + + /* use window->xwindow if no window->xgroup_leader */ + + group = NULL; + + /* Determine the ancestor of the window; its group setting will override the + * normal grouping rules; see bug 328211. + */ + ancestor = meta_window_find_root_ancestor (window); + + if (window->display->groups_by_leader) + { + if (ancestor != window) + group = ancestor->group; + else 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) + { + window->group = group; + group->refcount += 1; + } + else + { + if (ancestor != window && ancestor->xgroup_leader != None) + group = meta_group_new (window->display, + ancestor->xgroup_leader); + else if (window->xgroup_leader != None) + group = meta_group_new (window->display, + window->xgroup_leader); + else + group = meta_group_new (window->display, + window->xwindow); + + window->group = group; + } + + window->group->windows = g_slist_prepend (window->group->windows, window); + + meta_topic (META_DEBUG_GROUPS, + "Adding %s to group with leader 0x%lx\n", + window->desc, group->group_leader); + +} + +static void +remove_window_from_group (MetaWindow *window) +{ + if (window->group != NULL) + { + meta_topic (META_DEBUG_GROUPS, + "Removing %s from group with leader 0x%lx\n", + window->desc, window->group->group_leader); + + window->group->windows = + g_slist_remove (window->group->windows, + window); + meta_group_unref (window->group); + window->group = NULL; + } +} + +void +meta_window_group_leader_changed (MetaWindow *window) +{ + remove_window_from_group (window); + meta_window_compute_group (window); +} + +void +meta_window_shutdown_group (MetaWindow *window) +{ + remove_window_from_group (window); +} + +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); +} + +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; + +} |