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 <time.h>
27 #include <X11/Xlib.h>
28 #if USE_XRANDR
29 #include <X11/extensions/Xrandr.h>
30 #endif
31
32 #include "E.h"
33 #include "aclass.h"
34 #include "animation.h"
35 #include "backgrounds.h"
36 #include "buttons.h"
37 #include "desktops.h"
38 #include "dialog.h"
39 #include "ecompmgr.h"
40 #include "emodule.h"
41 #include "eobj.h"
42 #include "events.h"
43 #include "ewins.h"
44 #include "focus.h"
45 #include "grabs.h"
46 #include "hints.h"
47 #include "iclass.h"
48 #include "screen.h"
49 #include "settings.h"
50 #include "slide.h"
51 #include "timers.h"
52 #include "tooltips.h"
53 #include "xprop.h"
54 #include "xwin.h"
55
56 #define DESK_EVENT_MASK1 \
57 (ButtonPressMask | ButtonReleaseMask)
58 #define DESK_EVENT_MASK2 \
59 (EnterWindowMask | LeaveWindowMask | \
60 SubstructureNotifyMask | SubstructureRedirectMask | PropertyChangeMask)
61
62 #define DESK_EVENT_MASK (DESK_EVENT_MASK1 | DESK_EVENT_MASK2)
63
64 #define ENLIGHTENMENT_CONF_NUM_DESKTOPS 32
65
66 typedef struct {
67 Desk *current;
68 Desk *previous;
69 Desk *desk[ENLIGHTENMENT_CONF_NUM_DESKTOPS];
70 unsigned int order[ENLIGHTENMENT_CONF_NUM_DESKTOPS];
71 int drag_x0, drag_y0;
72 unsigned int prev_num;
73 Animator *anim_slide;
74 } Desktops;
75
76 static void DeskRaise(unsigned int num);
77 static void DeskLower(unsigned int num);
78 static void DeskHandleEvents(Win win, XEvent * ev, void *prm);
79 static void DeskButtonCallback(void *prm, XEvent * ev,
80 ActionClass * ac);
81
82 /* The desktops */
83 static Desktops desks;
84
85 #define _DeskGet(d) (desks.desk[d])
86
87 static void
DeskControlsCreate(Desk * dsk)88 DeskControlsCreate(Desk * dsk)
89 {
90 char s[512];
91 const char *ic1, *ic2, *ic3;
92
93 #if ENABLE_DESKRAY
94 const char *ic4;
95 #endif
96 char ac1[64], ac2[64], ac3[64];
97 Button *b;
98 ActionClass *ac;
99 Action *a;
100 int x[3], y[3], w[3], h[3], m, n, o;
101 const char *t;
102
103 if (Conf.desks.dragdir < 0 || Conf.desks.dragdir > 3)
104 Conf.desks.dragdir = 2;
105 if (Conf.desks.dragbar_ordering < 0 || Conf.desks.dragbar_ordering > 5)
106 Conf.desks.dragbar_ordering = 1;
107 if (Conf.desks.dragbar_width < 0)
108 Conf.desks.dragbar_width = 0;
109 else if (Conf.desks.dragbar_width > 64)
110 Conf.desks.dragbar_width = 64;
111 if (Conf.desks.dragbar_length < 0)
112 Conf.desks.dragbar_length = 0;
113 else if (Conf.desks.dragbar_length > WinGetW(VROOT))
114 Conf.desks.dragbar_length = WinGetW(VROOT);
115
116 Esnprintf(ac1, sizeof(ac1), "DRAGBAR_DESKTOP_%i", dsk->num);
117 if (!ActionclassFind(ac1))
118 {
119 ac = ActionclassCreate(ac1, 0);
120 a = ActionCreate(EVENT_MOUSE_DOWN, 0, 0, 0, 1, 0, NULL, NULL);
121 ActionclassAddAction(ac, a);
122
123 Esnprintf(s, sizeof(s), "desk drag %i", dsk->num);
124 ActionAddTo(a, s);
125
126 a = ActionCreate(EVENT_MOUSE_DOWN, 0, 0, 0, 3, 0, NULL, NULL);
127 ActionclassAddAction(ac, a);
128 ActionAddTo(a, "menus show deskmenu");
129
130 a = ActionCreate(EVENT_MOUSE_DOWN, 0, 0, 0, 2, 0, NULL, NULL);
131 ActionclassAddAction(ac, a);
132 ActionAddTo(a, "menus show windowlist");
133
134 if (dsk->num > 0)
135 {
136 t = _("Hold down the mouse button and drag\n"
137 "the mouse to be able to drag the desktop\n"
138 "back and forth.\n"
139 "Click right mouse button for a list of all\n"
140 "Desktops and their applications.\n"
141 "Click middle mouse button for a list of all\n"
142 "applications currently running.\n");
143 ActionclassSetTooltipString(ac, t);
144 }
145 else
146 {
147 t = _("This is the Root desktop.\n"
148 "You cannot drag the root desktop around.\n"
149 "Click right mouse button for a list of all\n"
150 "Desktops and their applications.\n"
151 "Click middle mouse button for a list of all\n"
152 "applications currently running.\n");
153 ActionclassSetTooltipString(ac, t);
154 }
155 }
156
157 Esnprintf(ac2, sizeof(ac2), "RAISEBUTTON_DESKTOP_%i", dsk->num);
158 if (!ActionclassFind(ac2))
159 {
160 ac = ActionclassCreate(ac2, 0);
161 a = ActionCreate(EVENT_MOUSE_UP, 1, 0, 1, 0, 0, NULL, NULL);
162 ActionclassAddAction(ac, a);
163
164 ActionAddTo(a, "desk next");
165 t = _("Click here to raise this desktop\nto the top.");
166 ActionclassSetTooltipString(ac, t);
167 }
168
169 Esnprintf(ac3, sizeof(ac3), "LOWERBUTTON_DESKTOP_%i", dsk->num);
170 if (!ActionclassFind(ac3))
171 {
172 ac = ActionclassCreate(ac3, 0);
173 a = ActionCreate(EVENT_MOUSE_UP, 1, 0, 1, 0, 0, NULL, NULL);
174 ActionclassAddAction(ac, a);
175
176 ActionAddTo(a, "desk prev");
177 t = _("Click here to lower this desktop\nto the bottom.");
178 ActionclassSetTooltipString(ac, t);
179 }
180
181 if (Conf.desks.dragdir < 2)
182 {
183 ic1 = "DESKTOP_DRAGBUTTON_VERT";
184 ic2 = "DESKTOP_RAISEBUTTON_VERT";
185 ic3 = "DESKTOP_LOWERBUTTON_VERT";
186 #if ENABLE_DESKRAY
187 ic4 = "DESKTOP_DESKRAY_VERT";
188 #endif
189 }
190 else
191 {
192 ic1 = "DESKTOP_DRAGBUTTON_HORIZ";
193 ic2 = "DESKTOP_RAISEBUTTON_HORIZ";
194 ic3 = "DESKTOP_LOWERBUTTON_HORIZ";
195 #if ENABLE_DESKRAY
196 ic4 = "DESKTOP_DESKRAY_HORIZ";
197 #endif
198 }
199
200 switch (Conf.desks.dragbar_ordering)
201 {
202 case 0:
203 m = 0;
204 n = 1;
205 o = 2;
206 break;
207 case 1:
208 m = 0;
209 n = 2;
210 o = 1;
211 break;
212 case 2:
213 m = 2;
214 n = 0;
215 o = 1;
216 break;
217 case 3:
218 m = 1;
219 n = 0;
220 o = 2;
221 break;
222 case 4:
223 m = 1;
224 n = 2;
225 o = 0;
226 break;
227 case 5:
228 m = 2;
229 n = 1;
230 o = 0;
231 break;
232 default:
233 m = 0;
234 n = 1;
235 o = 2;
236 break;
237 }
238
239 switch (Conf.desks.dragdir)
240 {
241 default:
242 case 0:
243 w[0] = w[1] = w[2] = h[0] = h[1] = Conf.desks.dragbar_width;
244 if (Conf.desks.dragbar_length == 0)
245 h[2] = WinGetH(VROOT) - (Conf.desks.dragbar_width * 2);
246 else
247 h[2] = Conf.desks.dragbar_length;
248 x[0] = x[1] = x[2] = 0;
249 y[m] = 0;
250 y[n] = y[m] + h[m];
251 y[o] = y[n] + h[n];
252 break;
253 case 1:
254 w[0] = w[1] = w[2] = h[0] = h[1] = Conf.desks.dragbar_width;
255 if (Conf.desks.dragbar_length == 0)
256 h[2] = WinGetH(VROOT) - (Conf.desks.dragbar_width * 2);
257 else
258 h[2] = Conf.desks.dragbar_length;
259 x[0] = x[1] = x[2] = WinGetW(VROOT) - Conf.desks.dragbar_width;
260 y[m] = 0;
261 y[n] = y[m] + h[m];
262 y[o] = y[n] + h[n];
263 break;
264 case 2:
265 h[0] = h[1] = h[2] = w[0] = w[1] = Conf.desks.dragbar_width;
266 if (Conf.desks.dragbar_length == 0)
267 w[2] = WinGetW(VROOT) - (Conf.desks.dragbar_width * 2);
268 else
269 w[2] = Conf.desks.dragbar_length;
270 y[0] = y[1] = y[2] = 0;
271 x[m] = 0;
272 x[n] = x[m] + w[m];
273 x[o] = x[n] + w[n];
274 break;
275 case 3:
276 h[0] = h[1] = h[2] = w[0] = w[1] = Conf.desks.dragbar_width;
277 if (Conf.desks.dragbar_length == 0)
278 w[2] = WinGetW(VROOT) - (Conf.desks.dragbar_width * 2);
279 else
280 w[2] = Conf.desks.dragbar_length;
281 y[0] = y[1] = y[2] = WinGetH(VROOT) - Conf.desks.dragbar_width;
282 x[m] = 0;
283 x[n] = x[m] + w[m];
284 x[o] = x[n] + w[n];
285 break;
286 }
287
288 b = NULL;
289
290 if (Conf.desks.dragbar_width > 0)
291 {
292 ButtonCreate("_DESKTOP_DRAG_CONTROL", 1, ic2, ac2, NULL, NULL,
293 -1, FLAG_FIXED, 1, 99999, 1, 99999, 0, 0, x[0], 0,
294 y[0], 0, 0, w[0], 0, h[0], 0, dsk->num, 0);
295 ButtonCreate("_DESKTOP_DRAG_CONTROL", 1, ic3, ac3, NULL, NULL,
296 -1, FLAG_FIXED, 1, 99999, 1, 99999, 0, 0, x[1], 0,
297 y[1], 0, 0, w[1], 0, h[1], 0, dsk->num, 0);
298 b = ButtonCreate("_DESKTOP_DRAG_CONTROL", 1, ic1, ac1, NULL, NULL,
299 -1, FLAG_FIXED, 1, 99999, 1, 99999, 0, 0, x[2], 0,
300 y[2], 0, 0, w[2], 0, h[2], 0, dsk->num, 0);
301 ButtonSetCallback(b, DeskButtonCallback, dsk);
302 }
303
304 #if ENABLE_DESKRAY
305 if (dsk->num > 0)
306 {
307 if (Conf.desks.dragdir == 0)
308 {
309 b = ButtonCreate("_DESKTOP_DESKRAY_DRAG_CONTROL", 2, ic4, ac1,
310 NULL, NULL, 1, FLAG_FIXED_VERT, 1, 99999, 1,
311 99999, 0, 0, EoGetX(dsk), 0, EoGetY(dsk),
312 0, 0, 0, 0, 0, 1, 0, 1);
313 }
314 else if (Conf.desks.dragdir == 1)
315 {
316 b = ButtonCreate("_DESKTOP_DESKRAY_DRAG_CONTROL", 2, ic4, ac1,
317 NULL, NULL, 1, FLAG_FIXED_VERT, 1, 99999, 1,
318 99999, 0, 0,
319 EoGetX(dsk) + WinGetW(VROOT) -
320 Conf.desks.dragbar_width, 0, EoGetY(dsk),
321 0, 0, 0, 0, 0, 1, 0, 1);
322 }
323 else if (Conf.desks.dragdir == 2)
324 {
325 b = ButtonCreate("_DESKTOP_DESKRAY_DRAG_CONTROL", 2, ic4, ac1,
326 NULL, NULL, 1, FLAG_FIXED_HORIZ, 1, 99999, 1,
327 99999, 0, 0, EoGetX(dsk), 0, EoGetY(dsk),
328 0, 0, 0, 0, 0, 1, 0, 1);
329 }
330 else
331 {
332 b = ButtonCreate("_DESKTOP_DESKRAY_DRAG_CONTROL", 2, ic4, ac1,
333 NULL, NULL, 1, FLAG_FIXED_HORIZ, 1, 99999, 1,
334 99999, 0, 0, EoGetX(dsk), 0,
335 EoGetY(dsk) + WinGetH(VROOT) -
336 Conf.desks.dragbar_width, 0, 0, 0, 0, 0, 1, 0, 1);
337 }
338 }
339 #endif
340
341 dsk->tag = b;
342 }
343
344 static void
DeskControlsDestroy(Desk * dsk,int id)345 DeskControlsDestroy(Desk * dsk, int id)
346 {
347 ButtonsForeach(id, dsk, ButtonDestroy);
348 }
349
350 static void
DeskControlsShow(Desk * dsk,int id)351 DeskControlsShow(Desk * dsk, int id)
352 {
353 ButtonsForeach(id, dsk, ButtonShow);
354 }
355
356 static void
DeskConfigure(Desk * dsk)357 DeskConfigure(Desk * dsk)
358 {
359 Background *bg;
360
361 DeskControlsCreate(dsk);
362 DeskControlsShow(dsk, 1);
363
364 bg = BackgroundGetForDesk(dsk->num);
365 DeskBackgroundSet(dsk, bg);
366
367 dsk->bg.pixel = 0xffffffff;
368
369 if (dsk->num > 0)
370 {
371 EoMove(dsk, WinGetW(VROOT), 0);
372 EoMap(dsk, 0);
373 }
374
375 ModulesSignal(ESIGNAL_DESK_ADDED, dsk);
376 }
377
378 static Desk *
DeskCreate(int desk,int configure)379 DeskCreate(int desk, int configure)
380 {
381 #if USE_COMPOSITE
382 EObj *eo;
383 #endif
384 Desk *dsk;
385 Win win;
386 char buf[64];
387
388 if (desk < 0 || desk >= ENLIGHTENMENT_CONF_NUM_DESKTOPS)
389 return NULL;
390
391 dsk = ECALLOC(Desk, 1);
392 if (!dsk)
393 return dsk;
394
395 desks.desk[desk] = dsk;
396 dsk->num = desk;
397 desks.order[desk] = desk;
398
399 win = (desk == 0) ? VROOT : NULL;
400
401 Esnprintf(buf, sizeof(buf), "Desk-%d", desk);
402 EoSetNoRedirect(dsk, 1);
403 EoInit(dsk, EOBJ_TYPE_DESK, win,
404 0, 0, WinGetW(VROOT), WinGetH(VROOT), 0, buf);
405 EventCallbackRegister(EoGetWin(dsk), DeskHandleEvents, dsk);
406 dsk->bg.o = EoObj(dsk);
407 if (desk == 0)
408 {
409 desks.current = dsk;
410 #if !USE_BG_WIN_ON_ALL_DESKS /* TBD - Use per virtual root bg window? */
411 #if USE_COMPOSITE
412 /* Add background window */
413 eo = EobjWindowCreate(EOBJ_TYPE_ROOT_BG,
414 0, 0, WinGetW(VROOT), WinGetH(VROOT),
415 0, "Root-bg");
416 eo->floating = 0;
417 EobjSetLayer(eo, 0);
418 EventCallbackRegister(EobjGetWin(eo), DeskHandleEvents, dsk);
419 dsk->bg.o_bg = eo;
420 ESelectInput(EobjGetWin(eo), EnterWindowMask);
421 #endif
422 #endif
423 }
424 else
425 {
426 EoSetFloating(dsk, 1);
427 EoSetLayer(dsk, 0);
428 /* Set the _XROOT... atoms so apps will find them even before the bg is set */
429 HintsSetRootInfo(EoGetWin(dsk), NoXID, 0);
430 }
431
432 #if USE_BG_WIN_ON_ALL_DESKS /* TBD - Use per virtual root bg window? */
433 #if USE_COMPOSITE
434 /* Add background window */
435 Esnprintf(buf, sizeof(buf), "Desk-bg-%d", desk);
436 eo = EobjWindowCreate(EOBJ_TYPE_MISC,
437 0, 0, WinGetW(VROOT), WinGetH(VROOT), 0, buf);
438 eo->floating = 0;
439 EobjReparent(eo, EoObj(dsk), 0, 0);
440 EobjSetLayer(eo, 0);
441 dsk->bg.o_bg = eo;
442 EventCallbackRegister(EobjGetWin(eo), DeskHandleEvents, dsk);
443 #endif
444 #endif
445
446 HintsSetRootHints(EoGetWin(dsk));
447
448 if (configure)
449 DeskConfigure(dsk);
450
451 /* Root window: Don't include ButtonPressMask as it may cause the event
452 * selection to fail for the other events too.
453 * The ButtonPress/ReleaseMask events are selected in SetupX(). */
454 if (desk == 0)
455 ESelectInputChange(EoGetWin(dsk), DESK_EVENT_MASK2, 0);
456 else
457 ESelectInput(EoGetWin(dsk), DESK_EVENT_MASK);
458
459 return dsk;
460 }
461
462 static void
DeskDestroy(Desk * dsk)463 DeskDestroy(Desk * dsk)
464 {
465 ModulesSignal(ESIGNAL_DESK_REMOVED, dsk);
466
467 #if USE_COMPOSITE
468 if (dsk->bg.o_bg)
469 {
470 EventCallbackUnregister(EobjGetWin(dsk->bg.o_bg), DeskHandleEvents,
471 dsk);
472 EobjWindowDestroy(dsk->bg.o_bg);
473 }
474 #endif
475 EventCallbackUnregister(EoGetWin(dsk), DeskHandleEvents, dsk);
476
477 DeskControlsDestroy(dsk, 1);
478 DeskControlsDestroy(dsk, 2);
479
480 if (dsk->bg.bg)
481 BackgroundDecRefcount(dsk->bg.bg);
482
483 EoFini(dsk);
484
485 desks.desk[dsk->num] = NULL;
486 Efree(dsk);
487 }
488
489 EObj *
DeskGetBackgroundObj(const Desk * dsk)490 DeskGetBackgroundObj(const Desk * dsk)
491 {
492 return (dsk) ? dsk->bg.o : NULL;
493 }
494
495 EX_Pixmap
DeskGetBackgroundPixmap(const Desk * dsk)496 DeskGetBackgroundPixmap(const Desk * dsk)
497 {
498 if (!dsk)
499 return NoXID;
500 return dsk->bg.pmap;
501 }
502
503 Background *
DeskBackgroundGet(const Desk * dsk)504 DeskBackgroundGet(const Desk * dsk)
505 {
506 return (dsk) ? dsk->bg.bg : NULL;
507 }
508
509 static void
DeskBackgroundConfigure(Desk * dsk)510 DeskBackgroundConfigure(Desk * dsk)
511 {
512 Win win;
513 EX_Pixmap pmap = dsk->bg.pmap;
514 unsigned int pixel = dsk->bg.pixel;
515
516 if (EDebug(EDBUG_TYPE_DESKS))
517 Eprintf("%s: %d v=%d %#x/%#x: ext=%d pmap=%#x/%#x pixel=%#x/%#x\n",
518 __func__,
519 dsk->num, dsk->viewable, EoGetXwin(dsk), EobjGetXwin(dsk->bg.o),
520 BackgroundIsNone(dsk->bg.bg), pmap, dsk->bg.pmap_set, pixel,
521 dsk->bg.pixel);
522
523 #if USE_COMPOSITE
524 if (dsk->bg.o_bg)
525 {
526 if (ECompMgrIsActive())
527 {
528 dsk->bg.o = dsk->bg.o_bg;
529 EobjMap(dsk->bg.o_bg, 0);
530 }
531 else
532 {
533 dsk->bg.o = EoObj(dsk);
534 EobjUnmap(dsk->bg.o_bg);
535 }
536 }
537 #endif
538
539 win = EobjGetWin(dsk->bg.o);
540
541 if (dsk->viewable || !dsk->bg.bg)
542 {
543 #if USE_COMPOSITE && !USE_BG_WIN_ON_ALL_DESKS
544 if (ECompMgrIsActive())
545 {
546 ECompMgrDeskConfigure(dsk);
547 ESetWindowBackgroundPixmap(win, NoXID, 0);
548 }
549 else
550 #endif
551 {
552 if (pmap != NoXID)
553 {
554 ESetWindowBackgroundPixmap(win, pmap, 1);
555 if (dsk->num == 0 && win != VROOT)
556 ESetWindowBackgroundPixmap(VROOT, pmap, 1);
557 }
558 else
559 {
560 ESetWindowBackground(win, pixel);
561 if (dsk->num == 0 && win != VROOT)
562 ESetWindowBackground(VROOT, pixel);
563 }
564 EClearWindow(win);
565 }
566
567 HintsSetRootInfo(EoGetWin(dsk), pmap, pixel);
568 }
569 else if (dsk->bg.bg)
570 {
571 if (!Conf.hints.set_xroot_info_on_root_window)
572 HintsSetRootInfo(EoGetWin(dsk), NoXID, 0);
573
574 ESetWindowBackgroundPixmap(win, NoXID, 0);
575 if (dsk->num == 0 && win != VROOT)
576 ESetWindowBackgroundPixmap(VROOT, NoXID, 0);
577 }
578 }
579
580 static void
DeskBackgroundRefresh(Desk * dsk,int why)581 DeskBackgroundRefresh(Desk * dsk, int why)
582 {
583 Background *bg = dsk->bg.bg;
584 EX_Pixmap pmap = dsk->bg.pmap;
585 unsigned int pixel = dsk->bg.pixel;
586 int changed = 0;
587 int reconfigure = 0;
588
589 if (EDebug(EDBUG_TYPE_DESKS))
590 Eprintf("%s: %d v=%d why=%d pmap=%#x pixel=%#x\n", __func__,
591 dsk->num, dsk->viewable, why, pmap, pixel);
592
593 switch (why)
594 {
595 case DESK_BG_REFRESH:
596 if (bg && dsk->viewable)
597 BackgroundTouch(bg);
598 break;
599
600 case DESK_BG_RECONFIGURE_ALL:
601 reconfigure = 1;
602 break;
603
604 case DESK_BG_TIMEOUT:
605 if (bg && dsk->viewable)
606 BackgroundTouch(bg);
607 return;
608
609 case DESK_BG_FREE:
610 if (!bg || dsk->viewable)
611 return;
612 break;
613 }
614
615 if (bg)
616 {
617 if (dsk->viewable)
618 {
619 if (BackgroundGetSeqNo(bg) == dsk->bg.seq_no)
620 goto done;
621
622 pmap = BackgroundGetPixmap(bg);
623 pixel = 0;
624
625 if (pmap == NoXID)
626 BackgroundRealize(bg, EoGetWin(dsk), NoXID,
627 EoGetW(dsk), EoGetH(dsk), 1, &pmap, &pixel);
628 if (pmap != NoXID)
629 BackgroundPixmapSet(bg, pmap);
630
631 dsk->bg.seq_no = BackgroundGetSeqNo(bg);
632 changed = 1;
633 }
634 else
635 {
636 if (dsk->bg.pmap == NoXID)
637 return;
638
639 pmap = NoXID;
640 pixel = 0;
641 dsk->bg.seq_no = 0;
642 }
643 }
644 else
645 {
646 pmap = (Mode.root.ext_pmap_valid) ? Mode.root.ext_pmap : NoXID;
647 pixel = 0;
648 changed = pmap != dsk->bg.pmap_set;
649 dsk->bg.seq_no = 0;
650 }
651
652 done:
653 dsk->bg.pmap = pmap;
654 if (reconfigure || pmap != dsk->bg.pmap_set || pixel != dsk->bg.pixel)
655 {
656 dsk->bg.pixel = pixel;
657 DeskBackgroundConfigure(dsk);
658 dsk->bg.pmap_set = pmap;
659 }
660
661 if (bg && dsk->viewable)
662 if (Conf.hints.set_xroot_info_on_root_window)
663 HintsSetRootInfo(VROOT, pmap, pixel);
664
665 if (changed)
666 ModulesSignal(ESIGNAL_BACKGROUND_CHANGE, dsk);
667 }
668
669 void
DeskBackgroundSet(Desk * dsk,Background * bg)670 DeskBackgroundSet(Desk * dsk, Background * bg)
671 {
672 if (!dsk)
673 return;
674
675 BackgroundSetForDesk(bg, dsk->num);
676 if (bg && BackgroundIsNone(bg))
677 bg = NULL;
678
679 if (dsk->bg.bg != bg)
680 {
681 if (dsk->bg.bg)
682 BackgroundDecRefcount(dsk->bg.bg);
683 if (bg)
684 BackgroundIncRefcount(bg);
685 }
686
687 dsk->bg.bg = bg;
688
689 DeskBackgroundRefresh(dsk, DESK_BG_REFRESH);
690 }
691
692 void
DesksBackgroundRefresh(Background * bg,int why)693 DesksBackgroundRefresh(Background * bg, int why)
694 {
695 Desk *dsk;
696 unsigned int i;
697
698 for (i = 0; i < Conf.desks.num; i++)
699 {
700 dsk = _DeskGet(i);
701 if (!dsk) /* May happen during init */
702 continue;
703 if (bg && dsk->bg.bg != bg)
704 continue;
705 DeskBackgroundRefresh(dsk, why);
706 }
707 }
708
709 static void
DeskResize(int desk,int w,int h)710 DeskResize(int desk, int w, int h)
711 {
712 Desk *dsk;
713 int x;
714
715 dsk = _DeskGet(desk);
716
717 if (dsk->num != 0)
718 {
719 x = (dsk->viewable) ? EoGetX(dsk) : WinGetW(VROOT);
720 EoMoveResize(dsk, x, 0, w, h);
721 }
722 #if USE_COMPOSITE
723 if (dsk->bg.o_bg)
724 EobjMoveResize(dsk->bg.o_bg, 0, 0, w, h);
725 #endif
726 DeskBackgroundRefresh(dsk, DESK_BG_REFRESH);
727 DeskControlsDestroy(dsk, 1);
728 DeskControlsCreate(dsk);
729 DeskControlsShow(dsk, 1);
730 }
731
732 Desk *
DeskGet(unsigned int desk)733 DeskGet(unsigned int desk)
734 {
735 if (desk >= Conf.desks.num)
736 return NULL;
737
738 return _DeskGet(desk);
739 }
740
741 Desk *
DeskGetValid(unsigned int desk)742 DeskGetValid(unsigned int desk)
743 {
744 if (desk >= Conf.desks.num)
745 desk = 0;
746
747 return _DeskGet(desk);
748 }
749
750 Desk *
DeskGetRelative(Desk * dsk,int inc)751 DeskGetRelative(Desk * dsk, int inc)
752 {
753 unsigned int desk, num;
754
755 num = Conf.desks.num;
756 desk = (dsk) ? dsk->num : 0;
757 inc %= (int)num;
758 desk += num + inc;
759 desk %= num;
760
761 return _DeskGet(desk);
762 }
763
764 void
DeskGetArea(const Desk * dsk,int * ax,int * ay)765 DeskGetArea(const Desk * dsk, int *ax, int *ay)
766 {
767 if (!dsk)
768 {
769 *ax = *ay = 0;
770 return;
771 }
772 *ax = dsk->current_area_x;
773 *ay = dsk->current_area_y;
774 }
775
776 void
DeskSetArea(Desk * dsk,int ax,int ay)777 DeskSetArea(Desk * dsk, int ax, int ay)
778 {
779 if (!dsk)
780 return;
781
782 dsk->current_area_x = ax;
783 dsk->current_area_y = ay;
784 }
785
786 void
DeskSetDirtyStack(Desk * dsk,EObj * eo)787 DeskSetDirtyStack(Desk * dsk, EObj * eo)
788 {
789 dsk->stack.dirty++;
790 dsk->stack.latest = eo;
791 if (EobjGetType(eo) == EOBJ_TYPE_EWIN)
792 dsk->stack.update_client_list = 1;
793 if (EDebug(EDBUG_TYPE_STACKING))
794 Eprintf("%s: %d (%d): %s\n", __func__, dsk->num, dsk->stack.dirty,
795 EobjGetName(eo));
796 }
797
798 void
DeskCurrentGetArea(int * ax,int * ay)799 DeskCurrentGetArea(int *ax, int *ay)
800 {
801 DeskGetArea(desks.current, ax, ay);
802 }
803
804 static void
DeskCurrentSetArea(int ax,int ay)805 DeskCurrentSetArea(int ax, int ay)
806 {
807 DeskSetArea(desks.current, ax, ay);
808 }
809
810 unsigned int
DesksGetNumber(void)811 DesksGetNumber(void)
812 {
813 return Conf.desks.num;
814 }
815
816 Desk *
DesksGetCurrent(void)817 DesksGetCurrent(void)
818 {
819 return desks.current;
820 }
821
822 unsigned int
DesksGetCurrentNum(void)823 DesksGetCurrentNum(void)
824 {
825 return desks.current->num;
826 }
827
828 void
DesksSetCurrent(Desk * dsk)829 DesksSetCurrent(Desk * dsk)
830 {
831 if (!dsk)
832 return;
833 desks.current = dsk;
834 }
835
836 static void
DesksResize(int w,int h)837 DesksResize(int w, int h)
838 {
839 unsigned int i;
840
841 BackgroundsInvalidate(0);
842
843 for (i = 0; i < Conf.desks.num; i++)
844 DeskResize(i, w, h);
845
846 EdgeWindowsShow();
847
848 ModulesSignal(ESIGNAL_DESK_RESIZE, NULL);
849 }
850
851 static void
ChangeNumberOfDesktops(unsigned int quantity)852 ChangeNumberOfDesktops(unsigned int quantity)
853 {
854 unsigned int i;
855 int j, num;
856 EWin *const *lst;
857
858 if (quantity >= ENLIGHTENMENT_CONF_NUM_DESKTOPS)
859 quantity = ENLIGHTENMENT_CONF_NUM_DESKTOPS;
860
861 if (quantity <= 0 || quantity == Conf.desks.num)
862 return;
863
864 for (i = quantity; i < Conf.desks.num; i++)
865 DeskLower(i);
866
867 if (quantity > Conf.desks.num)
868 {
869 while (Conf.desks.num < quantity)
870 {
871 Conf.desks.num++;
872 DeskCreate(Conf.desks.num - 1, 1);
873 }
874 }
875 else if (quantity < Conf.desks.num)
876 {
877 lst = EwinListGetAll(&num);
878 for (j = 0; j < num; j++)
879 {
880 if (EoGetDeskNum(lst[j]) >= quantity)
881 EwinMoveToDesktop(lst[j], _DeskGet(0));
882 }
883
884 while (Conf.desks.num > quantity)
885 {
886 DeskDestroy(_DeskGet(Conf.desks.num - 1));
887 Conf.desks.num--;
888 }
889 }
890
891 if (DesksGetCurrentNum() >= Conf.desks.num)
892 DeskGotoNum(Conf.desks.num - 1);
893
894 HintsSetDesktopConfig();
895
896 autosave();
897 }
898
899 static void
DesksControlsCreate(void)900 DesksControlsCreate(void)
901 {
902 unsigned int i;
903
904 for (i = 0; i < Conf.desks.num; i++)
905 DeskControlsCreate(_DeskGet(i));
906 }
907
908 static void
DesksControlsDestroy(void)909 DesksControlsDestroy(void)
910 {
911 unsigned int i;
912
913 for (i = 0; i < Conf.desks.num; i++)
914 DeskControlsDestroy(_DeskGet(i), 1);
915 }
916
917 static void
DesksControlsShow(void)918 DesksControlsShow(void)
919 {
920 unsigned int i;
921
922 for (i = 0; i < Conf.desks.num; i++)
923 DeskControlsShow(_DeskGet(i), 1);
924 }
925
926 static void
DesksControlsRefresh(void)927 DesksControlsRefresh(void)
928 {
929 DesksControlsDestroy();
930 DesksControlsCreate();
931 DesksControlsShow();
932
933 autosave();
934 }
935
936 #if 0 /* Unused */
937 static void
938 DeskShowTabs(void)
939 {
940 ButtonsForeach(2, NULL, ButtonShow);
941 }
942
943 static void
944 DeskHideTabs(void)
945 {
946 ButtonsForeach(2, NULL, ButtonHide);
947 }
948 #endif
949
950 static void
DeskButtonShowDefault(Button * b)951 DeskButtonShowDefault(Button * b)
952 {
953 if (!ButtonDoShowDefault(b))
954 return;
955 ButtonShow(b);
956 }
957
958 static void
DeskShowButtons(void)959 DeskShowButtons(void)
960 {
961 ButtonsForeach(0, NULL, DeskButtonShowDefault);
962 }
963
964 static void
MoveToDeskTop(Desk * dsk)965 MoveToDeskTop(Desk * dsk)
966 {
967 int i, j;
968
969 EoRaise(dsk);
970
971 j = -1;
972 i = 0;
973 while (j < 0 && i < (int)Conf.desks.num)
974 {
975 if (desks.order[i] == dsk->num)
976 j = i;
977 i++;
978 }
979 if (j < 0)
980 return;
981 if (j > 0)
982 {
983 for (i = j - 1; i >= 0; i--)
984 desks.order[i + 1] = desks.order[i];
985 desks.order[0] = dsk->num;
986 }
987 }
988
989 static void
MoveToDeskBottom(Desk * dsk)990 MoveToDeskBottom(Desk * dsk)
991 {
992 int i, j;
993
994 EoLower(dsk);
995
996 j = -1;
997 i = 0;
998 while (j < 0 && i < (int)Conf.desks.num)
999 {
1000 if (desks.order[i] == dsk->num)
1001 j = i;
1002 i++;
1003 }
1004 if (j < 0)
1005 return;
1006 if (j < (int)Conf.desks.num - 1)
1007 {
1008 for (i = j; i < (int)Conf.desks.num - 1; i++)
1009 desks.order[i] = desks.order[i + 1];
1010 desks.order[Conf.desks.num - 1] = dsk->num;
1011 }
1012 }
1013
1014 Desk *
DesktopAt(int x,int y)1015 DesktopAt(int x, int y)
1016 {
1017 Desk *dsk;
1018 unsigned int i;
1019
1020 for (i = 0; i < Conf.desks.num; i++)
1021 {
1022 dsk = _DeskGet(desks.order[i]);
1023 if (x >= EoGetX(dsk) && x < (EoGetX(dsk) + WinGetW(VROOT)) &&
1024 y >= EoGetY(dsk) && y < (EoGetY(dsk) + WinGetH(VROOT)))
1025 return _DeskGet(desks.order[i]);
1026 }
1027 return _DeskGet(0);
1028 }
1029
1030 static void
DesksStackingCheck(void)1031 DesksStackingCheck(void)
1032 {
1033 Desk *dsk;
1034 unsigned int i;
1035
1036 for (i = 0; i < Conf.desks.num; i++)
1037 {
1038 dsk = _DeskGet(i);
1039 if (i && !dsk->viewable)
1040 continue;
1041 if (!dsk->stack.dirty)
1042 continue;
1043 DeskRestack(dsk);
1044 }
1045 }
1046
1047 static void
_DesksIdler(void * data __UNUSED__)1048 _DesksIdler(void *data __UNUSED__)
1049 {
1050 DesksStackingCheck();
1051 }
1052
1053 static void
DeskMove(Desk * dsk,int x,int y)1054 DeskMove(Desk * dsk, int x, int y)
1055 {
1056 Desk *dd;
1057 unsigned int i;
1058 int n, v, dx, dy;
1059
1060 if (dsk->num <= 0)
1061 return;
1062
1063 n = -1;
1064 i = 0;
1065 while (n < 0 && i < Conf.desks.num)
1066 {
1067 if (desks.order[i] == dsk->num)
1068 n = i;
1069 i++;
1070 }
1071 if (n < 0) /* Should not be possible */
1072 return;
1073
1074 dx = x - EoGetX(dsk);
1075 dy = y - EoGetY(dsk);
1076
1077 if (x == 0 && y == 0)
1078 {
1079 /* Desks below are obscured - touch and set unviewable */
1080 for (i = n + 1; i < Conf.desks.num; i++)
1081 {
1082 dd = _DeskGet(desks.order[i]);
1083 if (dd->viewable)
1084 BackgroundTouch(dd->bg.bg);
1085 dd->viewable = 0;
1086 }
1087 }
1088 else
1089 {
1090 v = dsk->viewable;
1091
1092 for (i = n + 1; i < Conf.desks.num; i++)
1093 {
1094 dd = _DeskGet(desks.order[i]);
1095 if (!dd->viewable && v)
1096 {
1097 dd->viewable = 1;
1098 DeskBackgroundRefresh(_DeskGet(desks.order[i]),
1099 DESK_BG_REFRESH);
1100 }
1101 else if (dd->viewable && !v)
1102 {
1103 BackgroundTouch(dd->bg.bg);
1104 dd->viewable = 0;
1105 }
1106
1107 if (EoGetX(dd) == 0 && EoGetY(dd) == 0)
1108 v = 0;
1109 }
1110 }
1111
1112 EoMove(dsk, x, y);
1113
1114 if (dsk->tag)
1115 ButtonMoveRelative(dsk->tag, dx, dy);
1116
1117 #if 0 /* FIXME - Remove? */
1118 EWin *const *lst;
1119
1120 lst = EwinListGetAll(&n);
1121 for (i = 0; i < (unsigned int)n; i++)
1122 if (EoGetDesk(lst[i]) == dsk)
1123 ICCCM_Configure(lst[i]);
1124 #endif
1125 }
1126
1127 static void
DeskHide(unsigned int desk)1128 DeskHide(unsigned int desk)
1129 {
1130 Desk *dsk;
1131
1132 if (desk <= 0 || desk >= Conf.desks.num)
1133 return;
1134
1135 dsk = _DeskGet(desk);
1136
1137 if (dsk->viewable)
1138 BackgroundTouch(dsk->bg.bg);
1139 dsk->viewable = 0;
1140 EoMove(dsk, WinGetW(VROOT), 0);
1141 }
1142
1143 static void
DeskEnter(Desk * dsk)1144 DeskEnter(Desk * dsk)
1145 {
1146 int i;
1147
1148 EGrabServer();
1149
1150 dsk->viewable = 1;
1151 DeskBackgroundRefresh(dsk, DESK_BG_REFRESH);
1152 MoveToDeskTop(dsk);
1153
1154 desks.prev_num = desks.current->num;
1155 desks.previous = desks.current = dsk;
1156
1157 if (dsk->num == 0)
1158 {
1159 for (i = Conf.desks.num - 1; i > 0; i--)
1160 DeskHide(desks.order[i]);
1161 }
1162
1163 EwinsMoveStickyToDesk(dsk);
1164 ButtonsMoveStickyToDesk(dsk);
1165 DesksStackingCheck();
1166 EdgeWindowsShow();
1167
1168 EUngrabServer();
1169 }
1170
1171 void
DeskGotoNum(unsigned int desk)1172 DeskGotoNum(unsigned int desk)
1173 {
1174 Desk *dsk;
1175
1176 if (Conf.desks.desks_wraparound)
1177 desk %= Conf.desks.num;
1178 if (desk >= Conf.desks.num || desk == desks.current->num)
1179 return;
1180
1181 dsk = _DeskGet(desk);
1182 DeskGoto(dsk);
1183 }
1184
1185 static void
DeskSwitchStart(void)1186 DeskSwitchStart(void)
1187 {
1188 FocusNewDeskBegin();
1189 }
1190
1191 static void
DeskSwitchDone(void)1192 DeskSwitchDone(void)
1193 {
1194 HintsSetCurrentDesktop();
1195 FocusNewDesk();
1196 }
1197
1198 static void
_DeskGotoStart(Desk * dsk)1199 _DeskGotoStart(Desk * dsk)
1200 {
1201 if (EDebug(EDBUG_TYPE_DESKS))
1202 Eprintf("%s: %d\n", __func__, dsk->num);
1203
1204 ModulesSignal(ESIGNAL_DESK_SWITCH_START, NULL);
1205
1206 MoveResizeSuspend();
1207 DeskSwitchStart();
1208 }
1209
1210 static void
_DeskGotoEnd(Desk * dsk)1211 _DeskGotoEnd(Desk * dsk)
1212 {
1213 DeskSwitchDone();
1214 MoveResizeResume();
1215
1216 ModulesSignal(ESIGNAL_DESK_SWITCH_DONE, NULL);
1217
1218 if (EDebug(EDBUG_TYPE_DESKS))
1219 Eprintf("%s: %d\n", __func__, dsk->num);
1220 }
1221
1222 static int
_DeskGotoRun(EObj * eo,int run,void * state)1223 _DeskGotoRun(EObj * eo, int run, void *state)
1224 {
1225 int *xy = (int *)state;
1226 int x, y;
1227 Desk *dsk = (Desk *) eo;
1228
1229 x = (run * xy[0]) >> 10;
1230 y = (run * xy[1]) >> 10;
1231
1232 EobjMove(eo, x, y);
1233
1234 if (run == 0)
1235 {
1236 if (xy[2])
1237 DeskEnter(dsk);
1238 DeskMove(dsk, 0, 0);
1239 _DeskGotoEnd(dsk);
1240 EventsBlock(0);
1241 }
1242
1243 return 0;
1244 }
1245
1246 void
DeskGoto(Desk * dsk)1247 DeskGoto(Desk * dsk)
1248 {
1249 if (!dsk || dsk == desks.previous)
1250 return;
1251
1252 _DeskGotoStart(dsk);
1253
1254 if (dsk->num > 0)
1255 {
1256 if (Conf.desks.slidein)
1257 {
1258 EventsBlock(1);
1259 if (!dsk->viewable)
1260 {
1261 int x, y;
1262
1263 switch (Conf.desks.dragdir)
1264 {
1265 default:
1266 case 0:
1267 x = WinGetW(VROOT);
1268 y = 0;
1269 break;
1270 case 1:
1271 x = -WinGetW(VROOT);
1272 y = 0;
1273 break;
1274 case 2:
1275 x = 0;
1276 y = WinGetH(VROOT);
1277 break;
1278 case 3:
1279 x = 0;
1280 y = -WinGetH(VROOT);
1281 break;
1282 }
1283 DeskMove(dsk, x, y);
1284 int xy[3] = { x, y, 0 };
1285 DeskEnter(dsk);
1286 AnimatorAdd(EoObj(dsk), ANIM_SLIDE, _DeskGotoRun,
1287 1000000 / Conf.desks.slidespeed,
1288 0, sizeof(xy), xy);
1289 }
1290 else
1291 {
1292 int xy[3] = { EoGetX(dsk), EoGetY(dsk), 1 };
1293 AnimatorAdd(EoObj(dsk), ANIM_SLIDE, _DeskGotoRun,
1294 1000000 / Conf.desks.slidespeed,
1295 0, sizeof(xy), xy);
1296 }
1297 return;
1298 }
1299 else
1300 {
1301 DeskEnter(dsk);
1302 }
1303 DeskMove(dsk, 0, 0);
1304 }
1305 else
1306 {
1307 DeskEnter(dsk);
1308 }
1309
1310 _DeskGotoEnd(dsk);
1311 }
1312
1313 static void
UncoverDesktop(unsigned int desk)1314 UncoverDesktop(unsigned int desk)
1315 {
1316 Desk *dsk;
1317
1318 if (desk >= Conf.desks.num)
1319 return;
1320
1321 dsk = _DeskGet(desk);
1322
1323 dsk->viewable = 1;
1324 DeskBackgroundRefresh(dsk, DESK_BG_REFRESH);
1325 }
1326
1327 static void
DeskRaise(unsigned int desk)1328 DeskRaise(unsigned int desk)
1329 {
1330 Desk *dsk;
1331
1332 if (desk >= Conf.desks.num)
1333 return;
1334
1335 dsk = _DeskGet(desk);
1336
1337 if (EDebug(EDBUG_TYPE_DESKS))
1338 Eprintf("%s: %d current=%d\n", __func__, desk, desks.current->num);
1339
1340 DeskSwitchStart();
1341 DeskEnter(dsk);
1342 DeskSwitchDone();
1343
1344 ModulesSignal(ESIGNAL_DESK_SWITCH_DONE, NULL);
1345
1346 ESync(ESYNC_DESKS);
1347 }
1348
1349 static void
DeskLower(unsigned int desk)1350 DeskLower(unsigned int desk)
1351 {
1352 Desk *dsk;
1353
1354 if ((desk <= 0) || (desk >= Conf.desks.num))
1355 return;
1356
1357 dsk = _DeskGet(desk);
1358
1359 DeskSwitchStart();
1360 MoveToDeskBottom(dsk);
1361
1362 if (EDebug(EDBUG_TYPE_DESKS))
1363 Eprintf("%s: %d %d -> %d\n", __func__, desk, desks.current->num,
1364 desks.order[0]);
1365
1366 desks.previous = desks.current = DeskGet(desks.order[0]);
1367
1368 EGrabServer();
1369
1370 UncoverDesktop(desks.order[0]);
1371 DeskHide(desk);
1372
1373 EwinsMoveStickyToDesk(desks.current);
1374 ButtonsMoveStickyToDesk(desks.current);
1375 DesksStackingCheck();
1376 DeskSwitchDone();
1377 if (Mode.mode == MODE_NONE)
1378 ModulesSignal(ESIGNAL_DESK_SWITCH_DONE, NULL);
1379
1380 EUngrabServer();
1381 ESync(ESYNC_DESKS);
1382 }
1383
1384 #if 0 /* Unused */
1385 void
1386 DeskShow(int desk)
1387 {
1388 Desk *dsk;
1389 int i;
1390
1391 if (desk < 0 || desk >= Conf.desks.num)
1392 return;
1393
1394 dsk = _DeskGet(desk);
1395
1396 dsk->viewable = 1;
1397 DeskBackgroundRefresh(dsk, DESK_BG_REFRESH);
1398 MoveToDeskTop(desk);
1399
1400 if (desk == 0)
1401 {
1402 for (i = Conf.desks.num - 1; i > 0; i--)
1403 DeskHide(desks.order[i]);
1404 }
1405 }
1406 #endif
1407
1408 static void
DeskRestackSimple(Desk * dsk)1409 DeskRestackSimple(Desk * dsk)
1410 {
1411 EObj *const *lst, *eo;
1412 int i, num;
1413 XWindowChanges xwc;
1414 unsigned int value_mask;
1415
1416 eo = dsk->stack.latest;
1417
1418 lst = EobjListStackGetForDesk(&num, dsk);
1419 for (i = 0; i < num; i++)
1420 if (lst[i] == eo)
1421 break;
1422 if (i >= num)
1423 return; /* eo not in list (can this happen?) */
1424
1425 eo->stacked = 1;
1426
1427 if (EDebug(EDBUG_TYPE_STACKING))
1428 Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
1429
1430 if (num < 2)
1431 return; /* Only one window in stack - done */
1432
1433 if (i < num - 1)
1434 {
1435 xwc.stack_mode = Above;
1436 xwc.sibling = EobjGetXwin(lst[i + 1]);
1437 }
1438 else
1439 {
1440 xwc.stack_mode = Below;
1441 xwc.sibling = EobjGetXwin(lst[i - 1]);
1442 }
1443 value_mask = CWSibling | CWStackMode;
1444 if (EDebug(EDBUG_TYPE_STACKING))
1445 Eprintf("%s: %#10x %s %#10lx\n", __func__, EobjGetXwin(eo),
1446 (xwc.stack_mode == Above) ? "Above" : "Below", xwc.sibling);
1447 XConfigureWindow(disp, EobjGetXwin(eo), value_mask, &xwc);
1448 }
1449
1450 #define _APPEND_TO_WIN_LIST(win) \
1451 { \
1452 wl = EREALLOC(EX_Window, wl, ++tot); \
1453 wl[tot - 1] = win; \
1454 }
1455 void
DeskRestack(Desk * dsk)1456 DeskRestack(Desk * dsk)
1457 {
1458 EX_Window *wl;
1459 int i, num, tot;
1460 EObj *const *lst, *eo;
1461
1462 if (!dsk->stack.dirty)
1463 return;
1464
1465 /* Special case if only one window needs restacking */
1466 if (dsk->stack.dirty == 1)
1467 {
1468 DeskRestackSimple(dsk);
1469 goto done;
1470 }
1471
1472 /* Build the window stack, top to bottom */
1473 tot = 0;
1474 wl = NULL;
1475 lst = EobjListStackGetForDesk(&num, dsk);
1476
1477 /* Normal objects */
1478 for (i = 0; i < num; i++)
1479 {
1480 eo = lst[i];
1481 _APPEND_TO_WIN_LIST(EobjGetXwin(eo));
1482 eo->stacked = 1;
1483 }
1484
1485 if (EDebug(EDBUG_TYPE_STACKING))
1486 {
1487 Eprintf("%s: %d (%d):\n", __func__, dsk->num, dsk->stack.dirty);
1488 for (i = 0; i < tot; i++)
1489 Eprintf(" win=%#10x parent=%#10x\n", wl[i],
1490 EXWindowGetParent(wl[i]));
1491 }
1492
1493 EXRestackWindows(wl, tot);
1494
1495 Efree(wl);
1496
1497 done:
1498 if (dsk->stack.update_client_list)
1499 {
1500 dsk->stack.update_client_list = 0;
1501 HintsSetClientStacking();
1502 ClickGrabsUpdate();
1503 }
1504 dsk->stack.dirty = 0;
1505 dsk->stack.latest = NULL;
1506 }
1507
1508 void
DeskGotoByEwin(EWin * ewin,int now)1509 DeskGotoByEwin(EWin * ewin, int now)
1510 {
1511 int slide;
1512
1513 if (EoIsSticky(ewin) || EoIsFloating(ewin))
1514 return;
1515
1516 slide = Conf.desks.slidein;
1517 if (now)
1518 Conf.desks.slidein = 0;
1519
1520 DeskGoto(EoGetDesk(ewin));
1521 DeskCurrentGotoArea(ewin->area_x, ewin->area_y);
1522
1523 Conf.desks.slidein = slide;
1524 }
1525
1526 /*
1527 * Areas
1528 */
1529
1530 void
DesksFixArea(int * ax,int * ay)1531 DesksFixArea(int *ax, int *ay)
1532 {
1533 if (*ax < 0)
1534 {
1535 if (Conf.desks.areas_wraparound)
1536 *ax = Conf.desks.areas_nx - 1;
1537 else
1538 *ax = 0;
1539 }
1540 else if (*ax >= Conf.desks.areas_nx)
1541 {
1542 if (Conf.desks.areas_wraparound)
1543 *ax = 0;
1544 else
1545 *ax = Conf.desks.areas_nx - 1;
1546 }
1547
1548 if (*ay < 0)
1549 {
1550 if (Conf.desks.areas_wraparound)
1551 *ay = Conf.desks.areas_ny - 1;
1552 else
1553 *ay = 0;
1554 }
1555 else if (*ay >= Conf.desks.areas_ny)
1556 {
1557 if (Conf.desks.areas_wraparound)
1558 *ay = 0;
1559 else
1560 *ay = Conf.desks.areas_ny - 1;
1561 }
1562 }
1563
1564 static int
AreaXYToLinear(int ax,int ay)1565 AreaXYToLinear(int ax, int ay)
1566 {
1567 DesksFixArea(&ax, &ay);
1568 return (ay * Conf.desks.areas_nx) + ax;
1569 }
1570
1571 static void
AreaLinearToXY(int a,int * ax,int * ay)1572 AreaLinearToXY(int a, int *ax, int *ay)
1573 {
1574 if (a < 0)
1575 a = 0;
1576 else if (a >= (Conf.desks.areas_nx * Conf.desks.areas_ny))
1577 a = (Conf.desks.areas_nx * Conf.desks.areas_ny) - 1;
1578 *ay = a / Conf.desks.areas_nx;
1579 *ax = a - (*ay * Conf.desks.areas_nx);
1580 }
1581
1582 static void
SetAreaSize(int aw,int ah)1583 SetAreaSize(int aw, int ah)
1584 {
1585 if (aw < 1)
1586 aw = 1;
1587 if (ah < 1)
1588 ah = 1;
1589 Conf.desks.areas_nx = aw;
1590 Conf.desks.areas_ny = ah;
1591 HintsSetViewportConfig();
1592 EdgeWindowsShow();
1593 ModulesSignal(ESIGNAL_AREA_CONFIGURED, NULL);
1594 }
1595
1596 void
DesksGetAreaSize(int * aw,int * ah)1597 DesksGetAreaSize(int *aw, int *ah)
1598 {
1599 *aw = Conf.desks.areas_nx;
1600 *ah = Conf.desks.areas_ny;
1601 }
1602
1603 static void
SetNewAreaSize(int ax,int ay)1604 SetNewAreaSize(int ax, int ay)
1605 {
1606
1607 int a, b, i, num;
1608 EWin *const *lst;
1609
1610 if (ax <= 0)
1611 return;
1612 if (ay <= 0)
1613 return;
1614
1615 DesksGetAreaSize(&a, &b);
1616 if ((a == ax) && (b == ay))
1617 return;
1618
1619 SetAreaSize(ax, ay);
1620
1621 lst = EwinListGetAll(&num);
1622 for (i = 0; i < num; i++)
1623 {
1624 if (!EoIsSticky(lst[i]))
1625 {
1626 if (lst[i]->area_x >= ax)
1627 EwinMoveToArea(lst[i], ax - 1, lst[i]->area_x);
1628 if (lst[i]->area_y >= ay)
1629 EwinMoveToArea(lst[i], lst[i]->area_x, ay - 1);
1630 }
1631 }
1632
1633 DeskCurrentGetArea(&a, &b);
1634 if (a >= ax)
1635 {
1636 DeskCurrentGotoArea(ax - 1, b);
1637 DeskCurrentGetArea(&a, &b);
1638 }
1639 if (b >= ay)
1640 DeskCurrentGotoArea(a, ay - 1);
1641
1642 autosave();
1643 }
1644
1645 static void
SetCurrentLinearArea(int a)1646 SetCurrentLinearArea(int a)
1647 {
1648 int ax, ay;
1649
1650 AreaLinearToXY(a, &ax, &ay);
1651 DeskCurrentGotoArea(ax, ay);
1652 }
1653
1654 static int
GetCurrentLinearArea(void)1655 GetCurrentLinearArea(void)
1656 {
1657 int ax, ay;
1658
1659 DeskCurrentGetArea(&ax, &ay);
1660
1661 return AreaXYToLinear(ax, ay);
1662 }
1663
1664 static void
MoveCurrentLinearAreaBy(int a)1665 MoveCurrentLinearAreaBy(int a)
1666 {
1667 SetCurrentLinearArea(GetCurrentLinearArea() + a);
1668 }
1669
1670 /* Return 1 to disable area switch */
1671 static int
_DeskAreaSwitchCheckEwins(void)1672 _DeskAreaSwitchCheckEwins(void)
1673 {
1674 EWin *const *lst, *ewin;
1675 int i, num;
1676
1677 lst = EwinListGetForDesk(&num, desks.current);
1678 for (i = 0; i < num; i++)
1679 {
1680 ewin = lst[i];
1681
1682 /* Disable if there are non-sticky shading windows */
1683 if (EoIsSticky(ewin) || ewin->state.iconified)
1684 continue;
1685 if (ewin->state.shading)
1686 return 1;
1687 }
1688
1689 return 0;
1690 }
1691
1692 static void
DeskAreaSwitchStart(void)1693 DeskAreaSwitchStart(void)
1694 {
1695 FocusNewDeskBegin();
1696 }
1697
1698 static void
DeskAreaSwitchDone(void)1699 DeskAreaSwitchDone(void)
1700 {
1701 HintsSetDesktopViewport();
1702 FocusNewDesk();
1703 }
1704
1705 static void
_DeskCurrentGotoAreaStart(int pax,int pay,int ax,int ay)1706 _DeskCurrentGotoAreaStart(int pax, int pay, int ax, int ay)
1707 {
1708 if (EDebug(EDBUG_TYPE_DESKS))
1709 Eprintf("%s: %d,%d\n", __func__, ax, ay);
1710
1711 ModulesSignal(ESIGNAL_AREA_SWITCH_START, NULL);
1712
1713 if (ax < pax)
1714 SoundPlay(SOUND_MOVE_AREA_LEFT);
1715 else if (ax > pax)
1716 SoundPlay(SOUND_MOVE_AREA_RIGHT);
1717 else if (ay < pay)
1718 SoundPlay(SOUND_MOVE_AREA_UP);
1719 else if (ay > pay)
1720 SoundPlay(SOUND_MOVE_AREA_DOWN);
1721
1722 MoveResizeSuspend();
1723
1724 DeskAreaSwitchStart();
1725
1726 /* set the current area up in out data structs */
1727 DeskCurrentSetArea(ax, ay);
1728 }
1729
1730 typedef struct {
1731 EWin *const *ewins_desk;
1732 EWin **ewins_slide;
1733 int n_ewins_desk, n_ewins_slide;
1734 int slide_dx, slide_dy;
1735 } slide_area_data_t;
1736
1737 static void
_DeskCurrentGotoAreaEnd(slide_area_data_t * sad)1738 _DeskCurrentGotoAreaEnd(slide_area_data_t * sad)
1739 {
1740 EWin *const *lst, *ewin;
1741 int i, num, dx, dy;
1742
1743 desks.anim_slide = NULL;
1744
1745 lst = sad->ewins_desk;
1746 num = sad->n_ewins_desk;
1747 dx = sad->slide_dx;
1748 dy = sad->slide_dy;
1749
1750 /* move all windows to their final positions */
1751 for (i = 0; i < num; i++)
1752 {
1753 ewin = lst[i];
1754 if (EwinIsTransientChild(ewin))
1755 continue;
1756 if (EoGetDesk(ewin) != DesksGetCurrent() && !EoIsFloating(ewin))
1757 continue;
1758
1759 if (EoIsSticky(ewin) ||
1760 (EoIsFloating(ewin) && Conf.movres.mode_move == MR_OPAQUE) ||
1761 (!ewin->state.iconified && Conf.desks.slidein))
1762 EwinMove(ewin, EoGetX(ewin), EoGetY(ewin), MRF_NOCHECK_ONSCREEN);
1763 else
1764 EwinMove(ewin, EoGetX(ewin) - dx, EoGetY(ewin) - dy,
1765 MRF_NOCHECK_ONSCREEN);
1766 }
1767
1768 Efree(sad->ewins_slide);
1769
1770 if (!Conf.desks.slidein)
1771 EobjsRepaint();
1772
1773 MoveResizeResume();
1774
1775 /* re-focus on a new ewin on that new desktop area */
1776 DeskAreaSwitchDone();
1777
1778 if (EDebug(EDBUG_TYPE_DESKS))
1779 Eprintf("%s done\n", __func__);
1780
1781 ModulesSignal(ESIGNAL_AREA_SWITCH_DONE, DesksGetCurrent());
1782
1783 /* update which "edge flip resistance" detector windows are visible */
1784 EdgeWindowsShow();
1785 }
1786
1787 static int
_DeskCurrentGotoAreaRun(EObj * eo __UNUSED__,int run,void * state)1788 _DeskCurrentGotoAreaRun(EObj * eo __UNUSED__, int run, void *state)
1789 {
1790 slide_area_data_t *sad = (slide_area_data_t *) state;
1791 EWin *ewin;
1792 int i, dx, dy;
1793
1794 dx = (run * sad->slide_dx) >> 10;
1795 dy = (run * sad->slide_dy) >> 10;
1796
1797 for (i = 0; i < sad->n_ewins_slide; i++)
1798 {
1799 ewin = sad->ewins_slide[i];
1800 EoMove(ewin, ewin->trg_x + dx, ewin->trg_y + dy);
1801 }
1802
1803 if (run == 0)
1804 {
1805 _DeskCurrentGotoAreaEnd(sad);
1806 EventsBlock(0);
1807 }
1808
1809 return 0;
1810 }
1811
1812 void
DeskCurrentGotoArea(int ax,int ay)1813 DeskCurrentGotoArea(int ax, int ay)
1814 {
1815 slide_area_data_t _sad, *sad = &_sad;
1816 EWin *const *lst, *ewin;
1817 int i, num, dx, dy, pax, pay;
1818
1819 if (desks.anim_slide)
1820 return;
1821
1822 if ((Mode.mode == MODE_RESIZE) || (Mode.mode == MODE_RESIZE_H)
1823 || (Mode.mode == MODE_RESIZE_V))
1824 return;
1825
1826 if (_DeskAreaSwitchCheckEwins())
1827 return;
1828
1829 DesksFixArea(&ax, &ay);
1830 DeskCurrentGetArea(&pax, &pay);
1831
1832 if (ax == pax && ay == pay)
1833 return;
1834
1835 _DeskCurrentGotoAreaStart(pax, pay, ax, ay);
1836
1837 /* move all the windows around */
1838 dx = WinGetW(VROOT) * (ax - pax);
1839 dy = WinGetH(VROOT) * (ay - pay);
1840 lst = EwinListGetAll(&num);
1841 sad->ewins_desk = lst;
1842 sad->n_ewins_desk = num;
1843 sad->ewins_slide = NULL;
1844 sad->n_ewins_slide = 0;
1845 sad->slide_dx = dx;
1846 sad->slide_dy = dy;
1847
1848 if (Conf.desks.slidein && Conf.desks.slidespeed > 10)
1849 {
1850 int wnum = 0;
1851 EWin **wl = NULL;
1852
1853 /* create the list of windwos to move */
1854 for (i = 0; i < num; i++)
1855 {
1856 ewin = lst[i];
1857 if (EoIsSticky(ewin) || ewin->state.iconified)
1858 continue;
1859 if (EoGetDesk(ewin) != DesksGetCurrent() && !EoIsFloating(ewin))
1860 continue;
1861
1862 if (EoIsFloating(ewin) && Conf.movres.mode_move == MR_OPAQUE)
1863 continue;
1864
1865 wnum++;
1866 wl = EREALLOC(EWin *, wl, wnum);
1867 wl[wnum - 1] = ewin;
1868 ewin->trg_x = EoGetX(ewin) - dx;
1869 ewin->trg_y = EoGetY(ewin) - dy;
1870 }
1871 sad->ewins_slide = wl;
1872 sad->n_ewins_slide = wnum;
1873
1874 /* slide them */
1875 if (wl)
1876 {
1877 desks.anim_slide =
1878 AnimatorAdd(NULL, ANIM_SLIDE, _DeskCurrentGotoAreaRun,
1879 1000000 / Conf.desks.slidespeed,
1880 0, sizeof(slide_area_data_t), sad);
1881 EventsBlock(1);
1882 return;
1883 }
1884 }
1885 _DeskCurrentGotoAreaEnd(sad);
1886 }
1887
1888 void
DeskCurrentMoveAreaBy(int dx,int dy)1889 DeskCurrentMoveAreaBy(int dx, int dy)
1890 {
1891 int ax, ay;
1892
1893 DeskCurrentGetArea(&ax, &ay);
1894 DeskCurrentGotoArea(ax + dx, ay + dy);
1895 }
1896
1897 /*
1898 * Actions, events
1899 */
1900 static char sentpress = 0;
1901
1902 static void
ButtonProxySendEvent(XEvent * ev)1903 ButtonProxySendEvent(XEvent * ev)
1904 {
1905 if (Mode.button_proxy_win)
1906 EXSendEvent(Mode.button_proxy_win, SubstructureNotifyMask, ev);
1907 }
1908
1909 static void
DeskDragStart(int desk)1910 DeskDragStart(int desk)
1911 {
1912 Desk *dsk;
1913
1914 dsk = DeskGet(desk);
1915 if (!dsk)
1916 return;
1917
1918 desks.drag_x0 = Mode.events.cx - EoGetX(dsk);
1919 desks.drag_y0 = Mode.events.cy - EoGetY(dsk);
1920
1921 Mode.mode = MODE_DESKDRAG;
1922 }
1923
1924 static void
DeskDragEnd(Desk * dsk __UNUSED__)1925 DeskDragEnd(Desk * dsk __UNUSED__)
1926 {
1927 Mode.mode = MODE_NONE;
1928 }
1929
1930 static void
DeskDragMotion(Desk * dsk)1931 DeskDragMotion(Desk * dsk)
1932 {
1933 int x, y;
1934
1935 x = Mode.events.mx - desks.drag_x0;
1936 y = Mode.events.my - desks.drag_y0;
1937
1938 switch (Conf.desks.dragdir)
1939 {
1940 case 0:
1941 if (x < 0)
1942 x = 0;
1943 y = 0;
1944 break;
1945 case 1:
1946 if (x > 0)
1947 x = 0;
1948 y = 0;
1949 break;
1950 case 2:
1951 x = 0;
1952 if (y < 0)
1953 y = 0;
1954 break;
1955 case 3:
1956 x = 0;
1957 if (y > 0)
1958 y = 0;
1959 break;
1960 default:
1961 break;
1962 }
1963 DeskMove(dsk, x, y);
1964 }
1965
1966 static void
DeskButtonCallback(void * prm,XEvent * ev,ActionClass * ac)1967 DeskButtonCallback(void *prm, XEvent * ev, ActionClass * ac)
1968 {
1969 Desk *dsk = (Desk *) prm;
1970
1971 if (Mode.mode != MODE_DESKDRAG)
1972 {
1973 if (ac)
1974 ActionclassEvent(ac, ev, NULL);
1975 return;
1976 }
1977
1978 switch (ev->type)
1979 {
1980 case ButtonRelease:
1981 DeskDragEnd(dsk);
1982 break;
1983 case MotionNotify:
1984 DeskDragMotion(dsk);
1985 break;
1986 }
1987 }
1988
1989 static int
DeskCheckAction(Desk * dsk __UNUSED__,XEvent * ev)1990 DeskCheckAction(Desk * dsk __UNUSED__, XEvent * ev)
1991 {
1992 ActionClass *ac;
1993
1994 ac = ActionclassFind("DESKBINDINGS");
1995 if (!ac)
1996 return 0;
1997
1998 return ActionclassEvent(ac, ev, NULL);
1999 }
2000
2001 static void
DeskEventButtonPress(Desk * dsk,XEvent * ev)2002 DeskEventButtonPress(Desk * dsk, XEvent * ev)
2003 {
2004 /* Don't handle desk bindings while doing stuff */
2005 if (Mode.mode)
2006 return;
2007
2008 GrabPointerRelease();
2009
2010 if (!DeskCheckAction(dsk, ev))
2011 ButtonProxySendEvent(ev);
2012 }
2013
2014 static void
DeskEventButtonRelease(Desk * dsk,XEvent * ev)2015 DeskEventButtonRelease(Desk * dsk, XEvent * ev)
2016 {
2017 /* Don't handle desk bindings while doing stuff */
2018 if (Mode.mode)
2019 return;
2020
2021 if (sentpress)
2022 {
2023 /* We never get here? */
2024 sentpress = 0;
2025 ButtonProxySendEvent(ev);
2026 }
2027
2028 DeskCheckAction(dsk, ev);
2029 }
2030
2031 static void
DeskRootResize(int root,int w,int h)2032 DeskRootResize(int root, int w, int h)
2033 {
2034 if (EDebug(EDBUG_TYPE_DESKS))
2035 Eprintf("%s: %d %dx%d\n", __func__, root, w, h);
2036
2037 if (root && (VROOT != RROOT))
2038 {
2039 WinGetW(RROOT) = w;
2040 WinGetH(RROOT) = h;
2041 }
2042
2043 /* Quit if no change */
2044 if (w == WinGetW(VROOT) && h == WinGetH(VROOT))
2045 return;
2046
2047 EWindowSync(VROOT);
2048
2049 /* Quit if size is not final */
2050 if (w != WinGetW(VROOT) || h != WinGetH(VROOT))
2051 return;
2052
2053 ScreenInit();
2054 DesksResize(w, h);
2055
2056 HintsSetDesktopConfig();
2057
2058 Mode.screen.w_old = WinGetW(VROOT);
2059 Mode.screen.h_old = WinGetH(VROOT);
2060 }
2061
2062 static ActionClass *
DeskGetAclass(void * data __UNUSED__)2063 DeskGetAclass(void *data __UNUSED__)
2064 {
2065 return ActionclassFind("DESKBINDINGS");
2066 }
2067
2068 static void
DeskPropertyChange(Desk * dsk,XEvent * ev)2069 DeskPropertyChange(Desk * dsk, XEvent * ev)
2070 {
2071 EX_Pixmap pmap;
2072
2073 if (ev->xproperty.atom == ea_m._XROOTPMAP_ID)
2074 {
2075 /* Possible race here? */
2076 pmap = HintsGetRootPixmap(EoGetWin(dsk));
2077 if (EDebug(EDBUG_TYPE_DESKS))
2078 Eprintf("%s: win=%#lx _XROOTPMAP_ID=%#x\n", __func__,
2079 ev->xany.window, pmap);
2080 if (ev->xany.window != WinGetXwin(VROOT))
2081 return;
2082 if (pmap == dsk->bg.pmap)
2083 return;
2084 if (pmap == Mode.root.ext_pmap)
2085 return;
2086 Mode.root.ext_pmap = pmap;
2087 Mode.root.ext_pmap_valid = EXDrawableOk(pmap);
2088 DesksBackgroundRefresh(NULL, DESK_BG_REFRESH);
2089 }
2090 else if (ev->xproperty.atom == ea_m._XROOTCOLOR_PIXEL)
2091 {
2092 if (EDebug(EDBUG_TYPE_DESKS))
2093 Eprintf("%s: win=%#lx _XROOTCOLOR_PIXEL\n", __func__,
2094 ev->xany.window);
2095 if (ev->xany.window != WinGetXwin(VROOT))
2096 return;
2097 }
2098 }
2099
2100 static void
DeskHandleEvents(Win win __UNUSED__,XEvent * ev,void * prm)2101 DeskHandleEvents(Win win __UNUSED__, XEvent * ev, void *prm)
2102 {
2103 Desk *dsk = (Desk *) prm;
2104
2105 switch (ev->type)
2106 {
2107 case ButtonPress:
2108 DeskEventButtonPress(dsk, ev);
2109 break;
2110 case ButtonRelease:
2111 DeskEventButtonRelease(dsk, ev);
2112 break;
2113
2114 case EnterNotify:
2115 FocusHandleEnter(NULL, ev);
2116 break;
2117 case LeaveNotify:
2118 FocusHandleLeave(NULL, ev);
2119 break;
2120
2121 case MotionNotify:
2122 /* Motion over desk buttons doesn't go here - We probably don't care much. */
2123 DesksSetCurrent(DesktopAt(Mode.events.mx, Mode.events.my));
2124 TooltipsSetPending(1, DeskGetAclass, dsk);
2125 break;
2126
2127 case ConfigureNotify:
2128 if (ev->xconfigure.window != WinGetXwin(VROOT))
2129 break;
2130 if (Mode.wm.window) /* This test should not be necessary but... */
2131 {
2132 Mode.wm.win_x = ev->xconfigure.x;
2133 Mode.wm.win_y = ev->xconfigure.y;
2134 }
2135 DeskRootResize(0, ev->xconfigure.width, ev->xconfigure.height);
2136 break;
2137
2138 case PropertyNotify:
2139 if (ev->xany.window == WinGetXwin(VROOT))
2140 DeskPropertyChange(dsk, ev);
2141 break;
2142
2143 #if USE_XRANDR
2144 case EX_EVENT_SCREEN_CHANGE_NOTIFY:
2145 {
2146 XRRScreenChangeNotifyEvent *rrev = (XRRScreenChangeNotifyEvent *) ev;
2147
2148 EventsRandrScreenChange(ev);
2149
2150 DeskRootResize(1, rrev->width, rrev->height);
2151 }
2152 break;
2153 #endif
2154 }
2155 }
2156
2157 /* Settings */
2158
2159 static void
DeskDragdirSet(const char * params)2160 DeskDragdirSet(const char *params)
2161 {
2162 Desk *dsk;
2163 unsigned int i;
2164 int pd;
2165
2166 pd = Conf.desks.dragdir;
2167
2168 if (params && params[0])
2169 Conf.desks.dragdir = atoi(params);
2170 else
2171 {
2172 Conf.desks.dragdir++;
2173 if (Conf.desks.dragdir > 3)
2174 Conf.desks.dragdir = 0;
2175 }
2176
2177 if (pd == Conf.desks.dragdir)
2178 return;
2179
2180 for (i = 1; i < Conf.desks.num; i++)
2181 {
2182 dsk = _DeskGet(i);
2183 EoMove(dsk, (dsk->viewable) ? 0 : WinGetW(VROOT), 0);
2184 }
2185 DesksControlsRefresh();
2186 }
2187
2188 static void
DeskDragbarOrderSet(const char * params)2189 DeskDragbarOrderSet(const char *params)
2190 {
2191 int pd;
2192
2193 pd = Conf.desks.dragbar_ordering;
2194
2195 if (params && params[0])
2196 Conf.desks.dragbar_ordering = atoi(params);
2197 else
2198 {
2199 Conf.desks.dragbar_ordering++;
2200 if (Conf.desks.dragbar_ordering > 5)
2201 Conf.desks.dragbar_ordering = 0;
2202 }
2203
2204 if (pd == Conf.desks.dragbar_ordering)
2205 return;
2206
2207 DesksControlsRefresh();
2208 }
2209
2210 #if 0 /* FIXME */
2211
2212 static int
2213 doDragbarWidthSet(EWin * edummy, const char *params)
2214 {
2215 int pd;
2216 Button *b;
2217
2218 pd = Conf.desks.dragbar_width;
2219 if (params)
2220 Conf.desks.dragbar_width = atoi(params);
2221
2222 if (pd != Conf.desks.dragbar_width)
2223 {
2224 DesksControlsRefresh();
2225 }
2226 return 0;
2227 }
2228
2229 static int
2230 doDragbarLengthSet(EWin * edummy, const char *params)
2231 {
2232 int pd;
2233 Button *b;
2234
2235 pd = Conf.desks.dragbar_length;
2236 if (params)
2237 Conf.desks.dragbar_length = atoi(params);
2238
2239 if (pd != Conf.desks.dragbar_length)
2240 {
2241 DesksControlsRefresh();
2242 }
2243 return 0;
2244 }
2245 #endif
2246
2247 #if ENABLE_DESKRAY
2248 static int
doDeskray(EWin * edummy,const char * params)2249 doDeskray(EWin * edummy, const char *params)
2250 {
2251 if (params)
2252 {
2253 if (!atoi(params))
2254 {
2255 DeskHideTabs();
2256 Conf.deskmode = MODE_NONE;
2257 }
2258 else
2259 {
2260 Conf.deskmode = MODE_DESKRAY;
2261 DeskShowTabs();
2262 }
2263 }
2264 else
2265 {
2266 if (Conf.deskmode == MODE_DESKRAY)
2267 {
2268 DeskHideTabs();
2269 Conf.deskmode = MODE_NONE;
2270 }
2271 else
2272 {
2273 Conf.deskmode = MODE_DESKRAY;
2274 DeskShowTabs();
2275 }
2276 }
2277 return 0;
2278 }
2279 #endif /* ENABLE_DESKRAY */
2280
2281 static void
DesksInit(void)2282 DesksInit(void)
2283 {
2284 unsigned int i;
2285
2286 memset(&desks, 0, sizeof(desks));
2287
2288 Mode.screen.w_old = WinGetW(VROOT);
2289 Mode.screen.h_old = WinGetH(VROOT);
2290
2291 Mode.backgrounds.mini_w = WinGetW(VROOT) / 12;
2292 Mode.backgrounds.mini_h = WinGetH(VROOT) / 12;
2293
2294 /* Backward compatibility hack */
2295 if (Conf.desks.edge_flip_resistance <= 0)
2296 Conf.desks.edge_flip_mode = EDGE_FLIP_OFF;
2297
2298 desks.previous = NULL;
2299
2300 for (i = 0; i < Conf.desks.num; i++)
2301 DeskCreate(i, 0);
2302
2303 SetAreaSize(Conf.desks.areas_nx, Conf.desks.areas_ny);
2304
2305 /* Retreive stuff from last time we were loaded if we're restarting */
2306 EHintsGetDeskInfo();
2307
2308 HintsSetDesktopConfig();
2309 HintsSetDesktopViewport();
2310 }
2311
2312 static void
DesksConfigure(void)2313 DesksConfigure(void)
2314 {
2315 unsigned int i;
2316
2317 for (i = 0; i < Conf.desks.num; i++)
2318 DeskConfigure(_DeskGet(i));
2319
2320 UncoverDesktop(0);
2321 }
2322
2323 /*
2324 * Desktops Module
2325 */
2326
2327 static void
DesksSighan(int sig,void * prm __UNUSED__)2328 DesksSighan(int sig, void *prm __UNUSED__)
2329 {
2330 switch (sig)
2331 {
2332 case ESIGNAL_INIT:
2333 DesksInit();
2334 break;
2335
2336 case ESIGNAL_CONFIGURE:
2337 DesksConfigure();
2338 break;
2339
2340 case ESIGNAL_START:
2341 /* Draw all the buttons that belong on the desktop */
2342 DeskShowButtons();
2343 IdlerAdd(_DesksIdler, NULL);
2344 break;
2345 }
2346 }
2347
2348 #if ENABLE_DIALOGS
2349 /*
2350 * Dialogs
2351 */
2352 typedef struct {
2353 int desktops;
2354 int prev_desktops;
2355 DItem *desk_text;
2356 char desktop_slide;
2357 int desktop_slide_speed;
2358 char desktop_wraparound;
2359 char dragbar;
2360 int dragdir;
2361 char initialised;
2362 Win wins[ENLIGHTENMENT_CONF_NUM_DESKTOPS];
2363 } DeskDlgData;
2364
2365 static void
_DlgApplyDesktops(Dialog * d,int val __UNUSED__,void * data __UNUSED__)2366 _DlgApplyDesktops(Dialog * d, int val __UNUSED__, void *data __UNUSED__)
2367 {
2368 DeskDlgData *dd = DLG_DATA_GET(d, DeskDlgData);
2369
2370 ChangeNumberOfDesktops(dd->desktops);
2371 Conf.desks.slidein = dd->desktop_slide;
2372 Conf.desks.slidespeed = dd->desktop_slide_speed;
2373 Conf.desks.desks_wraparound = dd->desktop_wraparound;
2374
2375 if ((Conf.desks.dragdir != dd->dragdir) ||
2376 ((dd->dragbar) && (Conf.desks.dragbar_width < 1)) ||
2377 ((!dd->dragbar) && (Conf.desks.dragbar_width > 0)))
2378 {
2379 if (dd->dragbar)
2380 Conf.desks.dragbar_width = 16;
2381 else
2382 Conf.desks.dragbar_width = 0;
2383 Conf.desks.dragdir = dd->dragdir;
2384 DesksControlsRefresh();
2385 }
2386
2387 autosave();
2388 }
2389
2390 static void
CB_DesktopDisplayRedraw(Dialog * d,int val,void * data)2391 CB_DesktopDisplayRedraw(Dialog * d, int val, void *data)
2392 {
2393 DeskDlgData *dd = DLG_DATA_GET(d, DeskDlgData);
2394 DItem *di = (DItem *) data;
2395 int i;
2396 int w, h;
2397 Win win;
2398 char s[64];
2399 ImageClass *ic;
2400
2401 if ((val != 1) && (dd->prev_desktops == dd->desktops))
2402 return;
2403
2404 dd->prev_desktops = dd->desktops;
2405 win = DialogItemAreaGetWindow(di);
2406 DialogItemAreaGetSize(di, &w, &h);
2407
2408 if (!dd->initialised)
2409 {
2410 ic = ImageclassFind("SETTINGS_DESKTOP_AREA", 1);
2411 ImageclassApply(ic, win, 0, 0, STATE_NORMAL);
2412 dd->initialised = 1;
2413 }
2414
2415 for (i = 0; i < dd->desktops; i++)
2416 {
2417 if (!dd->wins[i])
2418 {
2419 Background *bg;
2420
2421 dd->wins[i] =
2422 ECreateWindow(win, 0, 0, Mode.backgrounds.mini_w,
2423 Mode.backgrounds.mini_h, 0);
2424 ESetWindowBorderWidth(dd->wins[i], 1);
2425
2426 bg = DeskBackgroundGet(DeskGet(i));
2427 if (bg)
2428 {
2429 EX_Pixmap pmap;
2430
2431 pmap = EGetWindowBackgroundPixmap(dd->wins[i]);
2432 BackgroundApplyPmap(bg, dd->wins[i], pmap,
2433 Mode.backgrounds.mini_w,
2434 Mode.backgrounds.mini_h);
2435 }
2436 else
2437 {
2438 ic = ImageclassFind("SETTINGS_DESKTOP_AREA", 1);
2439 ImageclassApply(ic, dd->wins[i], 0, 0, STATE_NORMAL);
2440 }
2441 }
2442 }
2443
2444 for (i = dd->desktops - 1; i >= 0; i--)
2445 {
2446 int num;
2447
2448 num = dd->desktops - 1;
2449 if (num < 1)
2450 num = 1;
2451 EMoveWindow(dd->wins[i], (i * (w - Mode.backgrounds.mini_w - 2)) / num,
2452 (i * (h - Mode.backgrounds.mini_h - 2)) / num);
2453 ERaiseWindow(dd->wins[i]);
2454 EMapWindow(dd->wins[i]);
2455 }
2456
2457 for (i = dd->desktops; i < ENLIGHTENMENT_CONF_NUM_DESKTOPS; i++)
2458 {
2459 if (!dd->wins[i])
2460 continue;
2461 EUnmapWindow(dd->wins[i]);
2462 }
2463
2464 Esnprintf(s, sizeof(s), "%i", dd->desktops);
2465 DialogItemSetText(dd->desk_text, s);
2466 }
2467
2468 static void
CB_DesktopDisplayAreaRedraw(DItem * di,int val __UNUSED__,void * data __UNUSED__)2469 CB_DesktopDisplayAreaRedraw(DItem * di, int val __UNUSED__,
2470 void *data __UNUSED__)
2471 {
2472 CB_DesktopDisplayRedraw(DialogItemGetDialog(di), 1, di);
2473 }
2474
2475 static void
_DlgFillDesks(Dialog * d,DItem * table,void * data __UNUSED__)2476 _DlgFillDesks(Dialog * d, DItem * table, void *data __UNUSED__)
2477 {
2478 DeskDlgData *dd = DLG_DATA_GET(d, DeskDlgData);
2479 DItem *di, *slider, *radio;
2480
2481 dd->desktops = Conf.desks.num;
2482 dd->prev_desktops = -1;
2483 dd->desktop_slide = Conf.desks.slidein;
2484 dd->desktop_slide_speed = Conf.desks.slidespeed;
2485 dd->desktop_wraparound = Conf.desks.desks_wraparound;
2486 if (Conf.desks.dragbar_width < 1)
2487 dd->dragbar = 0;
2488 else
2489 dd->dragbar = 1;
2490 dd->dragdir = Conf.desks.dragdir;
2491
2492 DialogItemTableSetOptions(table, 2, 0, 0, 0);
2493
2494 di = DialogAddItem(table, DITEM_TEXT);
2495 DialogItemSetColSpan(di, 2);
2496 DialogItemSetText(di, _("Number of virtual desktops:"));
2497
2498 di = dd->desk_text = DialogAddItem(table, DITEM_TEXT);
2499 DialogItemSetColSpan(di, 2);
2500 DialogItemSetText(di, "X");
2501
2502 di = slider = DialogAddItem(table, DITEM_SLIDER);
2503 DialogItemSliderSetBounds(di, 1, 32);
2504 DialogItemSliderSetUnits(di, 1);
2505 DialogItemSliderSetJump(di, 1);
2506 DialogItemSetColSpan(di, 2);
2507 DialogItemSliderSetValPtr(di, &dd->desktops);
2508
2509 di = DialogAddItem(table, DITEM_AREA);
2510 DialogItemSetColSpan(di, 2);
2511 DialogItemAreaSetSize(di, 2 * Mode.backgrounds.mini_w,
2512 2 * Mode.backgrounds.mini_h);
2513 DialogItemAreaSetInitFunc(di, CB_DesktopDisplayAreaRedraw);
2514
2515 DialogItemSetCallback(slider, CB_DesktopDisplayRedraw, 0, di);
2516
2517 di = DialogAddItem(table, DITEM_SEPARATOR);
2518 DialogItemSetColSpan(di, 2);
2519
2520 di = DialogAddItem(table, DITEM_CHECKBUTTON);
2521 DialogItemSetColSpan(di, 2);
2522 DialogItemSetText(di, _("Slide desktops around when changing"));
2523 DialogItemCheckButtonSetPtr(di, &dd->desktop_slide);
2524
2525 di = DialogAddItem(table, DITEM_TEXT);
2526 DialogItemSetColSpan(di, 2);
2527 DialogItemSetAlign(di, 1024, 512);
2528 DialogItemSetText(di, _("Desktop Slide speed:"));
2529
2530 di = DialogAddItem(table, DITEM_SLIDER);
2531 DialogItemSetColSpan(di, 2);
2532 DialogItemSliderSetBounds(di, 0, 20000);
2533 DialogItemSliderSetUnits(di, 500);
2534 DialogItemSliderSetJump(di, 1000);
2535 DialogItemSliderSetValPtr(di, &dd->desktop_slide_speed);
2536
2537 di = DialogAddItem(table, DITEM_SEPARATOR);
2538 DialogItemSetColSpan(di, 2);
2539
2540 di = DialogAddItem(table, DITEM_CHECKBUTTON);
2541 DialogItemSetColSpan(di, 2);
2542 DialogItemSetText(di, _("Wrap desktops around"));
2543 DialogItemCheckButtonSetPtr(di, &dd->desktop_wraparound);
2544
2545 di = DialogAddItem(table, DITEM_SEPARATOR);
2546 DialogItemSetColSpan(di, 2);
2547
2548 di = DialogAddItem(table, DITEM_CHECKBUTTON);
2549 DialogItemSetColSpan(di, 2);
2550 DialogItemSetText(di, _("Display desktop dragbar"));
2551 DialogItemCheckButtonSetPtr(di, &dd->dragbar);
2552
2553 di = DialogAddItem(table, DITEM_TEXT);
2554 DialogItemSetColSpan(di, 2);
2555 DialogItemSetAlign(di, 0, 512);
2556 DialogItemSetText(di, _("Drag bar position:"));
2557
2558 radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
2559 DialogItemSetColSpan(di, 2);
2560 DialogItemSetText(di, _("Top"));
2561 DialogItemRadioButtonSetFirst(di, radio);
2562 DialogItemRadioButtonGroupSetVal(di, 2);
2563
2564 di = DialogAddItem(table, DITEM_RADIOBUTTON);
2565 DialogItemSetColSpan(di, 2);
2566 DialogItemSetText(di, _("Bottom"));
2567 DialogItemRadioButtonSetFirst(di, radio);
2568 DialogItemRadioButtonGroupSetVal(di, 3);
2569
2570 di = DialogAddItem(table, DITEM_RADIOBUTTON);
2571 DialogItemSetColSpan(di, 2);
2572 DialogItemSetText(di, _("Left"));
2573 DialogItemRadioButtonSetFirst(di, radio);
2574 DialogItemRadioButtonGroupSetVal(di, 0);
2575
2576 di = DialogAddItem(table, DITEM_RADIOBUTTON);
2577 DialogItemSetColSpan(di, 2);
2578 DialogItemSetText(di, _("Right"));
2579 DialogItemRadioButtonSetFirst(di, radio);
2580 DialogItemRadioButtonGroupSetVal(di, 1);
2581 DialogItemRadioButtonGroupSetValPtr(radio, &dd->dragdir);
2582 }
2583
2584 const DialogDef DlgDesks = {
2585 "CONFIGURE_DESKTOPS",
2586 N_("Desks"), N_("Multiple Desktop Settings"),
2587 sizeof(DeskDlgData),
2588 SOUND_SETTINGS_DESKTOPS,
2589 "pix/desktops.png",
2590 N_("Enlightenment Multiple Desktop\n" "Settings Dialog"),
2591 _DlgFillDesks,
2592 DLG_OAC, _DlgApplyDesktops, NULL
2593 };
2594
2595 typedef struct {
2596 int area_x;
2597 int area_y;
2598 int edge_flip;
2599 int edge_resist;
2600 DItem *area_text;
2601 char area_wraparound;
2602 int prev_ax, prev_ay;
2603 Win awin;
2604 } AreaDlgData;
2605
2606 static void
_DlgApplyAreas(Dialog * d,int val __UNUSED__,void * data __UNUSED__)2607 _DlgApplyAreas(Dialog * d, int val __UNUSED__, void *data __UNUSED__)
2608 {
2609 AreaDlgData *dd = DLG_DATA_GET(d, AreaDlgData);
2610
2611 SetNewAreaSize(dd->area_x, dd->area_y);
2612 Conf.desks.areas_wraparound = dd->area_wraparound;
2613 Conf.desks.edge_flip_mode = dd->edge_flip;
2614 if (dd->edge_resist < 1)
2615 dd->edge_resist = 1;
2616 Conf.desks.edge_flip_resistance = dd->edge_resist;
2617 EdgeWindowsShow();
2618
2619 autosave();
2620 }
2621
2622 static void
CB_AreaDisplayRedraw(Dialog * d,int val,void * data)2623 CB_AreaDisplayRedraw(Dialog * d, int val, void *data)
2624 {
2625 AreaDlgData *dd = DLG_DATA_GET(d, AreaDlgData);
2626 DItem *di = (DItem *) data;
2627 char s[64];
2628 Win win;
2629 int w, h, ww, hh;
2630
2631 if ((val != 1) && (dd->prev_ax == dd->area_x) && (dd->prev_ay == dd->area_y))
2632 return;
2633
2634 dd->prev_ax = dd->area_x;
2635 dd->prev_ay = dd->area_y;
2636
2637 win = DialogItemAreaGetWindow(di);
2638 DialogItemAreaGetSize(di, &w, &h);
2639
2640 if (val == 1)
2641 {
2642 ImageClass *ic;
2643 EX_Pixmap pmap;
2644
2645 ic = ImageclassFind("SETTINGS_AREA_AREA", 1);
2646 ImageclassApply(ic, win, 0, 0, STATE_NORMAL);
2647
2648 /* Note: awin is destroyed when the dialog is destroyed */
2649 dd->awin = ECreateWindow(win, 0, 0, 18, 14, 0);
2650 ic = ImageclassFind("SETTINGS_AREADESK_AREA", 1);
2651 pmap = EGetWindowBackgroundPixmap(dd->awin);
2652 ImageclassApplySimple(ic, dd->awin, pmap, STATE_NORMAL, 0, 0, 18, 14);
2653 }
2654 ww = 18 * dd->prev_ax;
2655 hh = 14 * dd->prev_ay;
2656 EMoveResizeWindow(dd->awin, (w - ww) / 2, (h - hh) / 2, ww, hh);
2657 EMapWindow(dd->awin);
2658
2659 Esnprintf(s, sizeof(s), "%i x %i", dd->prev_ax, dd->prev_ay);
2660 DialogItemSetText(dd->area_text, s);
2661 }
2662
2663 static void
CB_AreaDisplayAreaRedraw(DItem * di,int val __UNUSED__,void * data __UNUSED__)2664 CB_AreaDisplayAreaRedraw(DItem * di, int val __UNUSED__, void *data __UNUSED__)
2665 {
2666 CB_AreaDisplayRedraw(DialogItemGetDialog(di), 1, di);
2667 }
2668
2669 static void
_DlgFillAreas(Dialog * d,DItem * table,void * data __UNUSED__)2670 _DlgFillAreas(Dialog * d, DItem * table, void *data __UNUSED__)
2671 {
2672 AreaDlgData *dd = DLG_DATA_GET(d, AreaDlgData);
2673 DItem *di, *slider, *slider2, *table2, *radio;
2674
2675 dd->area_wraparound = Conf.desks.areas_wraparound;
2676
2677 dd->edge_flip = Conf.desks.edge_flip_mode;
2678 dd->edge_resist = Conf.desks.edge_flip_resistance;
2679
2680 DesksGetAreaSize(&dd->area_x, &dd->area_y);
2681
2682 DialogItemTableSetOptions(table, 1, 0, 0, 0);
2683
2684 di = DialogAddItem(table, DITEM_TEXT);
2685 DialogItemSetText(di, _("Virtual Desktop size:"));
2686
2687 di = dd->area_text = DialogAddItem(table, DITEM_TEXT);
2688 DialogItemSetText(di, "X");
2689
2690 table2 = DialogAddItem(table, DITEM_TABLE);
2691 DialogItemTableSetOptions(table2, 2, 0, 0, 0);
2692
2693 DialogAddItem(table2, DITEM_NONE);
2694
2695 di = slider = DialogAddItem(table2, DITEM_SLIDER);
2696 DialogItemSliderSetMinLength(di, 10);
2697 DialogItemSliderSetBounds(di, 1, 8);
2698 DialogItemSliderSetUnits(di, 1);
2699 DialogItemSliderSetJump(di, 1);
2700 DialogItemSliderSetValPtr(di, &dd->area_x);
2701
2702 di = slider2 = DialogAddItem(table2, DITEM_SLIDER);
2703 DialogItemSliderSetMinLength(di, 10);
2704 DialogItemSliderSetOrientation(di, 0);
2705 DialogItemSetFill(di, 0, 1);
2706 DialogItemSliderSetBounds(di, 1, 8);
2707 DialogItemSliderSetUnits(di, 1);
2708 DialogItemSliderSetJump(di, 1);
2709 DialogItemSliderSetValPtr(di, &dd->area_y);
2710
2711 di = DialogAddItem(table2, DITEM_AREA);
2712 DialogItemAreaSetSize(di, 160, 120);
2713 DialogItemAreaSetInitFunc(di, CB_AreaDisplayAreaRedraw);
2714
2715 DialogItemSetCallback(slider, CB_AreaDisplayRedraw, 0, di);
2716 DialogItemSetCallback(slider2, CB_AreaDisplayRedraw, 0, di);
2717
2718 DialogAddItem(table, DITEM_SEPARATOR);
2719
2720 di = DialogAddItem(table, DITEM_CHECKBUTTON);
2721 DialogItemSetText(di, _("Wrap virtual desktops around"));
2722 DialogItemCheckButtonSetPtr(di, &dd->area_wraparound);
2723
2724 DialogAddItem(table, DITEM_SEPARATOR);
2725
2726 di = DialogAddItem(table, DITEM_TEXT);
2727 DialogItemSetAlign(di, 0, 512);
2728 DialogItemSetText(di, _("Edge Flip Mode:"));
2729
2730 radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
2731 DialogItemSetText(di, _("Off"));
2732 DialogItemRadioButtonSetFirst(di, radio);
2733 DialogItemRadioButtonGroupSetVal(di, EDGE_FLIP_OFF);
2734
2735 di = DialogAddItem(table, DITEM_RADIOBUTTON);
2736 DialogItemSetText(di, _("On"));
2737 DialogItemRadioButtonSetFirst(di, radio);
2738 DialogItemRadioButtonGroupSetVal(di, EDGE_FLIP_ON);
2739
2740 di = DialogAddItem(table, DITEM_RADIOBUTTON);
2741 DialogItemSetText(di, _("Only when moving window"));
2742 DialogItemRadioButtonSetFirst(di, radio);
2743 DialogItemRadioButtonGroupSetVal(di, EDGE_FLIP_MOVE);
2744 DialogItemRadioButtonGroupSetValPtr(radio, &dd->edge_flip);
2745
2746 di = DialogAddItem(table, DITEM_TEXT);
2747 DialogItemSetText(di, _("Resistance at edge of screen:"));
2748
2749 di = DialogAddItem(table, DITEM_SLIDER);
2750 DialogItemSliderSetMinLength(di, 10);
2751 DialogItemSliderSetBounds(di, 1, 100);
2752 DialogItemSliderSetUnits(di, 1);
2753 DialogItemSliderSetJump(di, 10);
2754 DialogItemSliderSetValPtr(di, &dd->edge_resist);
2755 }
2756
2757 const DialogDef DlgAreas = {
2758 "CONFIGURE_AREA",
2759 N_("Areas"), N_("Virtual Desktop Settings"),
2760 sizeof(AreaDlgData),
2761 SOUND_SETTINGS_AREA,
2762 "pix/areas.png",
2763 N_("Enlightenment Virtual Desktop\n" "Settings Dialog"),
2764 _DlgFillAreas,
2765 DLG_OAC, _DlgApplyAreas, NULL
2766 };
2767 #endif /* ENABLE_DIALOGS */
2768
2769 /*
2770 * IPC functions
2771 */
2772
2773 static void
DeskOpGoto(unsigned int desk)2774 DeskOpGoto(unsigned int desk)
2775 {
2776 Desk *dsk;
2777 Desk *pd = DesksGetCurrent();
2778
2779 if (desk >= Conf.desks.num)
2780 return;
2781
2782 dsk = _DeskGet(desk);
2783
2784 DeskGoto(dsk);
2785
2786 if (DesksGetCurrent() != pd)
2787 SoundPlay(SOUND_DESKTOP_SHUT);
2788 }
2789
2790 static void
DeskOpGotoRel(int drel)2791 DeskOpGotoRel(int drel)
2792 {
2793 int desk;
2794
2795 desk = (int)DesksGetCurrentNum() + drel;
2796 if (Conf.desks.desks_wraparound)
2797 desk = (desk + Conf.desks.num) % Conf.desks.num;
2798
2799 DeskOpGoto((unsigned int)desk);
2800 }
2801
2802 static void
DeskOpDrag(int desk)2803 DeskOpDrag(int desk)
2804 {
2805 DeskDragStart(desk);
2806 }
2807
2808 static void
DesksIpcDesk(const char * params)2809 DesksIpcDesk(const char *params)
2810 {
2811 const char *p;
2812 char cmd[128], prm[128];
2813 int len, value;
2814 unsigned int desk;
2815
2816 cmd[0] = prm[0] = '\0';
2817 p = params;
2818 if (p)
2819 {
2820 len = 0;
2821 sscanf(p, "%100s %100s %n", cmd, prm, &len);
2822 p += len;
2823 }
2824
2825 desk = DesksGetCurrentNum();
2826
2827 if (!p || cmd[0] == '?')
2828 {
2829 IpcPrintf("Current Desktop: %d/%d\n", desk, Conf.desks.num);
2830 }
2831 else if (!strncmp(cmd, "set", 3))
2832 {
2833 sscanf(prm, "%u", &desk);
2834 ChangeNumberOfDesktops(desk);
2835 }
2836 else if (!strncmp(cmd, "list", 2))
2837 {
2838 Desk *dsk;
2839
2840 for (desk = 0; desk < Conf.desks.num; desk++)
2841 {
2842 dsk = _DeskGet(desk);
2843 IpcPrintf
2844 ("Desk %d: viewable=%d order=%d x,y=%4d,%4d wxh=%4dx%4d area x,y=%d,%d pmap=%#x\n",
2845 desk, dsk->viewable, desks.order[desk],
2846 EoGetX(dsk), EoGetY(dsk), EoGetW(dsk), EoGetH(dsk),
2847 dsk->current_area_x, dsk->current_area_y, dsk->bg.pmap);
2848 }
2849 }
2850 else if (!strncmp(cmd, "goto", 2))
2851 {
2852 sscanf(prm, "%u", &desk);
2853 DeskOpGoto(desk);
2854 }
2855 else if (!strncmp(cmd, "next", 2))
2856 {
2857 DeskOpGotoRel(1);
2858 }
2859 else if (!strncmp(cmd, "prev", 2))
2860 {
2861 DeskOpGotoRel(-1);
2862 }
2863 else if (!strncmp(cmd, "back", 2))
2864 {
2865 DeskOpGoto(desks.prev_num);
2866 }
2867 else if (!strncmp(cmd, "this", 2))
2868 {
2869 DeskOpGotoRel(0);
2870 }
2871 else if (!strncmp(cmd, "raise", 2))
2872 {
2873 sscanf(prm, "%u", &desk);
2874 SoundPlay(SOUND_DESKTOP_RAISE);
2875 DeskRaise(desk);
2876 }
2877 else if (!strncmp(cmd, "lower", 2))
2878 {
2879 sscanf(prm, "%u", &desk);
2880 SoundPlay(SOUND_DESKTOP_LOWER);
2881 DeskLower(desk);
2882 }
2883 else if (!strcmp(cmd, "drag"))
2884 {
2885 if (prm[0])
2886 desk = atoi(prm);
2887 DeskOpDrag(desk);
2888 }
2889 else if (!strcmp(cmd, "clear"))
2890 {
2891 if (!strcmp(prm, "on"))
2892 value = 1;
2893 else if (!strcmp(prm, "off"))
2894 value = 0;
2895 else
2896 value = !Mode.showing_desktop;
2897 EwinsShowDesktop(value);
2898 }
2899 else if (!strncmp(cmd, "arrange", 3))
2900 {
2901 ArrangeEwins(prm);
2902 }
2903 }
2904
2905 static void
DesksIpcArea(const char * params)2906 DesksIpcArea(const char *params)
2907 {
2908 const char *p;
2909 char cmd[128], prm[128];
2910 int len;
2911 int ax, ay, dx, dy;
2912
2913 cmd[0] = prm[0] = '\0';
2914 p = params;
2915 if (p)
2916 {
2917 len = 0;
2918 sscanf(p, "%100s %100s %n", cmd, prm, &len);
2919 p += len;
2920 }
2921
2922 DeskCurrentGetArea(&ax, &ay);
2923
2924 if (!p || cmd[0] == '?')
2925 {
2926 IpcPrintf("Current Area: %d %d\n", ax, ay);
2927 }
2928 else if (!strncmp(cmd, "set", 3))
2929 {
2930 sscanf(params, "%*s %i %i", &ax, &ay);
2931 SetNewAreaSize(ax, ay);
2932 }
2933 else if (!strncmp(cmd, "goto", 2))
2934 {
2935 sscanf(params, "%*s %i %i", &ax, &ay);
2936 DeskCurrentGotoArea(ax, ay);
2937 }
2938 else if (!strncmp(cmd, "move", 2))
2939 {
2940 dx = dy = 0;
2941 sscanf(params, "%*s %i %i", &dx, &dy);
2942 DeskCurrentMoveAreaBy(dx, dy);
2943 }
2944 else if (!strncmp(cmd, "lgoto", 2))
2945 {
2946 sscanf(params, "%*s %i", &ax);
2947 SetCurrentLinearArea(ax);
2948 }
2949 else if (!strncmp(cmd, "lmove", 2))
2950 {
2951 dx = 0;
2952 sscanf(params, "%*s %i", &dx);
2953 MoveCurrentLinearAreaBy(dx);
2954 }
2955 }
2956
2957 static const IpcItem DesksIpcArray[] = {
2958 {
2959 DesksIpcDesk,
2960 "desk", NULL,
2961 "Desktop functions",
2962 " desk ? Desktop info\n"
2963 " desk drag Start deskdrag\n"
2964 " desk set <nd> Set number of desktops\n"
2965 " desk goto <d> Goto specified desktop\n"
2966 " desk list Show desk info\n"
2967 " desk next Goto next desktop\n"
2968 " desk prev Goto previous desktop\n"
2969 " desk back Goto previous active desktop\n"
2970 " desk this Goto this desktop\n"
2971 " desk lower <d> Lower desktop\n"
2972 " desk raise <d> Raise desktop\n"
2973 " desk arrange Arrange windows on desktop\"\n"
2974 " desk clear [on/off] \"Show Desktop\"\n"}
2975 ,
2976 {
2977 DesksIpcArea,
2978 "area", NULL,
2979 "Area functions",
2980 " area ? Area info\n"
2981 " area set <nx> <ny> Set area size\n"
2982 " area goto <ax> <ay> Goto specified area\n"
2983 " area move <dx> <dy> Move relative to current area\n"
2984 " area lgoto <al> Goto specified linear area\n"
2985 " area lmove <dl> Move relative to current linear area\n"}
2986 ,
2987 };
2988
2989 static void
DesksCfgFuncCount(void * item __UNUSED__,const char * value)2990 DesksCfgFuncCount(void *item __UNUSED__, const char *value)
2991 {
2992 ChangeNumberOfDesktops(atoi(value));
2993 }
2994
2995 static void
DesksCfgFuncDragdir(void * item __UNUSED__,const char * value)2996 DesksCfgFuncDragdir(void *item __UNUSED__, const char *value)
2997 {
2998 DeskDragdirSet(value);
2999 }
3000
3001 static void
DesksCfgFuncDragdbarOrder(void * item __UNUSED__,const char * value)3002 DesksCfgFuncDragdbarOrder(void *item __UNUSED__, const char *value)
3003 {
3004 DeskDragbarOrderSet(value);
3005 }
3006
3007 static void
AreasCfgFuncSizeX(void * item __UNUSED__,const char * value)3008 AreasCfgFuncSizeX(void *item __UNUSED__, const char *value)
3009 {
3010 int ax, ay;
3011
3012 DesksGetAreaSize(&ax, &ay);
3013 SetNewAreaSize(atoi(value), ay);
3014 }
3015
3016 static void
AreasCfgFuncSizeY(void * item __UNUSED__,const char * value)3017 AreasCfgFuncSizeY(void *item __UNUSED__, const char *value)
3018 {
3019 int ax, ay;
3020
3021 DesksGetAreaSize(&ax, &ay);
3022 SetNewAreaSize(ax, atoi(value));
3023 }
3024
3025 static const CfgItem DesksCfgItems[] = {
3026 CFG_FUNC_INT(Conf.desks, num, 2, DesksCfgFuncCount),
3027 CFG_FUNC_INT(Conf.desks, dragdir, 2, DesksCfgFuncDragdir),
3028 CFG_ITEM_INT(Conf.desks, dragbar_width, 16),
3029 CFG_ITEM_INT(Conf.desks, dragbar_length, 0),
3030 CFG_FUNC_INT(Conf.desks, dragbar_ordering, 1, DesksCfgFuncDragdbarOrder),
3031 CFG_ITEM_BOOL(Conf.desks, desks_wraparound, 0),
3032 CFG_ITEM_BOOL(Conf.desks, slidein, 1),
3033 CFG_ITEM_INT(Conf.desks, slidespeed, 6000),
3034
3035 CFG_FUNC_INT(Conf.desks, areas_nx, 2, AreasCfgFuncSizeX),
3036 CFG_FUNC_INT(Conf.desks, areas_ny, 1, AreasCfgFuncSizeY),
3037 CFG_ITEM_BOOL(Conf.desks, areas_wraparound, 0),
3038
3039 CFG_ITEM_INT(Conf.desks, edge_flip_mode, EDGE_FLIP_ON),
3040 CFG_ITEM_INT(Conf.desks, edge_flip_resistance, 25),
3041 };
3042
3043 /*
3044 * Module descriptor
3045 */
3046 extern const EModule ModDesktops;
3047
3048 const EModule ModDesktops = {
3049 "desktops", "desk",
3050 DesksSighan,
3051 MOD_ITEMS(DesksIpcArray),
3052 MOD_ITEMS(DesksCfgItems)
3053 };
3054