e16/src/eobj.c

689 lines
13 KiB
C

/*
* Copyright (C) 2004-2008 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 "e16-ecore_hints.h"
#include "ecompmgr.h"
#include "eobj.h"
#include "ewins.h" /* FIXME - Should not be here */
#include "hints.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);
}
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);
}
#if 1 /* FIXME - Remove */
int
EobjIsShaped(const EObj * eo)
{
switch (eo->type)
{
default:
return 0; /* FIXME */
case EOBJ_TYPE_EWIN:
return ((EWin *) eo)->state.shaped;
}
}
#endif
#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 = ecore_x_icccm_title_get(WinGetXwin(win));
ecore_x_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))
EobjListStackAdd(eo, 1);
if (EDebug(EDBUG_TYPE_EWINS))
Eprintf("EobjInit: %#lx %s\n", EobjGetXwin(eo), EobjGetName(eo));
}
void
EobjFini(EObj * eo)
{
if (EDebug(EDBUG_TYPE_EWINS))
Eprintf("EobjFini: %#lx %s\n", EobjGetXwin(eo), EobjGetName(eo));
EobjListStackDel(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);
}
void
EobjDestroy(EObj * eo)
{
if (EDebug(EDBUG_TYPE_EWINS))
Eprintf("EobjDestroy: %#lx %s\n", 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 == NULL)
{
Efree(eo);
eo = NULL;
}
return eo;
}
void
EobjWindowDestroy(EObj * eo)
{
EobjDestroy(eo);
}
EObj *
EobjRegister(Window xwin, int type)
{
EObj *eo;
XWindowAttributes attr;
Win win;
eo = EobjListStackFind(xwin);
if (eo)
return eo;
if (!XGetWindowAttributes(disp, xwin, &attr))
return NULL;
if (type == EOBJ_TYPE_EXT && !attr.override_redirect)
return NULL;
win = ERegisterWindow(xwin, &attr);
if (!win)
return NULL;
eo = ECALLOC(EObj, 1);
if (!eo)
return eo;
#if __cplusplus
if (attr.c_class == InputOnly)
#else
if (attr.class == InputOnly)
#endif
eo->inputonly = 1;
eo->external = 1;
eo->fade = 1;
eo->shadow = 1;
EobjInit(eo, type, win, attr.x, attr.y, attr.width, attr.height, 0, NULL);
#if 1 /* FIXME - TBD */
if (type == EOBJ_TYPE_EXT)
{
eo->shaped = 0; /* FIXME - Assume unshaped for now */
EobjSetFloating(eo, 1);
EobjSetLayer(eo, 4);
}
#endif
#if 0
Eprintf("EobjRegister: %#lx type=%d or=%d: %s\n", xwin, type,
attr.override_redirect, EobjGetName(eo));
#endif
return eo;
}
void
EobjUnregister(EObj * eo)
{
#if 0
Eprintf("EobjUnregister: %#lx type=%d: %s\n", eo->win, 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)
{
int move, resize;
move = x != EobjGetX(eo) || y != EobjGetY(eo);
resize = w != EobjGetW(eo) || h != EobjGetH(eo);
#if USE_COMPOSITE
if (eo->type == EOBJ_TYPE_EWIN)
{
ECompMgrMoveResizeFix(eo, x, y, w, h);
}
else
#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);
}
void
EobjDamage(EObj * eo)
{
#if USE_COMPOSITE
if (eo->cmhook)
ECompMgrWinDamageArea(eo, 0, 0, 0, 0);
#else
eo = NULL;
#endif
}
void
EobjReparent(EObj * eo, EObj * dst, int x, int y)
{
int move;
move = x != EobjGetX(eo) || y != EobjGetY(eo);
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
}
Pixmap
EobjGetPixmap(const EObj * eo)
{
Pixmap pmap = None;
#if USE_COMPOSITE
pmap = ECompMgrWinGetPixmap(eo);
#else
eo = NULL;
#endif
return pmap;
}
void
EobjChangeOpacity(EObj * eo, unsigned int opacity)
{
#if USE_COMPOSITE
if (eo->opacity == opacity)
return;
eo->opacity = opacity;
ECompMgrWinChangeOpacity(eo, opacity);
#else
eo = NULL;
opacity = 0;
#endif
}
#if USE_COMPOSITE
void
EobjChangeShadow(EObj * eo, int shadow)
{
ECompMgrWinChangeShadow(eo, shadow);
}
#endif
void
EobjSlideTo(EObj * eo, int fx, int fy, int tx, int ty, int speed)
{
int k, x, y;
EGrabServer();
ETimedLoopInit(0, 1024, speed);
for (k = 0; k <= 1024;)
{
x = ((fx * (1024 - k)) + (tx * k)) >> 10;
y = ((fy * (1024 - k)) + (ty * k)) >> 10;
EobjMove(eo, x, y);
k = ETimedLoopNext();
}
EobjMove(eo, tx, ty);
EUngrabServer();
}
void
EobjsSlideBy(EObj ** peo, int num, int dx, int dy, int speed)
{
int i, k, x, y;
struct _xy {
int x, y;
} *xy;
if (num <= 0)
return;
xy = EMALLOC(struct _xy, num);
if (!xy)
return;
for (i = 0; i < num; i++)
{
xy[i].x = EobjGetX(peo[i]);
xy[i].y = EobjGetY(peo[i]);
}
ETimedLoopInit(0, 1024, speed);
for (k = 0; k <= 1024;)
{
for (i = 0; i < num; i++)
{
x = ((xy[i].x * (1024 - k)) + ((xy[i].x + dx) * k)) >> 10;
y = ((xy[i].y * (1024 - k)) + ((xy[i].y + dy) * k)) >> 10;
EobjMove(peo[i], x, y);
}
k = ETimedLoopNext();
}
for (i = 0; i < num; i++)
EobjMove(peo[i], xy[i].x + dx, xy[i].y + dy);
Efree(xy);
}
void
EobjSlideSizeTo(EObj * eo, int fx, int fy, int tx, int ty, int fw, int fh,
int tw, int th, int speed)
{
int k, x, y, w, h;
ETimedLoopInit(0, 1024, speed);
for (k = 0; k <= 1024;)
{
x = ((fx * (1024 - k)) + (tx * k)) >> 10;
y = ((fy * (1024 - k)) + (ty * k)) >> 10;
w = ((fw * (1024 - k)) + (tw * k)) >> 10;
h = ((fh * (1024 - k)) + (th * k)) >> 10;
EobjMoveResize(eo, x, y, w, h);
k = ETimedLoopNext();
}
EobjMoveResize(eo, tx, ty, tw, th);
}
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