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