698 lines
14 KiB
C
698 lines
14 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 "config.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include "E.h"
|
|
#include "animation.h"
|
|
#include "desktops.h"
|
|
#include "ecompmgr.h"
|
|
#include "eobj.h"
|
|
#include "ewins.h" /* FIXME - Should not be here */
|
|
#include "hints.h"
|
|
#include "xprop.h"
|
|
#include "xwin.h"
|
|
|
|
int
|
|
OpacityFix(int op, int op_0)
|
|
{
|
|
if (op <= 0)
|
|
op = op_0;
|
|
else if (op > 255)
|
|
op = 100;
|
|
else if (op > 100) /* Hack to convert old 0-255 range */
|
|
op = (100 * op) / 255;
|
|
return op;
|
|
}
|
|
|
|
unsigned int
|
|
OpacityFromPercent(int opx)
|
|
{
|
|
unsigned int op = (unsigned int)opx;
|
|
|
|
/* op is 0-100, extend to 32 bit */
|
|
/* op <= 0 and op > 100 is mapped to 100 (opaque) */
|
|
if (op >= 100)
|
|
return 0xffffffff;
|
|
return op * 42949672;
|
|
}
|
|
|
|
int
|
|
OpacityToPercent(unsigned int opacity)
|
|
{
|
|
return (int)(opacity / 42949672);
|
|
}
|
|
|
|
const char *
|
|
EobjGetNameSafe(const EObj *eo)
|
|
{
|
|
const char *name = NULL;
|
|
|
|
if (!eo)
|
|
goto done;
|
|
|
|
name = EobjGetName(eo);
|
|
|
|
done:
|
|
return name ? name : "None";
|
|
}
|
|
|
|
void
|
|
EobjSetName(EObj *eo, const char *name)
|
|
{
|
|
if (name != eo->icccm.wm_name)
|
|
EFREE_DUP(eo->icccm.wm_name, name);
|
|
|
|
HintsSetWindowName(EobjGetWin(eo), eo->icccm.wm_name);
|
|
}
|
|
|
|
void
|
|
EobjSetLayer(EObj *eo, int layer)
|
|
{
|
|
int ilayer = eo->ilayer;
|
|
|
|
eo->layer = layer;
|
|
/*
|
|
* For usual EWin's the internal layer is the "old" E-layer * 10.
|
|
*
|
|
* Internal layers:
|
|
* 0: Root
|
|
* 3: Desktop type apps
|
|
* 5: Below buttons
|
|
* 10: Lowest ewins
|
|
* 15: Normal buttons
|
|
* 20: Normal below ewins
|
|
* 40: Normal ewins
|
|
* 60: Above ewins
|
|
* 75: Above buttons
|
|
* 80: Ontop ewins
|
|
* 100: E-Dialogs
|
|
* 512-: Floating windows
|
|
* + 0: Virtual desktops
|
|
* +30: E-Menus
|
|
* +40: Override redirects
|
|
* +40: E-Tooltips
|
|
*/
|
|
|
|
switch (eo->type)
|
|
{
|
|
case EOBJ_TYPE_EWIN:
|
|
eo->ilayer = 10 * eo->layer;
|
|
if (eo->ilayer == 0)
|
|
eo->ilayer = 3;
|
|
break;
|
|
|
|
case EOBJ_TYPE_BUTTON:
|
|
if (eo->layer > 0)
|
|
eo->ilayer = 75; /* Ontop */
|
|
else if (eo->layer == 0)
|
|
eo->ilayer = 15; /* Normal */
|
|
else if (eo->layer < 0)
|
|
eo->ilayer = 5; /* Below */
|
|
if (eo->layer > 0 && eo->sticky)
|
|
eo->floating = 1;
|
|
break;
|
|
|
|
default:
|
|
eo->ilayer = 10 * eo->layer;
|
|
break;
|
|
}
|
|
|
|
if (eo->floating)
|
|
eo->ilayer |= 512;
|
|
else
|
|
eo->ilayer &= ~512;
|
|
if (eo->ghost)
|
|
eo->ilayer |= 1024;
|
|
|
|
if (eo->ilayer != ilayer)
|
|
EobjRaise(eo);
|
|
}
|
|
|
|
void
|
|
EobjSetFloating(EObj *eo, int floating)
|
|
{
|
|
if (floating == eo->floating)
|
|
return;
|
|
|
|
#if 0
|
|
switch (eo->type)
|
|
{
|
|
default:
|
|
break;
|
|
case EOBJ_TYPE_EWIN:
|
|
if (floating > 1)
|
|
eo->desk = 0;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
eo->floating = floating;
|
|
EobjSetLayer(eo, eo->layer);
|
|
}
|
|
|
|
bool
|
|
EobjShadowOk(const EObj *eo, bool sharp)
|
|
{
|
|
if (!eo->shadow)
|
|
return false; /* Disabled by configuration */
|
|
|
|
switch (eo->type)
|
|
{
|
|
default:
|
|
if (sharp)
|
|
return true; /* Enabled if sharp */
|
|
if (eo->shaped)
|
|
return false; /* Disabled if shaped */
|
|
break;
|
|
case EOBJ_TYPE_EWIN:
|
|
if (((EWin *) eo)->state.fullscreen)
|
|
return false; /* Disabled if fullscreen */
|
|
if (sharp)
|
|
return true; /* Enabled if sharp */
|
|
if (((EWin *) eo)->state.shaped)
|
|
return false; /* Disabled if client is shaped */
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if USE_GLX
|
|
#define WINTYPE(t) ((t == EOBJ_TYPE_GLX) ? WIN_TYPE_GLX : WIN_TYPE_INTERNAL)
|
|
#else
|
|
#define WINTYPE(t) WIN_TYPE_INTERNAL
|
|
#endif
|
|
|
|
void
|
|
EobjInit(EObj *eo, int type, Win win, int x, int y, int w, int h,
|
|
int su, const char *name)
|
|
{
|
|
if (!eo->desk)
|
|
eo->desk = DeskGet(0);
|
|
|
|
if (!win)
|
|
{
|
|
if (type == EOBJ_TYPE_EVENT)
|
|
{
|
|
win = ECreateEventWindow(VROOT, x, y, w, h);
|
|
eo->inputonly = 1;
|
|
}
|
|
else
|
|
{
|
|
win = ECreateObjectWindow(EoGetWin(eo->desk), x, y, w, h, su,
|
|
WINTYPE(type), NULL);
|
|
}
|
|
}
|
|
eo->type = type;
|
|
eo->win = win;
|
|
eo->shaped = -1;
|
|
if (!win)
|
|
return;
|
|
|
|
if (type == EOBJ_TYPE_EXT)
|
|
{
|
|
eo->icccm.wm_name = ex_icccm_title_get(WinGetXwin(win));
|
|
ex_icccm_name_class_get(WinGetXwin(win),
|
|
&eo->icccm.wm_res_name,
|
|
&eo->icccm.wm_res_class);
|
|
}
|
|
else if (name)
|
|
eo->icccm.wm_name = Estrdup(name);
|
|
if (!eo->icccm.wm_name)
|
|
eo->icccm.wm_name = Estrdup("-?-");
|
|
|
|
if (type != EOBJ_TYPE_EWIN && type != EOBJ_TYPE_EXT)
|
|
HintsSetWindowName(EobjGetWin(eo), eo->icccm.wm_name);
|
|
|
|
#if USE_COMPOSITE
|
|
switch (type)
|
|
{
|
|
case EOBJ_TYPE_EVENT:
|
|
case EOBJ_TYPE_MISC_NR:
|
|
case EOBJ_TYPE_ROOT_BG:
|
|
eo->noredir = 1;
|
|
break;
|
|
}
|
|
ECompMgrWinNew(eo);
|
|
#endif
|
|
if (EobjGetXwin(eo) != WinGetXwin(VROOT))
|
|
{
|
|
EobjListOrderAdd(eo);
|
|
EobjListStackAdd(eo, 1);
|
|
}
|
|
|
|
if (EDebug(EDBUG_TYPE_EWINS))
|
|
Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
|
|
}
|
|
|
|
void
|
|
EobjFini(EObj *eo)
|
|
{
|
|
if (EDebug(EDBUG_TYPE_EWINS))
|
|
Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
|
|
|
|
EobjListStackDel(eo);
|
|
EobjListOrderDel(eo);
|
|
|
|
#if USE_COMPOSITE
|
|
if (!eo->external)
|
|
eo->gone = 1; /* Actually not yet (but soon) */
|
|
|
|
if (eo->cmhook)
|
|
ECompMgrWinDel(eo);
|
|
#endif
|
|
|
|
if (eo->external)
|
|
EUnregisterWindow(EobjGetWin(eo));
|
|
else
|
|
EDestroyWindow(EobjGetWin(eo));
|
|
|
|
Efree(eo->icccm.wm_name);
|
|
Efree(eo->icccm.wm_res_name);
|
|
Efree(eo->icccm.wm_res_class);
|
|
AnimatorsFree(eo);
|
|
}
|
|
|
|
void
|
|
EobjDestroy(EObj *eo)
|
|
{
|
|
if (EDebug(EDBUG_TYPE_EWINS))
|
|
Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
|
|
|
|
EobjFini(eo);
|
|
|
|
Efree(eo);
|
|
}
|
|
|
|
EObj *
|
|
EobjWindowCreate(int type, int x, int y, int w, int h, int su, const char *name)
|
|
{
|
|
EObj *eo;
|
|
|
|
eo = ECALLOC(EObj, 1);
|
|
|
|
eo->floating = 1;
|
|
EobjSetLayer(eo, 20);
|
|
EobjInit(eo, type, EobjGetWin(eo), x, y, w, h, su, name);
|
|
if (!eo->win)
|
|
{
|
|
EFREE_NULL(eo);
|
|
}
|
|
|
|
return eo;
|
|
}
|
|
|
|
void
|
|
EobjWindowDestroy(EObj *eo)
|
|
{
|
|
#if USE_COMPOSITE
|
|
if (eo->shown && !eo->inputonly)
|
|
EobjUnmap(eo);
|
|
#endif
|
|
EobjDestroy(eo);
|
|
}
|
|
|
|
EObj *
|
|
EobjRegisterOR(EX_Window xwin __UNUSED__, XWindowAttributes *pxwa __UNUSED__,
|
|
int mapped __UNUSED__)
|
|
{
|
|
EObj *eo = NULL;
|
|
|
|
#if USE_COMPOSITE
|
|
XWindowAttributes attr;
|
|
Win win;
|
|
|
|
if (!ECompMgrIsActive())
|
|
return NULL;
|
|
|
|
eo = EobjListStackFind(xwin);
|
|
if (eo)
|
|
{
|
|
if (eo->external)
|
|
goto done;
|
|
else
|
|
return eo;
|
|
}
|
|
|
|
if (!pxwa)
|
|
{
|
|
pxwa = &attr;
|
|
if (!EXGetWindowAttributes(xwin, &attr))
|
|
return NULL;
|
|
}
|
|
if (!pxwa->override_redirect)
|
|
return NULL;
|
|
#ifndef __cplusplus
|
|
#define c_class class
|
|
#endif
|
|
if (pxwa->c_class != InputOutput)
|
|
return NULL;
|
|
|
|
win = ERegisterWindow(xwin, pxwa);
|
|
if (!win)
|
|
return NULL;
|
|
|
|
eo = ECALLOC(EObj, 1);
|
|
if (!eo)
|
|
return eo;
|
|
|
|
eo->external = 1;
|
|
eo->fade = 1;
|
|
eo->shadow = 1;
|
|
|
|
EobjInit(eo, EOBJ_TYPE_EXT, win,
|
|
pxwa->x, pxwa->y, pxwa->width, pxwa->height, 0, NULL);
|
|
|
|
if (win->argb)
|
|
eo->shadow = 0;
|
|
EobjSetFloating(eo, 1);
|
|
EobjSetLayer(eo, 4);
|
|
|
|
done:
|
|
if (mapped)
|
|
{
|
|
eo->shown = 1;
|
|
EobjListStackRaise(eo, 0);
|
|
ECompMgrWinMap(eo);
|
|
}
|
|
|
|
#if 0
|
|
Eprintf("%s: %#x depth=%d argb=%d %s\n", __func__,
|
|
EobjGetXwin(eo), win->depth, win->argb, EobjGetName(eo));
|
|
#endif
|
|
|
|
#endif /* USE_COMPOSITE */
|
|
|
|
return eo;
|
|
}
|
|
|
|
void
|
|
EobjUnregister(EObj *eo)
|
|
{
|
|
#if 0
|
|
Eprintf("%s: %#x type=%d: %s\n", __func__, EobjGetXwin(eo), eo->type,
|
|
EobjGetName(eo));
|
|
#endif
|
|
EobjDestroy(eo);
|
|
}
|
|
|
|
void
|
|
EobjMap(EObj *eo, int raise)
|
|
{
|
|
if (eo->shown)
|
|
return;
|
|
eo->shown = 1;
|
|
|
|
if (raise)
|
|
EobjListStackRaise(eo, 0);
|
|
|
|
if (eo->stacked <= 0 || raise > 1)
|
|
DeskRestack(eo->desk);
|
|
|
|
if (eo->shaped < 0)
|
|
EobjShapeUpdate(eo, 0);
|
|
|
|
EMapWindow(EobjGetWin(eo));
|
|
#if USE_COMPOSITE
|
|
ECompMgrWinMap(eo);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
EobjUnmap(EObj *eo)
|
|
{
|
|
if (!eo->shown)
|
|
return;
|
|
|
|
#if USE_COMPOSITE
|
|
if (eo->cmhook)
|
|
ECompMgrWinUnmap(eo);
|
|
#endif
|
|
EUnmapWindow(EobjGetWin(eo));
|
|
eo->shown = 0;
|
|
}
|
|
|
|
void
|
|
EobjMoveResize(EObj *eo, int x, int y, int w, int h)
|
|
{
|
|
#if USE_COMPOSITE
|
|
int move, resize;
|
|
|
|
move = x != EobjGetX(eo) || y != EobjGetY(eo);
|
|
resize = w != EobjGetW(eo) || h != EobjGetH(eo);
|
|
#endif
|
|
|
|
EMoveResizeWindow(EobjGetWin(eo), x, y, w, h);
|
|
|
|
#if USE_COMPOSITE
|
|
if (eo->cmhook)
|
|
ECompMgrWinMoveResize(eo, move, resize, 0);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
EobjMove(EObj *eo, int x, int y)
|
|
{
|
|
EobjMoveResize(eo, x, y, EobjGetW(eo), EobjGetH(eo));
|
|
}
|
|
|
|
void
|
|
EobjResize(EObj *eo, int w, int h)
|
|
{
|
|
EobjMoveResize(eo, EobjGetX(eo), EobjGetY(eo), w, h);
|
|
}
|
|
|
|
#if USE_COMPOSITE
|
|
void
|
|
EobjDamage(EObj *eo)
|
|
{
|
|
if (eo->cmhook)
|
|
ECompMgrWinDamageArea(eo, 0, 0, 0, 0);
|
|
}
|
|
#else
|
|
void
|
|
EobjDamage(EObj *eo __UNUSED__)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void
|
|
EobjReparent(EObj *eo, EObj *dst, int x, int y)
|
|
{
|
|
#if USE_COMPOSITE
|
|
int move;
|
|
|
|
move = x != EobjGetX(eo) || y != EobjGetY(eo);
|
|
#endif
|
|
|
|
EReparentWindow(EobjGetWin(eo), EobjGetWin(dst), x, y);
|
|
if (dst->type == EOBJ_TYPE_DESK)
|
|
{
|
|
Desk *dsk = (Desk *) dst;
|
|
|
|
if (eo->stacked < 0)
|
|
{
|
|
eo->desk = NULL;
|
|
eo->stacked = 0;
|
|
}
|
|
if (eo->desk != dsk)
|
|
DeskSetDirtyStack(dsk, eo);
|
|
#if USE_COMPOSITE
|
|
if (eo->cmhook)
|
|
ECompMgrWinReparent(eo, dsk, move);
|
|
#endif
|
|
eo->desk = dsk;
|
|
}
|
|
else
|
|
{
|
|
EobjListStackDel(eo);
|
|
#if USE_COMPOSITE
|
|
if (eo->cmhook)
|
|
ECompMgrWinDel(eo);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int
|
|
EobjRaise(EObj *eo)
|
|
{
|
|
#if USE_COMPOSITE
|
|
int num;
|
|
|
|
num = EobjListStackRaise(eo, 1);
|
|
if (num == 0)
|
|
return num;
|
|
|
|
if (num < 0)
|
|
num = EobjListStackRaise(eo, 0);
|
|
if (eo->shown && eo->cmhook)
|
|
ECompMgrWinRaiseLower(eo, num);
|
|
if (num > 0)
|
|
num = EobjListStackRaise(eo, 0);
|
|
|
|
return num;
|
|
#else
|
|
return EobjListStackRaise(eo, 0);
|
|
#endif
|
|
}
|
|
|
|
int
|
|
EobjLower(EObj *eo)
|
|
{
|
|
#if USE_COMPOSITE
|
|
int num;
|
|
|
|
num = EobjListStackLower(eo, 1);
|
|
if (num == 0)
|
|
return num;
|
|
|
|
if (num < 0)
|
|
num = EobjListStackLower(eo, 0);
|
|
if (eo->shown && eo->cmhook)
|
|
ECompMgrWinRaiseLower(eo, num);
|
|
if (num > 0)
|
|
num = EobjListStackLower(eo, 0);
|
|
|
|
return num;
|
|
#else
|
|
return EobjListStackLower(eo, 0);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
EobjShapeUpdate(EObj *eo, int propagate)
|
|
{
|
|
#if USE_COMPOSITE
|
|
int was_shaped = eo->shaped;
|
|
#endif
|
|
|
|
if (propagate)
|
|
eo->shaped = EShapePropagate(EobjGetWin(eo)) != 0;
|
|
else
|
|
eo->shaped = EShapeCheck(EobjGetWin(eo)) != 0;
|
|
|
|
#if USE_COMPOSITE
|
|
if (was_shaped <= 0 && eo->shaped <= 0)
|
|
return;
|
|
|
|
/* Shape may still be unchanged. Well ... */
|
|
if (eo->shown && eo->cmhook)
|
|
ECompMgrWinChangeShape(eo);
|
|
#endif
|
|
}
|
|
|
|
#if USE_COMPOSITE
|
|
EX_Pixmap
|
|
EobjGetPixmap(const EObj *eo)
|
|
{
|
|
return ECompMgrWinGetPixmap(eo);
|
|
}
|
|
#else
|
|
EX_Pixmap
|
|
EobjGetPixmap(const EObj *eo __UNUSED__)
|
|
{
|
|
return NoXID;
|
|
}
|
|
#endif
|
|
|
|
#if USE_COMPOSITE
|
|
/* Update now */
|
|
void
|
|
EobjChangeOpacityNow(EObj *eo, unsigned int opacity)
|
|
{
|
|
if (eo->opacity == opacity)
|
|
return;
|
|
eo->opacity = opacity;
|
|
ECompMgrWinSetOpacity(eo, opacity);
|
|
}
|
|
|
|
/* Change through fade, if enabled */
|
|
void
|
|
EobjChangeOpacity(EObj *eo, unsigned int opacity)
|
|
{
|
|
if (eo->opacity == opacity)
|
|
return;
|
|
eo->opacity = opacity;
|
|
ECompMgrWinChangeOpacity(eo, opacity);
|
|
}
|
|
|
|
void
|
|
EobjChangeShadow(EObj *eo, int shadow)
|
|
{
|
|
ECompMgrWinChangeShadow(eo, shadow);
|
|
}
|
|
#else
|
|
void
|
|
EobjChangeOpacityNow(EObj *eo __UNUSED__, unsigned int opacity __UNUSED__)
|
|
{
|
|
}
|
|
|
|
void
|
|
EobjChangeOpacity(EObj *eo __UNUSED__, unsigned int opacity __UNUSED__)
|
|
{
|
|
}
|
|
|
|
void
|
|
EobjChangeShadow(EObj *eo __UNUSED__, int shadow __UNUSED__)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void
|
|
EobjsRepaint(void)
|
|
{
|
|
#if USE_COMPOSITE
|
|
if (ECompMgrIsActive())
|
|
ECompMgrRepaint();
|
|
else
|
|
#endif
|
|
ESync(0);
|
|
}
|
|
|
|
#if USE_COMPOSITE
|
|
void
|
|
EobjsOpacityUpdate(int op_or)
|
|
{
|
|
EObj *eo, *const *lst;
|
|
int i, num;
|
|
|
|
lst = EobjListStackGet(&num);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
eo = lst[i];
|
|
switch (eo->type)
|
|
{
|
|
default:
|
|
break;
|
|
case EOBJ_TYPE_EWIN:
|
|
EwinUpdateOpacity((EWin *) eo);
|
|
break;
|
|
case EOBJ_TYPE_EXT:
|
|
EobjChangeOpacity(eo, OpacityFromPercent(op_or));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|