chiark / gitweb /
Imported Debian patch 1.0.0-6
[e16] / src / stacking.c
1 /*
2  * Copyright (C) 2004-2008 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "E.h"
24 #include "desktops.h"
25 #include "eobj.h"
26 #include "ewins.h"
27
28 #define ENABLE_DEBUG_STACKING 1
29
30 #define EobjGetCwin(p) \
31     ((p->type == EOBJ_TYPE_EWIN) ? EwinGetClientXwin(((EWin*)(p))) : None)
32
33 typedef struct _eobjlist EobjList;
34
35 struct _eobjlist {
36    const char         *name;
37    int                 nalloc;
38    int                 nwins;
39    EObj              **list;
40    char                layered;
41    char                type;
42 };
43
44 static int          EobjListRaise(EobjList * ewl, EObj * eo, int test);
45 static int          EobjListLower(EobjList * ewl, EObj * eo, int test);
46
47 #if ENABLE_DEBUG_STACKING
48 static void
49 EobjListShow(const char *txt, EobjList * ewl)
50 {
51    int                 i;
52    EObj               *eo;
53
54    if (!EDebug(EDBUG_TYPE_STACKING))
55       return;
56
57    Eprintf("%s-%s:\n", ewl->name, txt);
58    for (i = 0; i < ewl->nwins; i++)
59      {
60         eo = ewl->list[i];
61         Eprintf(" %2d: %#10lx %#10lx %d %d %s\n", i, EobjGetXwin(eo),
62                 EobjGetCwin(eo), eo->desk->num, eo->ilayer, EobjGetName(eo));
63      }
64 }
65 #else
66 #define EobjListShow(txt, ewl)
67 #endif
68
69 static int
70 EobjListGetIndex(EobjList * ewl, EObj * eo)
71 {
72    int                 i;
73
74    for (i = 0; i < ewl->nwins; i++)
75       if (ewl->list[i] == eo)
76          return i;
77
78    return -1;
79 }
80
81 static void
82 EobjListAdd(EobjList * ewl, EObj * eo, int ontop)
83 {
84    int                 i;
85
86    /* Quit if already in list */
87    i = EobjListGetIndex(ewl, eo);
88    if (i >= 0)
89       return;
90
91    if (ewl->nwins >= ewl->nalloc)
92      {
93         ewl->nalloc += 16;
94         ewl->list = EREALLOC(EObj *, ewl->list, ewl->nalloc);
95      }
96
97    if (ewl->layered)
98      {
99         /* The simple way for now (add, raise/lower) */
100         if (ontop)
101           {
102              ewl->list[ewl->nwins] = eo;
103              ewl->nwins++;
104              EobjListRaise(ewl, eo, 0);
105           }
106         else
107           {
108              memmove(ewl->list + 1, ewl->list, ewl->nwins * sizeof(EObj *));
109              ewl->list[0] = eo;
110              ewl->nwins++;
111              EobjListLower(ewl, eo, 0);
112           }
113         if (eo->stacked == 0)
114            DeskSetDirtyStack(eo->desk, eo);
115      }
116    else
117      {
118         if (ontop)
119           {
120              memmove(ewl->list + 1, ewl->list, ewl->nwins * sizeof(EObj *));
121              ewl->list[0] = eo;
122           }
123         else
124           {
125              ewl->list[ewl->nwins] = eo;
126           }
127         ewl->nwins++;
128      }
129
130    EobjListShow("EobjListAdd", ewl);
131 }
132
133 static void
134 EobjListDel(EobjList * ewl, EObj * eo)
135 {
136    int                 i, n;
137
138    /* Quit if not in list */
139    i = EobjListGetIndex(ewl, eo);
140    if (i < 0)
141       return;
142
143    ewl->nwins--;
144    n = ewl->nwins - i;
145    if (n > 0)
146      {
147         memmove(ewl->list + i, ewl->list + i + 1, n * sizeof(EObj *));
148      }
149    else if (ewl->nwins <= 0)
150      {
151         /* Enables autocleanup at shutdown, if ever implemented */
152         Efree(ewl->list);
153         ewl->list = NULL;
154         ewl->nalloc = 0;
155      }
156
157    EobjListShow("EobjListDel", ewl);
158 }
159
160 static int
161 EobjListLower(EobjList * ewl, EObj * eo, int test)
162 {
163    int                 i, j, n;
164
165    /* Quit if not in list */
166    i = EobjListGetIndex(ewl, eo);
167    if (i < 0)
168       return 0;
169
170    j = ewl->nwins - 1;
171    if (ewl->layered)
172      {
173         /* Take the layer into account */
174         for (; j >= 0; j--)
175            if (i != j && eo->ilayer <= ewl->list[j]->ilayer)
176               break;
177         if (j < i)
178            j++;
179      }
180
181    n = j - i;
182    if (test)
183       return n;
184
185    if (n > 0)
186      {
187         memmove(ewl->list + i, ewl->list + i + 1, n * sizeof(EObj *));
188         ewl->list[j] = eo;
189         if (ewl->layered && eo->stacked > 0)
190            DeskSetDirtyStack(eo->desk, eo);
191      }
192    else if (n < 0)
193      {
194         memmove(ewl->list + j + 1, ewl->list + j, -n * sizeof(EObj *));
195         ewl->list[j] = eo;
196         if (ewl->layered && eo->stacked > 0)
197            DeskSetDirtyStack(eo->desk, eo);
198      }
199
200    EobjListShow("EobjListLower", ewl);
201    return n;
202 }
203
204 static int
205 EobjListRaise(EobjList * ewl, EObj * eo, int test)
206 {
207    int                 i, j, n;
208
209    /* Quit if not in list */
210    i = EobjListGetIndex(ewl, eo);
211    if (i < 0)
212       return 0;
213
214    j = 0;
215    if (ewl->layered)
216      {
217         /* Take the layer into account */
218         for (; j < ewl->nwins; j++)
219            if (j != i && eo->ilayer >= ewl->list[j]->ilayer)
220               break;
221         if (j > i)
222            j--;
223      }
224
225    n = j - i;
226    if (test)
227       return n;
228
229    if (n > 0)
230      {
231         memmove(ewl->list + i, ewl->list + i + 1, n * sizeof(EObj *));
232         ewl->list[j] = eo;
233         if (ewl->layered && eo->stacked > 0)
234            DeskSetDirtyStack(eo->desk, eo);
235      }
236    else if (n < 0)
237      {
238         memmove(ewl->list + j + 1, ewl->list + j, -n * sizeof(EObj *));
239         ewl->list[j] = eo;
240         if (ewl->layered && eo->stacked > 0)
241            DeskSetDirtyStack(eo->desk, eo);
242      }
243
244    EobjListShow("EobjListRaise", ewl);
245    return n;
246 }
247
248 static EObj        *
249 EobjListFind(const EobjList * ewl, Window win)
250 {
251    int                 i;
252
253    for (i = 0; i < ewl->nwins; i++)
254       if (EobjGetXwin(ewl->list[i]) == win)
255          return ewl->list[i];
256
257    return NULL;
258 }
259
260 static int
261 EobjListTypeCount(const EobjList * ewl, int type)
262 {
263    int                 i, n;
264
265    for (i = n = 0; i < ewl->nwins; i++)
266       if (ewl->list[i]->type == type)
267          n++;
268
269    return n;
270 }
271
272 /*
273  * The global object/client lists
274  */
275 static EobjList     EwinListStack = { "Stack", 0, 0, NULL, 1, 0 };
276 static EobjList     EwinListFocus = { "Focus", 0, 0, NULL, 0, 1 };
277 static EobjList     EwinListOrder = { "Order", 0, 0, NULL, 0, 2 };
278
279 static EObj        *const *
280 EobjListGet(EobjList * ewl, int *num)
281 {
282    *num = ewl->nwins;
283    return ewl->list;
284 }
285
286 int
287 EobjListStackCheck(EObj * eo)
288 {
289    return EobjListGetIndex(&EwinListStack, eo);
290 }
291
292 EObj               *
293 EobjListStackFind(Window win)
294 {
295    return EobjListFind(&EwinListStack, win);
296 }
297
298 EObj               *const *
299 EobjListStackGet(int *num)
300 {
301    return EobjListGet(&EwinListStack, num);
302 }
303
304 void
305 EobjListStackAdd(EObj * eo, int ontop)
306 {
307    EobjListAdd(&EwinListStack, eo, ontop);
308 }
309
310 void
311 EobjListStackDel(EObj * eo)
312 {
313    EobjListDel(&EwinListStack, eo);
314 }
315
316 int
317 EobjListStackRaise(EObj * eo, int test)
318 {
319    return EobjListRaise(&EwinListStack, eo, test);
320 }
321
322 int
323 EobjListStackLower(EObj * eo, int test)
324 {
325    return EobjListLower(&EwinListStack, eo, test);
326 }
327
328 void
329 EobjListFocusAdd(EObj * eo, int ontop)
330 {
331    EobjListAdd(&EwinListFocus, eo, ontop);
332 }
333
334 void
335 EobjListFocusDel(EObj * eo)
336 {
337    EobjListDel(&EwinListFocus, eo);
338 }
339
340 int
341 EobjListFocusRaise(EObj * eo)
342 {
343    return EobjListRaise(&EwinListFocus, eo, 0);
344 }
345
346 EWin               *const *
347 EwinListStackGet(int *num)
348 {
349    static EWin       **lst = NULL;
350    static int          nalloc = 0;
351    const EobjList     *ewl;
352    int                 i, j, newins;
353    EObj               *eo;
354
355    ewl = &EwinListStack;
356    newins = EobjListTypeCount(ewl, EOBJ_TYPE_EWIN);
357    if (nalloc < newins)
358      {
359         nalloc = (newins + 16) & ~0xf;  /* 16 at the time */
360         lst = EREALLOC(EWin *, lst, nalloc);
361      }
362
363    for (i = j = 0; i < ewl->nwins; i++)
364      {
365         eo = ewl->list[i];
366         if (eo->type != EOBJ_TYPE_EWIN)
367            continue;
368
369         lst[j++] = (EWin *) eo;
370      }
371
372    *num = j;
373    return lst;
374 }
375
376 EWin               *const *
377 EwinListFocusGet(int *num)
378 {
379    return (EWin * const *)EobjListGet(&EwinListFocus, num);
380 }
381
382 EWin               *const *
383 EwinListGetForDesk(int *num, Desk * dsk)
384 {
385    static EWin       **lst = NULL;
386    static int          nalloc = 0;
387    const EobjList     *ewl;
388    int                 i, j, newins;
389    EObj               *eo;
390
391    ewl = &EwinListStack;
392    newins = EobjListTypeCount(ewl, EOBJ_TYPE_EWIN);
393    /* Too many - who cares. */
394    if (nalloc < newins)
395      {
396         nalloc = (newins + 16) & ~0xf;  /* 16 at the time */
397         lst = EREALLOC(EWin *, lst, nalloc);
398      }
399
400    for (i = j = 0; i < ewl->nwins; i++)
401      {
402         eo = ewl->list[i];
403         if (eo->type != EOBJ_TYPE_EWIN || eo->desk != dsk)
404            continue;
405
406         lst[j++] = (EWin *) eo;
407      }
408
409    *num = j;
410    return lst;
411 }
412
413 EObj               *const *
414 EobjListStackGetForDesk(int *num, Desk * dsk)
415 {
416    static EObj       **lst = NULL;
417    static int          nalloc = 0;
418    const EobjList     *ewl;
419    int                 i, j;
420    EObj               *eo;
421
422    ewl = &EwinListStack;
423
424    /* Too many - who cares. */
425    if (nalloc < ewl->nwins)
426      {
427         nalloc = (ewl->nwins + 16) & ~0xf;      /* 16 at the time */
428         lst = EREALLOC(EObj *, lst, nalloc);
429      }
430
431    for (i = j = 0; i < ewl->nwins; i++)
432      {
433         eo = ewl->list[i];
434         if (eo->desk != dsk)
435            continue;
436
437         lst[j++] = eo;
438      }
439
440    *num = j;
441    return lst;
442 }
443
444 #if 0                           /* Unused */
445 EWin               *
446 EwinListStackGetTop(void)
447 {
448    const EobjList     *ewl;
449    int                 i;
450    EObj               *eo;
451
452    ewl = &EwinListStack;
453
454    for (i = 0; i < ewl->nwins; i++)
455      {
456         eo = ewl->list[i];
457         if (eo->type == EOBJ_TYPE_EWIN)
458            return (EWin *) eo;
459      }
460
461    return NULL;
462 }
463 #endif
464
465 int
466 EwinListStackIsRaised(const EWin * ewin)
467 {
468    const EobjList     *ewl;
469    int                 i;
470    const EObj         *eo, *eox;
471
472    ewl = &EwinListStack;
473    eox = EoObj(ewin);
474
475    for (i = 0; i < ewl->nwins; i++)
476      {
477         eo = ewl->list[i];
478         if (eo->type != EOBJ_TYPE_EWIN)
479            continue;
480         if (eo->desk != eox->desk)
481            continue;
482         if (eo->ilayer > eox->ilayer)
483            continue;
484         if (EwinGetTransientFor((EWin *) eo) == EwinGetClientXwin(ewin))
485            continue;
486         return eo == eox;
487      }
488
489    return 1;                    /* It should be impossible to get here */
490 }
491
492 void
493 EobjListOrderAdd(EObj * eo)
494 {
495    EobjListAdd(&EwinListOrder, eo, 0);
496 }
497
498 void
499 EobjListOrderDel(EObj * eo)
500 {
501    EobjListDel(&EwinListOrder, eo);
502 }
503
504 EWin               *const *
505 EwinListOrderGet(int *num)
506 {
507    return (EWin * const *)EobjListGet(&EwinListOrder, num);
508 }