summaryrefslogtreecommitdiff
path: root/src/core/stack.h
blob: 3f439435e0e3eb623979a71eb5de9ca0d0c70240 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

/**
 * \file stack.h  Which windows cover which other windows
 *
 * There are two factors that determine window position.
 *
 * One is window->stack_position, which is a unique integer
 * indicating how windows are ordered with respect to one
 * another. The ordering here transcends layers; it isn't changed
 * as the window is moved among layers. This allows us to move several
 * windows from one layer to another, while preserving the relative
 * order of the moved windows. Also, it allows us to restore
 * the stacking order from a saved session.
 *
 * However when actually stacking windows on the screen, the
 * layer overrides the stack_position; windows are first sorted
 * by layer, then by stack_position within each layer.
 */

/*
 * Copyright (C) 2001 Havoc Pennington
 * Copyright (C) 2005 Elijah Newren
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#ifndef META_STACK_H
#define META_STACK_H

#include "screen-private.h"

/**
 * Layers a window can be in.
 * These MUST be in the order of stacking.
 */
typedef enum
{
  META_LAYER_DESKTOP        = 0,
  META_LAYER_BOTTOM         = 1,
  META_LAYER_NORMAL         = 2,
  META_LAYER_TOP            = 4, /* Same as DOCK; see EWMH and bug 330717 */
  META_LAYER_DOCK           = 4,
  META_LAYER_FULLSCREEN     = 5,
  META_LAYER_FOCUSED_WINDOW = 6,
  META_LAYER_LAST           = 7
} MetaStackLayer;

/**
 * A sorted list of windows bearing some level of resemblance to the stack of
 * windows on the X server.
 *
 * (This is only used as a field within a MetaScreen; we treat it as a separate
 * class for simplicity.)
 */
struct _MetaStack
{
  /** The MetaScreen containing this stack. */
  MetaScreen *screen;

  /**
   * A sequence of all the Windows (X handles, not MetaWindows) of the windows
   * we manage, sorted in order.  Suitable to be passed into _NET_CLIENT_LIST.
   */
  GArray *windows;

  /** The MetaWindows of the windows we manage, sorted in order. */
  GList *sorted;

  /**
   * MetaWindows waiting to be added to the "sorted" and "windows" list, after
   * being added by meta_stack_add() and before being assimilated by
   * stack_ensure_sorted().
   *
   * The order of the elements in this list is not important; what is important
   * is the stack_position element of each window.
   */
  GList *added;

  /**
   * Windows (X handles, not MetaWindows) waiting to be removed from the
   * "windows" list, after being removed by meta_stack_remove() and before
   * being assimilated by stack_ensure_sorted().  (We already removed them
   * from the "sorted" list.)
   *
   * The order of the elements in this list is not important.
   */
  GList *removed;

  /**
   * If this is zero, the local stack oughtn't to be brought up to date with
   * the X server's stack, because it is in the middle of being updated.
   * If it is positive, the local stack is said to be "frozen", and will need
   * to be thawed that many times before the stack can be brought up to date
   * again.  You may freeze the stack with meta_stack_freeze() and thaw it
   * with meta_stack_thaw().
   */
  int freeze_count;

  /**
   * The last-known stack of all windows, bottom to top.  We cache it here
   * so that subsequent times we'll be able to do incremental moves.
   */
  GArray *last_root_children_stacked;

  /**
   * Number of stack positions; same as the length of added, but
   * kept for quick reference.
   */
  gint n_positions;

  /** Is the stack in need of re-sorting? */
  unsigned int need_resort : 1;

  /**
   * Are the windows in the stack in need of having their
   * layers recalculated?
   */
  unsigned int need_relayer : 1;

  /**
   * Are the windows in the stack in need of having their positions
   * recalculated with respect to transiency (parent and child windows)?
   */
  unsigned int need_constrain : 1;
};

/**
 * Creates and initialises a MetaStack.
 *
 * \param screen  The MetaScreen which will be the parent of this stack.
 * \return The new screen.
 */
MetaStack *meta_stack_new       (MetaScreen     *screen);

/**
 * Destroys and frees a MetaStack.
 *
 * \param stack  The stack to destroy.
 */
void       meta_stack_free      (MetaStack      *stack);

/**
 * Adds a window to the local stack.  It is a fatal error to call this
 * function on a window which already exists on the stack of any screen.
 *
 * \param window  The window to add
 * \param stack  The stack to add it to
 */
void       meta_stack_add       (MetaStack      *stack,
                                 MetaWindow     *window);

/**
 * Removes a window from the local stack.  It is a fatal error to call this
 * function on a window which exists on the stack of any screen.
 *
 * \param window  The window to remove
 * \param stack   The stack to remove it from
 */
void       meta_stack_remove    (MetaStack      *stack,
                                 MetaWindow     *window);
/**
 * Recalculates the correct layer for all windows in the stack,
 * and moves them about accordingly.
 *
 * \param window  Dummy parameter
 * \param stack   The stack to recalculate
 * \bug What's with the dummy parameter?
 */
void       meta_stack_update_layer    (MetaStack      *stack,
                                       MetaWindow     *window);

/**
 * Recalculates the correct stacking order for all windows in the stack
 * according to their transience, and moves them about accordingly.
 *
 * \param window  Dummy parameter
 * \param stack   The stack to recalculate
 * \bug What's with the dummy parameter?
 */
void       meta_stack_update_transient (MetaStack     *stack,
                                        MetaWindow    *window);

/**
 * Move a window to the top of its layer.
 *
 * \param stack  The stack to modify.
 * \param window  The window that's making an ascension.
 *                (Amulet of Yendor not required.)
 */
void       meta_stack_raise     (MetaStack      *stack,
                                 MetaWindow     *window);
/**
 * Move a window to the bottom of its layer.
 *
 * \param stack  The stack to modify.
 * \param window  The window that's on the way downwards.
 */
void       meta_stack_lower     (MetaStack      *stack,
                                 MetaWindow     *window);

/**
 * Prevent syncing to server until the next call of meta_stack_thaw(),
 * so that we can carry out multiple operations in one go without having
 * everything halfway reflected on the X server.
 *
 * (Calls to meta_stack_freeze() nest, so that multiple calls to
 * meta_stack_freeze will require multiple calls to meta_stack_thaw().)
 *
 * \param stack  The stack to freeze.
 */
void       meta_stack_freeze    (MetaStack      *stack);

/**
 * Undoes a meta_stack_freeze(), and processes anything which has become
 * necessary during the freeze.  It is an error to call this function if
 * the stack has not been frozen.
 *
 * \param stack  The stack to thaw.
 */
void       meta_stack_thaw      (MetaStack      *stack);

/**
 * Finds the top window on the stack.
 *
 * \param stack  The stack to examine.
 * \return The top window on the stack, or NULL in the vanishingly unlikely
 *         event that you have no windows on your screen whatsoever.
 */
MetaWindow* meta_stack_get_top    (MetaStack  *stack);

/**
 * Finds the window at the bottom of the stack.  Since that's pretty much
 * always the desktop, this isn't the most useful of functions, and nobody
 * actually calls it.  We should probably get rid of it.
 *
 * \param stack  The stack to search
 */
MetaWindow* meta_stack_get_bottom (MetaStack  *stack);

/**
 * Finds the window above a given window in the stack.
 * It is not an error to pass in a window which does not exist in
 * the stack; the function will merely return NULL.
 *
 * \param stack   The stack to search.
 * \param window  The window to look above.
 * \param only_within_layer  If true, will return NULL if "window" is the
 *                           top window in its layer.
 * \return NULL if there is no such window;
 *         the window above "window" otherwise.
 */
MetaWindow* meta_stack_get_above  (MetaStack  *stack,
                                   MetaWindow *window,
                                   gboolean    only_within_layer);

/**
 * Finds the window below a given window in the stack.
 * It is not an error to pass in a window which does not exist in
 * the stack; the function will merely return NULL.
 *
 * \param stack   The stack to search.
 * \param window  The window to look below.
 * \param only_within_layer  If true, will return NULL if "window" is the
 *                           bottom window in its layer.
 * \return NULL if there is no such window;
 *         the window below "window" otherwise.
 */
MetaWindow* meta_stack_get_below  (MetaStack  *stack,
                                   MetaWindow *window,
                                   gboolean    only_within_layer);

/**
 * Find the topmost, focusable, mapped, window in a stack.  If you supply
 * a window as "not_this_one", we won't return that one (presumably
 * because it's going to be going away).  But if you do supply "not_this_one"
 * and we find its parent, we'll return that; and if "not_this_one" is in
 * a group, we'll return the top window of that group.
 *
 * Also, we are prejudiced against dock windows.  Every kind of window, even
 * the desktop, will be returned in preference to a dock window.
 *
 * \param stack  The stack to search.
 * \param workspace  NULL to search all workspaces; otherwise only windows
 *                   from that workspace will be returned.
 * \param not_this_one  Window to ignore because it's being unfocussed or
 *                      going away.
 * \return The window matching all these constraints or NULL if none does.
 *
 * \bug Never called!
  */
MetaWindow* meta_stack_get_default_focus_window          (MetaStack     *stack,
                                                          MetaWorkspace *workspace,
                                                          MetaWindow    *not_this_one);

/**
 * Find the topmost, focusable, mapped, window in a stack.  If you supply
 * a window as "not_this_one", we won't return that one (presumably
 * because it's going to be going away).  But if you do supply "not_this_one"
 * and we find its parent, we'll return that; and if "not_this_one" is in
 * a group, we'll return the top window of that group.
 *
 * Also, we are prejudiced against dock windows.  Every kind of window, even
 * the desktop, will be returned in preference to a dock window.
 *
 * \param stack  The stack to search.
 * \param workspace  NULL to search all workspaces; otherwise only windows
 *                   from that workspace will be returned.
 * \param not_this_one  Window to ignore because it's being unfocussed or
 *                      going away.
 * \param root_x  The returned window must contain this point,
 *                unless it's a dock.
 * \param root_y  See root_x.
 * \return The window matching all these constraints or NULL if none does.
 */
MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack     *stack,
                                                          MetaWorkspace *workspace,
                                                          MetaWindow    *not_this_one,
                                                          int            root_x,
                                                          int            root_y);

/**
 * Finds all the windows in the stack, in order.
 *
 * \param stack  The stack to examine.
 * \param workspace  If non-NULL, only windows on this workspace will be
 *                   returned; otherwise all windows in the stack will be
 *                   returned.
 * \return A list of windows, in stacking order, honouring layers.
 */
GList*      meta_stack_list_windows (MetaStack *stack,
                                     MetaWorkspace *workspace);

/**
 * Comparison function for windows within a stack.  This is not directly
 * suitable for use within a standard comparison routine, because it takes
 * an extra parameter; you will need to wrap it.
 *
 * (FIXME: We could remove the stack parameter and use the stack of
 * the screen of window A, and complain if the stack of the screen of
 * window B differed; then this would be a usable general comparison function.)
 *
 * (FIXME: Apparently identical to compare_window_position(). Merge them.)
 *
 * \param stack  A stack containing both window_a and window_b
 * \param window_a  A window
 * \param window_b  Another window
 * \return -1 if window_a is below window_b, honouring layers; 1 if it's
 *         above it; 0 if you passed in the same window twice!
 */
int         meta_stack_windows_cmp  (MetaStack  *stack,
                                     MetaWindow *window_a,
                                     MetaWindow *window_b);

/**
 * Sets the position of a window within the stack.  This will only move it
 * up or down within its layer.  It is an error to attempt to move this
 * below position zero or above the last position in the stack (however, since
 * we don't provide a simple way to tell the number of windows in the stack,
 * this requirement may not be easy to fulfil).
 *
 * \param window  The window which is moving.
 * \param position  Where it should move to (0 is the bottom).
 */
void meta_window_set_stack_position (MetaWindow *window,
                                     int         position);

/**
 * Returns the current stack state, allowing rudimentary transactions.
 *
 * \param stack  The stack to examine.
 * \return An opaque GList representing the current stack sort order;
 *         it is the caller's responsibility to free it.
 *         Pass this to meta_stack_set_positions() later if you want to restore
 *         the state to where it was when you called this function.
 */
GList* meta_stack_get_positions (MetaStack *stack);

/**
 * Rolls back a transaction, given the list returned from
 * meta_stack_get_positions().
 *
 * \param stack  The stack to roll back.
 * \param windows  The list returned from meta_stack_get_positions().
 */
void   meta_stack_set_positions (MetaStack *stack,
                                 GList     *windows);

#endif