00001
00002
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00137
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
00145 stack->added = g_list_remove (stack->added, window);
00146 stack->sorted = g_list_remove (stack->sorted, window);
00147
00148
00149
00150
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
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
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
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
00284
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
00327
00328
00329
00330
00331
00332 if (WINDOW_HAS_TRANSIENT_TYPE(window) &&
00333 (window->xtransient_for == None ||
00334 window->transient_parent_is_root_window))
00335 {
00336
00337
00338
00339
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
00361
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
00371 if (window_a->layer < window_b->layer)
00372 return 1;
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;
00377 else if (window_a->stack_position > window_b->stack_position)
00378 return -1;
00379 else
00380 return 0;
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 typedef struct Constraint Constraint;
00421
00422 struct Constraint
00423 {
00424 MetaWindow *above;
00425 MetaWindow *below;
00426
00427
00428
00429
00430 Constraint *next;
00431
00432
00433 GSList *next_nodes;
00434
00435
00436
00437
00438 unsigned int applied : 1;
00439
00440
00441
00442
00443
00444
00445
00446
00447 unsigned int has_prev : 1;
00448 };
00449
00450
00451
00452
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
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
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
00531 if (!(meta_window_is_ancestor_of_transient (w, group_window)) &&
00532 !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window)) ;
00533 #else
00534
00535
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
00583
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
00594
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
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
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
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
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
00734
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
00746
00747
00748 i = stack->windows->len;
00749 while (i > 0)
00750 {
00751 --i;
00752
00753
00754
00755
00756
00757
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
00796
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
00811 stack->sorted = g_list_prepend (stack->sorted, w);
00812
00813 ++i;
00814 tmp = tmp->next;
00815 }
00816
00817 stack->need_resort = TRUE;
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
00861
00862
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
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
00963
00964
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
00982
00983
00984
00985 i = n_children - 1;
00986 while (i >= 0)
00987 {
00988 if (children[i] == xwindow)
00989 {
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999 }
01000 else if (meta_display_lookup_x_window (screen->display,
01001 children[i]) != NULL)
01002 {
01003 XWindowChanges changes;
01004
01005
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
01029
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
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
01064
01065
01066
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
01082 g_array_prepend_val (stacked, w->xwindow);
01083
01084
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
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
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
01113
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
01125
01126
01127
01128
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
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
01154
01155
01156 ++oldp;
01157 }
01158 else
01159 {
01160
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
01171
01172
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
01197 meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
01198 (int) (new_end - newp));
01199
01200
01201
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
01212
01213
01214
01215
01216
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
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
01339
01340
01341
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
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
01399
01400
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
01409
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);
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
01482
01483 stack_ensure_sorted (stack);
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;
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;
01506 else if (window_a->stack_position > window_b->stack_position)
01507 return 1;
01508 else
01509 return 0;
01510 }
01511
01512 GList*
01513 meta_stack_get_positions (MetaStack *stack)
01514 {
01515 GList *tmp;
01516
01517
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)
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);
01561 }
01562
01563 void
01564 meta_stack_set_positions (MetaStack *stack,
01565 GList *windows)
01566 {
01567 int i;
01568 GList *tmp;
01569
01570
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 }