e16/src/ewins.c

2108 lines
47 KiB
C

/*
* Copyright (C) 2000-2005 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2005 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 "ecompmgr.h"
#include "snaps.h"
#include <sys/time.h>
#define EWIN_TOP_EVENT_MASK \
(ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask | PointerMotionMask /* | \
StructureNotifyMask */)
#define EWIN_CONTAINER_EVENT_MASK \
(/* ButtonPressMask | ButtonReleaseMask | */ \
/* StructureNotifyMask | ResizeRedirectMask | */ \
SubstructureNotifyMask | SubstructureRedirectMask)
#define EWIN_CLIENT_EVENT_MASK \
(EnterWindowMask | LeaveWindowMask | FocusChangeMask | \
/* StructureNotifyMask | */ ResizeRedirectMask | \
PropertyChangeMask | ColormapChangeMask | VisibilityChangeMask)
static void EwinHandleEventsToplevel(XEvent * ev, void *prm);
static void EwinHandleEventsContainer(XEvent * ev, void *prm);
static void EwinHandleEventsClient(XEvent * ev, void *prm);
static void
EwinEventsConfigure(EWin * ewin, int mode)
{
long emask;
emask = (mode) ? ~((long)0) : ~(EnterWindowMask | LeaveWindowMask);
ESelectInput(EoGetWin(ewin), EWIN_TOP_EVENT_MASK & emask);
ESelectInput(ewin->client.win, ewin->client.event_mask & emask);
EwinBorderEventsConfigure(ewin, mode);
}
static EWin *
EwinCreate(Window win, int type)
{
EWin *ewin;
XSetWindowAttributes att;
ewin = Ecalloc(1, sizeof(EWin));
ewin->type = type;
ewin->state = (Mode.wm.startup) ? EWIN_STATE_STARTUP : EWIN_STATE_NEW;
ewin->ld = -1;
ewin->lx = -1;
ewin->ly = -1;
ewin->lw = -1;
ewin->lh = -1;
ewin->client.x = -1;
ewin->client.y = -1;
ewin->client.w = -1;
ewin->client.h = -1;
ewin->client.need_input = 1;
ewin->client.aspect_min = 0.0;
ewin->client.aspect_max = 65535.0;
ewin->client.w_inc = 1;
ewin->client.h_inc = 1;
ewin->client.width.max = 65535;
ewin->client.height.max = 65535;
ewin->client.mwm_decor_border = 1;
ewin->client.mwm_decor_resizeh = 1;
ewin->client.mwm_decor_title = 1;
ewin->client.mwm_decor_menu = 1;
ewin->client.mwm_decor_minimize = 1;
ewin->client.mwm_decor_maximize = 1;
ewin->client.mwm_func_resize = 1;
ewin->client.mwm_func_move = 1;
ewin->client.mwm_func_minimize = 1;
ewin->client.mwm_func_maximize = 1;
ewin->client.mwm_func_close = 1;
EoSetWin(ewin, ECreateWindow(VRoot.win, -10, -10, 1, 1, 1));
ewin->win_container = ECreateWindow(EoGetWin(ewin), 0, 0, 1, 1, 0);
#if 0 /* ENABLE_GNOME - Not actually used */
ewin->expanded_width = -1;
ewin->expanded_height = -1;
#endif
ewin->area_x = -1;
ewin->area_y = -1;
EobjInit(&ewin->o, EOBJ_TYPE_EWIN, -1, -1, -1, -1);
EoSetDesk(ewin, DesksGetCurrent());
EoSetLayer(ewin, 4);
ewin->props.opacity = 0xFFFFFFFF;
att.event_mask = EWIN_CONTAINER_EVENT_MASK;
att.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
EChangeWindowAttributes(ewin->win_container,
CWEventMask | CWDontPropagate, &att);
EMapWindow(ewin->win_container);
att.event_mask = EWIN_TOP_EVENT_MASK;
att.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
EChangeWindowAttributes(EoGetWin(ewin), CWEventMask | CWDontPropagate, &att);
ewin->client.win = win;
FocusEwinSetGrabs(ewin);
GrabButtonGrabs(ewin);
EobjListStackAdd(&ewin->o, 0);
EobjListFocusAdd(&ewin->o, 0);
ewin->client.event_mask = EWIN_CLIENT_EVENT_MASK;
AddItem(ewin, "EWIN", win, LIST_TYPE_EWIN);
XShapeSelectInput(disp, win, ShapeNotifyMask);
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinCreate %#lx frame=%#lx state=%d\n", ewin->client.win,
EoGetWin(ewin), ewin->state);
EventCallbackRegister(EoGetWin(ewin), 0, EwinHandleEventsToplevel, ewin);
EventCallbackRegister(ewin->win_container, 0, EwinHandleEventsContainer,
ewin);
ERegisterWindow(ewin->client.win);
EventCallbackRegister(ewin->client.win, 0, EwinHandleEventsClient, ewin);
if (!EwinIsInternal(ewin))
{
XSetWindowBorderWidth(disp, win, 0);
ewin->client.bw = 0;
}
ModulesSignal(ESIGNAL_EWIN_CREATE, ewin);
return ewin;
}
static void
EwinCleanup(EWin * ewin)
{
EwinBorderDetach(ewin);
}
static void
EwinDestroy(EWin * ewin)
{
EWin **lst;
int i, num;
if (!ewin)
return;
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinDestroy %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
/* FIXME - Fading */
ECompMgrWinDel(&ewin->o, True, False);
RemoveItem(NULL, ewin->client.win, LIST_FINDBY_ID, LIST_TYPE_EWIN);
EventCallbackUnregister(EoGetWin(ewin), 0, EwinHandleEventsToplevel, ewin);
EventCallbackUnregister(ewin->win_container, 0, EwinHandleEventsContainer,
ewin);
EventCallbackUnregister(ewin->client.win, 0, EwinHandleEventsClient, ewin);
if (!EwinIsInternal(ewin))
EUnregisterWindow(ewin->client.win);
EobjListStackDel(&ewin->o);
EobjListFocusDel(&ewin->o);
HintsSetClientList();
SnapshotEwinUnmatch(ewin);
ModulesSignal(ESIGNAL_EWIN_DESTROY, ewin);
lst = EwinListTransientFor(ewin, &num);
for (i = 0; i < num; i++)
{
lst[i]->has_transients--;
if (lst[i]->has_transients < 0) /* Paranoia? */
lst[i]->has_transients = 0;
}
if (lst)
Efree(lst);
EwinCleanup(ewin);
if (ewin->icccm.wm_name)
Efree(ewin->icccm.wm_name);
if (ewin->icccm.wm_res_class)
Efree(ewin->icccm.wm_res_class);
if (ewin->icccm.wm_res_name)
Efree(ewin->icccm.wm_res_name);
if (ewin->icccm.wm_role)
Efree(ewin->icccm.wm_role);
if (ewin->icccm.wm_command)
Efree(ewin->icccm.wm_command);
if (ewin->icccm.wm_machine)
Efree(ewin->icccm.wm_machine);
#if ENABLE_EWMH
if (ewin->ewmh.wm_name)
Efree(ewin->ewmh.wm_name);
if (ewin->ewmh.wm_icon_name)
Efree(ewin->ewmh.wm_icon_name);
#endif
if (ewin->icccm.wm_icon_name)
Efree(ewin->icccm.wm_icon_name);
if (EoGetWin(ewin))
EDestroyWindow(EoGetWin(ewin));
if (ewin->bits)
Efree(ewin->bits);
if (ewin->session_id)
Efree(ewin->session_id);
FreePmapMask(&ewin->mini_pmm);
if (ewin->icon_image)
{
imlib_context_set_image(ewin->icon_image);
imlib_free_image_and_decache();
}
GroupsEwinRemove(ewin);
Efree(ewin);
}
void
DetermineEwinFloat(EWin * ewin, int dx, int dy)
{
char dofloat = 0;
int desk, x, y, w, h, xd, yd;
desk = EoGetDesk(ewin);
x = EoGetX(ewin);
y = EoGetY(ewin);
w = EoGetW(ewin);
h = EoGetH(ewin);
xd = DeskGetX(desk);
yd = DeskGetY(desk);
if ((desk != 0) && (EoIsFloating(ewin) < 2) &&
((xd != 0) || (yd != 0) || (DesksGetCurrent() != desk)))
{
switch (Conf.desks.dragdir)
{
case 0:
if (((x + dx < 0) ||
((x + dx + w <= VRoot.w) &&
((DesktopAt(xd + x + dx + w - 1, yd) != desk)))))
dofloat = 1;
break;
case 1:
if (((x + dx + w > VRoot.w) ||
((x + dx >= 0) && ((DesktopAt(xd + x + dx, yd) != desk)))))
dofloat = 1;
break;
case 2:
if (((y + dy < 0) ||
((y + dy + h <= VRoot.h) &&
((DesktopAt(xd, yd + y + dy + h - 1) != desk)))))
dofloat = 1;
break;
case 3:
if (((y + dy + h > VRoot.h) ||
((y + dy >= 0) && ((DesktopAt(xd, yd + y + dy) != desk)))))
dofloat = 1;
break;
}
if (dofloat)
FloatEwinAt(ewin, x + xd, y + yd);
}
}
EWin *
GetEwinByCurrentPointer(void)
{
Window rt, ch;
int dum, x, y;
unsigned int mr;
XQueryPointer(disp, DeskGetWin(DesksGetCurrent()), &rt, &ch, &x, &y, &dum,
&dum, &mr);
return FindEwinByBase(ch);
}
EWin *
GetEwinPointerInClient(void)
{
Window rt, ch;
int dum, px, py, desk;
EWin *const *lst, *ewin;
int i, num;
desk = DesktopAt(Mode.x, Mode.y);
XQueryPointer(disp, DeskGetWin(desk), &rt, &ch, &dum, &dum, &px, &py,
(unsigned int *)&dum);
px -= DeskGetX(desk);
py -= DeskGetY(desk);
lst = EwinListGetForDesk(&num, desk);
for (i = 0; i < num; i++)
{
int x, y, w, h;
ewin = lst[i];
x = EoGetX(ewin);
y = EoGetY(ewin);
w = EoGetW(ewin);
h = EoGetH(ewin);
if ((px >= x) && (py >= y) && (px < (x + w)) && (py < (y + h)) &&
EwinIsMapped(ewin))
return ewin;
}
return NULL;
}
EWin *
GetFocusEwin(void)
{
return Mode.focuswin;
}
EWin *
GetContextEwin(void)
{
EWin *ewin;
#if 0
ewin = Mode.mouse_over_ewin;
if (ewin && ewin->type != EWIN_TYPE_MENU)
return ewin;
#endif
ewin = Mode.context_ewin;
if (ewin)
goto done;
ewin = Mode.focuswin;
if (ewin && ewin->type != EWIN_TYPE_MENU)
goto done;
ewin = NULL;
done:
#if 0
Eprintf("GetContextEwin %#lx %s\n", EwinGetClientWin(ewin),
EwinGetName(ewin));
#endif
return ewin;
}
void
SetContextEwin(EWin * ewin)
{
if (ewin && ewin->type == EWIN_TYPE_MENU)
return;
#if 0
Eprintf("SetContextEwin %#lx %s\n", EwinGetClientWin(ewin),
EwinGetName(ewin));
#endif
Mode.context_ewin = ewin;
}
static void
EwinDetermineArea(EWin * ewin)
{
int ax, ay;
DeskGetArea(EoGetDesk(ewin), &ax, &ay);
ax = (EoGetX(ewin) + (EoGetW(ewin) / 2) + (ax * VRoot.w)) / VRoot.w;
ay = (EoGetY(ewin) + (EoGetH(ewin) / 2) + (ay * VRoot.h)) / VRoot.h;
AreaFix(&ax, &ay);
if (ax != ewin->area_x || ay != ewin->area_y)
{
ewin->area_x = ax;
ewin->area_y = ay;
HintsSetWindowArea(ewin);
}
}
/*
* Derive frame window position from client window and border properties
*/
static void
EwinGetPosition(const EWin * ewin, int *px, int *py)
{
int x, y, bw, frame_lr, frame_tb;
x = ewin->client.x;
y = ewin->client.y;
bw = ewin->client.bw;
frame_lr = ewin->border->border.left + ewin->border->border.right;
frame_tb = ewin->border->border.top + ewin->border->border.bottom;
switch (ewin->client.grav)
{
case NorthWestGravity:
case SouthWestGravity:
case WestGravity:
x -= bw;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
x -= frame_lr / 2;
break;
case NorthGravity:
case CenterGravity:
case SouthGravity:
x -= frame_lr - bw;
break;
case StaticGravity:
x -= ewin->border->border.left;
break;
default:
break;
}
switch (ewin->client.grav)
{
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
y -= bw;
break;
case WestGravity:
case CenterGravity:
case EastGravity:
y -= frame_tb / 2;
break;
case SouthWestGravity:
case SouthGravity:
case SouthEastGravity:
y -= frame_tb - bw;
break;
case StaticGravity:
y -= ewin->border->border.top;
break;
default:
break;
}
*px = x;
*py = y;
}
/*
* Derive frame window geometry from client window properties
*/
static void
EwinGetGeometry(EWin * ewin)
{
int x, y;
EwinGetPosition(ewin, &x, &y);
ewin->client.x = x + ewin->border->border.left;
ewin->client.y = y + ewin->border->border.top;
EoSetX(ewin, ewin->shape_x = x);
EoSetY(ewin, ewin->shape_y = y);
EoSetW(ewin, ewin->client.w +
ewin->border->border.left + ewin->border->border.right);
EoSetH(ewin, ewin->client.h +
ewin->border->border.top + ewin->border->border.bottom);
}
void
EwinPropagateShapes(EWin * ewin)
{
if (!ewin->docked)
PropagateShapes(EoGetWin(ewin));
}
static void
EwinAdopt(EWin * ewin)
{
/* We must reparent after getting original window position */
EReparentWindow(ewin->client.win, ewin->win_container, 0, 0);
ICCCM_Adopt(ewin);
}
static EWin *
Adopt(EWin * ewin, Window win)
{
if (ewin)
EwinCleanup(ewin);
else
ewin = EwinCreate(win, EWIN_TYPE_NORMAL);
ICCCM_AdoptStart(ewin);
ICCCM_GetTitle(ewin, 0);
ICCCM_GetHints(ewin, 0);
ICCCM_GetInfo(ewin, 0);
ICCCM_GetColormap(ewin);
ICCCM_GetShapeInfo(ewin);
ICCCM_GetGeoms(ewin, 0);
HintsGetWindowHints(ewin);
SessionGetInfo(ewin, 0);
#if 0 /* Do we want this? */
MatchEwinToSM(ewin);
#endif
WindowMatchEwinOps(ewin); /* Window matches */
SnapshotEwinMatch(ewin); /* Saved settings */
if (Mode.wm.startup)
EHintsGetInfo(ewin); /* E restart hints */
ICCCM_MatchSize(ewin);
EwinAdopt(ewin);
EwinBorderSelect(ewin); /* Select border before calculating geometry */
EwinGetGeometry(ewin); /* Calculate window geometry before border parts */
EwinBorderSetTo(ewin, NULL);
EwinEventsConfigure(ewin, 1);
if (ewin->shaded)
EwinInstantShade(ewin, 1);
HintsSetWindowState(ewin);
HintsSetClientList();
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("Adopt %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
return ewin;
}
static EWin *
AdoptInternal(Window win, Border * border, int type, void (*init) (EWin *
ewin,
void *ptr),
void *ptr)
{
EWin *ewin;
ewin = EwinCreate(win, type);
ewin->border = border;
if (init)
init(ewin, ptr); /* Type specific initialisation */
ICCCM_AdoptStart(ewin);
ICCCM_GetTitle(ewin, 0);
ICCCM_GetInfo(ewin, 0);
ICCCM_GetShapeInfo(ewin);
ICCCM_GetGeoms(ewin, 0);
WindowMatchEwinOps(ewin); /* Window matches */
SnapshotEwinMatch(ewin); /* Saved settings */
ICCCM_MatchSize(ewin);
EwinAdopt(ewin);
EwinBorderSelect(ewin);
EwinGetGeometry(ewin);
EwinBorderSetTo(ewin, NULL);
EwinEventsConfigure(ewin, 1);
if (ewin->shaded)
EwinInstantShade(ewin, 1);
HintsSetWindowState(ewin);
HintsSetClientList();
return ewin;
}
void
AddToFamily(EWin * ewin, Window win)
{
EWin *ewin2;
EWin **lst;
int i, k, num, fx, fy, x, y, desk;
char doslide, manplace;
ecore_x_grab();
if (!WinExists(win))
{
Eprintf("Window is gone %#lx\n", win);
ecore_x_ungrab();
return;
}
/* adopt the new baby */
ewin = Adopt(ewin, win);
/* if it hasn't been planted on a desktop - assign it the current desktop */
desk = EoGetDesk(ewin);
/* if is an afterstep/windowmaker dock app - dock it */
if (Conf.dock.enable && ewin->docked)
{
DockIt(ewin);
ewin->props.donthide = 1;
ewin->focusclick = 1;
}
doslide = Conf.mapslide && !Mode.wm.startup;
/* if set for borderless then dont slide it in */
if ((!ewin->client.mwm_decor_title) && (!ewin->client.mwm_decor_border))
doslide = 0;
ewin2 = NULL;
if (ewin->client.transient)
{
if (ewin->client.transient_for == None ||
ewin->client.transient_for == VRoot.win)
{
/* Group transient */
ewin->client.transient_for = VRoot.win;
#if 0 /* Maybe? */
ewin->layer++;
#endif
/* Don't treat this as a normal transient */
ewin->client.transient = -1;
}
else if (ewin->client.transient_for == ewin->client.win)
{
/* Some apps actually do this. Why? */
ewin->client.transient = 0;
}
else
{
/* Regular transient */
}
if (ewin->client.transient)
{
/* Tag the parent window if this is a transient */
lst = EwinListTransientFor(ewin, &num);
for (i = 0; i < num; i++)
{
lst[i]->has_transients++;
if (EoGetLayer(ewin) < EoGetLayer(lst[i]))
EoSetLayer(ewin, EoGetLayer(lst[i]));
}
if (lst)
{
ewin2 = lst[0];
EoSetSticky(ewin, EoIsSticky(lst[0]));
Efree(lst);
}
else
{
/* No parents? - not a transient */
ewin->client.transient = 0;
}
}
}
if (ewin->client.transient && Conf.focus.transientsfollowleader)
{
EWin *const *lst2;
if (!ewin2)
ewin2 = FindItem(NULL, ewin->client.group, LIST_FINDBY_ID,
LIST_TYPE_EWIN);
if (!ewin2)
{
lst2 = EwinListGetAll(&num);
for (i = 0; i < num; i++)
{
if ((lst2[i]->iconified) ||
(ewin->client.group != lst2[i]->client.group))
continue;
ewin2 = lst2[i];
break;
}
}
if (ewin2)
{
desk = EoGetDesk(ewin2);
if (!Mode.wm.startup && Conf.focus.switchfortransientmap &&
!ewin->iconified)
DeskGotoByEwin(ewin2);
}
}
if (ewin->st.fullscreen)
{
ewin->st.fullscreen = 0;
EwinSetFullscreen(ewin, 1);
ewin->client.already_placed = 1;
ShowEwin(ewin);
ecore_x_ungrab();
return;
}
ResizeEwin(ewin, ewin->client.w, ewin->client.h);
manplace = 0;
if ((!ewin->client.transient) && (Conf.place.manual)
&& (!ewin->client.already_placed) && (!Mode.wm.startup) && (!Mode.place))
{
char cangrab;
cangrab = GrabPointerSet(VRoot.win, ECSR_GRAB, 0);
if (cangrab == GrabSuccess)
manplace = 1;
}
/* if it hasn't been placed yet.... find a spot for it */
x = EoGetX(ewin);
y = EoGetY(ewin);
if ((!ewin->client.already_placed) && (!manplace))
{
/* Place the window below the mouse pointer */
if (Conf.place.manual_mouse_pointer)
{
int rx, ry, wx, wy;
unsigned int mask;
Window junk, root_return;
int newWinX = 0, newWinY = 0;
/* if the loser has manual placement on and the app asks to be on */
/* a desktop, then send E to that desktop so the user can place */
/* the window there */
DeskGoto(desk);
XQueryPointer(disp, VRoot.win, &root_return, &junk, &rx, &ry, &wx,
&wy, &mask);
Mode.x = rx;
Mode.y = ry;
ewin->client.already_placed = 1;
/* try to center the window on the mouse pointer */
newWinX = rx;
newWinY = ry;
if (EoGetW(ewin))
newWinX -= EoGetW(ewin) / 2;
if (EoGetH(ewin))
newWinY -= EoGetH(ewin) / 2;
/* keep it all on this screen if possible */
newWinX = MIN(newWinX, VRoot.w - EoGetW(ewin));
newWinY = MIN(newWinY, VRoot.h - EoGetH(ewin));
newWinX = MAX(newWinX, 0);
newWinY = MAX(newWinY, 0);
/* this works for me... */
EoSetX(ewin, x = newWinX);
EoSetY(ewin, y = newWinY);
}
else
{
ewin->client.already_placed = 1;
ArrangeEwinXY(ewin, &x, &y);
}
}
/* Force reparent if not on desk 0 */
EoSetDesk(ewin, 0);
/* if the window asked to be iconified at the start */
if (ewin->client.start_iconified)
{
#if 0 /* FIXME - Remove? */
EwinBorderDraw(ewin, 1, 1, 0);
#endif
MoveEwinToDesktopAt(ewin, desk, x, y);
ecore_x_ungrab();
ewin->state = EWIN_STATE_MAPPED;
EwinIconify(ewin);
ewin->state = EWIN_STATE_ICONIC;
return;
}
/* if we should slide it in and are not currently in the middle of a slide */
if ((manplace) && (!ewin->client.already_placed))
{
int rx, ry, wx, wy;
unsigned int mask;
Window junk, root_return;
#if 0 /* FIXME: Disable for now */
/* if the loser has manual placement on and the app asks to be on */
/* a desktop, then send E to that desktop so the user can place */
/* the window there */
DeskGoto(desk);
#endif
XQueryPointer(disp, VRoot.win, &root_return, &junk, &rx, &ry, &wx, &wy,
&mask);
Mode.x = rx;
Mode.y = ry;
ewin->client.already_placed = 1;
x = Mode.x + 1;
y = Mode.y + 1;
#if 0 /* FIXME - Remove? */
EwinBorderDraw(ewin, 1, 1, 0);
#endif
MoveEwinToDesktop(ewin, desk);
RaiseEwin(ewin);
MoveEwin(ewin, x, y);
RaiseEwin(ewin);
ShowEwin(ewin);
GrabPointerSet(VRoot.win, ECSR_GRAB, 0);
Mode.have_place_grab = 1;
Mode.place = 1;
ecore_x_ungrab();
EoSetFloating(ewin, 1); /* Causes reparenting to root */
ActionMoveStart(ewin, 1, 0, 0);
return;
}
else if ((doslide) && (!Mode.doingslide))
{
MoveEwin(ewin, VRoot.w, VRoot.h);
k = rand() % 4;
if (k == 0)
{
fx = (rand() % (VRoot.w)) - EoGetW(ewin);
fy = -EoGetH(ewin);
}
else if (k == 1)
{
fx = (rand() % (VRoot.w));
fy = VRoot.h;
}
else if (k == 2)
{
fx = -EoGetW(ewin);
fy = (rand() % (VRoot.h));
}
else
{
fx = VRoot.w;
fy = (rand() % (VRoot.h)) - EoGetH(ewin);
}
#if 0 /* FIXME - Remove? */
EwinBorderDraw(ewin, 1, 1, 0);
#endif
MoveEwinToDesktop(ewin, desk);
RaiseEwin(ewin);
MoveEwin(ewin, fx, fy);
ShowEwin(ewin);
SlideEwinTo(ewin, fx, fy, x, y, Conf.slidespeedmap);
MoveEwinToDesktopAt(ewin, desk, x, y);
}
else
{
#if 0 /* FIXME - Remove? */
EwinBorderDraw(ewin, 1, 1, 0);
#endif
MoveEwinToDesktopAt(ewin, desk, x, y);
RaiseEwin(ewin);
ShowEwin(ewin);
}
EwinDetermineArea(ewin);
ecore_x_ungrab();
}
EWin *
AddInternalToFamily(Window win, const char *bname, int type, void *ptr,
void (*init) (EWin * ewin, void *ptr))
{
EWin *ewin;
Border *b;
b = NULL;
if (bname)
{
b = FindItem(bname, 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
if (!b)
b = FindItem("DEFAULT", 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
}
ecore_x_grab();
ewin = AdoptInternal(win, b, type, init, ptr);
#if 0
Eprintf("Desk=%d, layer=%d, sticky=%d, floating=%d\n",
EoGetDesk(ewin), EoGetLayer(ewin), EoIsSticky(ewin),
EoIsFloating(ewin));
#endif
#if 0 /* FIXME - Remove? */
EwinBorderDraw(ewin, 1, 1, 1);
#endif
EwinConformToDesktop(ewin);
EwinDetermineArea(ewin);
ecore_x_ungrab();
return ewin;
}
static void
EwinWithdraw(EWin * ewin)
{
Window win;
int x, y;
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinWithdraw %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
ecore_x_grab();
/* Park the client window on the root */
x = ewin->client.x;
y = ewin->client.y;
XTranslateCoordinates(disp, ewin->client.win, VRoot.win,
-ewin->border->border.left,
-ewin->border->border.top, &x, &y, &win);
EReparentWindow(ewin->client.win, VRoot.win, x, y);
ICCCM_Withdraw(ewin);
HintsDelWindowHints(ewin);
ecore_x_sync();
ecore_x_ungrab();
if (EwinIsInternal(ewin))
EwinDestroy(ewin);
}
void
EwinConformToDesktop(EWin * ewin)
{
Window dwin;
dwin = DeskGetWin(EoGetDesk(ewin));
if ((ewin->iconified) && (ewin->parent != dwin))
{
ewin->parent = dwin;
EReparentWindow(EoGetWin(ewin), dwin, EoGetX(ewin), EoGetY(ewin));
RaiseEwin(ewin);
ICCCM_Configure(ewin);
}
else if (EoIsFloating(ewin))
{
if ((ewin->parent != VRoot.win) && (EoIsFloating(ewin) == 2))
{
ewin->parent = VRoot.win;
EReparentWindow(EoGetWin(ewin), VRoot.win, EoGetX(ewin),
EoGetY(ewin));
EoSetDesk(ewin, 0);
}
RaiseEwin(ewin);
ICCCM_Configure(ewin);
EdgeWindowsShow();
}
else if (ewin->parent != dwin)
{
ewin->parent = dwin;
EReparentWindow(EoGetWin(ewin), dwin, EoGetX(ewin), EoGetY(ewin));
RaiseEwin(ewin);
MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin));
}
else
{
RaiseEwin(ewin);
MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin));
}
/* FIXME - This should not be necessary. It is when a new window is added as
* the only one in the lowest layer (e.g. desktop type).
* In stead EobjListStackAdd() should mark the object stack dirty. */
StackDesktop(EoGetDesk(ewin));
EwinDetermineArea(ewin);
HintsSetWindowDesktop(ewin);
}
void
EwinReparent(EWin * ewin, Window parent)
{
EReparentWindow(ewin->client.win, parent, 0, 0);
}
static void
EwinEventMapRequest(EWin * ewin, Window win)
{
if (ewin)
{
if (ewin->state == EWIN_STATE_ICONIC)
EwinDeIconify(ewin);
if (ewin->state == EWIN_STATE_WITHDRAWN)
AddToFamily(ewin, win);
else
Eprintf("AddToFamily: Already managing %s %#lx\n", "A",
ewin->client.win);
}
else
{
/* Check if we are already managing it */
ewin = FindItem(NULL, win, LIST_FINDBY_ID, LIST_TYPE_EWIN);
/* Some clients MapRequest more than once ?!? */
if (ewin)
{
Eprintf("AddToFamily: Already managing %s %#lx\n", "B",
ewin->client.win);
ShowEwin(ewin);
}
else
AddToFamily(NULL, win);
}
}
static void
EwinEventDestroy(EWin * ewin)
{
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinEventDestroy %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
EwinDestroy(ewin);
}
static void
EwinEventMap(EWin * ewin)
{
int old_state = ewin->state;
ewin->state = EWIN_STATE_MAPPED;
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinEventMap %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
/* If first time we may want to focus it (unless during startup) */
if (old_state == EWIN_STATE_NEW)
FocusToEWin(ewin, FOCUS_EWIN_NEW);
else
FocusToEWin(ewin, FOCUS_SET);
ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
}
static void
EwinEventUnmap(EWin * ewin)
{
if (GetZoomEWin() == ewin)
Zoom(NULL);
if (EventDebug(EDBUG_TYPE_EWINS))
Eprintf("EwinEventUnmap %#lx %s state=%d\n", ewin->client.win,
EwinGetName(ewin), ewin->state);
if (ewin->state == EWIN_STATE_WITHDRAWN)
return;
if (ewin->iconified)
ewin->state = EWIN_STATE_ICONIC;
else
ewin->state = EWIN_STATE_WITHDRAWN;
ewin->shown = 0;
ActionsEnd(ewin);
if (ewin == GetContextEwin())
SlideoutsHide();
if (ewin == Mode.focuswin)
FocusToEWin(ewin, FOCUS_EWIN_GONE);
if (ewin == Mode.mouse_over_ewin)
Mode.mouse_over_ewin = NULL;
if (ewin == Mode.context_ewin)
Mode.context_ewin = NULL;
if (Mode.doingslide)
{
DrawEwinShape(ewin, Conf.slidemode, ewin->shape_x, ewin->shape_y,
ewin->client.w, ewin->client.h, 2);
Mode.doingslide = 0;
}
/* FIXME - This is to sync the client.win EXID mapped state */
EUnmapWindow(ewin->client.win);
EUnmapWindow(EoGetWin(ewin));
ModulesSignal(ESIGNAL_EWIN_UNMAP, ewin);
if (ewin->iconified)
return;
if (ewin->Close)
ewin->Close(ewin);
if (WinGetParent(ewin->client.win) == ewin->win_container)
EwinWithdraw(ewin);
}
static void
EwinEventConfigureRequest(EWin * ewin, XEvent * ev)
{
Window win, winrel;
EWin *ewin2;
int x = 0, y = 0, w = 0, h = 0;
XWindowChanges xwc;
win = ev->xconfigurerequest.window;
if (ewin)
{
x = EoGetX(ewin);
y = EoGetY(ewin);
w = ewin->client.w;
h = ewin->client.h;
winrel = 0;
if (ev->xconfigurerequest.value_mask & CWX)
x = ev->xconfigurerequest.x;
if (ev->xconfigurerequest.value_mask & CWY)
y = ev->xconfigurerequest.y;
if (ev->xconfigurerequest.value_mask & CWWidth)
w = ev->xconfigurerequest.width;
if (ev->xconfigurerequest.value_mask & CWHeight)
h = ev->xconfigurerequest.height;
if (ev->xconfigurerequest.value_mask & CWSibling)
winrel = ev->xconfigurerequest.above;
if (ev->xconfigurerequest.value_mask & CWStackMode)
{
ewin2 = FindItem(NULL, winrel, LIST_FINDBY_ID, LIST_TYPE_EWIN);
if (ewin2)
winrel = EoGetWin(ewin2);
xwc.sibling = winrel;
xwc.stack_mode = ev->xconfigurerequest.detail;
if (Mode.mode == MODE_NONE)
{
if (xwc.stack_mode == Above)
RaiseEwin(ewin);
else if (xwc.stack_mode == Below)
LowerEwin(ewin);
}
/* else
* XConfigureWindow(disp, EoGetWin(ewin),
* ev->xconfigurerequest.value_mask &
* (CWSibling | CWStackMode), &xwc); */
}
#if 0 /* Let's try disabling this */
/* this ugly workaround here is because x11amp is very brain-dead */
/* and sets its minunum and maximm sizes the same - fair enough */
/* to ensure it doesnt get resized - BUT hwne it shades itself */
/* it resizes down to a smaller size - of course keeping the */
/* minimum and maximim size same - E unconditionally disallows any */
/* client window to be resized outside of its constraints */
/* (any client could do this resize - not just x11amp thus E is */
/* imposing the hints x11amp set up - this works around by */
/* modifying the constraints to fit what the app requested */
if (w < ewin->client.width.min)
ewin->client.width.min = w;
if (w > ewin->client.width.max)
ewin->client.width.max = w;
if (h < ewin->client.height.min)
ewin->client.height.min = h;
if (h > ewin->client.height.max)
ewin->client.height.max = h;
#endif
if (ev->xconfigurerequest.value_mask & (CWX | CWY))
{
/* Correct position taking gravity into account */
ewin->client.x = x;
ewin->client.y = y;
EwinGetPosition(ewin, &x, &y);
}
Mode.move.check = 0; /* Don't restrict client requests */
MoveResizeEwin(ewin, x, y, w, h);
Mode.move.check = 1;
{
char pshaped;
pshaped = ewin->client.shaped;
ICCCM_GetShapeInfo(ewin);
if (pshaped != ewin->client.shaped)
{
SyncBorderToEwin(ewin);
EwinPropagateShapes(ewin);
}
}
ReZoom(ewin);
}
else
{
xwc.x = ev->xconfigurerequest.x;
xwc.y = ev->xconfigurerequest.y;
xwc.width = ev->xconfigurerequest.width;
xwc.height = ev->xconfigurerequest.height;
xwc.border_width = ev->xconfigurerequest.border_width;
xwc.sibling = ev->xconfigurerequest.above;
xwc.stack_mode = ev->xconfigurerequest.detail;
EConfigureWindow(win, ev->xconfigurerequest.value_mask, &xwc);
}
}
static void
EwinEventResizeRequest(EWin * ewin, XEvent * ev)
{
Window win;
int w, h;
win = ev->xresizerequest.window;
if (ewin)
{
w = ev->xresizerequest.width;
h = ev->xresizerequest.height;
ResizeEwin(ewin, w, h);
{
char pshaped;
pshaped = ewin->client.shaped;
ICCCM_GetShapeInfo(ewin);
if (pshaped != ewin->client.shaped)
{
SyncBorderToEwin(ewin);
EwinPropagateShapes(ewin);
}
}
ReZoom(ewin);
}
else
{
EResizeWindow(win, ev->xresizerequest.width, ev->xresizerequest.height);
}
}
static void
EwinEventCirculateRequest(EWin * ewin, XEvent * ev)
{
Window win;
win = ev->xcirculaterequest.window;
if (ewin)
{
if (ev->xcirculaterequest.place == PlaceOnTop)
RaiseEwin(ewin);
else
LowerEwin(ewin);
}
else
{
if (ev->xcirculaterequest.place == PlaceOnTop)
ERaiseWindow(win);
else
ELowerWindow(win);
}
}
static void
EwinEventPropertyNotify(EWin * ewin, XEvent * ev)
{
ecore_x_grab();
EwinChangesStart(ewin);
HintsProcessPropertyChange(ewin, ev->xproperty.atom);
SessionGetInfo(ewin, ev->xproperty.atom);
SyncBorderToEwin(ewin);
EwinChangesProcess(ewin);
ecore_x_ungrab();
}
static void
EwinEventShapeChange(EWin * ewin)
{
const Border *b;
b = ewin->border;
SyncBorderToEwin(ewin);
if (ewin->border == b)
EwinPropagateShapes(ewin);
}
static void
EwinEventVisibility(EWin * ewin, int state)
{
ewin->visibility = state;
}
void
EwinRefresh(EWin * ewin)
{
if (!ewin)
return;
if (TransparencyEnabled())
EwinBorderDraw(ewin, 0, 1, 0); /* Update the border */
if (ewin->Refresh)
ewin->Refresh(ewin);
}
void
EwinUpdateAfterMoveResize(EWin * ewin, int resize)
{
if (!ewin)
return;
EwinDetermineArea(ewin);
if (TransparencyEnabled())
EwinBorderDraw(ewin, resize, 1, 0); /* Update the border */
if (ewin->MoveResize)
ewin->MoveResize(ewin, resize);
SnapshotEwinUpdate(ewin, SNAP_USE_POS | SNAP_USE_SIZE);
ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
}
#if 0 /* Unused */
void
FloatEwin(EWin * ewin)
{
static int call_depth = 0;
EWin **lst;
int i, num;
call_depth++;
if (call_depth > 256)
return;
EoSetFloating(ewin, 1);
EoSetDesk(ewin, 0);
EwinConformToDesktop(ewin);
RaiseEwin(ewin);
lst = EwinListTransients(ewin, &num, 0);
for (i = 0; i < num; i++)
FloatEwin(lst[i]);
if (lst)
Efree(lst);
call_depth--;
}
#endif
void
FloatEwinAt(EWin * ewin, int x, int y)
{
static int call_depth = 0;
int dx, dy;
EWin **lst;
int i, num;
call_depth++;
if (call_depth > 256)
return;
if (EoIsFloating(ewin))
{
/* Reparenting to root moves the desktop-relative coordinates */
dx = DeskGetX(EoGetDesk(ewin));
dy = DeskGetY(EoGetDesk(ewin));
ewin->shape_x += dx;
ewin->shape_y += dy;
ewin->req_x += dx;
ewin->req_y += dy;
EoSetFloating(ewin, 2);
}
else
{
ewin->ld = EoGetDesk(ewin);
EoSetFloating(ewin, 1);
}
dx = x - EoGetX(ewin);
dy = y - EoGetY(ewin);
EoSetX(ewin, x);
EoSetY(ewin, y);
EwinConformToDesktop(ewin);
lst = EwinListTransients(ewin, &num, 0);
for (i = 0; i < num; i++)
FloatEwinAt(lst[i], EoGetX(lst[i]) + dx, EoGetY(lst[i]) + dy);
if (lst)
Efree(lst);
call_depth--;
}
/*
* Place particular EWin at appropriate location in the window stack
*/
static void
RestackEwin(EWin * ewin)
{
EWin *const *lst;
int i, num;
XWindowChanges xwc;
unsigned int value_mask;
if (EventDebug(EDBUG_TYPE_STACKING))
Eprintf("RestackEwin %#lx %s\n", ewin->client.win, EwinGetName(ewin));
lst = EwinListGetForDesk(&num, EoGetDesk(ewin));
if (num < 2)
goto done;
for (i = 0; i < num; i++)
if (lst[i] == ewin)
break;
if (i < num - 1)
{
xwc.stack_mode = Above;
xwc.sibling = EoGetWin(lst[i + 1]);
}
else
{
xwc.stack_mode = Below;
xwc.sibling = EoGetWin(lst[i - 1]);
}
value_mask = CWSibling | CWStackMode;
if (EventDebug(EDBUG_TYPE_STACKING))
Eprintf("RestackEwin %#10lx %s %#10lx\n", EoGetWin(ewin),
(xwc.stack_mode == Above) ? "Above" : "Below", xwc.sibling);
XConfigureWindow(disp, EoGetWin(ewin), value_mask, &xwc);
HintsSetClientStacking();
ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
done:
;
}
void
RaiseEwin(EWin * ewin)
{
static int call_depth = 0;
EWin **lst;
int i, num;
if (call_depth > 256)
return;
call_depth++;
if (EventDebug(EDBUG_TYPE_RAISELOWER))
Eprintf("RaiseEwin(%d) %#lx %s\n", call_depth, ewin->client.win,
EwinGetName(ewin));
if (EoGetWin(ewin))
{
num = EwinListStackRaise(ewin);
if (num == 0) /* Quit if stacking is unchanged */
goto done;
lst = EwinListTransients(ewin, &num, 1);
for (i = 0; i < num; i++)
RaiseEwin(lst[i]);
if (lst)
Efree(lst);
if (call_depth == 1)
{
if (num > 0)
StackDesktop(EoGetDesk(ewin)); /* Do the full stacking */
else
RestackEwin(ewin); /* Restack this one only */
}
}
done:
call_depth--;
}
void
LowerEwin(EWin * ewin)
{
static int call_depth = 0;
EWin **lst;
int i, num;
if (call_depth > 256)
return;
call_depth++;
if (EventDebug(EDBUG_TYPE_RAISELOWER))
Eprintf("LowerEwin(%d) %#lx %s\n", call_depth, ewin->client.win,
EwinGetName(ewin));
if (EoGetWin(ewin))
{
num = EwinListStackLower(ewin);
if (num == 0) /* Quit if stacking is unchanged */
goto done;
lst = EwinListTransientFor(ewin, &num);
for (i = 0; i < num; i++)
LowerEwin(lst[i]);
if (lst)
Efree(lst);
if (call_depth == 1)
{
if (num > 0)
StackDesktop(EoGetDesk(ewin)); /* Do the full stacking */
else
RestackEwin(ewin); /* Restack this one only */
}
}
done:
call_depth--;
}
void
ShowEwin(EWin * ewin)
{
if (ewin->shown)
return;
ewin->shown = 1;
if (ewin->client.win)
{
if (ewin->shaded)
EMoveResizeWindow(ewin->win_container, -30, -30, 1, 1);
EMapWindow(ewin->client.win);
}
if (EoGetWin(ewin))
EMapWindow(EoGetWin(ewin));
}
void
HideEwin(EWin * ewin)
{
if (!ewin->shown || !EwinIsMapped(ewin))
return;
ewin->shown = 0;
if (GetZoomEWin() == ewin)
Zoom(NULL);
EUnmapWindow(ewin->client.win);
if (EoGetWin(ewin))
EUnmapWindow(EoGetWin(ewin));
}
Window
EwinGetClientWin(const EWin * ewin)
{
return (ewin) ? ewin->client.win : None;
}
const char *
EwinGetName(const EWin * ewin)
{
const char *name;
if (!ewin)
return NULL;
#if ENABLE_EWMH
name = ewin->ewmh.wm_name;
if (name)
goto done;
#endif
name = ewin->icccm.wm_name;
if (name)
goto done;
done:
return (name && name[0]) ? name : NULL;
}
const char *
EwinGetIconName(const EWin * ewin)
{
const char *name;
#if ENABLE_EWMH
name = ewin->ewmh.wm_icon_name;
if (name)
goto done;
#endif
name = ewin->icccm.wm_icon_name;
if (name)
goto done;
return EwinGetName(ewin);
done:
return (name && strlen(name)) ? name : NULL;
}
int
EwinIsOnScreen(EWin * ewin)
{
int x, y, w, h;
if (EoIsSticky(ewin))
return 1;
if (EoGetDesk(ewin) != DesksGetCurrent())
return 0;
x = EoGetX(ewin);
y = EoGetY(ewin);
w = EoGetW(ewin);
h = EoGetH(ewin);
if (x + w <= 0 || x >= VRoot.w || y + h <= 0 || y >= VRoot.h)
return 0;
return 1;
}
/*
* Save current position in absolute viewport coordinates
*/
void
EwinRememberPositionSet(EWin * ewin)
{
int ax, ay;
ewin->req_x = EoGetX(ewin);
ewin->req_y = EoGetY(ewin);
if (!EoIsSticky(ewin))
{
DeskGetArea(EoGetDesk(ewin), &ax, &ay);
ewin->req_x += ax * VRoot.w;
ewin->req_y += ay * VRoot.h;
}
}
/*
* Get saved position in relative viewport coordinates
*/
void
EwinRememberPositionGet(EWin * ewin, int *px, int *py)
{
int x, y, ax, ay;
x = ewin->req_x;
y = ewin->req_y;
if (!EoIsSticky(ewin))
{
DeskGetArea(EoGetDesk(ewin), &ax, &ay);
x -= ax * VRoot.w;
y -= ay * VRoot.h;
}
*px = x;
*py = y;
}
/*
* Change requests
*/
static struct
{
unsigned int flags;
EWin ewin_old;
} EWinChanges;
void
EwinChange(EWin * ewin, unsigned int flag)
{
EWinChanges.flags |= flag;
return;
ewin = NULL;
}
void
EwinChangesStart(EWin * ewin)
{
EWinChanges.flags = 0;
/* Brute force :) */
EWinChanges.ewin_old = *ewin;
}
void
EwinChangesProcess(EWin * ewin)
{
if (!EWinChanges.flags)
return;
if (EWinChanges.flags & EWIN_CHANGE_NAME)
{
EwinBorderUpdateInfo(ewin);
EwinBorderCalcSizes(ewin);
}
if (EWinChanges.flags & EWIN_CHANGE_DESKTOP)
{
int desk, pdesk;
desk = EoGetDesk(ewin);
pdesk = EoGetDesk(&EWinChanges.ewin_old);
if (desk != pdesk && !EoIsSticky(ewin))
{
EoSetDesk(ewin, pdesk);
MoveEwinToDesktop(ewin, desk);
}
}
if (EWinChanges.flags & EWIN_CHANGE_ICON_PMAP)
{
ModulesSignal(ESIGNAL_EWIN_CHANGE_ICON, ewin);
}
EWinChanges.flags = 0;
}
void
EwinsEventsConfigure(int mode)
{
EWin *const *lst, *ewin;
int i, num;
lst = EwinListGetAll(&num);
for (i = 0; i < num; i++)
{
ewin = lst[i];
EwinEventsConfigure(lst[i], mode);
/* This is a hack. Maybe we should do something with expose events. */
if (mode)
if (Mode.mode == MODE_DESKSWITCH && EoIsSticky(ewin) && ewin->shown)
EwinRefresh(ewin);
}
}
static void
EwinsTouch(void)
{
int i, num;
EWin *const *lst, *ewin;
lst = EwinListStackGet(&num);
for (i = num - 1; i >= 0; i--)
{
ewin = lst[i];
if (EwinIsMapped(ewin))
MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin));
}
}
void
EwinsSetFree(void)
{
int i, num;
EWin *const *lst, *ewin;
if (EventDebug(EDBUG_TYPE_SESSION))
Eprintf("EwinsSetFree\n");
lst = EwinListStackGet(&num);
for (i = num - 1; i >= 0; i--)
{
ewin = lst[i];
if (EwinIsInternal(ewin))
continue;
if (ewin->iconified)
ICCCM_DeIconify(ewin);
/* This makes E determine the client window stacking at exit */
EwinInstantUnShade(ewin);
EReparentWindow(ewin->client.win, VRoot.win,
ewin->client.x, ewin->client.y);
}
}
/*
* Event handlers
*/
static int
ActionsCheck(const char *which, EWin * ewin, XEvent * ev)
{
ActionClass *ac;
if (Mode.action_inhibit) /* Probably not here */
return 0;
ac = FindItem(which, 0, LIST_FINDBY_NAME, LIST_TYPE_ACLASS);
if (!ac)
return 0;
if (ev->type == ButtonPress)
GrabPointerSet(EoGetWin(ewin), ECSR_GRAB, 0);
else if (ev->type == ButtonRelease)
GrabPointerRelease();
return EventAclass(ev, ewin, ac);
}
#define DEBUG_EWIN_EVENTS 0
static void
EwinHandleEventsToplevel(XEvent * ev, void *prm)
{
EWin *ewin = (EWin *) prm;
switch (ev->type)
{
case ButtonPress:
ActionsCheck("BUTTONBINDINGS", ewin, ev);
break;
case ButtonRelease:
ActionsCheck("BUTTONBINDINGS", ewin, ev);
break;
case EnterNotify:
FocusHandleEnter(ewin, ev);
break;
case LeaveNotify:
FocusHandleLeave(ewin, ev);
break;
case MotionNotify:
break;
default:
#if DEBUG_EWIN_EVENTS
Eprintf("EwinHandleEventsToplevel: type=%2d win=%#lx: %s\n",
ev->type, ewin->client.win, EwinGetName(ewin));
#endif
break;
}
}
static void
EwinHandleEventsContainer(XEvent * ev, void *prm)
{
EWin *ewin = (EWin *) prm;
#if 0
Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n",
ev->type, ewin->client.win, EwinGetName(ewin));
#endif
switch (ev->type)
{
case ButtonPress:
FocusHandleClick(ewin, ev->xany.window);
break;
case MapRequest:
EwinEventMapRequest(ewin, ev->xmaprequest.window);
break;
case ConfigureRequest:
EwinEventConfigureRequest(ewin, ev);
break;
case ResizeRequest:
EwinEventResizeRequest(ewin, ev);
break;
case CirculateRequest:
EwinEventCirculateRequest(ewin, ev);
break;
case DestroyNotify:
EwinEventDestroy(ewin);
break;
case UnmapNotify:
#if 0
if (ewin->state == EWIN_STATE_NEW)
{
Eprintf("EwinEventUnmap %#lx: Ignoring bogus Unmap event\n",
ewin->client.win);
break;
}
#endif
EwinEventUnmap(ewin);
break;
case MapNotify:
EwinEventMap(ewin);
break;
case ReparentNotify:
/* Check if window parent hasn't changed already (compress?) */
if (WinGetParent(ev->xreparent.window) != ev->xreparent.parent)
break;
if (ev->xreparent.parent != ewin->win_container)
EwinEventDestroy(ewin);
break;
case GravityNotify:
case ConfigureNotify:
break;
default:
Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n",
ev->type, ewin->client.win, EwinGetName(ewin));
break;
}
}
static void
EwinHandleEventsClient(XEvent * ev, void *prm)
{
EWin *ewin = (EWin *) prm;
switch (ev->type)
{
case ButtonPress:
case ButtonRelease:
case MotionNotify:
case EnterNotify:
case LeaveNotify:
case FocusIn:
case FocusOut:
case ConfigureNotify:
case GravityNotify:
break;
case VisibilityNotify:
EwinEventVisibility(ewin, ev->xvisibility.state);
break;
#if 0 /* FIXME - Remove? */
case DestroyNotify:
EwinEventDestroy(ewin);
break;
case UnmapNotify:
#if 0
if (ewin->state == EWIN_STATE_NEW)
{
Eprintf("EwinEventUnmap %#lx: Ignoring bogus Unmap event\n",
ewin->client.win);
break;
}
#endif
EwinEventUnmap(ewin);
break;
case MapNotify:
EwinEventMap(ewin);
break;
case ReparentNotify:
/* Check if window parent hasn't changed already (compress?) */
if (WinGetParent(ev->xreparent.window) != ev->xreparent.parent)
break;
if (ev->xreparent.parent == VRoot.win)
EwinEventDestroy(ewin);
break;
#endif
#if 0
case ConfigureRequest:
if (ev->xconfigurerequest.window == ewin->client.win)
EwinEventConfigureRequest(ewin, ev);
break;
case ResizeRequest:
if (ev->xresizerequest.window == ewin->client.win)
EwinEventResizeRequest(ewin, ev);
break;
case CirculateRequest:
EwinEventCirculateRequest(ewin, ev);
break;
#endif
case PropertyNotify:
EwinEventPropertyNotify(ewin, ev);
break;
case EX_EVENT_SHAPE_NOTIFY:
EwinEventShapeChange(ewin);
default:
#if DEBUG_EWIN_EVENTS
Eprintf("EwinHandleEventsClient: type=%2d win=%#lx: %s\n",
ev->type, ewin->client.win, EwinGetName(ewin));
#endif
break;
}
}
static void
EwinHandleEventsRoot(XEvent * ev, void *prm __UNUSED__)
{
EWin *ewin;
switch (ev->type)
{
case EnterNotify:
FocusHandleEnter(NULL, ev);
break;
case LeaveNotify:
FocusHandleLeave(NULL, ev);
break;
case MapRequest:
EwinEventMapRequest(NULL, ev->xmaprequest.window);
break;
case ConfigureRequest:
#if 0
Eprintf("EwinHandleEventsRoot ConfigureRequest %#lx\n",
ev->xconfigurerequest.window);
#endif
ewin = FindItem(NULL, ev->xconfigurerequest.window, LIST_FINDBY_ID,
LIST_TYPE_EWIN);
EwinEventConfigureRequest(ewin, ev);
break;
case ResizeRequest:
#if 0
Eprintf("EwinHandleEventsRoot ResizeRequest %#lx\n",
ev->xresizerequest.window);
#endif
ewin = FindItem(NULL, ev->xresizerequest.window, LIST_FINDBY_ID,
LIST_TYPE_EWIN);
EwinEventResizeRequest(ewin, ev);
break;
case CirculateRequest:
#if 0
Eprintf("EwinHandleEventsRoot CirculateRequest %#lx\n",
ev->xcirculaterequest.window);
#endif
EwinEventCirculateRequest(NULL, ev);
break;
case UnmapNotify:
/* Catch clients unmapped after MapRequest but before being reparented */
ewin = FindItem(NULL, ev->xunmap.window, LIST_FINDBY_ID,
LIST_TYPE_EWIN);
if (ewin)
EwinEventUnmap(ewin);
break;
case DestroyNotify:
/* Catch clients destroyed after MapRequest but before being reparented */
ewin = FindItem(NULL, ev->xdestroywindow.window, LIST_FINDBY_ID,
LIST_TYPE_EWIN);
if (!ewin)
ewin = FindEwinByBase(ev->xdestroywindow.window);
if (ewin)
EwinEventDestroy(ewin);
break;
default:
#if 0
Eprintf("EwinHandleEventsRoot: type=%2d win=%#lx\n",
ev->type, ev->xany.window);
#endif
break;
}
}
static void
EwinsInit(void)
{
EventCallbackRegister(VRoot.win, 0, EwinHandleEventsRoot, NULL);
}
/*
* Ewins module
* This is the WM.
*/
static void
EwinsSighan(int sig, void *prm __UNUSED__)
{
switch (sig)
{
case ESIGNAL_INIT:
EwinsInit();
break;
#if 0
case ESIGNAL_CONFIGURE:
if (!Conf.mapslide || Mode.wm.restart)
MapUnmap(1);
break;
case ESIGNAL_START:
if (Conf.mapslide && !Mode.wm.restart)
MapUnmap(1);
break;
#endif
case ESIGNAL_DESK_RESIZE:
EwinsTouch();
break;
}
}
#if 0
IpcItem EwinsIpcArray[] = {
};
#define N_IPC_FUNCS (sizeof(EwinsIpcArray)/sizeof(IpcItem))
#else
#define N_IPC_FUNCS 0
#define EwinsIpcArray NULL
#endif
/*
* Module descriptor
*/
EModule ModEwins = {
"ewins", NULL,
EwinsSighan,
{N_IPC_FUNCS, EwinsIpcArray}
,
{0, NULL}
};