group.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity window groups */
00004 
00005 /* 
00006  * Copyright (C) 2002 Red Hat Inc.
00007  * Copyright (C) 2003 Rob Adams
00008  * 
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of the
00012  * License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00022  * 02111-1307, USA.
00023  */
00024 
00025 #include <config.h>
00026 #include "util.h"
00027 #include "group-private.h"
00028 #include "group-props.h"
00029 #include "window.h"
00030 
00031 static MetaGroup*
00032 meta_group_new (MetaDisplay *display,
00033                 Window       group_leader)
00034 {
00035   MetaGroup *group;
00036 #define N_INITIAL_PROPS 3
00037   Atom initial_props[N_INITIAL_PROPS];
00038   int i;
00039   
00040   g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props));
00041   
00042   group = g_new0 (MetaGroup, 1);
00043 
00044   group->display = display;
00045   group->windows = NULL;
00046   group->group_leader = group_leader;
00047   group->refcount = 1; /* owned by caller, hash table has only weak ref */
00048   
00049   if (display->groups_by_leader == NULL)
00050     display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash,
00051                                                   meta_unsigned_long_equal);
00052 
00053   g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL);
00054 
00055   g_hash_table_insert (display->groups_by_leader,
00056                        &group->group_leader,
00057                        group);
00058 
00059   /* Fill these in the order we want them to be gotten */
00060   i = 0;
00061   initial_props[i++] = display->atom_WM_CLIENT_MACHINE;
00062   initial_props[i++] = display->atom__NET_WM_PID;
00063   initial_props[i++] = display->atom__NET_STARTUP_ID;
00064   g_assert (N_INITIAL_PROPS == i);
00065   
00066   meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS);
00067 
00068   meta_topic (META_DEBUG_GROUPS,
00069               "Created new group with leader 0x%lx\n",
00070               group->group_leader);
00071   
00072   return group;
00073 }
00074 
00075 static void
00076 meta_group_unref (MetaGroup *group)
00077 {
00078   g_return_if_fail (group->refcount > 0);
00079 
00080   group->refcount -= 1;
00081   if (group->refcount == 0)
00082     {
00083       meta_topic (META_DEBUG_GROUPS,
00084                   "Destroying group with leader 0x%lx\n",
00085                   group->group_leader);      
00086       
00087       g_assert (group->display->groups_by_leader != NULL);
00088       
00089       g_hash_table_remove (group->display->groups_by_leader,
00090                            &group->group_leader);
00091 
00092       /* mop up hash table, this is how it gets freed on display close */
00093       if (g_hash_table_size (group->display->groups_by_leader) == 0)
00094         {
00095           g_hash_table_destroy (group->display->groups_by_leader);
00096           group->display->groups_by_leader = NULL;
00097         }
00098 
00099       g_free (group->wm_client_machine);
00100       g_free (group->startup_id);
00101       
00102       g_free (group);
00103     }
00104 }
00105 
00106 MetaGroup*
00107 meta_window_get_group (MetaWindow *window)
00108 {
00109   if (window->unmanaging)
00110     return NULL;
00111 
00112   return window->group;
00113 }
00114 
00115 void
00116 meta_window_compute_group (MetaWindow* window)
00117 {
00118   MetaGroup *group;
00119   MetaWindow *ancestor;
00120 
00121   /* use window->xwindow if no window->xgroup_leader */
00122       
00123   group = NULL;
00124       
00125   /* Determine the ancestor of the window; its group setting will override the
00126    * normal grouping rules; see bug 328211.
00127    */
00128   ancestor = meta_window_find_root_ancestor (window);
00129 
00130   if (window->display->groups_by_leader)
00131     {
00132       if (ancestor != window)
00133         group = ancestor->group;
00134       else if (window->xgroup_leader != None)
00135         group = g_hash_table_lookup (window->display->groups_by_leader,
00136                                      &window->xgroup_leader);
00137       else
00138         group = g_hash_table_lookup (window->display->groups_by_leader,
00139                                      &window->xwindow);
00140     }
00141       
00142   if (group != NULL)
00143     {
00144       window->group = group;
00145       group->refcount += 1;
00146     }
00147   else
00148     {
00149       if (ancestor != window && ancestor->xgroup_leader != None)
00150         group = meta_group_new (window->display,
00151                                 ancestor->xgroup_leader);
00152       else if (window->xgroup_leader != None)
00153         group = meta_group_new (window->display,
00154                                 window->xgroup_leader);
00155       else
00156         group = meta_group_new (window->display,
00157                                 window->xwindow);
00158           
00159       window->group = group;
00160     }
00161 
00162   window->group->windows = g_slist_prepend (window->group->windows, window);
00163 
00164   meta_topic (META_DEBUG_GROUPS,
00165               "Adding %s to group with leader 0x%lx\n",
00166               window->desc, group->group_leader);
00167 
00168 }
00169 
00170 static void
00171 remove_window_from_group (MetaWindow *window)
00172 {
00173   if (window->group != NULL)
00174     {
00175       meta_topic (META_DEBUG_GROUPS,
00176                   "Removing %s from group with leader 0x%lx\n",
00177                   window->desc, window->group->group_leader);
00178       
00179       window->group->windows =
00180         g_slist_remove (window->group->windows,
00181                         window);
00182       meta_group_unref (window->group);
00183       window->group = NULL;
00184     }
00185 }
00186 
00187 void
00188 meta_window_group_leader_changed (MetaWindow *window)
00189 {
00190   remove_window_from_group (window);
00191   meta_window_compute_group (window);
00192 }
00193 
00194 void
00195 meta_window_shutdown_group (MetaWindow *window)
00196 {
00197   remove_window_from_group (window);
00198 }
00199 
00200 MetaGroup*
00201 meta_display_lookup_group (MetaDisplay *display,
00202                            Window       group_leader)
00203 {
00204   MetaGroup *group;
00205   
00206   group = NULL;
00207   
00208   if (display->groups_by_leader)
00209     group = g_hash_table_lookup (display->groups_by_leader,
00210                                  &group_leader);
00211 
00212   return group;
00213 }
00214 
00215 GSList*
00216 meta_group_list_windows (MetaGroup *group)
00217 {
00218   return g_slist_copy (group->windows);
00219 }
00220 
00221 void
00222 meta_group_update_layers (MetaGroup *group)
00223 {
00224   GSList *tmp;
00225   GSList *frozen_stacks;
00226   
00227   if (group->windows == NULL)
00228     return;
00229 
00230   frozen_stacks = NULL;
00231   tmp = group->windows;
00232   while (tmp != NULL)
00233     {
00234       MetaWindow *window = tmp->data;
00235 
00236       /* we end up freezing the same stack a lot of times,
00237        * but doesn't hurt anything. have to handle
00238        * groups that span 2 screens.
00239        */
00240       meta_stack_freeze (window->screen->stack);
00241       frozen_stacks = g_slist_prepend (frozen_stacks, window->screen->stack);
00242 
00243       meta_stack_update_layer (window->screen->stack,
00244                                window);
00245       
00246       tmp = tmp->next;
00247     }
00248 
00249   tmp = frozen_stacks;
00250   while (tmp != NULL)
00251     {
00252       meta_stack_thaw (tmp->data);
00253       tmp = tmp->next;
00254     }
00255 
00256   g_slist_free (frozen_stacks);
00257 }
00258 
00259 const char*
00260 meta_group_get_startup_id (MetaGroup *group)
00261 {
00262   return group->startup_id;
00263 }
00264 
00265 gboolean
00266 meta_group_property_notify (MetaGroup  *group,
00267                             XEvent     *event)
00268 {
00269   meta_group_reload_property (group,
00270                               event->xproperty.atom);
00271 
00272   return TRUE;
00273 
00274 }

Generated on Sat Aug 23 22:04:16 2008 for metacity by  doxygen 1.5.5