stack.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00007 /* 
00008  * Copyright (C) 2001 Havoc Pennington
00009  * Copyright (C) 2002, 2003 Red Hat, Inc.
00010  * Copyright (C) 2004 Rob Adams
00011  * Copyright (C) 2004, 2005 Elijah Newren
00012  * 
00013  * This program is free software; you can redistribute it and/or
00014  * modify it under the terms of the GNU General Public License as
00015  * published by the Free Software Foundation; either version 2 of the
00016  * License, or (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful, but
00019  * WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  * General Public License for more details.
00022  * 
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00026  * 02111-1307, USA.
00027  */
00028 
00029 #include <config.h>
00030 #include "stack.h"
00031 #include "window-private.h"
00032 #include "errors.h"
00033 #include "frame-private.h"
00034 #include "group.h"
00035 #include "prefs.h"
00036 #include "workspace.h"
00037 
00038 #include <X11/Xatom.h>
00039 
00040 #define WINDOW_HAS_TRANSIENT_TYPE(w)                    \
00041           (w->type == META_WINDOW_DIALOG ||             \
00042            w->type == META_WINDOW_MODAL_DIALOG ||       \
00043            w->type == META_WINDOW_TOOLBAR ||            \
00044            w->type == META_WINDOW_MENU ||               \
00045            w->type == META_WINDOW_UTILITY)
00046 
00047 #define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w)             \
00048          ((w->xtransient_for == None ||                 \
00049            w->transient_parent_is_root_window) &&       \
00050           WINDOW_HAS_TRANSIENT_TYPE (w))
00051 
00052 #define WINDOW_IN_STACK(w) (w->stack_position >= 0)
00053 
00054 static void stack_sync_to_server (MetaStack *stack);
00055 static void meta_window_set_stack_position_no_sync (MetaWindow *window,
00056                                                     int         position);
00057 static void stack_do_window_deletions (MetaStack *stack);
00058 static void stack_do_window_additions (MetaStack *stack);
00059 static void stack_do_relayer          (MetaStack *stack);
00060 static void stack_do_constrain        (MetaStack *stack);
00061 static void stack_do_resort           (MetaStack *stack);
00062 
00063 static void stack_ensure_sorted (MetaStack *stack);
00064 
00065 MetaStack*
00066 meta_stack_new (MetaScreen *screen)
00067 {
00068   MetaStack *stack;
00069   
00070   stack = g_new (MetaStack, 1);
00071 
00072   stack->screen = screen;
00073   stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
00074 
00075   stack->sorted = NULL;
00076   stack->added = NULL;
00077   stack->removed = NULL;
00078 
00079   stack->freeze_count = 0;
00080   stack->last_root_children_stacked = NULL;
00081 
00082   stack->n_positions = 0;
00083 
00084   stack->need_resort = FALSE;
00085   stack->need_relayer = FALSE;
00086   stack->need_constrain = FALSE;
00087   
00088   return stack;
00089 }
00090 
00091 void
00092 meta_stack_free (MetaStack *stack)
00093 {
00094   g_array_free (stack->windows, TRUE);
00095 
00096   g_list_free (stack->sorted);
00097   g_list_free (stack->added);
00098   g_list_free (stack->removed);
00099 
00100   if (stack->last_root_children_stacked)
00101     g_array_free (stack->last_root_children_stacked, TRUE);
00102   
00103   g_free (stack);
00104 }
00105 
00106 void
00107 meta_stack_add (MetaStack  *stack,
00108                 MetaWindow *window)
00109 {
00110   meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc);
00111 
00112   if (window->stack_position >= 0)
00113     meta_bug ("Window %s had stack position already\n", window->desc);
00114   
00115   stack->added = g_list_prepend (stack->added, window);
00116 
00117   window->stack_position = stack->n_positions;
00118   stack->n_positions += 1;
00119   meta_topic (META_DEBUG_STACK,
00120               "Window %s has stack_position initialized to %d\n",
00121               window->desc, window->stack_position);
00122   
00123   stack_sync_to_server (stack);
00124 }
00125 
00126 void
00127 meta_stack_remove (MetaStack  *stack,
00128                    MetaWindow *window)
00129 {
00130   meta_topic (META_DEBUG_STACK, "Removing window %s from the stack\n", window->desc);
00131 
00132   if (window->stack_position < 0)
00133     meta_bug ("Window %s removed from stack but had no stack position\n",
00134               window->desc);
00135 
00136   /* Set window to top position, so removing it will not leave gaps
00137    * in the set of positions
00138    */
00139   meta_window_set_stack_position_no_sync (window,
00140                                           stack->n_positions - 1);
00141   window->stack_position = -1;
00142   stack->n_positions -= 1;  
00143 
00144   /* We don't know if it's been moved from "added" to "stack" yet */
00145   stack->added = g_list_remove (stack->added, window);
00146   stack->sorted = g_list_remove (stack->sorted, window);
00147 
00148   /* Remember the window ID to remove it from the stack array.
00149    * The macro is safe to use: Window is guaranteed to be 32 bits, and
00150    * GUINT_TO_POINTER says it only works on 32 bits.
00151    */
00152   stack->removed = g_list_prepend (stack->removed,
00153                                    GUINT_TO_POINTER (window->xwindow));
00154   if (window->frame)
00155     stack->removed = g_list_prepend (stack->removed,
00156                                      GUINT_TO_POINTER (window->frame->xwindow));
00157   
00158   stack_sync_to_server (stack);
00159 }
00160 
00161 void
00162 meta_stack_update_layer (MetaStack  *stack,
00163                          MetaWindow *window)
00164 {
00165   stack->need_relayer = TRUE;
00166   
00167   stack_sync_to_server (stack);
00168 }
00169 
00170 void
00171 meta_stack_update_transient (MetaStack  *stack,
00172                              MetaWindow *window)
00173 {
00174   stack->need_constrain = TRUE;
00175   
00176   stack_sync_to_server (stack);
00177 }
00178 
00179 /* raise/lower within a layer */
00180 void
00181 meta_stack_raise (MetaStack  *stack,
00182                   MetaWindow *window)
00183 {  
00184   meta_window_set_stack_position_no_sync (window,
00185                                           stack->n_positions - 1);
00186   
00187   stack_sync_to_server (stack);
00188 }
00189 
00190 void
00191 meta_stack_lower (MetaStack  *stack,
00192                   MetaWindow *window)
00193 {
00194   meta_window_set_stack_position_no_sync (window, 0);
00195   
00196   stack_sync_to_server (stack);
00197 }
00198 
00199 void
00200 meta_stack_freeze (MetaStack *stack)
00201 {
00202   stack->freeze_count += 1;
00203 }
00204 
00205 void
00206 meta_stack_thaw (MetaStack *stack)
00207 {
00208   g_return_if_fail (stack->freeze_count > 0);
00209   
00210   stack->freeze_count -= 1;
00211   stack_sync_to_server (stack);
00212 }
00213 
00214 static gboolean
00215 is_focused_foreach (MetaWindow *window,
00216                     void       *data)
00217 {
00218   if (window == window->display->expected_focus_window)
00219     {
00220       *((gboolean*) data) = TRUE;
00221       return FALSE;
00222     }
00223   return TRUE;
00224 }
00225 
00226 static gboolean
00227 windows_on_different_xinerama (MetaWindow *a,
00228                                MetaWindow *b)
00229 {
00230   if (a->screen != b->screen)
00231     return TRUE;
00232 
00233   return meta_screen_get_xinerama_for_window (a->screen, a) !=
00234     meta_screen_get_xinerama_for_window (b->screen, b);
00235 }
00236 
00237 /* Get layer ignoring any transient or group relationships */
00238 static MetaStackLayer
00239 get_standalone_layer (MetaWindow *window)
00240 {
00241   MetaStackLayer layer;
00242   gboolean focused_transient = FALSE;
00243   
00244   switch (window->type)
00245     {
00246     case META_WINDOW_DESKTOP:
00247       layer = META_LAYER_DESKTOP;
00248       break;
00249 
00250     case META_WINDOW_DOCK:
00251       /* still experimenting here */
00252       if (window->wm_state_below)
00253         layer = META_LAYER_BOTTOM;
00254       else
00255         layer = META_LAYER_DOCK;
00256       break;
00257 
00258     default:       
00259       meta_window_foreach_transient (window,
00260                                      is_focused_foreach,
00261                                      &focused_transient);
00262 
00263       if (window->wm_state_below)
00264         layer = META_LAYER_BOTTOM;
00265       else if (window->fullscreen &&
00266                (focused_transient ||
00267                 window == window->display->expected_focus_window ||
00268                 window->display->expected_focus_window == NULL ||
00269                 (window->display->expected_focus_window != NULL &&
00270                  windows_on_different_xinerama (window,
00271                                                 window->display->expected_focus_window))))
00272         layer = META_LAYER_FULLSCREEN;
00273       else if (window->wm_state_above)
00274         layer = META_LAYER_TOP;
00275       else
00276         layer = META_LAYER_NORMAL;
00277       break;
00278     }
00279 
00280   return layer;
00281 }
00282 
00283 /* Note that this function can never use window->layer only
00284  * get_standalone_layer, or we'd have issues.
00285  */
00286 static MetaStackLayer
00287 get_maximum_layer_in_group (MetaWindow *window)
00288 {
00289   GSList *members;
00290   MetaGroup *group;
00291   GSList *tmp;
00292   MetaStackLayer max;
00293   MetaStackLayer layer;
00294   
00295   max = META_LAYER_DESKTOP;
00296   
00297   group = meta_window_get_group (window);
00298 
00299   if (group != NULL)
00300     members = meta_group_list_windows (group);
00301   else
00302     members = NULL;
00303   
00304   tmp = members;
00305   while (tmp != NULL)
00306     {
00307       MetaWindow *w = tmp->data;
00308 
00309       layer = get_standalone_layer (w);
00310       if (layer > max)
00311         max = layer;
00312       
00313       tmp = tmp->next;
00314     }
00315 
00316   g_slist_free (members);
00317   
00318   return max;
00319 }
00320 
00321 static void
00322 compute_layer (MetaWindow *window)
00323 {
00324   window->layer = get_standalone_layer (window);
00325   
00326   /* We can only do promotion-due-to-group for dialogs and other
00327    * transients, or weird stuff happens like the desktop window and
00328    * nautilus windows getting in the same layer, or all gnome-terminal
00329    * windows getting in fullscreen layer if any terminal is
00330    * fullscreen.
00331    */
00332   if (WINDOW_HAS_TRANSIENT_TYPE(window) &&
00333       (window->xtransient_for == None ||
00334        window->transient_parent_is_root_window))
00335     {
00336       /* We only do the group thing if the dialog is NOT transient for
00337        * a particular window. Imagine a group with a normal window, a dock,
00338        * and a dialog transient for the normal window; you don't want the dialog
00339        * above the dock if it wouldn't normally be.
00340        */
00341       
00342       MetaStackLayer group_max;
00343       
00344       group_max = get_maximum_layer_in_group (window);
00345       
00346       if (group_max > window->layer)
00347         {
00348           meta_topic (META_DEBUG_STACK,
00349                       "Promoting window %s from layer %u to %u due to group membership\n",
00350                       window->desc, window->layer, group_max);
00351           window->layer = group_max;
00352         }
00353     }
00354 
00355   meta_topic (META_DEBUG_STACK, "Window %s on layer %u type = %u has_focus = %d\n",
00356               window->desc, window->layer,
00357               window->type, window->has_focus);
00358 }
00359 
00360 /* Front of the layer list is the topmost window,
00361  * so the lower stack position is later in the list
00362  */
00363 static int
00364 compare_window_position (void *a,
00365                          void *b)
00366 {
00367   MetaWindow *window_a = a;
00368   MetaWindow *window_b = b;
00369 
00370   /* Go by layer, then stack_position */
00371   if (window_a->layer < window_b->layer)
00372     return 1; /* move window_a later in list */
00373   else if (window_a->layer > window_b->layer)
00374     return -1;
00375   else if (window_a->stack_position < window_b->stack_position)
00376     return 1; /* move window_a later in list */
00377   else if (window_a->stack_position > window_b->stack_position)
00378     return -1;
00379   else
00380     return 0; /* not reached */
00381 }
00382   
00383 /*
00384  * Stacking constraints
00385  * 
00386  * Assume constraints of the form "AB" meaning "window A must be
00387  * below window B"
00388  *
00389  * If we have windows stacked from bottom to top
00390  * "ABC" then raise A we get "BCA". Say C is
00391  * transient for B is transient for A. So
00392  * we have constraints AB and BC.
00393  *
00394  * After raising A, we need to reapply the constraints.
00395  * If we do this by raising one window at a time -
00396  *
00397  *  start:    BCA
00398  *  apply AB: CAB
00399  *  apply BC: ABC
00400  *
00401  * but apply constraints in the wrong order and it breaks:
00402  * 
00403  *  start:    BCA
00404  *  apply BC: BCA
00405  *  apply AB: CAB
00406  *
00407  * We make a directed graph of the constraints by linking
00408  * from "above windows" to "below windows as follows:
00409  * 
00410  *   AB -> BC -> CD
00411  *          \
00412  *           CE
00413  *
00414  * If we then walk that graph and apply the constraints in the order
00415  * that they appear, we will apply them correctly. Note that the
00416  * graph MAY have cycles, so we have to guard against that.
00417  *
00418  */
00419 
00420 typedef struct Constraint Constraint;
00421 
00422 struct Constraint
00423 {
00424   MetaWindow *above;
00425   MetaWindow *below;
00426 
00427   /* used to keep the constraint in the
00428    * list of constraints for window "below"
00429    */
00430   Constraint *next;
00431 
00432   /* used to create the graph. */
00433   GSList *next_nodes;
00434   
00435   /* constraint has been applied, used
00436    * to detect cycles.
00437    */
00438   unsigned int applied : 1;
00439 
00440   /* constraint has a previous node in the graph,
00441    * used to find places to start in the graph.
00442    * (I think this also has the side effect
00443    * of preventing cycles, since cycles will
00444    * have no starting point - so maybe
00445    * the "applied" flag isn't needed.)
00446    */
00447   unsigned int has_prev : 1;
00448 };
00449 
00450 /* We index the array of constraints by window
00451  * stack positions, just because the stack
00452  * positions are a convenient index.
00453  */
00454 static void
00455 add_constraint (Constraint **constraints,
00456                 MetaWindow  *above,
00457                 MetaWindow  *below)
00458 {
00459   Constraint *c;
00460 
00461   g_assert (above->screen == below->screen);
00462   
00463   /* check if constraint is a duplicate */
00464   c = constraints[below->stack_position];
00465   while (c != NULL)
00466     {
00467       if (c->above == above)
00468         return;
00469       c = c->next;
00470     }
00471 
00472   /* if not, add the constraint */
00473   c = g_new (Constraint, 1);
00474   c->above = above;
00475   c->below = below;
00476   c->next = constraints[below->stack_position];
00477   c->next_nodes = NULL;
00478   c->applied = FALSE;
00479   c->has_prev = FALSE;
00480 
00481   constraints[below->stack_position] = c;
00482 }
00483 
00484 static void
00485 create_constraints (Constraint **constraints,
00486                     GList       *windows)
00487 {
00488   GList *tmp;
00489   
00490   tmp = windows;
00491   while (tmp != NULL)
00492     {
00493       MetaWindow *w = tmp->data;
00494 
00495       if (!WINDOW_IN_STACK (w))
00496         {
00497           meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n",
00498                       w->desc);
00499           tmp = tmp->next;
00500           continue;
00501         }
00502       
00503       if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w))
00504         {
00505           GSList *group_windows;
00506           GSList *tmp2;
00507           MetaGroup *group;
00508 
00509           group = meta_window_get_group (w);
00510 
00511           if (group != NULL)
00512             group_windows = meta_group_list_windows (group);
00513           else
00514             group_windows = NULL;
00515           
00516           tmp2 = group_windows;
00517           
00518           while (tmp2 != NULL)
00519             {
00520               MetaWindow *group_window = tmp2->data;
00521 
00522               if (!WINDOW_IN_STACK (group_window) ||
00523                   w->screen != group_window->screen)
00524                 {
00525                   tmp2 = tmp2->next;
00526                   continue;
00527                 }
00528               
00529 #if 0
00530               /* old way of doing it */
00531               if (!(meta_window_is_ancestor_of_transient (w, group_window)) &&
00532                   !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window))  /* note */;/*note*/
00533 #else
00534               /* better way I think, so transient-for-group are constrained
00535                * only above non-transient-type windows in their group
00536                */
00537               if (!WINDOW_HAS_TRANSIENT_TYPE (group_window))
00538 #endif
00539                 {
00540                   meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n",
00541                               w->desc, group_window->desc);
00542                   add_constraint (constraints, w, group_window);
00543                 }
00544               
00545               tmp2 = tmp2->next;
00546             }
00547 
00548           g_slist_free (group_windows);
00549         }
00550       else if (w->xtransient_for != None &&
00551                !w->transient_parent_is_root_window)
00552         {
00553           MetaWindow *parent;
00554           
00555           parent =
00556             meta_display_lookup_x_window (w->display, w->xtransient_for);
00557 
00558           if (parent && WINDOW_IN_STACK (parent) &&
00559               parent->screen == w->screen)
00560             {
00561               meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n",
00562                           w->desc, parent->desc);
00563               add_constraint (constraints, w, parent);
00564             }
00565         }
00566       
00567       tmp = tmp->next;
00568     }
00569 }
00570 
00571 static void
00572 graph_constraints (Constraint **constraints,
00573                    int          n_constraints)
00574 {
00575   int i;
00576 
00577   i = 0;
00578   while (i < n_constraints)
00579     {
00580       Constraint *c;
00581 
00582       /* If we have "A below B" and "B below C" then AB -> BC so we
00583        * add BC to next_nodes in AB.
00584        */
00585       
00586       c = constraints[i];
00587       while (c != NULL)
00588         {
00589           Constraint *n;
00590             
00591           g_assert (c->below->stack_position == i);
00592 
00593           /* Constraints where ->above is below are our
00594            * next_nodes and we are their previous
00595            */
00596           n = constraints[c->above->stack_position];
00597           while (n != NULL)
00598             {
00599               c->next_nodes = g_slist_prepend (c->next_nodes,
00600                                                n);
00601               /* c is a previous node of n */
00602               n->has_prev = TRUE;
00603               
00604               n = n->next;
00605             }
00606           
00607           c = c->next;
00608         }
00609 
00610       ++i;
00611     }
00612 }
00613 
00614 static void
00615 free_constraints (Constraint **constraints,
00616                   int          n_constraints)
00617 {
00618   int i;
00619 
00620   i = 0;
00621   while (i < n_constraints)
00622     {
00623       Constraint *c;
00624       
00625       c = constraints[i];
00626       while (c != NULL)
00627         {
00628           Constraint *next = c->next;
00629           
00630           g_slist_free (c->next_nodes);
00631 
00632           g_free (c);
00633           
00634           c = next;
00635         }
00636 
00637       ++i;
00638     }
00639 }
00640 
00641 static void
00642 ensure_above (MetaWindow *above,
00643               MetaWindow *below)
00644 {  
00645   if (WINDOW_HAS_TRANSIENT_TYPE(above) &&
00646       above->layer < below->layer)
00647     {
00648       meta_topic (META_DEBUG_STACK,
00649                   "Promoting window %s from layer %u to %u due to contraint\n",
00650                   above->desc, above->layer, below->layer);
00651       above->layer = below->layer;
00652     }
00653 
00654   if (above->stack_position < below->stack_position)
00655     {
00656       /* move above to below->stack_position bumping below down the stack */
00657       meta_window_set_stack_position_no_sync (above, below->stack_position);
00658       g_assert (below->stack_position + 1 == above->stack_position);
00659     }
00660   meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n",
00661               above->desc, above->stack_position,
00662               below->desc, below->stack_position);
00663 }
00664 
00665 static void
00666 traverse_constraint (Constraint *c)
00667 {
00668   GSList *tmp;
00669 
00670   if (c->applied)
00671     return;
00672   
00673   ensure_above (c->above, c->below);
00674   c->applied = TRUE;
00675   
00676   tmp = c->next_nodes;
00677   while (tmp != NULL)
00678     {
00679       traverse_constraint (tmp->data);
00680 
00681       tmp = tmp->next;
00682     }
00683 }
00684 
00685 static void
00686 apply_constraints (Constraint **constraints,
00687                    int          n_constraints)
00688 {
00689   GSList *heads;
00690   GSList *tmp;
00691   int i;
00692 
00693   /* List all heads in an ordered constraint chain */
00694   heads = NULL;
00695   i = 0;
00696   while (i < n_constraints)
00697     {
00698       Constraint *c;
00699       
00700       c = constraints[i];
00701       while (c != NULL)
00702         {
00703           if (!c->has_prev)
00704             heads = g_slist_prepend (heads, c);
00705           
00706           c = c->next;
00707         }
00708 
00709       ++i;
00710     }
00711 
00712   /* Now traverse the chain and apply constraints */
00713   tmp = heads;
00714   while (tmp != NULL)
00715     {
00716       Constraint *c = tmp->data;
00717 
00718       traverse_constraint (c);
00719       
00720       tmp = tmp->next;
00721     }
00722 
00723   g_slist_free (heads);
00724 }
00725 
00730 static void
00731 stack_do_window_deletions (MetaStack *stack)
00732 {
00733   /* Do removals before adds, with paranoid idea that we might re-add
00734    * the same window IDs.
00735    */
00736   GList *tmp;
00737   int i;
00738     
00739   tmp = stack->removed;
00740   while (tmp != NULL)
00741     {
00742       Window xwindow;
00743       xwindow = GPOINTER_TO_UINT (tmp->data);
00744 
00745       /* We go from the end figuring removals are more
00746        * likely to be recent.
00747        */
00748       i = stack->windows->len;
00749       while (i > 0)
00750         {
00751           --i;
00752           
00753           /* there's no guarantee we'll actually find windows to
00754            * remove, e.g. the same xwindow could have been
00755            * added/removed before we ever synced, and we put
00756            * both the window->xwindow and window->frame->xwindow
00757            * in the removal list.
00758            */
00759           if (xwindow == g_array_index (stack->windows, Window, i))
00760             {
00761               g_array_remove_index (stack->windows, i);
00762               goto next;
00763             }
00764         }
00765 
00766     next:
00767       tmp = tmp->next;
00768     }
00769 
00770   g_list_free (stack->removed);
00771   stack->removed = NULL;
00772 }
00773 
00774 static void
00775 stack_do_window_additions (MetaStack *stack)
00776 {
00777   GList *tmp;
00778   gint i, n_added;
00779 
00780   n_added = g_list_length (stack->added);
00781   if (n_added > 0)
00782     {
00783       Window *end;
00784       int old_size;
00785 
00786       meta_topic (META_DEBUG_STACK,
00787                   "Adding %d windows to sorted list\n",
00788                   n_added);
00789       
00790       old_size = stack->windows->len;
00791       g_array_set_size (stack->windows, old_size + n_added);
00792       
00793       end = &g_array_index (stack->windows, Window, old_size);
00794 
00795       /* stack->added has the most recent additions at the
00796        * front of the list, so we need to reverse it
00797        */
00798       stack->added = g_list_reverse (stack->added);
00799       
00800       i = 0;
00801       tmp = stack->added;
00802       while (tmp != NULL)
00803         {
00804           MetaWindow *w;
00805           
00806           w = tmp->data;
00807           
00808           end[i] = w->xwindow;
00809 
00810           /* add to the main list */
00811           stack->sorted = g_list_prepend (stack->sorted, w);
00812           
00813           ++i;
00814           tmp = tmp->next;
00815         }
00816       
00817       stack->need_resort = TRUE; /* may not be needed as we add to top */
00818       stack->need_constrain = TRUE;
00819       stack->need_relayer = TRUE;
00820     }
00821 
00822   g_list_free (stack->added);
00823   stack->added = NULL;
00824 }
00825 
00829 static void
00830 stack_do_relayer (MetaStack *stack)
00831 {
00832   GList *tmp;
00833     
00834   if (!stack->need_relayer)
00835       return;
00836     
00837   meta_topic (META_DEBUG_STACK,
00838               "Recomputing layers\n");
00839       
00840   tmp = stack->sorted;
00841 
00842   while (tmp != NULL)
00843     {
00844       MetaWindow *w;
00845       MetaStackLayer old_layer;
00846 
00847       w = tmp->data;
00848       old_layer = w->layer;
00849 
00850       compute_layer (w);
00851 
00852       if (w->layer != old_layer)
00853         {
00854           meta_topic (META_DEBUG_STACK,
00855                       "Window %s moved from layer %u to %u\n",
00856                       w->desc, old_layer, w->layer);
00857               
00858           stack->need_resort = TRUE;
00859           stack->need_constrain = TRUE;
00860           /* don't need to constrain as constraining
00861            * purely operates in terms of stack_position
00862            * not layer
00863            */
00864         }
00865           
00866       tmp = tmp->next;
00867     }
00868 
00869   stack->need_relayer = FALSE;
00870 }
00871 
00876 static void
00877 stack_do_constrain (MetaStack *stack)
00878 {
00879   Constraint **constraints;
00880 
00881   /* It'd be nice if this were all faster, probably */
00882   
00883   if (!stack->need_constrain)
00884     return;
00885 
00886   meta_topic (META_DEBUG_STACK,
00887               "Reapplying constraints\n");
00888 
00889   constraints = g_new0 (Constraint*,
00890                         stack->n_positions);
00891 
00892   create_constraints (constraints, stack->sorted);
00893 
00894   graph_constraints (constraints, stack->n_positions);
00895 
00896   apply_constraints (constraints, stack->n_positions);
00897   
00898   free_constraints (constraints, stack->n_positions);
00899   g_free (constraints);
00900   
00901   stack->need_constrain = FALSE;
00902 }
00903 
00907 static void
00908 stack_do_resort (MetaStack *stack)
00909 {
00910   if (!stack->need_resort)
00911     return;
00912   
00913   meta_topic (META_DEBUG_STACK,
00914               "Sorting stack list\n");
00915       
00916   stack->sorted = g_list_sort (stack->sorted,
00917                                (GCompareFunc) compare_window_position);
00918 
00919   stack->need_resort = FALSE;
00920 }
00921 
00931 static void
00932 stack_ensure_sorted (MetaStack *stack)
00933 {
00934   stack_do_window_deletions (stack);
00935   stack_do_window_additions (stack);
00936   stack_do_relayer (stack);
00937   stack_do_constrain (stack);
00938   stack_do_resort (stack);
00939 }
00940 
00952 static void
00953 raise_window_relative_to_managed_windows (MetaScreen *screen,
00954                                           Window      xwindow)
00955 {
00956 
00957   Window ignored1, ignored2;
00958   Window *children;
00959   unsigned int n_children;
00960   int i;
00961 
00962   /* Normally XQueryTree() means "must grab server" but here
00963    * we don't, since we know we won't manage any new windows
00964    * or restack any windows before using the XQueryTree results.
00965    */
00966   
00967   meta_error_trap_push_with_return (screen->display);
00968   
00969   XQueryTree (screen->display->xdisplay,
00970               screen->xroot,
00971               &ignored1, &ignored2, &children, &n_children);
00972 
00973   if (meta_error_trap_pop_with_return (screen->display, TRUE) != Success)
00974     {
00975       meta_topic (META_DEBUG_STACK,
00976                   "Error querying root children to raise window 0x%lx\n",
00977                   xwindow);
00978       return;
00979     }
00980 
00981   /* Children are in order from bottom to top. We want to
00982    * find the topmost managed child, then configure
00983    * our window to be above it.
00984    */
00985   i = n_children - 1;
00986   while (i >= 0)
00987     {
00988       if (children[i] == xwindow)
00989         {
00990           /* Do nothing. This means we're already the topmost managed
00991            * window, but it DOES NOT mean we are already just above
00992            * the topmost managed window. This is important because if
00993            * an override redirect window is up, and we map a new
00994            * managed window, the new window is probably above the old
00995            * popup by default, and we want to push it below that
00996            * popup. So keep looking for a sibling managed window
00997            * to be moved below.
00998            */
00999         }
01000       else if (meta_display_lookup_x_window (screen->display,
01001                                              children[i]) != NULL)
01002         {
01003           XWindowChanges changes;
01004           
01005           /* children[i] is the topmost managed child */
01006           meta_topic (META_DEBUG_STACK,
01007                       "Moving 0x%lx above topmost managed child window 0x%lx\n",
01008                       xwindow, children[i]);
01009 
01010           changes.sibling = children[i];
01011           changes.stack_mode = Above;
01012 
01013           meta_error_trap_push (screen->display);
01014           XConfigureWindow (screen->display->xdisplay,
01015                             xwindow,
01016                             CWSibling | CWStackMode,
01017                             &changes);
01018           meta_error_trap_pop (screen->display, FALSE);
01019 
01020           break;
01021         }
01022 
01023       --i;
01024     }
01025 
01026   if (i < 0)
01027     {
01028       /* No sibling to use, just lower ourselves to the bottom
01029        * to be sure we're below any override redirect windows.
01030        */
01031       meta_error_trap_push (screen->display);
01032       XLowerWindow (screen->display->xdisplay,
01033                     xwindow);
01034       meta_error_trap_pop (screen->display, FALSE);
01035     }
01036   
01037   if (children)
01038     XFree (children);
01039 }
01040 
01048 static void
01049 stack_sync_to_server (MetaStack *stack)
01050 {
01051   GArray *stacked;
01052   GArray *root_children_stacked;
01053   GList *tmp;
01054   
01055   /* Bail out if frozen */
01056   if (stack->freeze_count > 0)
01057     return;
01058   
01059   meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");  
01060 
01061   stack_ensure_sorted (stack);
01062   
01063   /* Create stacked xwindow arrays.
01064    * Painfully, "stacked" is in bottom-to-top order for the
01065    * _NET hints, and "root_children_stacked" is in top-to-bottom
01066    * order for XRestackWindows()
01067    */
01068   stacked = g_array_new (FALSE, FALSE, sizeof (Window));
01069   root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
01070 
01071   meta_topic (META_DEBUG_STACK, "Top to bottom: ");
01072   meta_push_no_msg_prefix ();
01073   
01074   tmp = stack->sorted;
01075   while (tmp != NULL)
01076     {
01077       MetaWindow *w;
01078       
01079       w = tmp->data;
01080       
01081       /* remember, stacked is in reverse order (bottom to top) */
01082       g_array_prepend_val (stacked, w->xwindow);
01083       
01084       /* build XRestackWindows() array from top to bottom */
01085       if (w->frame)
01086         g_array_append_val (root_children_stacked, w->frame->xwindow);
01087       else
01088         g_array_append_val (root_children_stacked, w->xwindow);
01089       
01090       meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc);
01091           
01092       tmp = tmp->next;
01093     }
01094 
01095   meta_topic (META_DEBUG_STACK, "\n");
01096   meta_pop_no_msg_prefix ();
01097 
01098   /* All windows should be in some stacking order */
01099   if (stacked->len != stack->windows->len)
01100     meta_bug ("%u windows stacked, %u windows exist in stack\n",
01101               stacked->len, stack->windows->len);
01102   
01103   /* Sync to server */
01104 
01105   meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
01106               root_children_stacked->len);
01107   
01108   meta_error_trap_push (stack->screen->display);
01109 
01110   if (stack->last_root_children_stacked == NULL)
01111     {
01112       /* Just impose our stack, we don't know the previous state.
01113        * This involves a ton of circulate requests and may flicker.
01114        */
01115       meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
01116 
01117       if (root_children_stacked->len > 0)
01118         XRestackWindows (stack->screen->display->xdisplay,
01119                          (Window *) root_children_stacked->data,
01120                          root_children_stacked->len);
01121     }
01122   else if (root_children_stacked->len > 0)
01123     {
01124       /* Try to do minimal window moves to get the stack in order */
01125       /* A point of note: these arrays include frames not client windows,
01126        * so if a client window has changed frame since last_root_children_stacked
01127        * was saved, then we may have inefficiency, but I don't think things
01128        * break...
01129        */
01130       const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
01131       const Window *new_stack = (Window *) root_children_stacked->data;
01132       const int old_len = stack->last_root_children_stacked->len;
01133       const int new_len = root_children_stacked->len;
01134       const Window *oldp = old_stack;
01135       const Window *newp = new_stack;
01136       const Window *old_end = old_stack + old_len;
01137       const Window *new_end = new_stack + new_len;
01138       Window last_window = None;
01139       
01140       while (oldp != old_end &&
01141              newp != new_end)
01142         {
01143           if (*oldp == *newp)
01144             {
01145               /* Stacks are the same here, move on */
01146               ++oldp;
01147               last_window = *newp;
01148               ++newp;
01149             }
01150           else if (meta_display_lookup_x_window (stack->screen->display,
01151                                                  *oldp) == NULL)
01152             {
01153               /* *oldp is no longer known to us (probably destroyed),
01154                * so we can just skip it
01155                */
01156               ++oldp;
01157             }
01158           else
01159             {
01160               /* Move *newp below last_window */
01161               if (last_window == None)
01162                 {
01163                   meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
01164 
01165                   raise_window_relative_to_managed_windows (stack->screen,
01166                                                             *newp);
01167                 }
01168               else
01169                 {
01170                   /* This means that if last_window is dead, but not
01171                    * *newp, then we fail to restack *newp; but on
01172                    * unmanaging last_window, we'll fix it up.
01173                    */
01174                   
01175                   XWindowChanges changes;
01176 
01177                   changes.sibling = last_window;
01178                   changes.stack_mode = Below;
01179 
01180                   meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
01181                               *newp, last_window);
01182                   
01183                   XConfigureWindow (stack->screen->display->xdisplay,
01184                                     *newp,
01185                                     CWSibling | CWStackMode,
01186                                     &changes);
01187                 }
01188 
01189               last_window = *newp;
01190               ++newp;
01191             }
01192         }
01193 
01194       if (newp != new_end)
01195         {
01196           /* Restack remaining windows */
01197           meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
01198                         (int) (new_end - newp));
01199           /* We need to include an already-stacked window
01200            * in the restack call, so we get in the proper position
01201            * with respect to it.
01202            */
01203           if (newp != new_stack)
01204             --newp;
01205           XRestackWindows (stack->screen->display->xdisplay,
01206                            (Window *) newp, new_end - newp);
01207         }
01208     }
01209 
01210   meta_error_trap_pop (stack->screen->display, FALSE);
01211   /* on error, a window was destroyed; it should eventually
01212    * get removed from the stacking list when we unmanage it
01213    * and we'll fix stacking at that time.
01214    */
01215   
01216   /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
01217 
01218   XChangeProperty (stack->screen->display->xdisplay,
01219                    stack->screen->xroot,
01220                    stack->screen->display->atom__NET_CLIENT_LIST,
01221                    XA_WINDOW,
01222                    32, PropModeReplace,
01223                    (unsigned char *)stack->windows->data,
01224                    stack->windows->len);
01225   XChangeProperty (stack->screen->display->xdisplay,
01226                    stack->screen->xroot,
01227                    stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
01228                    XA_WINDOW,
01229                    32, PropModeReplace,
01230                    (unsigned char *)stacked->data,
01231                    stacked->len);
01232 
01233   g_array_free (stacked, TRUE);
01234 
01235   if (stack->last_root_children_stacked)
01236     g_array_free (stack->last_root_children_stacked, TRUE);
01237   stack->last_root_children_stacked = root_children_stacked;
01238   
01239   /* That was scary... */
01240 }
01241 
01242 MetaWindow*
01243 meta_stack_get_top (MetaStack *stack)
01244 {
01245   stack_ensure_sorted (stack);
01246 
01247   if (stack->sorted)
01248     return stack->sorted->data;
01249   else
01250     return NULL;
01251 }
01252 
01253 MetaWindow*
01254 meta_stack_get_bottom (MetaStack  *stack)
01255 {
01256   GList *link;
01257 
01258   stack_ensure_sorted (stack);
01259 
01260   link = g_list_last (stack->sorted);
01261   if (link != NULL)
01262     return link->data;
01263   else
01264     return NULL;
01265 }
01266 
01267 MetaWindow*
01268 meta_stack_get_above (MetaStack      *stack,
01269                       MetaWindow     *window,
01270                       gboolean        only_within_layer)
01271 {
01272   GList *link;
01273   MetaWindow *above;
01274   
01275   stack_ensure_sorted (stack);
01276   
01277   link = g_list_find (stack->sorted, window);
01278   if (link == NULL)
01279     return NULL;
01280   if (link->prev == NULL)
01281     return NULL;
01282 
01283   above = link->prev->data;
01284 
01285   if (only_within_layer &&
01286       above->layer != window->layer)
01287     return NULL;
01288   else
01289     return above;
01290 }
01291 
01292 MetaWindow*
01293 meta_stack_get_below (MetaStack      *stack,
01294                       MetaWindow     *window,
01295                       gboolean        only_within_layer)
01296 {
01297   GList *link;
01298   MetaWindow *below;
01299   
01300   stack_ensure_sorted (stack);
01301 
01302   link = g_list_find (stack->sorted, window);
01303 
01304   if (link == NULL)
01305     return NULL;
01306   if (link->next == NULL)
01307     return NULL;
01308   
01309   below = link->next->data;
01310 
01311   if (only_within_layer &&
01312       below->layer != window->layer)
01313     return NULL;
01314   else
01315     return below;
01316 }
01317 
01318 static gboolean
01319 window_contains_point (MetaWindow *window,
01320                        int         root_x,
01321                        int         root_y)
01322 {
01323   MetaRectangle rect;
01324 
01325   meta_window_get_outer_rect (window, &rect);
01326 
01327   return POINT_IN_RECT (root_x, root_y, rect);
01328 }
01329 
01330 static MetaWindow*
01331 get_default_focus_window (MetaStack     *stack,
01332                           MetaWorkspace *workspace,
01333                           MetaWindow    *not_this_one,
01334                           gboolean       must_be_at_point,
01335                           int            root_x,
01336                           int            root_y)
01337 {
01338   /* Find the topmost, focusable, mapped, window.
01339    * not_this_one is being unfocused or going away, so exclude it.
01340    * Also, prefer to focus transient parent of not_this_one,
01341    * or top window in same group as not_this_one.
01342    */
01343 
01344   MetaWindow *topmost_dock;
01345   MetaWindow *transient_parent;
01346   MetaWindow *topmost_in_group;
01347   MetaWindow *topmost_overall;
01348   MetaGroup *not_this_one_group;
01349   GList *link;
01350   
01351   topmost_dock = NULL;
01352   transient_parent = NULL;
01353   topmost_in_group = NULL;
01354   topmost_overall = NULL;
01355   if (not_this_one)
01356     not_this_one_group = meta_window_get_group (not_this_one);
01357   else
01358     not_this_one_group = NULL;
01359 
01360   stack_ensure_sorted (stack);
01361 
01362   /* top of this layer is at the front of the list */
01363   link = stack->sorted;
01364       
01365   while (link)
01366     {
01367       MetaWindow *window = link->data;
01368 
01369       if (window &&
01370           window != not_this_one &&
01371           (window->unmaps_pending == 0) &&
01372           !window->minimized &&
01373           (window->input || window->take_focus) &&
01374           (workspace == NULL ||
01375            meta_window_located_on_workspace (window, workspace)))
01376         {
01377           if (topmost_dock == NULL &&
01378               window->type == META_WINDOW_DOCK)
01379             topmost_dock = window;
01380 
01381           if (not_this_one != NULL)
01382             {
01383               if (transient_parent == NULL &&
01384                   not_this_one->xtransient_for != None &&
01385                   not_this_one->xtransient_for == window->xwindow &&
01386                   (!must_be_at_point ||
01387                    window_contains_point (window, root_x, root_y)))
01388                 transient_parent = window;
01389 
01390               if (topmost_in_group == NULL &&
01391                   not_this_one_group != NULL &&
01392                   not_this_one_group == meta_window_get_group (window) &&
01393                   (!must_be_at_point ||
01394                    window_contains_point (window, root_x, root_y)))
01395                 topmost_in_group = window;
01396             }
01397 
01398           /* Note that DESKTOP windows can be topmost_overall so
01399            * we prefer focusing desktop or other windows over
01400            * focusing dock, even though docks are stacked higher.
01401            */
01402           if (topmost_overall == NULL &&
01403               window->type != META_WINDOW_DOCK &&
01404               (!must_be_at_point ||
01405                window_contains_point (window, root_x, root_y)))
01406             topmost_overall = window;
01407 
01408           /* We could try to bail out early here for efficiency in
01409            * some cases, but it's just not worth the code.
01410            */
01411         }
01412 
01413       link = link->next;
01414     }
01415 
01416   if (transient_parent)
01417     return transient_parent;
01418   else if (topmost_in_group)
01419     return topmost_in_group;
01420   else if (topmost_overall)
01421     return topmost_overall;
01422   else
01423     return topmost_dock;
01424 }
01425 
01426 MetaWindow*
01427 meta_stack_get_default_focus_window_at_point (MetaStack     *stack,
01428                                               MetaWorkspace *workspace,
01429                                               MetaWindow    *not_this_one,
01430                                               int            root_x,
01431                                               int            root_y)
01432 {
01433   return get_default_focus_window (stack, workspace, not_this_one,
01434                                    TRUE, root_x, root_y);
01435 }
01436 
01437 MetaWindow*
01438 meta_stack_get_default_focus_window (MetaStack     *stack,
01439                                      MetaWorkspace *workspace,
01440                                      MetaWindow    *not_this_one)
01441 {
01442   return get_default_focus_window (stack, workspace, not_this_one,
01443                                    FALSE, 0, 0);
01444 }
01445 
01446 GList*
01447 meta_stack_list_windows (MetaStack     *stack,
01448                          MetaWorkspace *workspace)
01449 {
01450   GList *workspace_windows = NULL;
01451   GList *link;
01452   
01453   stack_ensure_sorted (stack); /* do adds/removes */
01454   
01455   link = stack->sorted;
01456   
01457   while (link)
01458     {
01459       MetaWindow *window = link->data;
01460       
01461       if (window &&
01462           (workspace == NULL || meta_window_located_on_workspace (window, workspace)))
01463         {
01464           workspace_windows = g_list_prepend (workspace_windows,
01465                                               window);
01466         }
01467       
01468       link = link->next;
01469     }
01470 
01471   return workspace_windows;
01472 }
01473 
01474 int
01475 meta_stack_windows_cmp  (MetaStack  *stack,
01476                          MetaWindow *window_a,
01477                          MetaWindow *window_b)
01478 {
01479   g_return_val_if_fail (window_a->screen == window_b->screen, 0);
01480 
01481   /* -1 means a below b */
01482 
01483   stack_ensure_sorted (stack); /* update constraints, layers */
01484   
01485   if (window_a->layer < window_b->layer)
01486     return -1;
01487   else if (window_a->layer > window_b->layer)
01488     return 1;
01489   else if (window_a->stack_position < window_b->stack_position)
01490     return -1;
01491   else if (window_a->stack_position > window_b->stack_position)
01492     return 1;
01493   else
01494     return 0; /* not reached */
01495 }
01496 
01497 static int
01498 compare_just_window_stack_position (void *a,
01499                                     void *b)
01500 {
01501   MetaWindow *window_a = a;
01502   MetaWindow *window_b = b;
01503 
01504   if (window_a->stack_position < window_b->stack_position)
01505     return -1; /* move window_a earlier in list */
01506   else if (window_a->stack_position > window_b->stack_position)
01507     return 1;
01508   else
01509     return 0; /* not reached */
01510 }
01511 
01512 GList*
01513 meta_stack_get_positions (MetaStack *stack)
01514 {
01515   GList *tmp;
01516 
01517   /* Make sure to handle any adds or removes */
01518   stack_ensure_sorted (stack);
01519 
01520   tmp = g_list_copy (stack->sorted);
01521   tmp = g_list_sort (tmp, (GCompareFunc) compare_just_window_stack_position);
01522 
01523   return tmp;
01524 }
01525 
01526 static gint
01527 compare_pointers (gconstpointer a,
01528                   gconstpointer b)
01529 {
01530   if (a > b)
01531     return 1;
01532   else if (a < b)
01533     return -1;
01534   else 
01535     return 0;
01536 }
01537 
01538 static gboolean
01539 lists_contain_same_windows (GList *a,
01540                             GList *b)
01541 {
01542   GList *copy1, *copy2;
01543   GList *tmp1, *tmp2;
01544 
01545   if (g_list_length (a) != g_list_length (b))
01546     return FALSE;
01547 
01548   tmp1 = copy1 = g_list_sort (g_list_copy (a), compare_pointers);
01549   tmp2 = copy2 = g_list_sort (g_list_copy (b), compare_pointers);
01550 
01551   while (tmp1 && tmp1->data == tmp2->data)   /* tmp2 is non-NULL if tmp1 is */
01552     {
01553       tmp1 = tmp1->next;
01554       tmp2 = tmp2->next;
01555     }
01556 
01557   g_list_free (copy1);
01558   g_list_free (copy2);
01559 
01560   return (tmp1 == NULL);    /* tmp2 is non-NULL if tmp1 is */
01561 }
01562 
01563 void
01564 meta_stack_set_positions (MetaStack *stack,
01565                           GList     *windows)
01566 {
01567   int i;
01568   GList *tmp;
01569 
01570   /* Make sure any adds or removes aren't in limbo -- is this needed? */
01571   stack_ensure_sorted (stack);
01572   
01573   if (!lists_contain_same_windows (windows, stack->sorted))
01574     {
01575       meta_warning ("This list of windows has somehow changed; not resetting "
01576                     "positions of the windows.\n");
01577       return;
01578     }
01579 
01580   g_list_free (stack->sorted);
01581   stack->sorted = g_list_copy (windows);
01582 
01583   stack->need_resort = TRUE;
01584   stack->need_constrain = TRUE;
01585    
01586   i = 0;
01587   tmp = windows;
01588   while (tmp != NULL)
01589     {
01590       MetaWindow *w = tmp->data;
01591       w->stack_position = i++;
01592       tmp = tmp->next;
01593     }
01594   
01595   meta_topic (META_DEBUG_STACK,
01596               "Reset the stack positions of (nearly) all windows\n");
01597 
01598   stack_sync_to_server (stack);
01599 }
01600 
01601 void
01602 meta_window_set_stack_position_no_sync (MetaWindow *window,
01603                                         int         position)
01604 {
01605   int low, high, delta;
01606   GList *tmp;
01607   
01608   g_return_if_fail (window->screen->stack != NULL);
01609   g_return_if_fail (window->stack_position >= 0);
01610   g_return_if_fail (position >= 0);
01611   g_return_if_fail (position < window->screen->stack->n_positions);
01612 
01613   if (position == window->stack_position)
01614     {
01615       meta_topic (META_DEBUG_STACK, "Window %s already has position %d\n",
01616                   window->desc, position);
01617       return;
01618     }
01619 
01620   window->screen->stack->need_resort = TRUE;
01621   window->screen->stack->need_constrain = TRUE;
01622   
01623   if (position < window->stack_position)
01624     {
01625       low = position;
01626       high = window->stack_position - 1;
01627       delta = 1;
01628     }
01629   else
01630     {
01631       low = window->stack_position + 1;
01632       high = position;
01633       delta = -1;
01634     }
01635 
01636   tmp = window->screen->stack->sorted;
01637   while (tmp != NULL)
01638     {
01639       MetaWindow *w = tmp->data;
01640 
01641       if (w->stack_position >= low &&
01642           w->stack_position <= high)
01643         w->stack_position += delta;
01644 
01645       tmp = tmp->next;
01646     }
01647   
01648   window->stack_position = position;
01649 
01650   meta_topic (META_DEBUG_STACK,
01651               "Window %s had stack_position set to %d\n",
01652               window->desc, window->stack_position);
01653 }
01654 
01655 void
01656 meta_window_set_stack_position (MetaWindow *window,
01657                                 int         position)
01658 {
01659   meta_window_set_stack_position_no_sync (window, position);
01660   stack_sync_to_server (window->screen->stack);
01661 }

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