~elementary-os/ubuntu-package-imports/mutter-bionic

« back to all changes in this revision

Viewing changes to src/core/stack.c

  • Committer: RabbitBot
  • Date: 2018-04-11 14:49:36 UTC
  • Revision ID: rabbitbot@elementary.io-20180411144936-hgymqa9d8d1xfpbh
Initial import, version 3.28.0-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/*
 
4
 * SECTION:stack
 
5
 * @short_description: Which windows cover which other windows
 
6
 */
 
7
 
 
8
/*
 
9
 * Copyright (C) 2001 Havoc Pennington
 
10
 * Copyright (C) 2002, 2003 Red Hat, Inc.
 
11
 * Copyright (C) 2004 Rob Adams
 
12
 * Copyright (C) 2004, 2005 Elijah Newren
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation; either version 2 of the
 
17
 * License, or (at your option) any later version.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
26
 */
 
27
 
 
28
#include <config.h>
 
29
#include "stack.h"
 
30
#include "window-private.h"
 
31
#include <meta/errors.h>
 
32
#include "frame.h"
 
33
#include <meta/group.h>
 
34
#include <meta/prefs.h>
 
35
#include <meta/workspace.h>
 
36
#include "backends/meta-logical-monitor.h"
 
37
 
 
38
#include <X11/Xatom.h>
 
39
 
 
40
#include "x11/group-private.h"
 
41
 
 
42
#define WINDOW_HAS_TRANSIENT_TYPE(w)                    \
 
43
          (w->type == META_WINDOW_DIALOG ||             \
 
44
           w->type == META_WINDOW_MODAL_DIALOG ||       \
 
45
           w->type == META_WINDOW_TOOLBAR ||            \
 
46
           w->type == META_WINDOW_MENU ||               \
 
47
           w->type == META_WINDOW_UTILITY)
 
48
 
 
49
#define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w)                     \
 
50
  (WINDOW_HAS_TRANSIENT_TYPE (w) && w->transient_for == NULL)
 
51
 
 
52
static void stack_sync_to_xserver (MetaStack *stack);
 
53
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
 
54
                                                    int         position);
 
55
static void stack_do_window_deletions (MetaStack *stack);
 
56
static void stack_do_window_additions (MetaStack *stack);
 
57
static void stack_do_relayer          (MetaStack *stack);
 
58
static void stack_do_constrain        (MetaStack *stack);
 
59
static void stack_do_resort           (MetaStack *stack);
 
60
 
 
61
static void stack_ensure_sorted (MetaStack *stack);
 
62
 
 
63
MetaStack*
 
64
meta_stack_new (MetaScreen *screen)
 
65
{
 
66
  MetaStack *stack;
 
67
 
 
68
  stack = g_new (MetaStack, 1);
 
69
 
 
70
  stack->screen = screen;
 
71
  stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
 
72
 
 
73
  stack->sorted = NULL;
 
74
  stack->added = NULL;
 
75
  stack->removed = NULL;
 
76
 
 
77
  stack->freeze_count = 0;
 
78
  stack->n_positions = 0;
 
79
 
 
80
  stack->need_resort = FALSE;
 
81
  stack->need_relayer = FALSE;
 
82
  stack->need_constrain = FALSE;
 
83
 
 
84
  return stack;
 
85
}
 
86
 
 
87
void
 
88
meta_stack_free (MetaStack *stack)
 
89
{
 
90
  g_array_free (stack->xwindows, TRUE);
 
91
 
 
92
  g_list_free (stack->sorted);
 
93
  g_list_free (stack->added);
 
94
  g_list_free (stack->removed);
 
95
 
 
96
  g_free (stack);
 
97
}
 
98
 
 
99
void
 
100
meta_stack_add (MetaStack  *stack,
 
101
                MetaWindow *window)
 
102
{
 
103
  g_return_if_fail (meta_window_is_stackable (window));
 
104
 
 
105
  meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc);
 
106
 
 
107
  if (meta_window_is_in_stack (window))
 
108
    meta_bug ("Window %s had stack position already\n", window->desc);
 
109
 
 
110
  stack->added = g_list_prepend (stack->added, window);
 
111
 
 
112
  window->stack_position = stack->n_positions;
 
113
  stack->n_positions += 1;
 
114
  meta_topic (META_DEBUG_STACK,
 
115
              "Window %s has stack_position initialized to %d\n",
 
116
              window->desc, window->stack_position);
 
117
 
 
118
  stack_sync_to_xserver (stack);
 
119
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
120
}
 
121
 
 
122
void
 
123
meta_stack_remove (MetaStack  *stack,
 
124
                   MetaWindow *window)
 
125
{
 
126
  meta_topic (META_DEBUG_STACK, "Removing window %s from the stack\n", window->desc);
 
127
 
 
128
  /* Set window to top position, so removing it will not leave gaps
 
129
   * in the set of positions
 
130
   */
 
131
  meta_window_set_stack_position_no_sync (window,
 
132
                                          stack->n_positions - 1);
 
133
  window->stack_position = -1;
 
134
  stack->n_positions -= 1;
 
135
 
 
136
  /* We don't know if it's been moved from "added" to "stack" yet */
 
137
  stack->added = g_list_remove (stack->added, window);
 
138
  stack->sorted = g_list_remove (stack->sorted, window);
 
139
 
 
140
  /* stack->removed is only used to update stack->xwindows */
 
141
  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
 
142
    {
 
143
      /* Remember the window ID to remove it from the stack array.
 
144
       * The macro is safe to use: Window is guaranteed to be 32 bits, and
 
145
       * GUINT_TO_POINTER says it only works on 32 bits.
 
146
       */
 
147
      stack->removed = g_list_prepend (stack->removed,
 
148
                                       GUINT_TO_POINTER (window->xwindow));
 
149
      if (window->frame)
 
150
        stack->removed = g_list_prepend (stack->removed,
 
151
                                         GUINT_TO_POINTER (window->frame->xwindow));
 
152
    }
 
153
 
 
154
  stack_sync_to_xserver (stack);
 
155
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
156
}
 
157
 
 
158
void
 
159
meta_stack_update_layer (MetaStack  *stack,
 
160
                         MetaWindow *window)
 
161
{
 
162
  stack->need_relayer = TRUE;
 
163
 
 
164
  stack_sync_to_xserver (stack);
 
165
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
166
}
 
167
 
 
168
void
 
169
meta_stack_update_transient (MetaStack  *stack,
 
170
                             MetaWindow *window)
 
171
{
 
172
  stack->need_constrain = TRUE;
 
173
 
 
174
  stack_sync_to_xserver (stack);
 
175
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
176
}
 
177
 
 
178
/* raise/lower within a layer */
 
179
void
 
180
meta_stack_raise (MetaStack  *stack,
 
181
                  MetaWindow *window)
 
182
{
 
183
  GList *l;
 
184
  int max_stack_position = window->stack_position;
 
185
  MetaWorkspace *workspace;
 
186
 
 
187
  stack_ensure_sorted (stack);
 
188
 
 
189
  workspace = meta_window_get_workspace (window);
 
190
  for (l = stack->sorted; l; l = l->next)
 
191
    {
 
192
      MetaWindow *w = (MetaWindow *) l->data;
 
193
      if (meta_window_located_on_workspace (w, workspace) &&
 
194
          w->stack_position > max_stack_position)
 
195
        max_stack_position = w->stack_position;
 
196
    }
 
197
 
 
198
  if (max_stack_position == window->stack_position)
 
199
    return;
 
200
 
 
201
  meta_window_set_stack_position_no_sync (window, max_stack_position);
 
202
 
 
203
  stack_sync_to_xserver (stack);
 
204
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
205
}
 
206
 
 
207
void
 
208
meta_stack_lower (MetaStack  *stack,
 
209
                  MetaWindow *window)
 
210
{
 
211
  GList *l;
 
212
  int min_stack_position = window->stack_position;
 
213
  MetaWorkspace *workspace;
 
214
 
 
215
  stack_ensure_sorted (stack);
 
216
 
 
217
  workspace = meta_window_get_workspace (window);
 
218
  for (l = stack->sorted; l; l = l->next)
 
219
    {
 
220
      MetaWindow *w = (MetaWindow *) l->data;
 
221
      if (meta_window_located_on_workspace (w, workspace) &&
 
222
          w->stack_position < min_stack_position)
 
223
        min_stack_position = w->stack_position;
 
224
    }
 
225
 
 
226
  if (min_stack_position == window->stack_position)
 
227
    return;
 
228
 
 
229
  meta_window_set_stack_position_no_sync (window, min_stack_position);
 
230
 
 
231
  stack_sync_to_xserver (stack);
 
232
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 
233
}
 
234
 
 
235
void
 
236
meta_stack_freeze (MetaStack *stack)
 
237
{
 
238
  stack->freeze_count += 1;
 
239
}
 
240
 
 
241
void
 
242
meta_stack_thaw (MetaStack *stack)
 
243
{
 
244
  g_return_if_fail (stack->freeze_count > 0);
 
245
 
 
246
  stack->freeze_count -= 1;
 
247
  stack_sync_to_xserver (stack);
 
248
  meta_stack_update_window_tile_matches (stack, NULL);
 
249
}
 
250
 
 
251
void
 
252
meta_stack_update_window_tile_matches (MetaStack     *stack,
 
253
                                       MetaWorkspace *workspace)
 
254
{
 
255
  GList *windows, *tmp;
 
256
 
 
257
  if (stack->freeze_count > 0)
 
258
    return;
 
259
 
 
260
  windows = meta_stack_list_windows (stack, workspace);
 
261
  tmp = windows;
 
262
  while (tmp)
 
263
    {
 
264
      meta_window_compute_tile_match ((MetaWindow *) tmp->data);
 
265
      tmp = tmp->next;
 
266
    }
 
267
 
 
268
  g_list_free (windows);
 
269
}
 
270
 
 
271
/* Get layer ignoring any transient or group relationships */
 
272
static MetaStackLayer
 
273
get_standalone_layer (MetaWindow *window)
 
274
{
 
275
  MetaStackLayer layer;
 
276
 
 
277
  switch (window->type)
 
278
    {
 
279
    case META_WINDOW_DESKTOP:
 
280
      layer = META_LAYER_DESKTOP;
 
281
      break;
 
282
 
 
283
    case META_WINDOW_DOCK:
 
284
      if (window->wm_state_below ||
 
285
          (window->monitor && window->monitor->in_fullscreen))
 
286
        layer = META_LAYER_BOTTOM;
 
287
      else
 
288
        layer = META_LAYER_DOCK;
 
289
      break;
 
290
 
 
291
    case META_WINDOW_DROPDOWN_MENU:
 
292
    case META_WINDOW_POPUP_MENU:
 
293
    case META_WINDOW_TOOLTIP:
 
294
    case META_WINDOW_NOTIFICATION:
 
295
    case META_WINDOW_COMBO:
 
296
    case META_WINDOW_OVERRIDE_OTHER:
 
297
      layer = META_LAYER_OVERRIDE_REDIRECT;
 
298
      break;
 
299
    default:
 
300
      if (window->wm_state_below)
 
301
        layer = META_LAYER_BOTTOM;
 
302
      else if (window->wm_state_above && !META_WINDOW_MAXIMIZED (window))
 
303
        layer = META_LAYER_TOP;
 
304
      else
 
305
        layer = META_LAYER_NORMAL;
 
306
      break;
 
307
    }
 
308
 
 
309
  return layer;
 
310
}
 
311
 
 
312
/* Note that this function can never use window->layer only
 
313
 * get_standalone_layer, or we'd have issues.
 
314
 */
 
315
static MetaStackLayer
 
316
get_maximum_layer_in_group (MetaWindow *window)
 
317
{
 
318
  GSList *members;
 
319
  MetaGroup *group;
 
320
  GSList *tmp;
 
321
  MetaStackLayer max;
 
322
  MetaStackLayer layer;
 
323
 
 
324
  max = META_LAYER_DESKTOP;
 
325
 
 
326
  group = meta_window_get_group (window);
 
327
 
 
328
  if (group != NULL)
 
329
    members = meta_group_list_windows (group);
 
330
  else
 
331
    members = NULL;
 
332
 
 
333
  tmp = members;
 
334
  while (tmp != NULL)
 
335
    {
 
336
      MetaWindow *w = tmp->data;
 
337
 
 
338
      if (!w->override_redirect)
 
339
        {
 
340
          layer = get_standalone_layer (w);
 
341
          if (layer > max)
 
342
            max = layer;
 
343
        }
 
344
 
 
345
      tmp = tmp->next;
 
346
    }
 
347
 
 
348
  g_slist_free (members);
 
349
 
 
350
  return max;
 
351
}
 
352
 
 
353
static void
 
354
compute_layer (MetaWindow *window)
 
355
{
 
356
  window->layer = get_standalone_layer (window);
 
357
 
 
358
  /* We can only do promotion-due-to-group for dialogs and other
 
359
   * transients, or weird stuff happens like the desktop window and
 
360
   * nautilus windows getting in the same layer, or all gnome-terminal
 
361
   * windows getting in fullscreen layer if any terminal is
 
362
   * fullscreen.
 
363
   */
 
364
  if (window->layer != META_LAYER_DESKTOP &&
 
365
      WINDOW_HAS_TRANSIENT_TYPE(window) &&
 
366
      window->transient_for == NULL)
 
367
    {
 
368
      /* We only do the group thing if the dialog is NOT transient for
 
369
       * a particular window. Imagine a group with a normal window, a dock,
 
370
       * and a dialog transient for the normal window; you don't want the dialog
 
371
       * above the dock if it wouldn't normally be.
 
372
       */
 
373
 
 
374
      MetaStackLayer group_max;
 
375
 
 
376
      group_max = get_maximum_layer_in_group (window);
 
377
 
 
378
      if (group_max > window->layer)
 
379
        {
 
380
          meta_topic (META_DEBUG_STACK,
 
381
                      "Promoting window %s from layer %u to %u due to group membership\n",
 
382
                      window->desc, window->layer, group_max);
 
383
          window->layer = group_max;
 
384
        }
 
385
    }
 
386
 
 
387
  meta_topic (META_DEBUG_STACK, "Window %s on layer %u type = %u has_focus = %d\n",
 
388
              window->desc, window->layer,
 
389
              window->type, window->has_focus);
 
390
}
 
391
 
 
392
/* Front of the layer list is the topmost window,
 
393
 * so the lower stack position is later in the list
 
394
 */
 
395
static int
 
396
compare_window_position (void *a,
 
397
                         void *b)
 
398
{
 
399
  MetaWindow *window_a = a;
 
400
  MetaWindow *window_b = b;
 
401
 
 
402
  /* Go by layer, then stack_position */
 
403
  if (window_a->layer < window_b->layer)
 
404
    return 1; /* move window_a later in list */
 
405
  else if (window_a->layer > window_b->layer)
 
406
    return -1;
 
407
  else if (window_a->stack_position < window_b->stack_position)
 
408
    return 1; /* move window_a later in list */
 
409
  else if (window_a->stack_position > window_b->stack_position)
 
410
    return -1;
 
411
  else
 
412
    return 0; /* not reached */
 
413
}
 
414
 
 
415
/*
 
416
 * Stacking constraints
 
417
 *
 
418
 * Assume constraints of the form "AB" meaning "window A must be
 
419
 * below window B"
 
420
 *
 
421
 * If we have windows stacked from bottom to top
 
422
 * "ABC" then raise A we get "BCA". Say C is
 
423
 * transient for B is transient for A. So
 
424
 * we have constraints AB and BC.
 
425
 *
 
426
 * After raising A, we need to reapply the constraints.
 
427
 * If we do this by raising one window at a time -
 
428
 *
 
429
 *  start:    BCA
 
430
 *  apply AB: CAB
 
431
 *  apply BC: ABC
 
432
 *
 
433
 * but apply constraints in the wrong order and it breaks:
 
434
 *
 
435
 *  start:    BCA
 
436
 *  apply BC: BCA
 
437
 *  apply AB: CAB
 
438
 *
 
439
 * We make a directed graph of the constraints by linking
 
440
 * from "above windows" to "below windows as follows:
 
441
 *
 
442
 *   AB -> BC -> CD
 
443
 *          \
 
444
 *           CE
 
445
 *
 
446
 * If we then walk that graph and apply the constraints in the order
 
447
 * that they appear, we will apply them correctly. Note that the
 
448
 * graph MAY have cycles, so we have to guard against that.
 
449
 *
 
450
 */
 
451
 
 
452
typedef struct Constraint Constraint;
 
453
 
 
454
struct Constraint
 
455
{
 
456
  MetaWindow *above;
 
457
  MetaWindow *below;
 
458
 
 
459
  /* used to keep the constraint in the
 
460
   * list of constraints for window "below"
 
461
   */
 
462
  Constraint *next;
 
463
 
 
464
  /* used to create the graph. */
 
465
  GSList *next_nodes;
 
466
 
 
467
  /* constraint has been applied, used
 
468
   * to detect cycles.
 
469
   */
 
470
  unsigned int applied : 1;
 
471
 
 
472
  /* constraint has a previous node in the graph,
 
473
   * used to find places to start in the graph.
 
474
   * (I think this also has the side effect
 
475
   * of preventing cycles, since cycles will
 
476
   * have no starting point - so maybe
 
477
   * the "applied" flag isn't needed.)
 
478
   */
 
479
  unsigned int has_prev : 1;
 
480
};
 
481
 
 
482
/* We index the array of constraints by window
 
483
 * stack positions, just because the stack
 
484
 * positions are a convenient index.
 
485
 */
 
486
static void
 
487
add_constraint (Constraint **constraints,
 
488
                MetaWindow  *above,
 
489
                MetaWindow  *below)
 
490
{
 
491
  Constraint *c;
 
492
 
 
493
  g_assert (above->screen == below->screen);
 
494
 
 
495
  /* check if constraint is a duplicate */
 
496
  c = constraints[below->stack_position];
 
497
  while (c != NULL)
 
498
    {
 
499
      if (c->above == above)
 
500
        return;
 
501
      c = c->next;
 
502
    }
 
503
 
 
504
  /* if not, add the constraint */
 
505
  c = g_new (Constraint, 1);
 
506
  c->above = above;
 
507
  c->below = below;
 
508
  c->next = constraints[below->stack_position];
 
509
  c->next_nodes = NULL;
 
510
  c->applied = FALSE;
 
511
  c->has_prev = FALSE;
 
512
 
 
513
  constraints[below->stack_position] = c;
 
514
}
 
515
 
 
516
static void
 
517
create_constraints (Constraint **constraints,
 
518
                    GList       *windows)
 
519
{
 
520
  GList *tmp;
 
521
 
 
522
  tmp = windows;
 
523
  while (tmp != NULL)
 
524
    {
 
525
      MetaWindow *w = tmp->data;
 
526
 
 
527
      if (!meta_window_is_in_stack (w))
 
528
        {
 
529
          meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n",
 
530
                      w->desc);
 
531
          tmp = tmp->next;
 
532
          continue;
 
533
        }
 
534
 
 
535
      if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w))
 
536
        {
 
537
          GSList *group_windows;
 
538
          GSList *tmp2;
 
539
          MetaGroup *group;
 
540
 
 
541
          group = meta_window_get_group (w);
 
542
 
 
543
          if (group != NULL)
 
544
            group_windows = meta_group_list_windows (group);
 
545
          else
 
546
            group_windows = NULL;
 
547
 
 
548
          tmp2 = group_windows;
 
549
 
 
550
          while (tmp2 != NULL)
 
551
            {
 
552
              MetaWindow *group_window = tmp2->data;
 
553
 
 
554
              if (!meta_window_is_in_stack (group_window) ||
 
555
                  w->screen != group_window->screen ||
 
556
                  group_window->override_redirect)
 
557
                {
 
558
                  tmp2 = tmp2->next;
 
559
                  continue;
 
560
                }
 
561
 
 
562
#if 0
 
563
              /* old way of doing it */
 
564
              if (!(meta_window_is_ancestor_of_transient (w, group_window)) &&
 
565
                  !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window))  /* note */;/*note*/
 
566
#else
 
567
              /* better way I think, so transient-for-group are constrained
 
568
               * only above non-transient-type windows in their group
 
569
               */
 
570
              if (!WINDOW_HAS_TRANSIENT_TYPE (group_window))
 
571
#endif
 
572
                {
 
573
                  meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n",
 
574
                              w->desc, group_window->desc);
 
575
                  add_constraint (constraints, w, group_window);
 
576
                }
 
577
 
 
578
              tmp2 = tmp2->next;
 
579
            }
 
580
 
 
581
          g_slist_free (group_windows);
 
582
        }
 
583
      else if (w->transient_for != NULL)
 
584
        {
 
585
          MetaWindow *parent;
 
586
 
 
587
          parent = w->transient_for;
 
588
 
 
589
          if (parent && meta_window_is_in_stack (parent))
 
590
            {
 
591
              meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n",
 
592
                          w->desc, parent->desc);
 
593
              add_constraint (constraints, w, parent);
 
594
            }
 
595
        }
 
596
 
 
597
      tmp = tmp->next;
 
598
    }
 
599
}
 
600
 
 
601
static void
 
602
graph_constraints (Constraint **constraints,
 
603
                   int          n_constraints)
 
604
{
 
605
  int i;
 
606
 
 
607
  i = 0;
 
608
  while (i < n_constraints)
 
609
    {
 
610
      Constraint *c;
 
611
 
 
612
      /* If we have "A below B" and "B below C" then AB -> BC so we
 
613
       * add BC to next_nodes in AB.
 
614
       */
 
615
 
 
616
      c = constraints[i];
 
617
      while (c != NULL)
 
618
        {
 
619
          Constraint *n;
 
620
 
 
621
          g_assert (c->below->stack_position == i);
 
622
 
 
623
          /* Constraints where ->above is below are our
 
624
           * next_nodes and we are their previous
 
625
           */
 
626
          n = constraints[c->above->stack_position];
 
627
          while (n != NULL)
 
628
            {
 
629
              c->next_nodes = g_slist_prepend (c->next_nodes,
 
630
                                               n);
 
631
              /* c is a previous node of n */
 
632
              n->has_prev = TRUE;
 
633
 
 
634
              n = n->next;
 
635
            }
 
636
 
 
637
          c = c->next;
 
638
        }
 
639
 
 
640
      ++i;
 
641
    }
 
642
}
 
643
 
 
644
static void
 
645
free_constraints (Constraint **constraints,
 
646
                  int          n_constraints)
 
647
{
 
648
  int i;
 
649
 
 
650
  i = 0;
 
651
  while (i < n_constraints)
 
652
    {
 
653
      Constraint *c;
 
654
 
 
655
      c = constraints[i];
 
656
      while (c != NULL)
 
657
        {
 
658
          Constraint *next = c->next;
 
659
 
 
660
          g_slist_free (c->next_nodes);
 
661
 
 
662
          g_free (c);
 
663
 
 
664
          c = next;
 
665
        }
 
666
 
 
667
      ++i;
 
668
    }
 
669
}
 
670
 
 
671
static void
 
672
ensure_above (MetaWindow *above,
 
673
              MetaWindow *below)
 
674
{
 
675
  if (WINDOW_HAS_TRANSIENT_TYPE(above) &&
 
676
      above->layer < below->layer)
 
677
    {
 
678
      meta_topic (META_DEBUG_STACK,
 
679
                  "Promoting window %s from layer %u to %u due to contraint\n",
 
680
                  above->desc, above->layer, below->layer);
 
681
      above->layer = below->layer;
 
682
    }
 
683
 
 
684
  if (above->stack_position < below->stack_position)
 
685
    {
 
686
      /* move above to below->stack_position bumping below down the stack */
 
687
      meta_window_set_stack_position_no_sync (above, below->stack_position);
 
688
      g_assert (below->stack_position + 1 == above->stack_position);
 
689
    }
 
690
  meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n",
 
691
              above->desc, above->stack_position,
 
692
              below->desc, below->stack_position);
 
693
}
 
694
 
 
695
static void
 
696
traverse_constraint (Constraint *c)
 
697
{
 
698
  GSList *tmp;
 
699
 
 
700
  if (c->applied)
 
701
    return;
 
702
 
 
703
  ensure_above (c->above, c->below);
 
704
  c->applied = TRUE;
 
705
 
 
706
  tmp = c->next_nodes;
 
707
  while (tmp != NULL)
 
708
    {
 
709
      traverse_constraint (tmp->data);
 
710
 
 
711
      tmp = tmp->next;
 
712
    }
 
713
}
 
714
 
 
715
static void
 
716
apply_constraints (Constraint **constraints,
 
717
                   int          n_constraints)
 
718
{
 
719
  GSList *heads;
 
720
  GSList *tmp;
 
721
  int i;
 
722
 
 
723
  /* List all heads in an ordered constraint chain */
 
724
  heads = NULL;
 
725
  i = 0;
 
726
  while (i < n_constraints)
 
727
    {
 
728
      Constraint *c;
 
729
 
 
730
      c = constraints[i];
 
731
      while (c != NULL)
 
732
        {
 
733
          if (!c->has_prev)
 
734
            heads = g_slist_prepend (heads, c);
 
735
 
 
736
          c = c->next;
 
737
        }
 
738
 
 
739
      ++i;
 
740
    }
 
741
 
 
742
  /* Now traverse the chain and apply constraints */
 
743
  tmp = heads;
 
744
  while (tmp != NULL)
 
745
    {
 
746
      Constraint *c = tmp->data;
 
747
 
 
748
      traverse_constraint (c);
 
749
 
 
750
      tmp = tmp->next;
 
751
    }
 
752
 
 
753
  g_slist_free (heads);
 
754
}
 
755
 
 
756
/**
 
757
 * stack_do_window_deletions:
 
758
 *
 
759
 * Go through "deleted" and take the matching windows
 
760
 * out of "windows".
 
761
 */
 
762
static void
 
763
stack_do_window_deletions (MetaStack *stack)
 
764
{
 
765
  /* Do removals before adds, with paranoid idea that we might re-add
 
766
   * the same window IDs.
 
767
   */
 
768
  GList *tmp;
 
769
  int i;
 
770
 
 
771
  tmp = stack->removed;
 
772
  while (tmp != NULL)
 
773
    {
 
774
      Window xwindow;
 
775
      xwindow = GPOINTER_TO_UINT (tmp->data);
 
776
 
 
777
      /* We go from the end figuring removals are more
 
778
       * likely to be recent.
 
779
       */
 
780
      i = stack->xwindows->len;
 
781
      while (i > 0)
 
782
        {
 
783
          --i;
 
784
 
 
785
          /* there's no guarantee we'll actually find windows to
 
786
           * remove, e.g. the same xwindow could have been
 
787
           * added/removed before we ever synced, and we put
 
788
           * both the window->xwindow and window->frame->xwindow
 
789
           * in the removal list.
 
790
           */
 
791
          if (xwindow == g_array_index (stack->xwindows, Window, i))
 
792
            {
 
793
              g_array_remove_index (stack->xwindows, i);
 
794
              goto next;
 
795
            }
 
796
        }
 
797
 
 
798
    next:
 
799
      tmp = tmp->next;
 
800
    }
 
801
 
 
802
  g_list_free (stack->removed);
 
803
  stack->removed = NULL;
 
804
}
 
805
 
 
806
static void
 
807
stack_do_window_additions (MetaStack *stack)
 
808
{
 
809
  GList *tmp;
 
810
  gint n_added;
 
811
 
 
812
  n_added = g_list_length (stack->added);
 
813
  if (n_added > 0)
 
814
    {
 
815
      meta_topic (META_DEBUG_STACK,
 
816
                  "Adding %d windows to sorted list\n",
 
817
                  n_added);
 
818
 
 
819
      /* stack->added has the most recent additions at the
 
820
       * front of the list, so we need to reverse it
 
821
       */
 
822
      stack->added = g_list_reverse (stack->added);
 
823
 
 
824
      tmp = stack->added;
 
825
      while (tmp != NULL)
 
826
        {
 
827
          MetaWindow *w;
 
828
 
 
829
          w = tmp->data;
 
830
 
 
831
          if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 
832
            g_array_append_val (stack->xwindows, w->xwindow);
 
833
 
 
834
          /* add to the main list */
 
835
          stack->sorted = g_list_prepend (stack->sorted, w);
 
836
 
 
837
          tmp = tmp->next;
 
838
        }
 
839
 
 
840
      stack->need_resort = TRUE; /* may not be needed as we add to top */
 
841
      stack->need_constrain = TRUE;
 
842
      stack->need_relayer = TRUE;
 
843
    }
 
844
 
 
845
  g_list_free (stack->added);
 
846
  stack->added = NULL;
 
847
}
 
848
 
 
849
/**
 
850
 * stack_do_relayer:
 
851
 *
 
852
 * Update the layers that windows are in
 
853
 */
 
854
static void
 
855
stack_do_relayer (MetaStack *stack)
 
856
{
 
857
  GList *tmp;
 
858
 
 
859
  if (!stack->need_relayer)
 
860
    return;
 
861
 
 
862
  meta_topic (META_DEBUG_STACK,
 
863
              "Recomputing layers\n");
 
864
 
 
865
  tmp = stack->sorted;
 
866
 
 
867
  while (tmp != NULL)
 
868
    {
 
869
      MetaWindow *w;
 
870
      MetaStackLayer old_layer;
 
871
 
 
872
      w = tmp->data;
 
873
      old_layer = w->layer;
 
874
 
 
875
      compute_layer (w);
 
876
 
 
877
      if (w->layer != old_layer)
 
878
        {
 
879
          meta_topic (META_DEBUG_STACK,
 
880
                      "Window %s moved from layer %u to %u\n",
 
881
                      w->desc, old_layer, w->layer);
 
882
          stack->need_resort = TRUE;
 
883
          stack->need_constrain = TRUE;
 
884
          /* don't need to constrain as constraining
 
885
           * purely operates in terms of stack_position
 
886
           * not layer
 
887
           */
 
888
        }
 
889
 
 
890
      tmp = tmp->next;
 
891
    }
 
892
 
 
893
  stack->need_relayer = FALSE;
 
894
}
 
895
 
 
896
/**
 
897
 * stack_do_constrain:
 
898
 *
 
899
 * Update stack_position and layer to reflect transiency
 
900
 * constraints
 
901
 */
 
902
static void
 
903
stack_do_constrain (MetaStack *stack)
 
904
{
 
905
  Constraint **constraints;
 
906
 
 
907
  /* It'd be nice if this were all faster, probably */
 
908
 
 
909
  if (!stack->need_constrain)
 
910
    return;
 
911
 
 
912
  meta_topic (META_DEBUG_STACK,
 
913
              "Reapplying constraints\n");
 
914
 
 
915
  constraints = g_new0 (Constraint*,
 
916
                        stack->n_positions);
 
917
 
 
918
  create_constraints (constraints, stack->sorted);
 
919
 
 
920
  graph_constraints (constraints, stack->n_positions);
 
921
 
 
922
  apply_constraints (constraints, stack->n_positions);
 
923
 
 
924
  free_constraints (constraints, stack->n_positions);
 
925
  g_free (constraints);
 
926
 
 
927
  stack->need_constrain = FALSE;
 
928
}
 
929
 
 
930
/**
 
931
 * stack_do_resort:
 
932
 *
 
933
 * Sort stack->sorted with layers having priority over stack_position.
 
934
 */
 
935
static void
 
936
stack_do_resort (MetaStack *stack)
 
937
{
 
938
  if (!stack->need_resort)
 
939
    return;
 
940
 
 
941
  meta_topic (META_DEBUG_STACK,
 
942
              "Sorting stack list\n");
 
943
 
 
944
  stack->sorted = g_list_sort (stack->sorted,
 
945
                               (GCompareFunc) compare_window_position);
 
946
 
 
947
  meta_screen_queue_check_fullscreen (stack->screen);
 
948
 
 
949
  stack->need_resort = FALSE;
 
950
}
 
951
 
 
952
/**
 
953
 * stack_ensure_sorted:
 
954
 *
 
955
 * Puts the stack into canonical form.
 
956
 *
 
957
 * Honour the removed and added lists of the stack, and then recalculate
 
958
 * all the layers (if the flag is set), re-run all the constraint calculations
 
959
 * (if the flag is set), and finally re-sort the stack (if the flag is set,
 
960
 * and if it wasn't already it might have become so during all the previous
 
961
 * activity).
 
962
 */
 
963
static void
 
964
stack_ensure_sorted (MetaStack *stack)
 
965
{
 
966
  stack_do_window_deletions (stack);
 
967
  stack_do_window_additions (stack);
 
968
  stack_do_relayer (stack);
 
969
  stack_do_constrain (stack);
 
970
  stack_do_resort (stack);
 
971
}
 
972
 
 
973
/**
 
974
 * stack_sync_to_server:
 
975
 *
 
976
 * Order the windows on the X server to be the same as in our structure.
 
977
 * We do this using XRestackWindows if we don't know the previous order,
 
978
 * or XConfigureWindow on a few particular windows if we do and can figure
 
979
 * out the minimum set of changes.  After that, we set __NET_CLIENT_LIST
 
980
 * and __NET_CLIENT_LIST_STACKING.
 
981
 *
 
982
 * FIXME: Now that we have a good view of the stacking order on the server
 
983
 * with MetaStackTracker it should be possible to do a simpler and better
 
984
 * job of computing the minimal set of stacking requests needed.
 
985
 */
 
986
static void
 
987
stack_sync_to_xserver (MetaStack *stack)
 
988
{
 
989
  GArray *x11_stacked;
 
990
  GArray *all_root_children_stacked; /* wayland OR x11 */
 
991
  GList *tmp;
 
992
  GArray *hidden_stack_ids;
 
993
 
 
994
  /* Bail out if frozen */
 
995
  if (stack->freeze_count > 0)
 
996
    return;
 
997
 
 
998
  meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
 
999
 
 
1000
  stack_ensure_sorted (stack);
 
1001
 
 
1002
  /* Create stacked xwindow arrays, in bottom-to-top order
 
1003
   */
 
1004
  x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
 
1005
 
 
1006
  all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
 
1007
  hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
 
1008
 
 
1009
  meta_topic (META_DEBUG_STACK, "Bottom to top: ");
 
1010
  meta_push_no_msg_prefix ();
 
1011
 
 
1012
  for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev)
 
1013
    {
 
1014
      MetaWindow *w = tmp->data;
 
1015
      guint64 top_level_window;
 
1016
      guint64 stack_id;
 
1017
 
 
1018
      if (w->unmanaging)
 
1019
        continue;
 
1020
 
 
1021
      meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
 
1022
                  w->layer, w->stack_position, w->desc);
 
1023
 
 
1024
      if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 
1025
        g_array_append_val (x11_stacked, w->xwindow);
 
1026
 
 
1027
      if (w->frame)
 
1028
        top_level_window = w->frame->xwindow;
 
1029
      else
 
1030
        top_level_window = w->xwindow;
 
1031
 
 
1032
      if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 
1033
        stack_id = top_level_window;
 
1034
      else
 
1035
        stack_id = w->stamp;
 
1036
 
 
1037
      /* We don't restack hidden windows along with the rest, though they are
 
1038
       * reflected in the _NET hints. Hidden windows all get pushed below
 
1039
       * the screens fullscreen guard_window. */
 
1040
      if (w->hidden)
 
1041
        {
 
1042
          g_array_append_val (hidden_stack_ids, stack_id);
 
1043
          continue;
 
1044
        }
 
1045
 
 
1046
      g_array_append_val (all_root_children_stacked, stack_id);
 
1047
    }
 
1048
 
 
1049
  meta_topic (META_DEBUG_STACK, "\n");
 
1050
  meta_pop_no_msg_prefix ();
 
1051
 
 
1052
  /* The screen guard window sits above all hidden windows and acts as
 
1053
   * a barrier to input reaching these windows. */
 
1054
  guint64 guard_window_id = stack->screen->guard_window;
 
1055
  g_array_append_val (hidden_stack_ids, guard_window_id);
 
1056
 
 
1057
  /* Sync to server */
 
1058
 
 
1059
  meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
 
1060
              all_root_children_stacked->len);
 
1061
 
 
1062
  meta_stack_tracker_restack_managed (stack->screen->stack_tracker,
 
1063
                                      (guint64 *)all_root_children_stacked->data,
 
1064
                                      all_root_children_stacked->len);
 
1065
  meta_stack_tracker_restack_at_bottom (stack->screen->stack_tracker,
 
1066
                                        (guint64 *)hidden_stack_ids->data,
 
1067
                                        hidden_stack_ids->len);
 
1068
 
 
1069
  /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
 
1070
 
 
1071
  XChangeProperty (stack->screen->display->xdisplay,
 
1072
                   stack->screen->xroot,
 
1073
                   stack->screen->display->atom__NET_CLIENT_LIST,
 
1074
                   XA_WINDOW,
 
1075
                   32, PropModeReplace,
 
1076
                   (unsigned char *)stack->xwindows->data,
 
1077
                   stack->xwindows->len);
 
1078
  XChangeProperty (stack->screen->display->xdisplay,
 
1079
                   stack->screen->xroot,
 
1080
                   stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
 
1081
                   XA_WINDOW,
 
1082
                   32, PropModeReplace,
 
1083
                   (unsigned char *)x11_stacked->data,
 
1084
                   x11_stacked->len);
 
1085
 
 
1086
  g_array_free (x11_stacked, TRUE);
 
1087
  g_array_free (hidden_stack_ids, TRUE);
 
1088
  g_array_free (all_root_children_stacked, TRUE);
 
1089
}
 
1090
 
 
1091
MetaWindow*
 
1092
meta_stack_get_top (MetaStack *stack)
 
1093
{
 
1094
  stack_ensure_sorted (stack);
 
1095
 
 
1096
  if (stack->sorted)
 
1097
    return stack->sorted->data;
 
1098
  else
 
1099
    return NULL;
 
1100
}
 
1101
 
 
1102
MetaWindow*
 
1103
meta_stack_get_bottom (MetaStack  *stack)
 
1104
{
 
1105
  GList *link;
 
1106
 
 
1107
  stack_ensure_sorted (stack);
 
1108
 
 
1109
  link = g_list_last (stack->sorted);
 
1110
  if (link != NULL)
 
1111
    return link->data;
 
1112
  else
 
1113
    return NULL;
 
1114
}
 
1115
 
 
1116
MetaWindow*
 
1117
meta_stack_get_above (MetaStack      *stack,
 
1118
                      MetaWindow     *window,
 
1119
                      gboolean        only_within_layer)
 
1120
{
 
1121
  GList *link;
 
1122
  MetaWindow *above;
 
1123
 
 
1124
  stack_ensure_sorted (stack);
 
1125
 
 
1126
  link = g_list_find (stack->sorted, window);
 
1127
  if (link == NULL)
 
1128
    return NULL;
 
1129
  if (link->prev == NULL)
 
1130
    return NULL;
 
1131
 
 
1132
  above = link->prev->data;
 
1133
 
 
1134
  if (only_within_layer &&
 
1135
      above->layer != window->layer)
 
1136
    return NULL;
 
1137
  else
 
1138
    return above;
 
1139
}
 
1140
 
 
1141
MetaWindow*
 
1142
meta_stack_get_below (MetaStack      *stack,
 
1143
                      MetaWindow     *window,
 
1144
                      gboolean        only_within_layer)
 
1145
{
 
1146
  GList *link;
 
1147
  MetaWindow *below;
 
1148
 
 
1149
  stack_ensure_sorted (stack);
 
1150
 
 
1151
  link = g_list_find (stack->sorted, window);
 
1152
 
 
1153
  if (link == NULL)
 
1154
    return NULL;
 
1155
  if (link->next == NULL)
 
1156
    return NULL;
 
1157
 
 
1158
  below = link->next->data;
 
1159
 
 
1160
  if (only_within_layer &&
 
1161
      below->layer != window->layer)
 
1162
    return NULL;
 
1163
  else
 
1164
    return below;
 
1165
}
 
1166
 
 
1167
static gboolean
 
1168
window_contains_point (MetaWindow *window,
 
1169
                       int         root_x,
 
1170
                       int         root_y)
 
1171
{
 
1172
  MetaRectangle rect;
 
1173
 
 
1174
  meta_window_get_frame_rect (window, &rect);
 
1175
 
 
1176
  return POINT_IN_RECT (root_x, root_y, rect);
 
1177
}
 
1178
 
 
1179
static MetaWindow*
 
1180
get_default_focus_window (MetaStack     *stack,
 
1181
                          MetaWorkspace *workspace,
 
1182
                          MetaWindow    *not_this_one,
 
1183
                          gboolean       must_be_at_point,
 
1184
                          int            root_x,
 
1185
                          int            root_y)
 
1186
{
 
1187
  /* Find the topmost, focusable, mapped, window.
 
1188
   * not_this_one is being unfocused or going away, so exclude it.
 
1189
   */
 
1190
 
 
1191
  GList *l;
 
1192
 
 
1193
  stack_ensure_sorted (stack);
 
1194
 
 
1195
  /* top of this layer is at the front of the list */
 
1196
  for (l = stack->sorted; l != NULL; l = l->next)
 
1197
    {
 
1198
      MetaWindow *window = l->data;
 
1199
 
 
1200
      if (!window)
 
1201
        continue;
 
1202
 
 
1203
      if (window == not_this_one)
 
1204
        continue;
 
1205
 
 
1206
      if (window->unmaps_pending > 0)
 
1207
        continue;
 
1208
 
 
1209
      if (window->unmanaging)
 
1210
        continue;
 
1211
 
 
1212
      if (!(window->input || window->take_focus))
 
1213
        continue;
 
1214
 
 
1215
      if (!meta_window_should_be_showing (window))
 
1216
        continue;
 
1217
 
 
1218
      if (must_be_at_point && !window_contains_point (window, root_x, root_y))
 
1219
        continue;
 
1220
 
 
1221
      if (window->type == META_WINDOW_DOCK)
 
1222
        continue;
 
1223
 
 
1224
      return window;
 
1225
    }
 
1226
 
 
1227
  return NULL;
 
1228
}
 
1229
 
 
1230
MetaWindow*
 
1231
meta_stack_get_default_focus_window_at_point (MetaStack     *stack,
 
1232
                                              MetaWorkspace *workspace,
 
1233
                                              MetaWindow    *not_this_one,
 
1234
                                              int            root_x,
 
1235
                                              int            root_y)
 
1236
{
 
1237
  return get_default_focus_window (stack, workspace, not_this_one,
 
1238
                                   TRUE, root_x, root_y);
 
1239
}
 
1240
 
 
1241
MetaWindow*
 
1242
meta_stack_get_default_focus_window (MetaStack     *stack,
 
1243
                                     MetaWorkspace *workspace,
 
1244
                                     MetaWindow    *not_this_one)
 
1245
{
 
1246
  return get_default_focus_window (stack, workspace, not_this_one,
 
1247
                                   FALSE, 0, 0);
 
1248
}
 
1249
 
 
1250
GList*
 
1251
meta_stack_list_windows (MetaStack     *stack,
 
1252
                         MetaWorkspace *workspace)
 
1253
{
 
1254
  GList *workspace_windows = NULL;
 
1255
  GList *link;
 
1256
 
 
1257
  stack_ensure_sorted (stack); /* do adds/removes */
 
1258
 
 
1259
  link = stack->sorted;
 
1260
 
 
1261
  while (link)
 
1262
    {
 
1263
      MetaWindow *window = link->data;
 
1264
 
 
1265
      if (window &&
 
1266
          (workspace == NULL || meta_window_located_on_workspace (window, workspace)))
 
1267
        {
 
1268
          workspace_windows = g_list_prepend (workspace_windows,
 
1269
                                              window);
 
1270
        }
 
1271
 
 
1272
      link = link->next;
 
1273
    }
 
1274
 
 
1275
  return workspace_windows;
 
1276
}
 
1277
 
 
1278
int
 
1279
meta_stack_windows_cmp  (MetaStack  *stack,
 
1280
                         MetaWindow *window_a,
 
1281
                         MetaWindow *window_b)
 
1282
{
 
1283
  g_return_val_if_fail (window_a->screen == window_b->screen, 0);
 
1284
 
 
1285
  /* -1 means a below b */
 
1286
 
 
1287
  stack_ensure_sorted (stack); /* update constraints, layers */
 
1288
 
 
1289
  if (window_a->layer < window_b->layer)
 
1290
    return -1;
 
1291
  else if (window_a->layer > window_b->layer)
 
1292
    return 1;
 
1293
  else if (window_a->stack_position < window_b->stack_position)
 
1294
    return -1;
 
1295
  else if (window_a->stack_position > window_b->stack_position)
 
1296
    return 1;
 
1297
  else
 
1298
    return 0; /* not reached */
 
1299
}
 
1300
 
 
1301
static int
 
1302
compare_just_window_stack_position (void *a,
 
1303
                                    void *b)
 
1304
{
 
1305
  MetaWindow *window_a = a;
 
1306
  MetaWindow *window_b = b;
 
1307
 
 
1308
  if (window_a->stack_position < window_b->stack_position)
 
1309
    return -1; /* move window_a earlier in list */
 
1310
  else if (window_a->stack_position > window_b->stack_position)
 
1311
    return 1;
 
1312
  else
 
1313
    return 0; /* not reached */
 
1314
}
 
1315
 
 
1316
GList*
 
1317
meta_stack_get_positions (MetaStack *stack)
 
1318
{
 
1319
  GList *tmp;
 
1320
 
 
1321
  /* Make sure to handle any adds or removes */
 
1322
  stack_ensure_sorted (stack);
 
1323
 
 
1324
  tmp = g_list_copy (stack->sorted);
 
1325
  tmp = g_list_sort (tmp, (GCompareFunc) compare_just_window_stack_position);
 
1326
 
 
1327
  return tmp;
 
1328
}
 
1329
 
 
1330
static gint
 
1331
compare_pointers (gconstpointer a,
 
1332
                  gconstpointer b)
 
1333
{
 
1334
  if (a > b)
 
1335
    return 1;
 
1336
  else if (a < b)
 
1337
    return -1;
 
1338
  else
 
1339
    return 0;
 
1340
}
 
1341
 
 
1342
static gboolean
 
1343
lists_contain_same_windows (GList *a,
 
1344
                            GList *b)
 
1345
{
 
1346
  GList *copy1, *copy2;
 
1347
  GList *tmp1, *tmp2;
 
1348
 
 
1349
  if (g_list_length (a) != g_list_length (b))
 
1350
    return FALSE;
 
1351
 
 
1352
  tmp1 = copy1 = g_list_sort (g_list_copy (a), compare_pointers);
 
1353
  tmp2 = copy2 = g_list_sort (g_list_copy (b), compare_pointers);
 
1354
 
 
1355
  while (tmp1 && tmp1->data == tmp2->data)   /* tmp2 is non-NULL if tmp1 is */
 
1356
    {
 
1357
      tmp1 = tmp1->next;
 
1358
      tmp2 = tmp2->next;
 
1359
    }
 
1360
 
 
1361
  g_list_free (copy1);
 
1362
  g_list_free (copy2);
 
1363
 
 
1364
  return (tmp1 == NULL);    /* tmp2 is non-NULL if tmp1 is */
 
1365
}
 
1366
 
 
1367
void
 
1368
meta_stack_set_positions (MetaStack *stack,
 
1369
                          GList     *windows)
 
1370
{
 
1371
  int i;
 
1372
  GList *tmp;
 
1373
 
 
1374
  /* Make sure any adds or removes aren't in limbo -- is this needed? */
 
1375
  stack_ensure_sorted (stack);
 
1376
 
 
1377
  if (!lists_contain_same_windows (windows, stack->sorted))
 
1378
    {
 
1379
      meta_warning ("This list of windows has somehow changed; not resetting "
 
1380
                    "positions of the windows.\n");
 
1381
      return;
 
1382
    }
 
1383
 
 
1384
  g_list_free (stack->sorted);
 
1385
  stack->sorted = g_list_copy (windows);
 
1386
 
 
1387
  stack->need_resort = TRUE;
 
1388
  stack->need_constrain = TRUE;
 
1389
 
 
1390
  i = 0;
 
1391
  tmp = windows;
 
1392
  while (tmp != NULL)
 
1393
    {
 
1394
      MetaWindow *w = tmp->data;
 
1395
      w->stack_position = i++;
 
1396
      tmp = tmp->next;
 
1397
    }
 
1398
 
 
1399
  meta_topic (META_DEBUG_STACK,
 
1400
              "Reset the stack positions of (nearly) all windows\n");
 
1401
 
 
1402
  stack_sync_to_xserver (stack);
 
1403
  meta_stack_update_window_tile_matches (stack, NULL);
 
1404
}
 
1405
 
 
1406
void
 
1407
meta_window_set_stack_position_no_sync (MetaWindow *window,
 
1408
                                        int         position)
 
1409
{
 
1410
  int low, high, delta;
 
1411
  GList *tmp;
 
1412
 
 
1413
  g_return_if_fail (window->screen->stack != NULL);
 
1414
  g_return_if_fail (window->stack_position >= 0);
 
1415
  g_return_if_fail (position >= 0);
 
1416
  g_return_if_fail (position < window->screen->stack->n_positions);
 
1417
 
 
1418
  if (position == window->stack_position)
 
1419
    {
 
1420
      meta_topic (META_DEBUG_STACK, "Window %s already has position %d\n",
 
1421
                  window->desc, position);
 
1422
      return;
 
1423
    }
 
1424
 
 
1425
  window->screen->stack->need_resort = TRUE;
 
1426
  window->screen->stack->need_constrain = TRUE;
 
1427
 
 
1428
  if (position < window->stack_position)
 
1429
    {
 
1430
      low = position;
 
1431
      high = window->stack_position - 1;
 
1432
      delta = 1;
 
1433
    }
 
1434
  else
 
1435
    {
 
1436
      low = window->stack_position + 1;
 
1437
      high = position;
 
1438
      delta = -1;
 
1439
    }
 
1440
 
 
1441
  tmp = window->screen->stack->sorted;
 
1442
  while (tmp != NULL)
 
1443
    {
 
1444
      MetaWindow *w = tmp->data;
 
1445
 
 
1446
      if (w->stack_position >= low &&
 
1447
          w->stack_position <= high)
 
1448
        w->stack_position += delta;
 
1449
 
 
1450
      tmp = tmp->next;
 
1451
    }
 
1452
 
 
1453
  window->stack_position = position;
 
1454
 
 
1455
  meta_topic (META_DEBUG_STACK,
 
1456
              "Window %s had stack_position set to %d\n",
 
1457
              window->desc, window->stack_position);
 
1458
}
 
1459
 
 
1460
void
 
1461
meta_window_set_stack_position (MetaWindow *window,
 
1462
                                int         position)
 
1463
{
 
1464
  meta_window_set_stack_position_no_sync (window, position);
 
1465
  stack_sync_to_xserver (window->screen->stack);
 
1466
  meta_stack_update_window_tile_matches (window->screen->stack,
 
1467
                                         window->screen->active_workspace);
 
1468
}