1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 Kim Woelders
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "config.h"
25
26 #include <X11/Xlib.h>
27
28 #include "E.h"
29 #include "aclass.h"
30 #include "borders.h"
31 #include "buttons.h"
32 #include "cursors.h"
33 #include "desktops.h"
34 #include "emodule.h"
35 #include "eobj.h"
36 #include "ewins.h"
37 #include "grabs.h"
38 #include "list.h"
39 #include "slide.h"
40 #include "xwin.h"
41
42 #define SLIDEOUT_EVENT_MASK \
43 (KeyPressMask | KeyReleaseMask | \
44 ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | \
45 PointerMotionMask)
46
47 typedef struct {
48 dlist_t list;
49 EObj o;
50 char *name;
51 char direction;
52 int num_objs;
53 EObj **objs;
54 unsigned int ref_count;
55 EWin *context_ewin;
56 } Slideout;
57
58 #define DIR_LEFT 0
59 #define DIR_RIGHT 1
60 #define DIR_UP 2
61 #define DIR_DOWN 3
62
63 static LIST_HEAD(slideout_list);
64
65 static struct {
66 Slideout *active;
67 } Mode_slideouts = {
68 NULL
69 };
70
71 static void SlideoutHandleEvent(Win win, XEvent * ev, void *prm);
72
73 static Slideout *
SlideoutCreate(const char * name,char dir)74 SlideoutCreate(const char *name, char dir)
75 {
76 Slideout *s;
77
78 s = ECALLOC(Slideout, 1);
79 if (!s)
80 return NULL;
81
82 s->name = Estrdup(name);
83 s->direction = dir;
84
85 EoInit(s, EOBJ_TYPE_MISC, NoXID, -10, -10, 1, 1, 1, name);
86 EoSetShadow(s, 1);
87 ESelectInput(EoGetWin(s), SLIDEOUT_EVENT_MASK);
88 EventCallbackRegister(EoGetWin(s), SlideoutHandleEvent, s);
89
90 return s;
91 }
92
93 static void
SlideoutCalcSize(Slideout * s)94 SlideoutCalcSize(Slideout * s)
95 {
96 int i;
97 int sw, sh, bw, bh;
98
99 sw = sh = 0;
100 for (i = 0; i < s->num_objs; i++)
101 {
102 bw = EobjGetW(s->objs[i]);
103 bh = EobjGetH(s->objs[i]);
104
105 switch (s->direction)
106 {
107 case DIR_UP:
108 case DIR_DOWN:
109 if (bw > sw)
110 sw = bw;
111 sh += bh;
112 break;
113 case DIR_LEFT:
114 case DIR_RIGHT:
115 if (bh > sh)
116 sh = bh;
117 sw += bw;
118 break;
119 default:
120 break;
121 }
122 }
123
124 EoResize(s, sw, sh);
125 }
126
127 static void
SlideoutArrange(Slideout * s,int dir)128 SlideoutArrange(Slideout * s, int dir)
129 {
130 int i, x, y;
131 int sw, sh, bw, bh;
132
133 x = y = 0;
134 sw = EoGetW(s);
135 sh = EoGetH(s);
136
137 for (i = 0; i < s->num_objs; i++)
138 {
139 bw = EobjGetW(s->objs[i]);
140 bh = EobjGetH(s->objs[i]);
141
142 switch (dir)
143 {
144 case DIR_UP:
145 y += bh;
146 EMoveWindow(EobjGetWin(s->objs[i]), (sw - bw) >> 1, sh - y);
147 break;
148 case DIR_DOWN:
149 EMoveWindow(EobjGetWin(s->objs[i]), (sw - bw) >> 1, y);
150 y += bh;
151 break;
152 case DIR_LEFT:
153 x += bw;
154 EMoveWindow(EobjGetWin(s->objs[i]), sw - x, (sh - bh) >> 1);
155 break;
156 case DIR_RIGHT:
157 EMoveWindow(EobjGetWin(s->objs[i]), x, (sh - bh) >> 1);
158 x += bw;
159 break;
160 default:
161 break;
162 }
163 }
164 EShapePropagate(EoGetWin(s));
165 }
166
167 static void
SlideoutShow(Slideout * s,EWin * ewin,Win win)168 SlideoutShow(Slideout * s, EWin * ewin, Win win)
169 {
170 int x, y, i, xx, yy, sw, sh;
171 int dir;
172 XSetWindowAttributes att;
173 int w, h;
174 Desk *dsk;
175
176 /* Don't ever show more than one slideout */
177 if (Mode_slideouts.active)
178 return;
179
180 SlideoutCalcSize(s);
181 ETranslateCoordinates(win, VROOT, 0, 0, &x, &y, NULL);
182
183 w = WinGetW(win);
184 h = WinGetH(win);
185 sw = EoGetW(s);
186 sh = EoGetH(s);
187 xx = 0;
188 yy = 0;
189
190 dir = s->direction;
191 switch (dir)
192 {
193 case DIR_UP:
194 xx = x + ((w - sw) >> 1);
195 yy = y - sh;
196 if (yy < 0 && WinGetH(VROOT) - (y + h) > y)
197 {
198 dir = DIR_DOWN;
199 yy = y + h;
200 }
201 break;
202 case DIR_DOWN:
203 xx = x + ((w - sw) >> 1);
204 yy = y + h;
205 if (yy + sh > WinGetH(VROOT) && WinGetH(VROOT) - (y + h) < y)
206 {
207 dir = DIR_UP;
208 yy = y - sh;
209 }
210 break;
211 case DIR_LEFT:
212 xx = x - sw;
213 yy = y + ((h - sh) >> 1);
214 if (xx < 0 && WinGetW(VROOT) - (x + w) > x)
215 {
216 dir = DIR_RIGHT;
217 xx = x + w;
218 }
219 break;
220 case DIR_RIGHT:
221 xx = x + w;
222 yy = y + ((h - sh) >> 1);
223 if (xx + sw > WinGetW(VROOT) && WinGetW(VROOT) - (x + w) < x)
224 {
225 dir = DIR_LEFT;
226 xx = x - sw;
227 }
228 break;
229 default:
230 break;
231 }
232
233 SlideoutArrange(s, dir);
234
235 if (ewin)
236 {
237 /* If the slideout is associated with an ewin,
238 * put it on the same virtual desktop. */
239 dsk = EoGetDesk(ewin);
240 if (BorderWinpartIndex(ewin, win) >= 0 &&
241 !EoIsFloating(ewin) /* && !ewin->sticky */ )
242 {
243 xx -= EoGetX(dsk);
244 yy -= EoGetY(dsk);
245 }
246 EoSetLayer(s, EoGetLayer(ewin));
247 }
248 else
249 {
250 dsk = DeskGet(0);
251 EoSetLayer(s, 10);
252 EoSetFloating(s, 1);
253 }
254 EoReparent(s, EoObj(dsk), xx, yy);
255
256 switch (dir)
257 {
258 case DIR_LEFT:
259 att.win_gravity = SouthEastGravity;
260 EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att);
261 att.win_gravity = NorthWestGravity;
262 for (i = 0; i < s->num_objs; i++)
263 EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att);
264 EoMoveResize(s, xx, yy, 1, 1);
265 ESync(ESYNC_SLIDEOUT);
266 EoMap(s, 2);
267 EobjSlideSizeTo(EoObj(s), xx + sw, yy, xx, yy, 1, sh, sw, sh,
268 Conf.shading.speed);
269 break;
270 case DIR_RIGHT:
271 att.win_gravity = NorthWestGravity;
272 EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att);
273 att.win_gravity = SouthEastGravity;
274 for (i = 0; i < s->num_objs; i++)
275 EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att);
276 EoMoveResize(s, xx, yy, 1, 1);
277 ESync(ESYNC_SLIDEOUT);
278 EoMap(s, 2);
279 EobjSlideSizeTo(EoObj(s), xx, yy, xx, yy, 1, sh, sw, sh,
280 Conf.shading.speed);
281 break;
282 case DIR_UP:
283 att.win_gravity = SouthEastGravity;
284 EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att);
285 att.win_gravity = NorthWestGravity;
286 for (i = 0; i < s->num_objs; i++)
287 EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att);
288 EoMoveResize(s, xx, yy, 1, 1);
289 ESync(ESYNC_SLIDEOUT);
290 EoMap(s, 2);
291 EobjSlideSizeTo(EoObj(s), xx, yy + sh, xx, yy, sw, 1, sw, sh,
292 Conf.shading.speed);
293 break;
294 case DIR_DOWN:
295 att.win_gravity = NorthWestGravity;
296 EChangeWindowAttributes(EoGetWin(s), CWWinGravity, &att);
297 att.win_gravity = SouthEastGravity;
298 for (i = 0; i < s->num_objs; i++)
299 EChangeWindowAttributes(EobjGetWin(s->objs[i]), CWWinGravity, &att);
300 EoMoveResize(s, xx, yy, 1, 1);
301 ESync(ESYNC_SLIDEOUT);
302 EoMap(s, 2);
303 EobjSlideSizeTo(EoObj(s), xx, yy, xx, yy, sw, 1, sw, sh,
304 Conf.shading.speed);
305 break;
306 default:
307 break;
308 }
309 s->ref_count++;
310 s->context_ewin = ewin;
311
312 GrabPointerSet(EoGetWin(s), ECSR_ROOT, 0);
313
314 Mode_slideouts.active = s;
315 }
316
317 static void
SlideoutHide(Slideout * s)318 SlideoutHide(Slideout * s)
319 {
320 if (!s)
321 return;
322
323 GrabPointerRelease();
324 EoUnmap(s);
325 s->context_ewin = NULL;
326 s->ref_count--;
327 Mode_slideouts.active = NULL;
328 }
329
330 static void
SlideoutButtonCallback(void * prm,XEvent * ev,ActionClass * ac)331 SlideoutButtonCallback(void *prm, XEvent * ev, ActionClass * ac)
332 {
333 Slideout *s = (Slideout *) prm;
334 EWin *ewin = s->context_ewin;
335
336 if (ev->type == ButtonRelease)
337 SlideoutHide(s);
338
339 if (ac)
340 ActionclassEvent(ac, ev, ewin);
341 }
342
343 static void
SlideoutAddButton(Slideout * s,const char * bname)344 SlideoutAddButton(Slideout * s, const char *bname)
345 {
346 Button *b;
347
348 if (!s)
349 return;
350
351 b = ButtonFind(bname);
352 if (!b)
353 return;
354
355 s->num_objs++;
356 s->objs = EREALLOC(EObj *, s->objs, s->num_objs);
357 s->objs[s->num_objs - 1] = ButtonSwallowInto(b, EoObj(s));
358 ButtonSetCallback(b, SlideoutButtonCallback, s);
359 }
360
361 #if 0
362 static void
363 SlideoutRemoveButton(Slideout * s, Button * b)
364 {
365 s = NULL;
366 b = NULL;
367 }
368 #endif
369
370 static void
SlideoutHandleEvent(Win win __UNUSED__,XEvent * ev,void * prm)371 SlideoutHandleEvent(Win win __UNUSED__, XEvent * ev, void *prm)
372 {
373 Slideout *s = (Slideout *) prm;
374
375 switch (ev->type)
376 {
377 case KeyPress:
378 case KeyRelease:
379 SlideoutHide(s);
380 break;
381 case ButtonPress:
382 break;
383 case ButtonRelease:
384 SlideoutHide(s);
385 break;
386 case EnterNotify:
387 if (ev->xcrossing.mode != NotifyGrab)
388 GrabPointerRelease();
389 break;
390 case LeaveNotify:
391 if (ev->xcrossing.mode != NotifyUngrab)
392 GrabPointerSet(EoGetWin(s), ECSR_ROOT, 0);
393 break;
394 }
395 }
396
397 static void
SlideoutsHide(void)398 SlideoutsHide(void)
399 {
400 if (Mode_slideouts.active)
401 SlideoutHide(Mode_slideouts.active);
402 }
403
404 /*
405 * Configuration load/save
406 */
407 #include "conf.h"
408
409 int
SlideoutsConfigLoad(FILE * fs)410 SlideoutsConfigLoad(FILE * fs)
411 {
412 int err = 0;
413 Slideout *slideout = 0;
414 int i1;
415 char s[FILEPATH_LEN_MAX];
416 char s2[FILEPATH_LEN_MAX];
417 char name[FILEPATH_LEN_MAX];
418
419 name[0] = '\0';
420
421 while (GetLine(s, sizeof(s), fs))
422 {
423 i1 = ConfigParseline1(s, s2, NULL, NULL);
424 switch (i1)
425 {
426 case CONFIG_CLOSE:
427 if (slideout)
428 LIST_PREPEND(Slideout, &slideout_list, slideout);
429 goto done;
430 case CONFIG_CLASSNAME:
431 strcpy(name, s2);
432 break;
433 case SLIDEOUT_DIRECTION:
434 slideout = SlideoutCreate(name, (char)atoi(s2));
435 break;
436 case CONFIG_BUTTON:
437 SlideoutAddButton(slideout, s2);
438 break;
439 default:
440 ConfigParseError("Slideout", s);
441 break;
442 }
443 }
444 err = -1;
445
446 done:
447 return err;
448 }
449
450 /*
451 * Slideouts Module
452 */
453
454 static void
SlideoutsSighan(int sig,void * prm)455 SlideoutsSighan(int sig, void *prm)
456 {
457 switch (sig)
458 {
459 case ESIGNAL_AREA_SWITCH_START:
460 case ESIGNAL_DESK_SWITCH_START:
461 SlideoutsHide();
462 break;
463
464 case ESIGNAL_EWIN_UNMAP:
465 if (Mode_slideouts.active
466 && Mode_slideouts.active->context_ewin == (EWin *) prm)
467 SlideoutsHide();
468 break;
469 }
470 }
471
472 static int
_SlideoutMatchName(const void * data,const void * match)473 _SlideoutMatchName(const void *data, const void *match)
474 {
475 return strcmp(((const Slideout *)data)->name, (const char *)match);
476 }
477
478 static Slideout *
SlideoutFind(const char * name)479 SlideoutFind(const char *name)
480 {
481 return LIST_FIND(Slideout, &slideout_list, _SlideoutMatchName, name);
482 }
483
484 static void
IPC_Slideout(const char * params)485 IPC_Slideout(const char *params)
486 {
487 Slideout *s;
488
489 if (!params)
490 return;
491
492 s = SlideoutFind(params);
493 if (!s)
494 return;
495
496 SoundPlay(SOUND_SLIDEOUT_SHOW);
497 SlideoutShow(s, GetContextEwin(), Mode.context_win);
498 }
499
500 static const IpcItem SlideoutsIpcArray[] = {
501 {
502 IPC_Slideout, "slideout", NULL, "Show slideout", NULL},
503 };
504
505 /*
506 * Module descriptor
507 */
508 extern const EModule ModSlideouts;
509
510 const EModule ModSlideouts = {
511 "slideouts", "slideout",
512 SlideoutsSighan,
513 MOD_ITEMS(SlideoutsIpcArray),
514 {0, NULL}
515 };
516