mutter/src/group.c

189 lines
4.7 KiB
C
Raw Normal View History

/* 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);
}