/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2021 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 #include "E.h" #include "aclass.h" #include "borders.h" #include "buttons.h" #include "cursors.h" #include "desktops.h" #include "emodule.h" #include "eobj.h" #include "ewins.h" #include "grabs.h" #include "list.h" #include "slide.h" #include "xwin.h" #define SLIDEOUT_EVENT_MASK \ (KeyPressMask | KeyReleaseMask | \ ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | \ PointerMotionMask) typedef struct { dlist_t list; EObj o; char *name; char direction; int num_objs; EObj **objs; unsigned int ref_count; EWin *context_ewin; } Slideout; #define DIR_LEFT 0 #define DIR_RIGHT 1 #define DIR_UP 2 #define DIR_DOWN 3 static LIST_HEAD(slideout_list); static struct { Slideout *active; } Mode_slideouts = { NULL }; static void SlideoutHandleEvent(Win win, XEvent * ev, void *prm); static Slideout * SlideoutCreate(const char *name, char dir) { Slideout *s; s = ECALLOC(Slideout, 1); if (!s) return NULL; s->name = Estrdup(name); s->direction = dir; EoInit(s, EOBJ_TYPE_MISC, NoXID, -10, -10, 1, 1, 1, name); EoSetShadow(s, 1); ESelectInput(EoGetWin(s), SLIDEOUT_EVENT_MASK); EventCallbackRegister(EoGetWin(s), SlideoutHandleEvent, s); return s; } static void SlideoutCalcSize(Slideout *s) { int i; int sw, sh, bw, bh; sw = sh = 0; for (i = 0; i < s->num_objs; i++) { bw = EobjGetW(s->objs[i]); bh = EobjGetH(s->objs[i]); switch (s->direction) { case DIR_UP: case DIR_DOWN: if (bw > sw) sw = bw; sh += bh; break; case DIR_LEFT: case DIR_RIGHT: if (bh > sh) sh = bh; sw += bw; break; default: break; } } EoResize(s, sw, sh); } static void SlideoutArrange(Slideout *s, int dir) { int i, x, y; int sw, sh, bw, bh; x = y = 0; sw = EoGetW(s); sh = EoGetH(s); for (i = 0; i < s->num_objs; i++) { bw = EobjGetW(s->objs[i]); bh = EobjGetH(s->objs[i]); switch (dir) { case DIR_UP: y += bh; EMoveWindow(EobjGetWin(s->objs[i]), (sw - bw) >> 1, sh - y); break; case DIR_DOWN: EMoveWindow(EobjGetWin(s->objs[i]), (sw - bw) >> 1, y); y += bh; break; case DIR_LEFT: x += bw; EMoveWindow(EobjGetWin(s->objs[i]), sw - x, (sh - bh) >> 1); break; case DIR_RIGHT: EMoveWindow(EobjGetWin(s->objs[i]), x, (sh - bh) >> 1); x += bw; break; default: break; } } EShapePropagate(EoGetWin(s)); } static void SlideoutShow(Slideout *s, EWin *ewin, Win win) { int x, y, i, xx, yy, sw, sh; int dir; XSetWindowAttributes att; int w, h; Desk *dsk; /* Don't ever show more than one slideout */ if (Mode_slideouts.active) return; SlideoutCalcSize(s); ETranslateCoordinates(win, VROOT, 0, 0, &x, &y, NULL); w = WinGetW(win); h = WinGetH(win); sw = EoGetW(s); sh = EoGetH(s); xx = 0; yy = 0; dir = s->direction; switch (dir) { case DIR_UP: xx = x + ((w - sw) >> 1); yy = y - sh; if (yy < 0 && WinGetH(VROOT) - (y + h) > y) { dir = DIR_DOWN; yy = y + h; } break; case DIR_DOWN: xx = x + ((w - sw) >> 1); yy = y + h; if (yy + sh > WinGetH(VROOT) && WinGetH(VROOT) - (y + h) < y) { dir = DIR_UP; yy = y - sh; } break; case DIR_LEFT: xx = x - sw; yy = y + ((h - sh) >> 1); if (xx < 0 && WinGetW(VROOT) - (x + w) > x) { dir = DIR_RIGHT; xx = x + w; } break; case DIR_RIGHT: xx = x + w; yy = y + ((h - sh) >> 1); if (xx + sw > WinGetW(VROOT) && WinGetW(VROOT) - (x + w) < x) { dir = DIR_LEFT; xx = x - sw; } break; default: break; } SlideoutArrange(s, dir); if (ewin) { /* If the slideout is associated with an ewin, * put it on the same virtual desktop. */ dsk = EoGetDesk(ewin); if (BorderWinpartIndex(ewin, win) >= 0 && !EoIsFloating(ewin) /* && !ewin->sticky */ ) { xx -= EoGetX(dsk); yy -= EoGetY(dsk); } EoSetLayer(s, EoGetLayer(ewin)); } else { dsk = DeskGet(0); EoSetLayer(s, 10); EoSetFloating(s, 1); } EoReparent(s, EoObj(dsk), xx, yy); switch (dir) { case DIR_LEFT: att.win_gravity = SouthEastGravity; EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att); att.win_gravity = NorthWestGravity; for (i = 0; i < s->num_objs; i++) EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att); EoMoveResize(s, xx, yy, 1, 1); ESync(ESYNC_SLIDEOUT); EoMap(s, 2); EobjSlideSizeTo(EoObj(s), xx + sw, yy, xx, yy, 1, sh, sw, sh, Conf.shading.speed); break; case DIR_RIGHT: att.win_gravity = NorthWestGravity; EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att); att.win_gravity = SouthEastGravity; for (i = 0; i < s->num_objs; i++) EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att); EoMoveResize(s, xx, yy, 1, 1); ESync(ESYNC_SLIDEOUT); EoMap(s, 2); EobjSlideSizeTo(EoObj(s), xx, yy, xx, yy, 1, sh, sw, sh, Conf.shading.speed); break; case DIR_UP: att.win_gravity = SouthEastGravity; EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att); att.win_gravity = NorthWestGravity; for (i = 0; i < s->num_objs; i++) EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att); EoMoveResize(s, xx, yy, 1, 1); ESync(ESYNC_SLIDEOUT); EoMap(s, 2); EobjSlideSizeTo(EoObj(s), xx, yy + sh, xx, yy, sw, 1, sw, sh, Conf.shading.speed); break; case DIR_DOWN: att.win_gravity = NorthWestGravity; EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att); att.win_gravity = SouthEastGravity; for (i = 0; i < s->num_objs; i++) EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att); EoMoveResize(s, xx, yy, 1, 1); ESync(ESYNC_SLIDEOUT); EoMap(s, 2); EobjSlideSizeTo(EoObj(s), xx, yy, xx, yy, sw, 1, sw, sh, Conf.shading.speed); break; default: break; } s->ref_count++; s->context_ewin = ewin; GrabPointerSet(EoGetWin(s), ECSR_ROOT, 0); Mode_slideouts.active = s; } static void SlideoutHide(Slideout *s) { if (!s) return; GrabPointerRelease(); EoUnmap(s); s->context_ewin = NULL; s->ref_count--; Mode_slideouts.active = NULL; } static void SlideoutButtonCallback(void *prm, XEvent *ev, ActionClass *ac) { Slideout *s = (Slideout *) prm; EWin *ewin = s->context_ewin; if (ev->type == ButtonRelease) SlideoutHide(s); if (ac) ActionclassEvent(ac, ev, ewin); } static void SlideoutAddButton(Slideout *s, const char *bname) { Button *b; if (!s) return; b = ButtonFind(bname); if (!b) return; s->num_objs++; s->objs = EREALLOC(EObj *, s->objs, s->num_objs); s->objs[s->num_objs - 1] = ButtonSwallowInto(b, EoObj(s)); ButtonSetCallback(b, SlideoutButtonCallback, s); } #if 0 static void SlideoutRemoveButton(Slideout *s, Button *b) { s = NULL; b = NULL; } #endif static void SlideoutHandleEvent(Win win __UNUSED__, XEvent *ev, void *prm) { Slideout *s = (Slideout *) prm; switch (ev->type) { case KeyPress: case KeyRelease: SlideoutHide(s); break; case ButtonPress: break; case ButtonRelease: SlideoutHide(s); break; case EnterNotify: if (ev->xcrossing.mode != NotifyGrab) GrabPointerRelease(); break; case LeaveNotify: if (ev->xcrossing.mode != NotifyUngrab) GrabPointerSet(EoGetWin(s), ECSR_ROOT, 0); break; } } static void SlideoutsHide(void) { if (Mode_slideouts.active) SlideoutHide(Mode_slideouts.active); } /* * Configuration load/save */ #include "conf.h" int SlideoutsConfigLoad(FILE *fs) { int err = 0; Slideout *slideout = 0; int i1; char s[FILEPATH_LEN_MAX]; char s2[FILEPATH_LEN_MAX]; char name[FILEPATH_LEN_MAX]; name[0] = '\0'; while (GetLine(s, sizeof(s), fs)) { i1 = ConfigParseline1(s, s2, NULL, NULL); switch (i1) { case CONFIG_CLOSE: if (slideout) LIST_PREPEND(Slideout, &slideout_list, slideout); goto done; case CONFIG_CLASSNAME: strcpy(name, s2); break; case SLIDEOUT_DIRECTION: slideout = SlideoutCreate(name, (char)atoi(s2)); break; case CONFIG_BUTTON: SlideoutAddButton(slideout, s2); break; default: ConfigParseError("Slideout", s); break; } } err = -1; done: return err; } /* * Slideouts Module */ static void SlideoutsSighan(int sig, void *prm) { switch (sig) { case ESIGNAL_AREA_SWITCH_START: case ESIGNAL_DESK_SWITCH_START: SlideoutsHide(); break; case ESIGNAL_EWIN_UNMAP: if (Mode_slideouts.active && Mode_slideouts.active->context_ewin == (EWin *) prm) SlideoutsHide(); break; } } static int _SlideoutMatchName(const void *data, const void *match) { return strcmp(((const Slideout *)data)->name, (const char *)match); } static Slideout * SlideoutFind(const char *name) { return LIST_FIND(Slideout, &slideout_list, _SlideoutMatchName, name); } static void IPC_Slideout(const char *params) { Slideout *s; if (!params) return; s = SlideoutFind(params); if (!s) return; SoundPlay(SOUND_SLIDEOUT_SHOW); SlideoutShow(s, GetContextEwin(), Mode.context_win); } static const IpcItem SlideoutsIpcArray[] = { { IPC_Slideout, "slideout", NULL, "Show slideout", NULL }, }; /* * Module descriptor */ extern const EModule ModSlideouts; const EModule ModSlideouts = { "slideouts", "slideout", SlideoutsSighan, MOD_ITEMS(SlideoutsIpcArray), { 0, NULL } };