523 lines
11 KiB
C
523 lines
11 KiB
C
/*
|
|
* Copyright (C) 2004-2022 Kim Woelders
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
* and software packages that this Software was used.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include "E.h"
|
|
#include "desktops.h"
|
|
#include "eobj.h"
|
|
#include "ewins.h"
|
|
|
|
#define ENABLE_DEBUG_STACKING 1
|
|
|
|
#define EobjGetCwin(p) \
|
|
((p->type == EOBJ_TYPE_EWIN) ? EwinGetClientXwin(((EWin*)(p))) : NoXID)
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
struct {
|
|
int nalloc;
|
|
int nobjs;
|
|
EObj **list;
|
|
} o;
|
|
struct {
|
|
int nalloc;
|
|
int nwins;
|
|
EWin **list;
|
|
} e;
|
|
char layered;
|
|
char changed; /* Used by _EwinListGet() */
|
|
} EobjList;
|
|
|
|
static int EobjListRaise(EobjList * eol, EObj * eo, int test);
|
|
static int EobjListLower(EobjList * eol, EObj * eo, int test);
|
|
|
|
#if ENABLE_DEBUG_STACKING
|
|
static void
|
|
EobjListShow(const char *txt, EobjList * eol)
|
|
{
|
|
int i;
|
|
EObj *eo;
|
|
|
|
if (EDebug(EDBUG_TYPE_STACKING) < 2)
|
|
return;
|
|
|
|
Eprintf("%s-%s:\n", eol->name, txt);
|
|
for (i = 0; i < eol->o.nobjs; i++)
|
|
{
|
|
eo = eol->o.list[i];
|
|
Eprintf(" %2d: %#10x %#10x %d %d %s\n", i, EobjGetXwin(eo),
|
|
EobjGetCwin(eo), eo->desk->num, eo->ilayer, EobjGetName(eo));
|
|
}
|
|
}
|
|
#else
|
|
#define EobjListShow(txt, eol)
|
|
#endif
|
|
|
|
static int
|
|
EobjListGetIndex(EobjList * eol, EObj * eo)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < eol->o.nobjs; i++)
|
|
if (eol->o.list[i] == eo)
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
EobjListAdd(EobjList * eol, EObj * eo, int ontop)
|
|
{
|
|
int i;
|
|
|
|
/* Quit if already in list */
|
|
i = EobjListGetIndex(eol, eo);
|
|
if (i >= 0)
|
|
return;
|
|
|
|
if (eol->o.nobjs >= eol->o.nalloc)
|
|
{
|
|
eol->o.nalloc += 16;
|
|
eol->o.list = EREALLOC(EObj *, eol->o.list, eol->o.nalloc);
|
|
}
|
|
|
|
if (eol->layered)
|
|
{
|
|
/* The simple way for now (add, raise/lower) */
|
|
if (ontop)
|
|
{
|
|
eol->o.list[eol->o.nobjs] = eo;
|
|
eol->o.nobjs++;
|
|
EobjListRaise(eol, eo, 0);
|
|
}
|
|
else
|
|
{
|
|
memmove(eol->o.list + 1, eol->o.list,
|
|
eol->o.nobjs * sizeof(EObj *));
|
|
eol->o.list[0] = eo;
|
|
eol->o.nobjs++;
|
|
EobjListLower(eol, eo, 0);
|
|
}
|
|
if (eo->stacked == 0)
|
|
DeskSetDirtyStack(eo->desk, eo);
|
|
}
|
|
else
|
|
{
|
|
if (ontop)
|
|
{
|
|
memmove(eol->o.list + 1, eol->o.list,
|
|
eol->o.nobjs * sizeof(EObj *));
|
|
eol->o.list[0] = eo;
|
|
}
|
|
else
|
|
{
|
|
eol->o.list[eol->o.nobjs] = eo;
|
|
}
|
|
eol->o.nobjs++;
|
|
}
|
|
|
|
eol->changed = 1;
|
|
|
|
EobjListShow("EobjListAdd", eol);
|
|
}
|
|
|
|
static void
|
|
EobjListDel(EobjList * eol, EObj * eo)
|
|
{
|
|
int i, n;
|
|
|
|
/* Quit if not in list */
|
|
i = EobjListGetIndex(eol, eo);
|
|
if (i < 0)
|
|
return;
|
|
|
|
eol->o.nobjs--;
|
|
n = eol->o.nobjs - i;
|
|
if (n > 0)
|
|
{
|
|
memmove(eol->o.list + i, eol->o.list + i + 1, n * sizeof(EObj *));
|
|
}
|
|
else if (eol->o.nobjs <= 0)
|
|
{
|
|
/* Enables autocleanup at shutdown, if ever implemented */
|
|
EFREE_NULL(eol->o.list);
|
|
eol->o.nalloc = 0;
|
|
}
|
|
|
|
eol->changed = 1;
|
|
|
|
EobjListShow("EobjListDel", eol);
|
|
}
|
|
|
|
static int
|
|
EobjListLower(EobjList * eol, EObj * eo, int test)
|
|
{
|
|
int i, j, n;
|
|
|
|
/* Quit if not in list */
|
|
i = EobjListGetIndex(eol, eo);
|
|
if (i < 0)
|
|
return 0;
|
|
|
|
j = eol->o.nobjs - 1;
|
|
if (eol->layered)
|
|
{
|
|
/* Take the layer into account */
|
|
for (; j >= 0; j--)
|
|
if (i != j && eo->ilayer <= eol->o.list[j]->ilayer)
|
|
break;
|
|
if (j < i)
|
|
j++;
|
|
}
|
|
|
|
n = j - i;
|
|
if (test)
|
|
return n;
|
|
|
|
if (n > 0)
|
|
{
|
|
memmove(eol->o.list + i, eol->o.list + i + 1, n * sizeof(EObj *));
|
|
eol->o.list[j] = eo;
|
|
if (eol->layered && eo->stacked > 0)
|
|
DeskSetDirtyStack(eo->desk, eo);
|
|
eol->changed = 1;
|
|
}
|
|
else if (n < 0)
|
|
{
|
|
memmove(eol->o.list + j + 1, eol->o.list + j, -n * sizeof(EObj *));
|
|
eol->o.list[j] = eo;
|
|
if (eol->layered && eo->stacked > 0)
|
|
DeskSetDirtyStack(eo->desk, eo);
|
|
eol->changed = 1;
|
|
}
|
|
|
|
EobjListShow("EobjListLower", eol);
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
EobjListRaise(EobjList * eol, EObj * eo, int test)
|
|
{
|
|
int i, j, n;
|
|
|
|
/* Quit if not in list */
|
|
i = EobjListGetIndex(eol, eo);
|
|
if (i < 0)
|
|
return 0;
|
|
|
|
j = 0;
|
|
if (eol->layered)
|
|
{
|
|
/* Take the layer into account */
|
|
for (; j < eol->o.nobjs; j++)
|
|
if (j != i && eo->ilayer >= eol->o.list[j]->ilayer)
|
|
break;
|
|
if (j > i)
|
|
j--;
|
|
}
|
|
|
|
n = j - i;
|
|
if (test)
|
|
return n;
|
|
|
|
if (n > 0)
|
|
{
|
|
memmove(eol->o.list + i, eol->o.list + i + 1, n * sizeof(EObj *));
|
|
eol->o.list[j] = eo;
|
|
if (eol->layered && eo->stacked > 0)
|
|
DeskSetDirtyStack(eo->desk, eo);
|
|
eol->changed = 1;
|
|
}
|
|
else if (n < 0)
|
|
{
|
|
memmove(eol->o.list + j + 1, eol->o.list + j, -n * sizeof(EObj *));
|
|
eol->o.list[j] = eo;
|
|
if (eol->layered && eo->stacked > 0)
|
|
DeskSetDirtyStack(eo->desk, eo);
|
|
eol->changed = 1;
|
|
}
|
|
|
|
EobjListShow("EobjListRaise", eol);
|
|
return n;
|
|
}
|
|
|
|
static EObj *
|
|
EobjListFind(const EobjList * eol, EX_Window win)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < eol->o.nobjs; i++)
|
|
if (EobjGetXwin(eol->o.list[i]) == win)
|
|
return eol->o.list[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if 0
|
|
static int
|
|
EobjListTypeCount(const EobjList * eol, int type)
|
|
{
|
|
int i, n;
|
|
|
|
for (i = n = 0; i < eol->o.nobjs; i++)
|
|
if (eol->o.list[i]->type == type)
|
|
n++;
|
|
|
|
return n;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* The global object/client lists
|
|
*/
|
|
#define EOBJ_LIST(_name, _layered) \
|
|
{ .name = _name, .layered = _layered }
|
|
|
|
static EobjList EobjListStack = EOBJ_LIST("Stack", 1);
|
|
static EobjList EwinListFocus = EOBJ_LIST("Focus", 0);
|
|
static EobjList EobjListOrder = EOBJ_LIST("Order", 0);
|
|
|
|
static EObj *const *
|
|
EobjListGet(EobjList * eol, int *num)
|
|
{
|
|
*num = eol->o.nobjs;
|
|
return eol->o.list;
|
|
}
|
|
|
|
int
|
|
EobjListStackCheck(EObj * eo)
|
|
{
|
|
return EobjListGetIndex(&EobjListStack, eo);
|
|
}
|
|
|
|
EObj *
|
|
EobjListStackFind(EX_Window win)
|
|
{
|
|
return EobjListFind(&EobjListStack, win);
|
|
}
|
|
|
|
EObj *const *
|
|
EobjListStackGet(int *num)
|
|
{
|
|
return EobjListGet(&EobjListStack, num);
|
|
}
|
|
|
|
void
|
|
EobjListStackAdd(EObj * eo, int ontop)
|
|
{
|
|
EobjListAdd(&EobjListStack, eo, ontop);
|
|
}
|
|
|
|
void
|
|
EobjListStackDel(EObj * eo)
|
|
{
|
|
EobjListDel(&EobjListStack, eo);
|
|
}
|
|
|
|
int
|
|
EobjListStackRaise(EObj * eo, int test)
|
|
{
|
|
return EobjListRaise(&EobjListStack, eo, test);
|
|
}
|
|
|
|
int
|
|
EobjListStackLower(EObj * eo, int test)
|
|
{
|
|
return EobjListLower(&EobjListStack, eo, test);
|
|
}
|
|
|
|
void
|
|
EobjListFocusAdd(EObj * eo, int ontop)
|
|
{
|
|
EobjListAdd(&EwinListFocus, eo, ontop);
|
|
}
|
|
|
|
void
|
|
EobjListFocusDel(EObj * eo)
|
|
{
|
|
EobjListDel(&EwinListFocus, eo);
|
|
}
|
|
|
|
int
|
|
EobjListFocusRaise(EObj * eo)
|
|
{
|
|
return EobjListRaise(&EwinListFocus, eo, 0);
|
|
}
|
|
|
|
static EWin *const *
|
|
_EwinListGet(EobjList * eol, int *pnum)
|
|
{
|
|
int i, j;
|
|
EObj *eo;
|
|
|
|
if (EDebug(EDBUG_TYPE_STACKING))
|
|
Eprintf("%s: %s changed=%d\n", __func__, eol->name, eol->changed);
|
|
|
|
if (!eol->changed)
|
|
goto done;
|
|
|
|
for (i = j = 0; i < eol->o.nobjs; i++)
|
|
{
|
|
eo = eol->o.list[i];
|
|
if (eo->type != EOBJ_TYPE_EWIN)
|
|
continue;
|
|
|
|
if (eol->e.nalloc <= j)
|
|
{
|
|
eol->e.nalloc += 16; /* 16 at the time */
|
|
eol->e.list = EREALLOC(EWin *, eol->e.list, eol->e.nalloc);
|
|
}
|
|
|
|
eol->e.list[j++] = (EWin *) eo;
|
|
}
|
|
|
|
eol->e.nwins = j;
|
|
eol->changed = 0;
|
|
|
|
done:
|
|
*pnum = eol->e.nwins;
|
|
return eol->e.list;
|
|
}
|
|
|
|
EWin *const *
|
|
EwinListStackGet(int *num)
|
|
{
|
|
return _EwinListGet(&EobjListStack, num);
|
|
}
|
|
|
|
EWin *const *
|
|
EwinListFocusGet(int *num)
|
|
{
|
|
return (EWin * const *)EobjListGet(&EwinListFocus, num);
|
|
}
|
|
|
|
EWin *const *
|
|
EwinListGetForDesk(int *num, Desk * dsk)
|
|
{
|
|
static EWin **lst = NULL;
|
|
static int nalloc = 0;
|
|
const EobjList *eol;
|
|
int i, j;
|
|
EObj *eo;
|
|
|
|
eol = &EobjListStack;
|
|
|
|
for (i = j = 0; i < eol->o.nobjs; i++)
|
|
{
|
|
eo = eol->o.list[i];
|
|
if (eo->type != EOBJ_TYPE_EWIN || eo->desk != dsk)
|
|
continue;
|
|
|
|
if (nalloc <= j)
|
|
{
|
|
nalloc += 16; /* 16 at the time */
|
|
lst = EREALLOC(EWin *, lst, nalloc);
|
|
}
|
|
|
|
lst[j++] = (EWin *) eo;
|
|
}
|
|
|
|
*num = j;
|
|
return lst;
|
|
}
|
|
|
|
EObj *const *
|
|
EobjListStackGetForDesk(int *num, Desk * dsk)
|
|
{
|
|
static EObj **lst = NULL;
|
|
static int nalloc = 0;
|
|
const EobjList *eol;
|
|
int i, j;
|
|
EObj *eo;
|
|
|
|
eol = &EobjListStack;
|
|
|
|
/* Too many - who cares. */
|
|
if (nalloc < eol->o.nobjs)
|
|
{
|
|
nalloc = (eol->o.nobjs + 16) & ~0xf; /* 16 at the time */
|
|
lst = EREALLOC(EObj *, lst, nalloc);
|
|
}
|
|
|
|
for (i = j = 0; i < eol->o.nobjs; i++)
|
|
{
|
|
eo = eol->o.list[i];
|
|
if (eo->desk != dsk)
|
|
continue;
|
|
|
|
lst[j++] = eo;
|
|
}
|
|
|
|
*num = j;
|
|
return lst;
|
|
}
|
|
|
|
int
|
|
EwinListStackIsRaised(const EWin * ewin)
|
|
{
|
|
const EobjList *eol;
|
|
int i;
|
|
const EObj *eo, *eox;
|
|
|
|
eol = &EobjListStack;
|
|
eox = EoObj(ewin);
|
|
|
|
for (i = 0; i < eol->o.nobjs; i++)
|
|
{
|
|
eo = eol->o.list[i];
|
|
if (eo->type != EOBJ_TYPE_EWIN)
|
|
continue;
|
|
if (eo->desk != eox->desk)
|
|
continue;
|
|
if (eo->ilayer > eox->ilayer)
|
|
continue;
|
|
if (EwinGetTransientFor((EWin *) eo) == EwinGetClientXwin(ewin))
|
|
continue;
|
|
return eo == eox;
|
|
}
|
|
|
|
return 1; /* It should be impossible to get here */
|
|
}
|
|
|
|
void
|
|
EobjListOrderAdd(EObj * eo)
|
|
{
|
|
EobjListAdd(&EobjListOrder, eo, 0);
|
|
}
|
|
|
|
void
|
|
EobjListOrderDel(EObj * eo)
|
|
{
|
|
EobjListDel(&EobjListOrder, eo);
|
|
}
|
|
|
|
EObj *const *
|
|
EobjListOrderGet(int *num)
|
|
{
|
|
return EobjListGet(&EobjListOrder, num);
|
|
}
|
|
|
|
EWin *const *
|
|
EwinListOrderGet(int *num)
|
|
{
|
|
return _EwinListGet(&EobjListOrder, num);
|
|
}
|