1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2021 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "config.h"
25 
26 #include <X11/Xlib.h>
27 #if USE_XRENDER
28 #include <X11/extensions/Xrender.h>
29 #endif
30 
31 #include "E.h"
32 #include "backgrounds.h"
33 #include "desktops.h"
34 #include "dialog.h"
35 #include "ecompmgr.h"
36 #include "emodule.h"
37 #include "ewins.h"
38 #include "focus.h"
39 #include "groups.h"
40 #include "hints.h"
41 #include "hiwin.h"
42 #include "iclass.h"
43 #include "list.h"
44 #include "menus.h"
45 #include "settings.h"
46 #include "timers.h"
47 #include "tooltips.h"
48 #include "xwin.h"
49 
50 #define DEBUG_PAGER 0
51 #if DEBUG_PAGER
52 #define Dprintf(fmt...) if(EDebug(EDBUG_TYPE_PAGER))Eprintf(fmt)
53 #else
54 #define Dprintf(fmt...)
55 #endif
56 
57 #define USE_PAGER_BACKGROUND_CACHE 1
58 #define HIQ ((Conf_pagers.hiq) ? 0x200 : 0x100)
59 
60 #define PAGER_MODE_SIMPLE 0
61 #define PAGER_MODE_SNAP   1
62 #define PAGER_MODE_LIVE   2
63 
64 #define PAGER_UPD_EWIN_GEOM     0
65 #define PAGER_UPD_EWIN_GONE     1
66 #define PAGER_UPD_EWIN_DAMAGE   2
67 
68 #define EwinGetVX(ew) (ew->vx)
69 #define EwinGetVY(ew) (ew->vy)
70 #define EwinGetVX2(ew) (ew->vx + EoGetW(ew))
71 #define EwinGetVY2(ew) (ew->vy + EoGetH(ew))
72 
73 static struct {
74    char                enable;
75    char                zoom;
76    char                title;
77    char                hiq;
78    int                 mode;
79    int                 scanspeed;
80    int                 sel_button;
81    int                 win_button;
82    int                 menu_button;
83 } Conf_pagers;
84 
85 static struct {
86    int                 zoom;
87    Idler              *idler;
88    char                update_pending;
89    char                timer_pending;
90 } Mode_pagers;
91 
92 typedef struct {
93    dlist_t             list;
94    EWin               *ewin;
95    Win                 win;
96    int                 w, h;
97    EX_Pixmap           bgpmap;
98    Desk               *dsk;
99    int                 dw, dh;
100    int                 screen_w, screen_h;
101    int                 update_phase;
102    Win                 sel_win;
103    Timer              *scan_timer;
104 
105    /* State flags */
106    char                do_newbg;
107    char                do_update;
108    int                 x1, y1, x2, y2;
109    float               scale;
110    unsigned int        serial;
111    int                 serdif;
112 } Pager;
113 
114 static void         PagerScanCancel(Pager * p);
115 static int          PagerScanTimeout(void *data);
116 static void         PagerCheckUpdate(Pager * p, void *prm);
117 static void         PagerUpdateEwinsFromPager(Pager * p);
118 static void         PagerHiwinHide(void);
119 static void         PagerEvent(Win win, XEvent * ev, void *prm);
120 static void         PagerHiwinEvent(Win win, XEvent * ev, void *prm);
121 
122 static              LIST_HEAD(pager_list);
123 
124 static Hiwin       *hiwin = NULL;
125 
126 static int
PagersGetMode(void)127 PagersGetMode(void)
128 {
129    int                 mode = Conf_pagers.mode;
130 
131    if (mode == PAGER_MODE_LIVE && !ECompMgrIsActive())
132       mode = PAGER_MODE_SNAP;
133 
134    return mode;
135 }
136 
137 static Pager       *
PagerCreate(void)138 PagerCreate(void)
139 {
140    Pager              *p;
141 
142    if (!Conf_pagers.enable)
143       return NULL;
144 
145    p = ECALLOC(Pager, 1);
146    if (!p)
147       return NULL;
148 
149    LIST_APPEND(Pager, &pager_list, p);
150 
151    p->win = ECreateClientWindow(VROOT, 0, 0, 1, 1);
152    EventCallbackRegister(p->win, PagerEvent, p);
153    p->sel_win = ECreateWindow(p->win, 0, 0, 1, 1, 0);
154 
155    return p;
156 }
157 
158 static void
PagerDestroy(Pager * p)159 PagerDestroy(Pager * p)
160 {
161    LIST_REMOVE(Pager, &pager_list, p);
162 
163    PagerScanCancel(p);
164    PagerHiwinHide();
165    if (p->bgpmap != NoXID)
166       EFreePixmap(p->bgpmap);
167 
168    Efree(p);
169 }
170 
171 static void
PagerScanTrig(Pager * p)172 PagerScanTrig(Pager * p)
173 {
174    if (p->scan_timer || Conf_pagers.scanspeed <= 0)
175       return;
176 
177    TIMER_ADD(p->scan_timer, 1000 / Conf_pagers.scanspeed, PagerScanTimeout, p);
178 }
179 
180 static void
PagerScanCancel(Pager * p)181 PagerScanCancel(Pager * p)
182 {
183    TIMER_DEL(p->scan_timer);
184 }
185 
186 static int
PagerScanTimeout(void * data)187 PagerScanTimeout(void *data)
188 {
189    static const char   offsets[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
190    Pager              *p = (Pager *) data;
191    EWin               *ewin;
192    int                 y, y2, phase, cx, cy, ww, hh, xx, yy;
193    int                 pager_mode = PagersGetMode();
194 
195    if (pager_mode != PAGER_MODE_SNAP)
196       goto nomore;
197 
198    if (Mode.events.block)
199       return 1;
200 
201    ewin = p->ewin;
202    if (!ewin || !EoIsShown(ewin))
203       goto nomore;
204    if (p->dsk != DesksGetCurrent())
205       goto nomore;
206    if (ewin->state.visibility == VisibilityFullyObscured)
207       goto nomore;
208 
209    if (Conf_pagers.scanspeed <= 0)
210       goto nomore;
211 
212    if (Mode.mode != MODE_NONE)
213       goto nomore;
214 
215    DeskCurrentGetArea(&cx, &cy);
216    ww = p->dw;
217    hh = p->dh;
218    xx = cx * ww;
219    yy = cy * hh;
220    phase = p->update_phase;
221    if (ww <= 0 || hh <= 0)
222       goto nomore;
223 
224 #if 0
225    /* Due to a bug in imlib2 <= 1.2.0 we have to scan left->right in stead
226     * of top->bottom, at least for now. */
227    y = ((phase & 0xfffffff8) + offsets[phase % 8]) % hh;
228    y2 = (y * WinGetH(VROOT)) / hh;
229 
230    ScaleRect(VROOT, WinGetXwin(VROOT), p->win, WinGetPmap(p->win), 0,
231 	     y2, WinGetW(VROOT), WinGetH(VROOT) / hh, xx, yy + y, ww, 1, HIQ);
232    EClearArea(p->win, xx, yy + y, ww, 1);
233    y2 = p->h;
234 #else
235    y = ((phase & 0xfffffff8) + offsets[phase % 8]) % ww;
236    y2 = (y * WinGetW(VROOT)) / ww;
237 
238    ScaleRect(VROOT, WinGetXwin(VROOT), p->win, WinGetPmap(p->win), y2,
239 	     0, WinGetW(VROOT) / ww, WinGetH(VROOT), xx + y, yy, 1, hh, HIQ);
240    EClearArea(p->win, xx + y, yy, 1, hh);
241    y2 = p->w;
242 #endif
243    p->update_phase++;
244    if (p->update_phase >= y2)
245      {
246 	PagerUpdateEwinsFromPager(p);
247 	p->update_phase = 0;
248      }
249 
250    TimerSetInterval(p->scan_timer, 1000 / Conf_pagers.scanspeed);
251    return 1;
252 
253  nomore:
254    p->scan_timer = NULL;
255    return 0;
256 }
257 
258 #if 0				/* FIXME - Remove? */
259 static void
260 PagerHiwinUpdate(Hiwin * phi, Pager * p __UNUSED__, EWin * ewin)
261 {
262    EImage             *im;
263 
264    if (!EoIsShown(phi) || !ewin->mini_pmm.pmap)
265       return;
266 
267    im = EImageGrabDrawable(ewin->mini_pmm.pmap, NoXID, 0, 0,
268 			   ewin->mini_pmm.w, ewin->mini_pmm.h, 0);
269    EImageRenderOnDrawable(im, EoGetWin(phi), 0, 0, 0, EoGetW(phi), EoGetH(phi));
270    EImageDecache(im);
271 }
272 #endif
273 
274 static void
PagerEwinUpdateMini(Pager * p,EWin * ewin)275 PagerEwinUpdateMini(Pager * p, EWin * ewin)
276 {
277    int                 w, h, update, use_iclass, serdif;
278    EX_Drawable         draw;
279    int                 pager_mode = PagersGetMode();
280 
281    w = (EoGetW(ewin) * p->dw) / WinGetW(VROOT);
282    h = (EoGetH(ewin) * p->dh) / WinGetH(VROOT);
283 
284    if (w < 1)
285       w = 1;
286    if (h < 1)
287       h = 1;
288 
289    serdif = EoGetSerial(ewin) - p->serial;
290 
291    update = 0;
292    if (!ewin->mini_pmm.pmap)
293       update = 1;
294    if (ewin->mini_pmm.w != w || ewin->mini_pmm.h != h)
295       update = 1;
296 
297    if (serdif > 0 && ewin->type != EWIN_TYPE_PAGER &&
298        pager_mode == PAGER_MODE_LIVE && Mode.mode == 0)
299       update = 1;
300    if (serdif > p->serdif)
301       p->serdif = serdif;
302 
303    if (!update)
304       return;
305 
306    Dprintf("%s %#x/%#x wxh=%dx%d ser=%#x/%#x dif=%d: %s\n", __func__,
307 	   EwinGetClientXwin(ewin), EoGetXwin(ewin), w, h,
308 	   EoGetSerial(ewin), p->serial, serdif, EwinGetTitle(ewin));
309 
310    p->do_update = 1;
311 
312    PmapMaskInit(&ewin->mini_pmm, EoGetWin(ewin), w, h);
313 
314    draw = NoXID;
315    if (pager_mode != PAGER_MODE_SIMPLE)
316      {
317 	draw = EoGetPixmap(ewin);
318 	if (draw == NoXID && EwinIsOnScreen(ewin))
319 	   draw = EoGetXwin(ewin);
320      }
321    use_iclass = draw == NoXID;
322 
323    if (use_iclass)
324      {
325 	ImageClass         *ic;
326 
327 	ic = ImageclassFind("PAGER_WIN", 1);
328 	ImageclassApplySimple(ic, EoGetWin(ewin), ewin->mini_pmm.pmap,
329 			      STATE_NORMAL, 0, 0, w, h);
330 	Dprintf("Use Iclass, pmap=%#x\n", ewin->mini_pmm.pmap);
331      }
332    else
333      {
334 	ScaleRect(EoGetWin(ewin), draw, EoGetWin(ewin), ewin->mini_pmm.pmap,
335 		  0, 0, EoGetW(ewin), EoGetH(ewin), 0, 0, w, h, HIQ);
336 	Dprintf("Grab scaled, pmap=%#x\n", ewin->mini_pmm.pmap);
337      }
338 
339 #if 0				/* FIXME - Remove? */
340    if (hiwin && ewin == hiwin->ewin)
341       PagerHiwinUpdate(hiwin, p, ewin);
342 #endif
343 }
344 
345 static void
doPagerUpdate(Pager * p)346 doPagerUpdate(Pager * p)
347 {
348    int                 cx, cy, vx, vy;
349    EWin               *const *lst;
350    int                 i, num, update_screen_included, update_screen_only;
351    int                 pager_mode = PagersGetMode();
352    EX_Pixmap           pmap;
353 
354 #if USE_COMPOSITE
355    EX_Picture          pager_pict, pict, alpha;
356    XRenderPictureAttributes pa;
357 #endif
358 
359    p->update_phase = 0;
360    DeskGetArea(p->dsk, &cx, &cy);
361    vx = cx * WinGetW(VROOT);
362    vy = cy * WinGetH(VROOT);
363 
364    update_screen_included = update_screen_only = 0;
365    if (pager_mode == PAGER_MODE_SNAP && p->dsk == DesksGetCurrent()
366        && Mode.mode == 0)
367      {
368 	/* Update from screen unless update area is entirely off-screen */
369 	if (!(p->x2 <= vx || p->y2 <= vy ||
370 	      p->x1 >= vx + WinGetW(VROOT) || p->y1 >= vy + WinGetH(VROOT)))
371 	   update_screen_included = 1;
372 
373 	/* Check if update area is entirely on-screen */
374 	if (p->x1 >= vx && p->y1 >= vy &&
375 	    p->x2 <= vx + WinGetW(VROOT) && p->y2 <= vy + WinGetH(VROOT))
376 	   update_screen_only = 1;
377      }
378    p->x1 = p->y1 = 99999;
379    p->x2 = p->y2 = -99999;
380 
381    pmap = EGetWindowBackgroundPixmap(p->win);
382 
383    if (update_screen_only)
384       goto do_screen_update;
385 
386    lst = EwinListGetForDesk(&num, p->dsk);
387    for (i = num - 1; i >= 0; i--)
388      {
389 	EWin               *ewin;
390 
391 	ewin = lst[i];
392 	if (!EoIsShown(ewin))
393 	   continue;
394 
395 	PagerEwinUpdateMini(p, ewin);
396      }
397    if (p->serdif > 0)
398       p->serial += p->serdif;
399    p->serdif = 0;
400 
401    if (!p->do_update)
402       return;
403    p->do_update = 0;
404 
405    Dprintf("%s %d: Repaint\n", __func__, p->dsk->num);
406 
407    /* Tile background over pager areas */
408 #if USE_COMPOSITE
409    pager_pict = EPictureCreate(NULL, pmap);
410    pict = EPictureCreate(NULL, p->bgpmap);
411    pa.repeat = True;
412    XRenderChangePicture(disp, pict, CPRepeat, &pa);
413    XRenderComposite(disp, PictOpSrc, pict, NoXID, pager_pict,
414 		    0, 0, 0, 0, 0, 0, p->w, p->h);
415    EPictureDestroy(pict);
416 #else
417    EXCopyAreaTiled(p->bgpmap, NoXID, pmap, 0, 0, p->w, p->h, 0, 0);
418 #endif
419 
420    for (i = num - 1; i >= 0; i--)
421      {
422 	EWin               *ewin;
423 	int                 wx, wy, ww, wh;
424 
425 	ewin = lst[i];
426 	if (!EoIsShown(ewin))
427 	   continue;
428 
429 	wx = (EwinGetVX(ewin) * p->dw) / WinGetW(VROOT);
430 	wy = (EwinGetVY(ewin) * p->dh) / WinGetH(VROOT);
431 	ww = (EoGetW(ewin) * p->dw) / WinGetW(VROOT);
432 	wh = (EoGetH(ewin) * p->dh) / WinGetH(VROOT);
433 
434 	if (ewin->mini_pmm.pmap)
435 	  {
436 #if USE_COMPOSITE
437 	     /*      pmap set by           depth determined by
438 	      * PagerEwinUpdateMini()           ewin
439 	      * PagerEwinUpdateFromPager()      p->win
440 	      */
441 	     pict = EPictureCreate(ewin->mini_pmm.depth == WinGetDepth(p->win) ?
442 				   p->win : EoGetWin(ewin),
443 				   ewin->mini_pmm.pmap);
444 	     alpha = ECompMgrWinGetAlphaPict(EoObj(ewin));
445 	     XRenderComposite(disp, PictOpOver, pict, alpha, pager_pict,
446 			      0, 0, 0, 0, wx, wy, ww, wh);
447 	     EPictureDestroy(pict);
448 #else
449 #if 0				/* Mask is currently not set anywhere */
450 	     if (ewin->mini_pmm.mask)
451 	       {
452 		  XSetClipMask(disp, gc, ewin->mini_pmm.mask);
453 		  XSetClipOrigin(disp, gc, wx, wy);
454 	       }
455 #endif
456 	     EXCopyArea(ewin->mini_pmm.pmap, pmap, 0, 0, ww, wh, wx, wy);
457 #if 0				/* Mask is currently not set anywhere */
458 	     if (ewin->mini_pmm.mask)
459 		XSetClipMask(disp, gc, NoXID);
460 #endif
461 #endif
462 	  }
463 	else
464 	  {
465 	     EXPaintRectangle(pmap, wx, wy, ww, wh,
466 			      Dpy.pixel_black, Dpy.pixel_white);
467 	  }
468      }
469 #if USE_COMPOSITE
470    EPictureDestroy(pager_pict);
471 #endif
472 
473    if (!update_screen_included)
474      {
475 	EClearWindow(p->win);
476 	goto done;
477      }
478 
479  do_screen_update:
480    EobjsRepaint();
481    Dprintf("%s %d: Snap screen\n", __func__, p->dsk->num);
482    /* Update pager area by snapshotting entire screen */
483    ScaleRect(VROOT, WinGetXwin(VROOT), p->win, pmap, 0, 0,
484 	     WinGetW(VROOT), WinGetH(VROOT), cx * p->dw, cy * p->dh,
485 	     p->dw, p->dh, HIQ);
486 
487    EClearWindow(p->win);
488 
489    /* Update ewin snapshots */
490    PagerUpdateEwinsFromPager(p);
491 
492  done:
493    ;
494 }
495 
496 static void
PagerUpdate(Pager * p,int why,int x1,int y1,int x2,int y2)497 PagerUpdate(Pager * p, int why, int x1, int y1, int x2, int y2)
498 {
499    if (!Conf_pagers.enable)
500       return;
501 
502    if (p->x1 > x1)
503       p->x1 = x1;
504    if (p->y1 > y1)
505       p->y1 = y1;
506    if (p->x2 < x2)
507       p->x2 = x2;
508    if (p->y2 < y2)
509       p->y2 = y2;
510 
511    p->do_update = 1;
512    Mode_pagers.update_pending |= 1 << why;
513 }
514 
515 static void
PagerReconfigure(Pager * p,int apply)516 PagerReconfigure(Pager * p, int apply)
517 {
518    int                 ax, ay, w, h, dx, dy;
519    float               aspect, f;
520 
521    DesksGetAreaSize(&ax, &ay);
522 
523    aspect = ((float)WinGetW(VROOT)) / ((float)WinGetH(VROOT));
524 
525    dx = 2;
526    for (;;)
527      {
528 	f = dx / aspect;
529 	dy = (int)(f + .5f);
530 	f -= (float)dy;
531 	if (f < 0)
532 	   f = -f;
533 	if (f < .1f)
534 	   break;
535 	if (dx >= 8)
536 	   break;
537 	dx += 1;
538      }
539 
540    ICCCM_SetSizeConstraints(p->ewin,
541 			    WinGetW(VROOT) / 64 * ax,
542 			    WinGetH(VROOT) / 64 * ay,
543 			    WinGetW(VROOT) / 4 * ax,
544 			    WinGetH(VROOT) / 4 * ay, 0, 0, dx * ax, dy * ay,
545 			    aspect * ((float)ax / (float)ay),
546 			    aspect * ((float)ax / (float)ay));
547 
548    if (apply)
549      {
550 	w = (int)((float)ax * (float)WinGetW(VROOT) / (float)p->scale + .5f);
551 	h = (int)((float)ay * (float)WinGetH(VROOT) / (float)p->scale + .5f);
552 	EwinResize(p->ewin, w + (dx * ax) / 2, h + (dy * ay) / 2, 0);
553 	EwinReposition(p->ewin);
554      }
555 }
556 
557 static void
PagerUpdateBg(Pager * p)558 PagerUpdateBg(Pager * p)
559 {
560    EX_Pixmap           pmap;
561    Background         *bg;
562    ImageClass         *ic;
563    int                 pager_mode = PagersGetMode();
564 
565    p->x1 = p->y1 = 0;
566    p->x2 = p->y2 = 99999;
567 
568    pmap = p->bgpmap;
569    if (pmap != NoXID)
570       EFreePixmap(pmap);
571    pmap = p->bgpmap = ECreatePixmap(p->win, p->dw, p->dh, 0);
572 
573    bg = DeskBackgroundGet(p->dsk);
574    if (pager_mode != PAGER_MODE_SIMPLE && bg)
575      {
576 #if USE_PAGER_BACKGROUND_CACHE
577 	char                s[4096];
578 	char               *uniq;
579 	EImage             *im;
580 
581 	uniq = BackgroundGetUniqueString(bg);
582 	Esnprintf(s, sizeof(s), "%s/cached/pager/%s.%i.%i.%s.png",
583 		  EDirUserCache(), BackgroundGetName(bg), p->dw, p->dh, uniq);
584 	Efree(uniq);
585 
586 	im = EImageLoad(s);
587 	if (im)
588 	  {
589 	     EImageRenderOnDrawable(im, p->win, pmap, 0, 0, 0, p->dw, p->dh);
590 	     EImageDecache(im);
591 	  }
592 	else
593 	  {
594 #endif
595 	     BackgroundApplyPmap(bg, p->win, pmap, p->dw, p->dh);
596 #if USE_PAGER_BACKGROUND_CACHE
597 	     im = EImageGrabDrawable(pmap, NoXID, 0, 0, p->dw, p->dh, 0);
598 	     EImageSave(im, s);
599 	     EImageDecache(im);
600 	  }
601 #endif
602 	return;
603      }
604 
605    if (pager_mode != PAGER_MODE_SIMPLE && p->dsk->bg.pmap)
606      {
607 	ScaleTile(VROOT, p->dsk->bg.pmap, p->win, pmap,
608 		  0, 0, p->dw, p->dh, HIQ);
609 	return;
610      }
611 
612    ic = ImageclassFind("PAGER_BACKGROUND", 1);
613    if (ic)
614      {
615 	ImageclassApplySimple(ic, p->win, pmap, STATE_NORMAL,
616 			      0, 0, p->dw, p->dh);
617 	return;
618      }
619 
620    EXPaintRectangle(pmap, 0, 0, p->dw, p->dh, Dpy.pixel_black, Dpy.pixel_white);
621 }
622 
623 static void
_PagerEwinInit(EWin * ewin)624 _PagerEwinInit(EWin * ewin)
625 {
626    Pager              *p = (Pager *) ewin->data;
627    char                s[128];
628 
629    p->ewin = ewin;
630 
631    Esnprintf(s, sizeof(s), "Pager-%i", p->dsk->num);
632    EwinSetTitle(ewin, s);
633    Esnprintf(s, sizeof(s), "%i", p->dsk->num);
634    EwinSetClass(ewin, s, "Enlightenment_Pager");
635 
636    ewin->props.skip_ext_task = 1;
637    ewin->props.skip_ext_pager = 1;
638    ewin->props.skip_focuslist = 1;
639    ewin->props.skip_winlist = 1;
640    EwinInhSetWM(ewin, focus, 1);
641    ewin->props.autosave = 1;
642 
643    EoSetSticky(ewin, 1);
644 }
645 
646 static void
_PagerEwinMoveResize(EWin * ewin,int resize __UNUSED__)647 _PagerEwinMoveResize(EWin * ewin, int resize __UNUSED__)
648 {
649    Pager              *p = (Pager *) ewin->data;
650    int                 w, h;
651    int                 ax, ay, cx, cy;
652    ImageClass         *ic;
653 
654    if (!Conf_pagers.enable || !p || Mode.mode != MODE_NONE)
655       return;
656 
657    w = ewin->client.w;
658    h = ewin->client.h;
659    if ((w == p->w && h == p->h) || w <= 1 || h <= 1)
660       return;
661 
662    DesksGetAreaSize(&ax, &ay);
663 
664    p->w = w;
665    p->h = h;
666    p->dw = w / ax;
667    p->dh = h / ay;
668 
669    if (p->scale <= 0.f || Mode.op_source == OPSRC_USER)
670       p->scale = ((float)WinGetW(VROOT) / p->dw +
671 		  (float)WinGetH(VROOT) / p->dh) / 2;
672 
673    p->do_newbg = 1;
674    PagerCheckUpdate(p, NULL);
675 
676    ic = ImageclassFind("PAGER_SEL", 0);
677    if (ic)
678      {
679 	DeskGetArea(p->dsk, &cx, &cy);
680 	EMoveResizeWindow(p->sel_win, cx * p->dw, cy * p->dh, p->dw, p->dh);
681 	ImageclassApply(ic, p->sel_win, 0, 0, STATE_NORMAL);
682      }
683 }
684 
685 static void
_PagerEwinClose(EWin * ewin)686 _PagerEwinClose(EWin * ewin)
687 {
688    PagerDestroy((Pager *) ewin->data);
689    ewin->data = NULL;
690 }
691 
692 static const EWinOps _PagerEwinOps = {
693    _PagerEwinInit,
694    NULL,
695    _PagerEwinMoveResize,
696    _PagerEwinClose,
697 };
698 
699 static void
PagerShow(Pager * p)700 PagerShow(Pager * p)
701 {
702    EWin               *ewin;
703 
704    if (!Conf_pagers.enable)
705       return;
706 
707    if (p->ewin)
708      {
709 	EwinShow(p->ewin);
710 	return;
711      }
712 
713    ewin = AddInternalToFamily(p->win, "PAGER", EWIN_TYPE_PAGER,
714 			      &_PagerEwinOps, p);
715    if (!ewin)
716       return;
717 
718    p->screen_w = WinGetW(VROOT);
719    p->screen_h = WinGetH(VROOT);
720 
721    PagerReconfigure(p, 0);
722 
723    ewin->client.event_mask |=
724       ButtonPressMask | ButtonReleaseMask |
725       EnterWindowMask | LeaveWindowMask | PointerMotionMask;
726    ESelectInput(p->win, ewin->client.event_mask);
727 
728    if (ewin->state.placed)
729      {
730 	EwinMoveResize(ewin, EoGetX(ewin), EoGetY(ewin),
731 		       ewin->client.w, ewin->client.h, 0);
732      }
733    else
734      {
735 	/* no snapshots ? first time ? make a row on the bottom left up */
736 	int                 ax, ay, x, y, w, h;
737 
738 	DesksGetAreaSize(&ax, &ay);
739 	w = ((48 * WinGetW(VROOT)) / WinGetH(VROOT)) * ax;
740 	h = 48 * ay;
741 	EwinResize(ewin, w, h, 0);	/* Does layout */
742 	x = 0;
743 	y = WinGetH(VROOT) - (DesksGetNumber() - p->dsk->num) * EoGetH(ewin);
744 	EwinMove(ewin, x, y, 0);
745      }
746 
747    EwinShow(ewin);
748 }
749 
750 typedef struct {
751    Desk               *dsk;
752    void                (*func)(Pager * p, void *prm);
753    void               *prm;
754 } pager_foreach_data;
755 
756 static void
_PagersForeachFunc(void * item,void * prm)757 _PagersForeachFunc(void *item, void *prm)
758 {
759    Pager              *p = (Pager *) item;
760    pager_foreach_data *data = (pager_foreach_data *) prm;
761 
762    if (data->dsk && data->dsk != p->dsk)
763       return;
764    data->func(p, data->prm);
765 }
766 
767 static void
PagersForeach(Desk * dsk,void (* func)(Pager * p,void * prm),void * prm)768 PagersForeach(Desk * dsk, void (*func)(Pager * p, void *prm), void *prm)
769 {
770    pager_foreach_data  data;
771 
772    data.dsk = dsk;
773    data.func = func;
774    data.prm = prm;
775    LIST_FOR_EACH_FUNC(Pager, &pager_list, _PagersForeachFunc, &data);
776 }
777 
778 typedef struct {
779    int                 why;
780    int                 x1, y1, x2, y2;
781 } pager_update_data;
782 
783 static void
_PagerUpdate(Pager * p,void * prm)784 _PagerUpdate(Pager * p, void *prm)
785 {
786    pager_update_data  *pud = (pager_update_data *) prm;
787 
788    PagerUpdate(p, pud->why, pud->x1, pud->y1, pud->x2, pud->y2);
789 }
790 
791 static void
PagersUpdate(Desk * dsk,int why,int x1,int y1,int x2,int y2)792 PagersUpdate(Desk * dsk, int why, int x1, int y1, int x2, int y2)
793 {
794    pager_update_data   pud;
795 
796    if (LIST_IS_EMPTY(&pager_list))
797       return;
798 
799    pud.why = why;
800    pud.x1 = x1;
801    pud.y1 = y1;
802    pud.x2 = x2;
803    pud.y2 = y2;
804    PagersForeach(dsk, _PagerUpdate, &pud);
805 }
806 
807 static void
PagerCheckUpdate(Pager * p,void * prm __UNUSED__)808 PagerCheckUpdate(Pager * p, void *prm __UNUSED__)
809 {
810    if (p->do_newbg)
811      {
812 	PagerUpdateBg(p);
813 	p->do_update = 1;
814      }
815 
816    if (p->do_update)
817       doPagerUpdate(p);
818 
819    p->do_newbg = p->do_update = 0;
820 }
821 
822 static int
_PagersUpdateTimeout(void * data __UNUSED__)823 _PagersUpdateTimeout(void *data __UNUSED__)
824 {
825    Mode_pagers.timer_pending = 0;
826 
827    return 0;
828 }
829 
830 static void
PagersCheckUpdate(void)831 PagersCheckUpdate(void)
832 {
833    static unsigned int tms_last = 0;
834    unsigned int        tms, dtms;
835 
836    if (!Mode_pagers.update_pending || !Conf_pagers.enable)
837       return;
838 
839    if (Mode_pagers.update_pending == (1 << PAGER_UPD_EWIN_DAMAGE))
840      {
841 	tms = GetTimeMs();
842 	dtms = (Conf_pagers.scanspeed > 0) ? 1000 / Conf_pagers.scanspeed : 100;
843 	if ((unsigned int)(tms - tms_last) < dtms)
844 	  {
845 	     /* The purpose of this timer is to trigger the idler */
846 	     if (Mode_pagers.timer_pending)
847 		return;
848 	     TIMER_ADD_NP(dtms, _PagersUpdateTimeout, NULL);
849 	     Mode_pagers.timer_pending = 1;
850 	     return;
851 	  }
852 	tms_last = tms;
853      }
854 
855    PagersForeach(NULL, PagerCheckUpdate, NULL);
856 
857    Mode_pagers.update_pending = 0;
858 }
859 
860 static void
_PagersIdler(void * data __UNUSED__)861 _PagersIdler(void *data __UNUSED__)
862 {
863    if (Mode.events.block)
864       return;
865    PagersCheckUpdate();
866 }
867 
868 static void
PagerEwinUpdateFromPager(Pager * p,EWin * ewin)869 PagerEwinUpdateFromPager(Pager * p, EWin * ewin)
870 {
871    int                 x, y, w, h;
872 
873    if (!EoIsShown(ewin) || !EwinIsOnScreen(ewin))
874       return;
875 
876    Dprintf("%s %d\n", __func__, p->dsk->num);
877 
878    x = EwinGetVX(ewin);
879    y = EwinGetVY(ewin);
880    w = EoGetW(ewin);
881    h = EoGetH(ewin);
882    x = (x * p->dw) / WinGetW(VROOT);
883    y = (y * p->dh) / WinGetH(VROOT);
884    w = (w * p->dw) / WinGetW(VROOT);
885    h = (h * p->dh) / WinGetH(VROOT);
886    if (w <= 0)
887       w = 1;
888    if (h <= 0)
889       h = 1;
890 
891    PmapMaskInit(&ewin->mini_pmm, p->win, w, h);
892    if (!ewin->mini_pmm.pmap)
893       return;
894 
895    EXCopyArea(WinGetPmap(p->win), ewin->mini_pmm.pmap, x, y, w, h, 0, 0);
896 
897 #if 0				/* FIXME - Remove? */
898    if (hiwin && ewin == hiwin->ewin)
899       PagerHiwinUpdate(hiwin, p, ewin);
900 #endif
901 }
902 
903 static void
PagerUpdateEwinsFromPager(Pager * p)904 PagerUpdateEwinsFromPager(Pager * p)
905 {
906    int                 i, num;
907    EWin               *const *lst;
908 
909    lst = EwinListGetForDesk(&num, p->dsk);
910    for (i = 0; i < num; i++)
911       PagerEwinUpdateFromPager(p, lst[i]);
912 }
913 
914 static void
PagersUpdateEwin(EWin * ewin,int why)915 PagersUpdateEwin(EWin * ewin, int why)
916 {
917    Desk               *dsk;
918 
919    if (!Conf_pagers.enable)
920       return;
921 
922    switch (why)
923      {
924      case PAGER_UPD_EWIN_GEOM:
925 	if (!EoIsShown(ewin))
926 	   return;
927 	break;
928 
929      case PAGER_UPD_EWIN_GONE:
930 	if (ewin == HiwinGetEwin(hiwin, 0))
931 	   PagerHiwinHide();
932 	break;
933 
934      case PAGER_UPD_EWIN_DAMAGE:
935 	if (ewin->type == EWIN_TYPE_PAGER)
936 	   return;
937 	if (PagersGetMode() != PAGER_MODE_LIVE)
938 	   return;
939 	break;
940      }
941 
942    dsk = (EoIsFloating(ewin)) ? DesksGetCurrent() : EoGetDesk(ewin);
943    PagersUpdate(dsk, why, EwinGetVX(ewin), EwinGetVY(ewin),
944 		EwinGetVX2(ewin), EwinGetVY2(ewin));
945 }
946 
947 static EWin        *
EwinInPagerAt(Pager * p,int px,int py)948 EwinInPagerAt(Pager * p, int px, int py)
949 {
950    EWin               *const *lst, *ewin;
951    int                 i, num, x, y, w, h;
952 
953    if (!Conf_pagers.enable)
954       return NULL;
955 
956    lst = EwinListGetForDesk(&num, p->dsk);
957    for (i = 0; i < num; i++)
958      {
959 	ewin = lst[i];
960 	if (!EoIsShown(ewin))
961 	   continue;
962 
963 	x = (EwinGetVX(ewin) * p->dw) / WinGetW(VROOT);
964 	y = (EwinGetVY(ewin) * p->dh) / WinGetH(VROOT);
965 	w = (EoGetW(ewin) * p->dw) / WinGetW(VROOT);
966 	h = (EoGetH(ewin) * p->dh) / WinGetH(VROOT);
967 
968 	if (px >= x && py >= y && px < (x + w) && py < (y + h))
969 	   return ewin;
970      }
971 
972    return NULL;
973 }
974 
975 static void
PagerMenuShow(Pager * p,int x,int y)976 PagerMenuShow(Pager * p, int x, int y)
977 {
978    Menu               *m;
979    MenuItem           *mi;
980    EWin               *ewin;
981    char                s[1024];
982 
983    if (!Conf_pagers.enable)
984       return;
985 
986    ewin = EwinInPagerAt(p, x, y);
987    if (ewin)
988      {
989 	m = MenuCreate("__pg_win", _("Window Options"), NULL, NULL);
990 	if (!m)
991 	   return;
992 
993 	MenuSetTransient(m);	/* Destroy when hidden */
994 
995 	Esnprintf(s, sizeof(s), "wop %#x ic", EwinGetClientXwin(ewin));
996 	mi = MenuItemCreate(_("Iconify"), NULL, s, NULL);
997 	MenuAddItem(m, mi);
998 
999 	Esnprintf(s, sizeof(s), "wop %#x close", EwinGetClientXwin(ewin));
1000 	mi = MenuItemCreate(_("Close"), NULL, s, NULL);
1001 	MenuAddItem(m, mi);
1002 
1003 	Esnprintf(s, sizeof(s), "wop %#x kill", EwinGetClientXwin(ewin));
1004 	mi = MenuItemCreate(_("Annihilate"), NULL, s, NULL);
1005 	MenuAddItem(m, mi);
1006 
1007 	Esnprintf(s, sizeof(s), "wop %#x st", EwinGetClientXwin(ewin));
1008 	mi = MenuItemCreate(_("Stick / Unstick"), NULL, s, NULL);
1009 	MenuAddItem(m, mi);
1010 
1011 	EFunc(NULL, "menus show __pg_win");
1012 	return;
1013      }
1014 
1015    m = MenuCreate("__pg", _("Desktop Options"), NULL, NULL);
1016    if (!m)
1017       return;
1018 
1019    MenuSetTransient(m);		/* Destroy when hidden */
1020 
1021    mi = MenuItemCreate(_("Pager Settings..."), NULL, "cfg pagers", NULL);
1022    MenuAddItem(m, mi);
1023 
1024    if (PagersGetMode() != PAGER_MODE_SIMPLE)
1025      {
1026 	mi = MenuItemCreate(_("Snapshotting Off"), NULL, "pg mode simp", NULL);
1027 	MenuAddItem(m, mi);
1028 
1029 	if (Conf_pagers.hiq)
1030 	   mi = MenuItemCreate(_("High Quality Off"), NULL, "pg hiq off", NULL);
1031 	else
1032 	   mi = MenuItemCreate(_("High Quality On"), NULL, "pg hiq on", NULL);
1033 	MenuAddItem(m, mi);
1034      }
1035    else
1036      {
1037 	mi = MenuItemCreate(_("Snapshotting On"), NULL, "pg mode live", NULL);
1038 	MenuAddItem(m, mi);
1039      }
1040    if (Conf_pagers.zoom)
1041       mi = MenuItemCreate(_("Zoom Off"), NULL, "pg zoom off", NULL);
1042    else
1043       mi = MenuItemCreate(_("Zoom On"), NULL, "pg zoom on", NULL);
1044    MenuAddItem(m, mi);
1045 
1046    EFunc(NULL, "menus show __pg");
1047 }
1048 
1049 static void
PagerClose(Pager * p)1050 PagerClose(Pager * p)
1051 {
1052    EwinHide(p->ewin);
1053 }
1054 
1055 static void
_PagerUpdateSel(Pager * p,void * prm __UNUSED__)1056 _PagerUpdateSel(Pager * p, void *prm __UNUSED__)
1057 {
1058    int                 cx, cy;
1059    ImageClass         *ic;
1060 
1061    if (p->dsk != DesksGetCurrent())
1062       EUnmapWindow(p->sel_win);
1063    else
1064      {
1065 	DeskGetArea(p->dsk, &cx, &cy);
1066 	EMoveWindow(p->sel_win, cx * p->dw, cy * p->dh);
1067 	EMapWindow(p->sel_win);
1068 	ic = ImageclassFind("PAGER_SEL", 0);
1069 	if (ic)
1070 	   ImageclassApply(ic, p->sel_win, 0, 0, STATE_NORMAL);
1071      }
1072 }
1073 
1074 static void
UpdatePagerSel(void)1075 UpdatePagerSel(void)
1076 {
1077    if (!Conf_pagers.enable)
1078       return;
1079 
1080    PagersForeach(NULL, _PagerUpdateSel, NULL);
1081 }
1082 
1083 static void
PagerShowTt(EWin * ewin)1084 PagerShowTt(EWin * ewin)
1085 {
1086    static EWin        *tt_ewin = NULL;
1087    ToolTip            *tt;
1088 
1089    Dprintf("%s %s\n", __func__, (ewin) ? EwinGetTitle(ewin) : NULL);
1090 
1091    if (!Conf_pagers.title || (ewin == tt_ewin))
1092       return;
1093 
1094    if (MenusActive())		/* Don't show Tooltip when menu is up */
1095       return;
1096 
1097    tt = TooltipFind("PAGER");
1098    if (tt)
1099      {
1100 	if (ewin)
1101 	   TooltipShow(tt, EwinGetTitle(ewin), NULL, Mode.events.cx,
1102 		       Mode.events.cy);
1103 	else
1104 	   TooltipHide(tt);
1105      }
1106 
1107    tt_ewin = ewin;
1108 }
1109 
1110 static void
PagerHiwinInit(Pager * p,EWin * ewin)1111 PagerHiwinInit(Pager * p, EWin * ewin)
1112 {
1113    Hiwin              *phi = hiwin;
1114    int                 wx, wy, ww, wh, px, py;
1115 
1116    wx = (EwinGetVX(ewin) * p->dw) / WinGetW(VROOT);
1117    wy = (EwinGetVY(ewin) * p->dh) / WinGetH(VROOT);
1118    ww = (EoGetW(ewin) * p->dw) / WinGetW(VROOT);
1119    wh = (EoGetH(ewin) * p->dh) / WinGetH(VROOT);
1120    ETranslateCoordinates(p->win, VROOT, 0, 0, &px, &py, NULL);
1121 
1122    HiwinInit(phi, ewin, EoObj(EoGetDesk(p->ewin)));
1123    HiwinSetGeom(phi, px + wx, py + wy, ww, wh);
1124    HiwinSetCallback(phi, PagerHiwinEvent, p);
1125 }
1126 
1127 static void
PagerHiwinHide(void)1128 PagerHiwinHide(void)
1129 {
1130    Dprintf("%s\n", __func__);
1131    HiwinHide(hiwin);
1132    PagerShowTt(NULL);
1133 }
1134 
1135 static void
PagerHiwinShow(Pager * p,EWin * ewin,int zoom,int confine)1136 PagerHiwinShow(Pager * p, EWin * ewin, int zoom, int confine)
1137 {
1138    Hiwin              *phi = hiwin;
1139 
1140    if (MenusActive())		/* Don't show HiWin when menu is up */
1141       return;
1142 
1143    Dprintf("%s\n", __func__);
1144 
1145    if (!phi)
1146      {
1147 	phi = HiwinCreate();
1148 	if (!phi)
1149 	   return;
1150 	hiwin = phi;
1151      }
1152 
1153    if (ewin)
1154       PagerHiwinInit(p, ewin);
1155 
1156    HiwinShow(phi, ewin, zoom, confine);
1157 }
1158 
1159 static void
PagerZoomChange(Pager * p,int delta)1160 PagerZoomChange(Pager * p, int delta)
1161 {
1162    Dprintf("%s delta=%d\n", __func__, delta);
1163 
1164    if (delta == 0)
1165       return;
1166 
1167    if (delta > 0)
1168      {
1169 	if (!ECompMgrIsActive() && Mode_pagers.zoom >= 2)
1170 	   return;
1171 	if (Mode_pagers.zoom >= 8)
1172 	   return;
1173 	Mode_pagers.zoom++;
1174      }
1175    else
1176      {
1177 	if (Mode_pagers.zoom <= 2)
1178 	   return;
1179 	Mode_pagers.zoom--;
1180      }
1181    PagerHiwinShow(p, NULL, Mode_pagers.zoom, 0);
1182 }
1183 
1184 static void
PagerHandleMotion(Pager * p,int x,int y)1185 PagerHandleMotion(Pager * p, int x, int y)
1186 {
1187    EWin               *ewin;
1188 
1189    if (!Conf_pagers.enable)
1190       return;
1191 
1192    if (Mode.events.on_screen && x >= 0 && x < p->w && y >= 0 && y < p->h)
1193       ewin = EwinInPagerAt(p, x, y);
1194    else
1195       ewin = NULL;
1196 
1197    if (!Conf_pagers.zoom)
1198      {
1199 	PagerShowTt(ewin);
1200 	return;
1201      }
1202 
1203    if (!ewin || EoGetLayer(ewin) <= 0)
1204      {
1205 	PagerHiwinHide();
1206      }
1207    else if (!hiwin || ewin != HiwinGetEwin(hiwin, 0))
1208      {
1209 	if (Mode_pagers.zoom < 2)
1210 	   Mode_pagers.zoom = 2;
1211 	PagerHiwinShow(p, ewin, Mode_pagers.zoom, 0);
1212      }
1213    if (Mode_pagers.zoom <= 2)
1214       PagerShowTt(ewin);
1215 }
1216 
1217 static void
NewPagerForDesktop(Desk * dsk)1218 NewPagerForDesktop(Desk * dsk)
1219 {
1220    Pager              *p;
1221 
1222    p = PagerCreate();
1223    if (!p)
1224       return;
1225 
1226    p->dsk = dsk;
1227    PagerShow(p);
1228 }
1229 
1230 static void
_PagerUpdateBackground(Pager * p,void * prm __UNUSED__)1231 _PagerUpdateBackground(Pager * p, void *prm __UNUSED__)
1232 {
1233    p->do_newbg = 1;
1234 }
1235 
1236 static void
PagersUpdateBackground(Desk * dsk)1237 PagersUpdateBackground(Desk * dsk)
1238 {
1239    PagersForeach(dsk, _PagerUpdateBackground, NULL);
1240 
1241    Mode_pagers.update_pending = 1;
1242 }
1243 
1244 static void
_EwinsMiniFree(void)1245 _EwinsMiniFree(void)
1246 {
1247    EWin               *const *lst;
1248    int                 i, num;
1249 
1250    lst = EwinListGetAll(&num);
1251    for (i = 0; i < num; i++)
1252       PmapMaskFree(&(lst[i]->mini_pmm));
1253 }
1254 
1255 static void
PagerSetHiQ(char onoff)1256 PagerSetHiQ(char onoff)
1257 {
1258    Conf_pagers.hiq = onoff;
1259 
1260    _EwinsMiniFree();
1261 
1262    PagersUpdateBackground(NULL);
1263 
1264    autosave();
1265 }
1266 
1267 static void
_PagerSetSnap(Pager * p,void * prm __UNUSED__)1268 _PagerSetSnap(Pager * p, void *prm __UNUSED__)
1269 {
1270    PagerScanTrig(p);
1271 }
1272 
1273 static void
PagersSetMode(int mode)1274 PagersSetMode(int mode)
1275 {
1276    if (mode == Conf_pagers.mode)
1277       return;
1278    Conf_pagers.mode = mode;
1279 
1280    _EwinsMiniFree();
1281 
1282    PagersUpdateBackground(NULL);
1283 
1284    if (Conf_pagers.mode == PAGER_MODE_SNAP && Conf_pagers.scanspeed > 0)
1285       PagersForeach(DesksGetCurrent(), _PagerSetSnap, NULL);
1286 
1287    autosave();
1288 }
1289 
1290 static void
PagersSetZoom(int onoff)1291 PagersSetZoom(int onoff)
1292 {
1293    if (Conf_pagers.zoom == onoff)
1294       return;
1295    Conf_pagers.zoom = onoff;
1296 
1297    autosave();
1298 }
1299 
1300 /*
1301  * Pager event handlers
1302  */
1303 
1304 static int         *gwin_px, *gwin_py;
1305 
1306 static void
PagerEwinGroupSet(void)1307 PagerEwinGroupSet(void)
1308 {
1309    int                 i, num;
1310    EWin               *ewin, **gwins;
1311 
1312    ewin = HiwinGetEwin(hiwin, 0);
1313    gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
1314 				      Mode.nogroup, &num);
1315    if (!gwins)
1316       return;
1317 
1318    gwin_px = EMALLOC(int, num);
1319    gwin_py = EMALLOC(int, num);
1320 
1321    for (i = 0; i < num; i++)
1322      {
1323 	gwin_px[i] = EoGetX(gwins[i]);
1324 	gwin_py[i] = EoGetY(gwins[i]);
1325      }
1326 
1327    Efree(gwins);
1328 }
1329 
1330 static void
PagerEwinGroupUnset(void)1331 PagerEwinGroupUnset(void)
1332 {
1333    EFREE_NULL(gwin_px);
1334    EFREE_NULL(gwin_py);
1335 }
1336 
1337 static void
PagerEventUnmap(Pager * p __UNUSED__)1338 PagerEventUnmap(Pager * p __UNUSED__)
1339 {
1340    PagerHiwinHide();
1341 }
1342 
1343 static void
EwinGroupMove(EWin * ewin,Desk * dsk,int x,int y)1344 EwinGroupMove(EWin * ewin, Desk * dsk, int x, int y)
1345 {
1346    int                 i, num, dx, dy, newdesk;
1347    EWin              **gwins;
1348 
1349    if (!ewin)
1350       return;
1351 
1352    /* Move all group members */
1353    newdesk = dsk != EoGetDesk(ewin);
1354    dx = x - EoGetX(ewin);
1355    dy = y - EoGetY(ewin);
1356    gwins =
1357       ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, Mode.nogroup, &num);
1358    for (i = 0; i < num; i++)
1359      {
1360 	if (gwins[i]->type == EWIN_TYPE_PAGER)
1361 	   continue;
1362 
1363 	if (newdesk)
1364 	   EwinOpMoveToDesktopAt(gwins[i], OPSRC_USER, dsk,
1365 				 EoGetX(gwins[i]) + dx, EoGetY(gwins[i]) + dy);
1366 	else
1367 	   EwinOpMove(gwins[i], OPSRC_USER, EoGetX(gwins[i]) + dx,
1368 		      EoGetY(gwins[i]) + dy);
1369      }
1370    Efree(gwins);
1371 }
1372 
1373 static void
PagerEwinMove(Pager * p __UNUSED__,Pager * pd,EWin * ewin)1374 PagerEwinMove(Pager * p __UNUSED__, Pager * pd, EWin * ewin)
1375 {
1376    int                 x, y, dx, dy, px, py;
1377    int                 cx, cy;
1378    Hiwin              *phi = hiwin;
1379 
1380    /* Delta in pager coords */
1381    dx = Mode.events.mx - Mode.events.px;
1382    dy = Mode.events.my - Mode.events.py;
1383 
1384    if (dx == 0 && dy == 0 && p == pd)
1385       return;
1386 
1387    /* Move mini window */
1388    HiwinGetXY(phi, &x, &y);
1389    HiwinMove(phi, x + dx, y + dy);
1390 
1391    /* Find real window position */
1392    ETranslateCoordinates(VROOT, pd->win, x, y, &px, &py, NULL);
1393    DeskGetArea(pd->dsk, &cx, &cy);
1394    x = (px * WinGetW(VROOT)) / pd->dw - cx * WinGetW(VROOT);
1395    y = (py * WinGetH(VROOT)) / pd->dh - cy * WinGetH(VROOT);
1396 
1397    /* Move all group members */
1398    EwinGroupMove(ewin, pd->dsk, x, y);
1399 }
1400 
1401 static void
PagerHandleMouseDown(Pager * p,int px,int py,int button)1402 PagerHandleMouseDown(Pager * p, int px, int py, int button)
1403 {
1404    int                 in_pager;
1405    EWin               *ewin;
1406 
1407    Dprintf("%s m=%d d=%d x,y=%d,%d\n", __func__, Mode.mode, p->dsk->num,
1408 	   px, py);
1409 
1410    in_pager = (px >= 0 && py >= 0 && px < p->w && py < p->h);
1411    if (!in_pager)
1412       return;
1413 
1414    if (button == Conf_pagers.menu_button)
1415      {
1416 	PagerHiwinHide();
1417 	PagerMenuShow(p, px, py);
1418      }
1419    else if (button == Conf_pagers.win_button)
1420      {
1421 	ewin = EwinInPagerAt(p, px, py);
1422 	if (ewin && ewin->type != EWIN_TYPE_PAGER && !ewin->state.inhibit_move)
1423 	  {
1424 	     PagerHiwinShow(p, ewin, 1, !Mode.wm.window);
1425 	     Mode.mode = MODE_PAGER_DRAG_PENDING;
1426 	     EwinRaise(ewin);
1427 	     PagerEwinGroupSet();
1428 	  }
1429      }
1430 }
1431 
1432 static void
PagerHandleMouseUp(Pager * p,int px,int py,int button)1433 PagerHandleMouseUp(Pager * p, int px, int py, int button)
1434 {
1435    int                 i, num, in_pager, in_vroot;
1436    EWin               *ewin, *ewin2, **gwins;
1437    int                 x, y;
1438 
1439    Dprintf("%s m=%d d=%d x,y=%d,%d\n", __func__, Mode.mode, p->dsk->num,
1440 	   px, py);
1441 
1442    in_pager = (px >= 0 && py >= 0 && px < p->w && py < p->h);
1443 
1444    if (button == Conf_pagers.sel_button)
1445      {
1446 	if (!in_pager)
1447 	   return;
1448 	DeskGoto(p->dsk);
1449 	DeskCurrentGotoArea(px / p->dw, py / p->dh);
1450 	return;
1451      }
1452 
1453    if (button != Conf_pagers.win_button)
1454       return;
1455 
1456    ewin = HiwinGetEwin(hiwin, 1);
1457    PagerHiwinHide();
1458 
1459    if (Mode.mode != MODE_PAGER_DRAG)
1460      {
1461 	if (Mode.mode == MODE_PAGER_DRAG_PENDING)
1462 	   Mode.mode = MODE_NONE;
1463 	if (!in_pager)
1464 	   goto done;
1465 	DeskGoto(p->dsk);
1466 	DeskCurrentGotoArea(px / p->dw, py / p->dh);
1467 	if (ewin)
1468 	   FocusToEWin(ewin, FOCUS_SET);
1469 	goto done;
1470      }
1471 
1472    Mode.mode = MODE_NONE;
1473 
1474    if (!ewin)
1475       goto done;
1476 
1477    /* Finish pager drag */
1478 
1479    in_vroot = (Mode.events.cx >= 0 && Mode.events.cx < WinGetW(VROOT) &&
1480 	       Mode.events.cy >= 0 && Mode.events.cy < WinGetH(VROOT));
1481 
1482    /* Find which pager or iconbox we are in (if any) */
1483    ewin2 = GetEwinPointerInClient();
1484    if ((ewin2) && (ewin2->type == EWIN_TYPE_PAGER))
1485      {
1486 	PagerEwinMove(p, (Pager *) ewin2->data, ewin);
1487      }
1488    else if ((ewin2) && (ewin2->type == EWIN_TYPE_ICONBOX))
1489      {
1490 	/* Pointer is in iconbox */
1491 
1492 	/* Iconify after moving back to pre-drag position */
1493 	gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
1494 					   Mode.nogroup, &num);
1495 	for (i = 0; i < num; i++)
1496 	  {
1497 	     if (gwins[i]->type != EWIN_TYPE_PAGER)
1498 	       {
1499 		  EwinMove(gwins[i], gwin_px[i], gwin_py[i], 0);
1500 		  EwinIconify(gwins[i]);
1501 	       }
1502 	  }
1503 	Efree(gwins);
1504      }
1505    else if (ewin2 && ewin2->props.vroot)
1506      {
1507 	/* Dropping onto virtual root */
1508 	EwinReparent(ewin, EwinGetClientWin(ewin2));
1509      }
1510    else if (!in_vroot)
1511      {
1512 	/* Move back to real root */
1513 	EwinReparent(ewin, RROOT);
1514      }
1515    else
1516      {
1517 	/* Pointer is not in pager or iconbox */
1518 	/* Move window(s) to pointer location */
1519 	x = Mode.events.cx - EoGetW(ewin) / 2;
1520 	y = Mode.events.cy - EoGetH(ewin) / 2;
1521 	EwinGroupMove(ewin, DesksGetCurrent(), x, y);
1522      }
1523 
1524  done:
1525    /* unallocate the space that was holding the old positions of the */
1526    /* windows */
1527    PagerEwinGroupUnset();
1528 }
1529 
1530 static void
PagerEvent(Win win __UNUSED__,XEvent * ev,void * prm)1531 PagerEvent(Win win __UNUSED__, XEvent * ev, void *prm)
1532 {
1533    Pager              *p = (Pager *) prm;
1534 
1535    Dprintf("%s ev=%d\n", __func__, ev->type);
1536 
1537    switch (ev->type)
1538      {
1539      case ButtonPress:
1540 	PagerHandleMouseDown(p, ev->xbutton.x, ev->xbutton.y,
1541 			     (int)ev->xbutton.button);
1542 	break;
1543      case ButtonRelease:
1544 	if (ev->xbutton.window != Mode.events.last_bpress)
1545 	   break;
1546 	PagerHandleMouseUp(p, ev->xbutton.x, ev->xbutton.y,
1547 			   (int)ev->xbutton.button);
1548 	break;
1549 
1550      case MotionNotify:
1551 	PagerHandleMotion(p, ev->xmotion.x, ev->xmotion.y);
1552 	break;
1553 
1554      case EnterNotify:
1555 	break;
1556      case LeaveNotify:
1557 	PagerShowTt(NULL);
1558 	break;
1559 
1560      case UnmapNotify:
1561 	PagerEventUnmap(p);
1562 	break;
1563 
1564      case VisibilityNotify:
1565 	if (ev->xvisibility.state != VisibilityFullyObscured)
1566 	   PagerScanTrig(p);
1567 	break;
1568      }
1569 }
1570 
1571 static void
PagerHiwinEvent(Win win __UNUSED__,XEvent * ev,void * prm)1572 PagerHiwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
1573 {
1574    Pager              *p = (Pager *) prm;
1575    int                 px, py;
1576    EWin               *ewin;
1577 
1578    if (!p)
1579       return;
1580 
1581    Dprintf("%s ev=%d\n", __func__, ev->type);
1582 
1583    switch (ev->type)
1584      {
1585      case ButtonPress:
1586 	switch (ev->xbutton.button)
1587 	  {
1588 	  case 4:
1589 	     if (Mode.mode != MODE_NONE)
1590 		break;
1591 	     PagerZoomChange(p, 1);
1592 	     break;
1593 	  case 5:
1594 	     if (Mode.mode != MODE_NONE)
1595 		break;
1596 	     PagerZoomChange(p, -1);
1597 	     break;
1598 	  default:
1599 	     /* Translate x,y to pager window coordinates */
1600 	     ETranslateCoordinates(RROOT, p->win,
1601 				   ev->xbutton.x_root, ev->xbutton.y_root,
1602 				   &px, &py, NULL);
1603 	     PagerHandleMouseDown(p, px, py, (int)ev->xbutton.button);
1604 	     break;
1605 	  }
1606 	break;
1607 
1608      case ButtonRelease:
1609 	switch (ev->xbutton.button)
1610 	  {
1611 	  case 4:
1612 	  case 5:
1613 	     break;
1614 	  default:
1615 	     /* Translate x,y to pager window coordinates */
1616 	     ETranslateCoordinates(RROOT, p->win,
1617 				   ev->xbutton.x_root, ev->xbutton.y_root,
1618 				   &px, &py, NULL);
1619 	     PagerHandleMouseUp(p, px, py, (int)ev->xbutton.button);
1620 	     break;
1621 	  }
1622 	break;
1623 
1624      case MotionNotify:
1625 	switch (Mode.mode)
1626 	  {
1627 	  case MODE_NONE:
1628 	     /* Translate x,y to pager window coordinates */
1629 	     ETranslateCoordinates(RROOT, p->win,
1630 				   ev->xbutton.x_root, ev->xbutton.y_root,
1631 				   &px, &py, NULL);
1632 	     PagerHandleMotion(p, px, py);
1633 	     break;
1634 
1635 	  case MODE_PAGER_DRAG_PENDING:
1636 	  case MODE_PAGER_DRAG:
1637 	     ewin = HiwinGetEwin(hiwin, 1);
1638 	     if (!ewin || ewin->type == EWIN_TYPE_PAGER)
1639 	       {
1640 		  Mode.mode = MODE_NONE;
1641 		  break;
1642 	       }
1643 
1644 	     Mode.mode = MODE_PAGER_DRAG;
1645 	     PagerEwinMove(p, p, ewin);
1646 	     break;
1647 	  }
1648 	break;
1649 
1650      case LeaveNotify:
1651 	PagerShowTt(NULL);
1652 	break;
1653      }
1654 }
1655 
1656 /*
1657  * Pagers handling
1658  */
1659 
1660 static int
PagersForDesktopCount(Desk * dsk)1661 PagersForDesktopCount(Desk * dsk)
1662 {
1663    Pager              *p;
1664    int                 num = 0;
1665 
1666    LIST_FOR_EACH(Pager, &pager_list, p)
1667    {
1668       if (p->dsk == dsk)
1669 	 num++;
1670    }
1671 
1672    return num;
1673 }
1674 
1675 static void
_PagerClose(Pager * p,void * prm __UNUSED__)1676 _PagerClose(Pager * p, void *prm __UNUSED__)
1677 {
1678    PagerClose(p);
1679 }
1680 
1681 static void
PagersForDesktopEnable(Desk * dsk)1682 PagersForDesktopEnable(Desk * dsk)
1683 {
1684    if (PagersForDesktopCount(dsk) <= 0)
1685       NewPagerForDesktop(dsk);
1686 }
1687 
1688 static void
PagersForDesktopDisable(Desk * dsk)1689 PagersForDesktopDisable(Desk * dsk)
1690 {
1691    PagersForeach(dsk, _PagerClose, NULL);
1692 }
1693 
1694 static void
PagersShow(int enable)1695 PagersShow(int enable)
1696 {
1697    unsigned int        i;
1698 
1699    if (enable && !Conf_pagers.enable)
1700      {
1701 	Conf_pagers.enable = 1;
1702 	for (i = 0; i < DesksGetNumber(); i++)
1703 	   PagersForDesktopEnable(DeskGet(i));
1704 	UpdatePagerSel();
1705 	Mode_pagers.idler = IdlerAdd(_PagersIdler, NULL);
1706      }
1707    else if (!enable && Conf_pagers.enable)
1708      {
1709 	for (i = 0; i < DesksGetNumber(); i++)
1710 	   PagersForDesktopDisable(DeskGet(i));
1711 	Conf_pagers.enable = 0;
1712 	IdlerDel(Mode_pagers.idler);
1713 	Mode_pagers.idler = NULL;
1714      }
1715 }
1716 
1717 static void
_PagerReconfigure(Pager * p,void * prm __UNUSED__)1718 _PagerReconfigure(Pager * p, void *prm __UNUSED__)
1719 {
1720    PagerReconfigure(p, 1);
1721 }
1722 
1723 static int
_PagersReconfigureTimeout(void * data __UNUSED__)1724 _PagersReconfigureTimeout(void *data __UNUSED__)
1725 {
1726    PagersForeach(NULL, _PagerReconfigure, NULL);
1727 
1728    return 0;
1729 }
1730 
1731 static void
PagersReconfigure(void)1732 PagersReconfigure(void)
1733 {
1734    if (!Conf_pagers.enable)
1735       return;
1736 
1737    TIMER_ADD_NP(500, _PagersReconfigureTimeout, NULL);
1738 }
1739 
1740 #if ENABLE_DIALOGS
1741 /*
1742  * Configuration dialog
1743  */
1744 typedef struct {
1745    char                show_pagers;
1746    char                pager_hiq;
1747    int                 pager_mode;
1748    char                pager_zoom;
1749    char                pager_title;
1750    char                pager_do_scan;
1751    int                 pager_scan_speed;
1752    int                 pager_sel_button;
1753    int                 pager_win_button;
1754    int                 pager_menu_button;
1755 } PagerDlgData;
1756 
1757 static void
_DlgApplyPagers(Dialog * d,int val __UNUSED__,void * data __UNUSED__)1758 _DlgApplyPagers(Dialog * d, int val __UNUSED__, void *data __UNUSED__)
1759 {
1760    PagerDlgData       *dd = DLG_DATA_GET(d, PagerDlgData);
1761 
1762    PagersShow(dd->show_pagers);
1763    if (Conf_pagers.hiq != dd->pager_hiq)
1764       PagerSetHiQ(dd->pager_hiq);
1765    Conf_pagers.zoom = dd->pager_zoom;
1766    Conf_pagers.title = dd->pager_title;
1767    Conf_pagers.sel_button = dd->pager_sel_button;
1768    Conf_pagers.win_button = dd->pager_win_button;
1769    Conf_pagers.menu_button = dd->pager_menu_button;
1770    if ((Conf_pagers.scanspeed != dd->pager_scan_speed)
1771        || ((!dd->pager_do_scan) && (Conf_pagers.scanspeed > 0))
1772        || ((dd->pager_do_scan) && (Conf_pagers.scanspeed == 0)))
1773      {
1774 	if (dd->pager_do_scan)
1775 	   Conf_pagers.scanspeed = dd->pager_scan_speed;
1776 	else
1777 	   Conf_pagers.scanspeed = 0;
1778      }
1779    PagersSetMode(dd->pager_mode);
1780 
1781    autosave();
1782 }
1783 
1784 static void
CB_PagerScanSlide(Dialog * d,int val __UNUSED__,void * data)1785 CB_PagerScanSlide(Dialog * d, int val __UNUSED__, void *data)
1786 {
1787    PagerDlgData       *dd = DLG_DATA_GET(d, PagerDlgData);
1788    DItem              *di = (DItem *) data;
1789    char                s[256];
1790 
1791    Esnprintf(s, sizeof(s), "%s %03i %s", _("Pager scanning speed:"),
1792 	     dd->pager_scan_speed, _("lines per second"));
1793    DialogItemSetText(di, s);
1794 }
1795 
1796 static void
_DlgFillPagers(Dialog * d,DItem * table,void * data __UNUSED__)1797 _DlgFillPagers(Dialog * d, DItem * table, void *data __UNUSED__)
1798 {
1799    PagerDlgData       *dd = DLG_DATA_GET(d, PagerDlgData);
1800    DItem              *di, *radio, *label;
1801    char                s[256];
1802 
1803    dd->show_pagers = Conf_pagers.enable;
1804    dd->pager_hiq = Conf_pagers.hiq;
1805    dd->pager_mode = Conf_pagers.mode;
1806    dd->pager_zoom = Conf_pagers.zoom;
1807    dd->pager_title = Conf_pagers.title;
1808    dd->pager_sel_button = Conf_pagers.sel_button;
1809    dd->pager_win_button = Conf_pagers.win_button;
1810    dd->pager_menu_button = Conf_pagers.menu_button;
1811    if (Conf_pagers.scanspeed == 0)
1812       dd->pager_do_scan = 0;
1813    else
1814       dd->pager_do_scan = 1;
1815    dd->pager_scan_speed = Conf_pagers.scanspeed;
1816 
1817    DialogItemTableSetOptions(table, 2, 0, 0, 0);
1818 
1819    di = DialogAddItem(table, DITEM_CHECKBUTTON);
1820    DialogItemSetColSpan(di, 2);
1821    DialogItemSetText(di, _("Enable pager display"));
1822    DialogItemCheckButtonSetPtr(di, &dd->show_pagers);
1823 
1824    di = DialogAddItem(table, DITEM_SEPARATOR);
1825    DialogItemSetColSpan(di, 2);
1826 
1827    di = DialogAddItem(table, DITEM_TEXT);
1828    DialogItemSetColSpan(di, 2);
1829    DialogItemSetFill(di, 0, 0);
1830    DialogItemSetAlign(di, 0, 512);
1831    DialogItemSetText(di, _("Pager Mode:"));
1832 
1833    radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
1834    DialogItemSetColSpan(di, 2);
1835    DialogItemSetText(di, _("Simple"));
1836    DialogItemRadioButtonSetFirst(di, radio);
1837    DialogItemRadioButtonGroupSetVal(di, 0);
1838 
1839    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1840    DialogItemSetColSpan(di, 2);
1841    DialogItemSetText(di, _("Make miniature snapshots of the screen"));
1842    DialogItemRadioButtonSetFirst(di, radio);
1843    DialogItemRadioButtonGroupSetVal(di, 1);
1844 
1845 #if USE_COMPOSITE
1846    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1847    DialogItemSetColSpan(di, 2);
1848    DialogItemSetText(di, _("Live Update"));
1849    DialogItemRadioButtonSetFirst(di, radio);
1850    DialogItemRadioButtonGroupSetVal(di, 2);
1851 #endif
1852    DialogItemRadioButtonGroupSetValPtr(radio, &dd->pager_mode);
1853 
1854    di = DialogAddItem(table, DITEM_SEPARATOR);
1855    DialogItemSetColSpan(di, 2);
1856 
1857    di = DialogAddItem(table, DITEM_CHECKBUTTON);
1858    DialogItemSetColSpan(di, 2);
1859    DialogItemSetText(di, _("Smooth high quality snapshots in snapshot mode"));
1860    DialogItemCheckButtonSetPtr(di, &dd->pager_hiq);
1861 
1862    di = DialogAddItem(table, DITEM_CHECKBUTTON);
1863    DialogItemSetColSpan(di, 2);
1864    DialogItemSetText(di, _("Zoom in on pager windows when mouse is over them"));
1865    DialogItemCheckButtonSetPtr(di, &dd->pager_zoom);
1866 
1867    di = DialogAddItem(table, DITEM_CHECKBUTTON);
1868    DialogItemSetColSpan(di, 2);
1869    DialogItemSetText(di,
1870 		     _("Pop up window title when mouse is over the window"));
1871    DialogItemCheckButtonSetPtr(di, &dd->pager_title);
1872 
1873    di = DialogAddItem(table, DITEM_CHECKBUTTON);
1874    DialogItemSetColSpan(di, 2);
1875    DialogItemSetText(di, _("Continuously scan screen to update pager"));
1876    DialogItemCheckButtonSetPtr(di, &dd->pager_do_scan);
1877 
1878    di = label = DialogAddItem(table, DITEM_TEXT);
1879    DialogItemSetColSpan(di, 2);
1880    DialogItemSetFill(di, 0, 0);
1881    DialogItemSetAlign(di, 0, 512);
1882    Esnprintf(s, sizeof(s), "%s %03i %s", _("Pager scanning speed:"),
1883 	     dd->pager_scan_speed, _("lines per second"));
1884    DialogItemSetText(di, s);
1885 
1886    di = DialogAddItem(table, DITEM_SLIDER);
1887    DialogItemSliderSetBounds(di, 1, 256);
1888    DialogItemSliderSetUnits(di, 1);
1889    DialogItemSliderSetJump(di, 1);
1890    DialogItemSetColSpan(di, 2);
1891    DialogItemSliderSetValPtr(di, &dd->pager_scan_speed);
1892    DialogItemSetCallback(di, CB_PagerScanSlide, 0, label);
1893 
1894    di = DialogAddItem(table, DITEM_TEXT);
1895    DialogItemSetColSpan(di, 2);
1896    DialogItemSetFill(di, 0, 0);
1897    DialogItemSetAlign(di, 0, 512);
1898    DialogItemSetText(di, _("Mouse button to select and drag windows:"));
1899 
1900    radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
1901    DialogItemSetColSpan(di, 2);
1902    DialogItemSetText(di, _("Left"));
1903    DialogItemRadioButtonSetFirst(di, radio);
1904    DialogItemRadioButtonGroupSetVal(di, 1);
1905 
1906    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1907    DialogItemSetColSpan(di, 2);
1908    DialogItemSetText(di, _("Middle"));
1909    DialogItemRadioButtonSetFirst(di, radio);
1910    DialogItemRadioButtonGroupSetVal(di, 2);
1911 
1912    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1913    DialogItemSetColSpan(di, 2);
1914    DialogItemSetText(di, _("Right"));
1915    DialogItemRadioButtonSetFirst(di, radio);
1916    DialogItemRadioButtonGroupSetVal(di, 3);
1917    DialogItemRadioButtonGroupSetValPtr(radio, &dd->pager_win_button);
1918 
1919    di = DialogAddItem(table, DITEM_TEXT);
1920    DialogItemSetColSpan(di, 2);
1921    DialogItemSetFill(di, 0, 0);
1922    DialogItemSetAlign(di, 0, 512);
1923    DialogItemSetText(di, _("Mouse button to select desktops:"));
1924 
1925    radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
1926    DialogItemSetColSpan(di, 2);
1927    DialogItemSetText(di, _("Left"));
1928    DialogItemRadioButtonSetFirst(di, radio);
1929    DialogItemRadioButtonGroupSetVal(di, 1);
1930 
1931    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1932    DialogItemSetColSpan(di, 2);
1933    DialogItemSetText(di, _("Middle"));
1934    DialogItemRadioButtonSetFirst(di, radio);
1935    DialogItemRadioButtonGroupSetVal(di, 2);
1936 
1937    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1938    DialogItemSetColSpan(di, 2);
1939    DialogItemSetText(di, _("Right"));
1940    DialogItemRadioButtonSetFirst(di, radio);
1941    DialogItemRadioButtonGroupSetVal(di, 3);
1942    DialogItemRadioButtonGroupSetValPtr(radio, &dd->pager_sel_button);
1943 
1944    di = DialogAddItem(table, DITEM_TEXT);
1945    DialogItemSetColSpan(di, 2);
1946    DialogItemSetFill(di, 0, 0);
1947    DialogItemSetAlign(di, 0, 512);
1948    DialogItemSetText(di, _("Mouse button to display pager menu:"));
1949 
1950    radio = di = DialogAddItem(table, DITEM_RADIOBUTTON);
1951    DialogItemSetColSpan(di, 2);
1952    DialogItemSetText(di, _("Left"));
1953    DialogItemRadioButtonSetFirst(di, radio);
1954    DialogItemRadioButtonGroupSetVal(di, 1);
1955 
1956    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1957    DialogItemSetColSpan(di, 2);
1958    DialogItemSetText(di, _("Middle"));
1959    DialogItemRadioButtonSetFirst(di, radio);
1960    DialogItemRadioButtonGroupSetVal(di, 2);
1961 
1962    di = DialogAddItem(table, DITEM_RADIOBUTTON);
1963    DialogItemSetColSpan(di, 2);
1964    DialogItemSetText(di, _("Right"));
1965    DialogItemRadioButtonSetFirst(di, radio);
1966    DialogItemRadioButtonGroupSetVal(di, 3);
1967    DialogItemRadioButtonGroupSetValPtr(radio, &dd->pager_menu_button);
1968 }
1969 
1970 const DialogDef     DlgPagers = {
1971    "CONFIGURE_PAGER",
1972    N_("Pagers"), N_("Pager Settings"),
1973    sizeof(PagerDlgData),
1974    SOUND_SETTINGS_PAGER,
1975    "pix/pager.png",
1976    N_("Enlightenment Desktop & Area\n" "Pager Settings Dialog"),
1977    _DlgFillPagers,
1978    DLG_OAC, _DlgApplyPagers, NULL
1979 };
1980 #endif /* ENABLE_DIALOGS */
1981 
1982 /*
1983  * Pagers Module
1984  */
1985 
1986 static void
PagersSighan(int sig,void * prm)1987 PagersSighan(int sig, void *prm)
1988 {
1989    switch (sig)
1990      {
1991      case ESIGNAL_INIT:
1992 	memset(&Mode_pagers, 0, sizeof(Mode_pagers));
1993 	break;
1994      case ESIGNAL_CONFIGURE:
1995 	break;
1996      case ESIGNAL_START:
1997 	if (!Conf_pagers.enable)
1998 	   break;
1999 	Conf_pagers.enable = 0;
2000 	PagersShow(1);
2001 	break;
2002 
2003      case ESIGNAL_AREA_CONFIGURED:
2004 	PagersReconfigure();
2005 	break;
2006      case ESIGNAL_AREA_SWITCH_START:
2007 	PagerHiwinHide();
2008 	break;
2009      case ESIGNAL_AREA_SWITCH_DONE:
2010 	PagersUpdate(DesksGetCurrent(), PAGER_UPD_EWIN_GEOM,
2011 		     0, 0, 99999, 99999);
2012 	UpdatePagerSel();
2013 	break;
2014 
2015      case ESIGNAL_DESK_ADDED:
2016 	if (Mode.wm.startup)
2017 	   break;
2018 	NewPagerForDesktop((Desk *) prm);
2019 	break;
2020      case ESIGNAL_DESK_REMOVED:
2021 	PagersForDesktopDisable((Desk *) prm);
2022 	break;
2023      case ESIGNAL_DESK_SWITCH_START:
2024 	PagerHiwinHide();
2025 	break;
2026      case ESIGNAL_DESK_SWITCH_DONE:
2027 	UpdatePagerSel();
2028 	break;
2029      case ESIGNAL_DESK_RESIZE:
2030 	PagersReconfigure();
2031 	break;
2032 
2033      case ESIGNAL_BACKGROUND_CHANGE:
2034 	PagersUpdateBackground((Desk *) prm);
2035 	break;
2036 
2037      case ESIGNAL_EWIN_UNMAP:
2038 	PagersUpdateEwin((EWin *) prm, PAGER_UPD_EWIN_GONE);
2039 	break;
2040      case ESIGNAL_EWIN_CHANGE:
2041 	PagersUpdateEwin((EWin *) prm, PAGER_UPD_EWIN_GEOM);
2042 	break;
2043      case ESIGNAL_EWIN_DAMAGE:
2044 	PagersUpdateEwin((EWin *) prm, PAGER_UPD_EWIN_DAMAGE);
2045 	break;
2046      }
2047 }
2048 
2049 static void
IPC_Pager(const char * params)2050 IPC_Pager(const char *params)
2051 {
2052    const char         *p = params;
2053    char                prm1[128];
2054    int                 len, desk;
2055    Desk               *dsk;
2056 
2057    if (!p)
2058       return;
2059 
2060    prm1[0] = '\0';
2061    len = 0;
2062    sscanf(p, "%100s %n", prm1, &len);
2063    p += len;
2064 
2065    if (!strcmp(prm1, "on"))
2066      {
2067 	PagersShow(1);
2068      }
2069    else if (!strcmp(prm1, "off"))
2070      {
2071 	PagersShow(0);
2072      }
2073    else if (!strcmp(prm1, "desk"))
2074      {
2075 	desk = -1;
2076 	prm1[0] = '\0';
2077 	sscanf(p, "%d %100s", &desk, prm1);
2078 	dsk = DeskGet(desk);
2079 
2080 	if (!dsk)
2081 	  {
2082 	     ;
2083 	  }
2084 	else if (!strcmp(prm1, "on"))
2085 	  {
2086 	     PagersForDesktopEnable(dsk);
2087 	  }
2088 	else if (!strcmp(prm1, "new"))
2089 	  {
2090 	     NewPagerForDesktop(dsk);
2091 	  }
2092 	else if (!strcmp(prm1, "off"))
2093 	  {
2094 	     PagersForDesktopDisable(dsk);
2095 	  }
2096      }
2097    else if (!strcmp(prm1, "hiq"))
2098      {
2099 	if (!strcmp(p, "on"))
2100 	   PagerSetHiQ(1);
2101 	else if (!strcmp(p, "off"))
2102 	   PagerSetHiQ(0);
2103      }
2104    else if (!strcmp(prm1, "mode"))
2105      {
2106 	if (!strncmp(p, "si", 2))
2107 	   PagersSetMode(PAGER_MODE_SIMPLE);
2108 	else if (!strncmp(p, "sn", 2))
2109 	   PagersSetMode(PAGER_MODE_SNAP);
2110 	else if (!strncmp(p, "li", 2))
2111 	   PagersSetMode(PAGER_MODE_LIVE);
2112      }
2113    else if (!strcmp(prm1, "zoom"))
2114      {
2115 	if (!strcmp(p, "on"))
2116 	   PagersSetZoom(1);
2117 	else if (!strcmp(p, "off"))
2118 	   PagersSetZoom(0);
2119      }
2120 }
2121 
2122 static const IpcItem PagersIpcArray[] = {
2123    {
2124     IPC_Pager,
2125     "pager", "pg",
2126     "Toggle the status of the Pager and various pager settings",
2127     "use \"pager <on/off>\" to set the current mode\nuse \"pager ?\" "
2128     "to get the current mode\n"
2129     "  pager <#> <on/off/?>   Toggle or test any desktop's pager\n"
2130     "  pager hiq <on/off>     Toggle high quality pager\n"
2131     "  pager scanrate <#>     Toggle number of line updates per second\n"
2132     "  pager mode <mode>      Set pager mode (simple/snapshot/live)\n"
2133     "  pager title <on/off>   Toggle title display in the pager\n"
2134     "  pager zoom <on/off>    Toggle zooming in the pager\n"}
2135    ,
2136 };
2137 
2138 /*
2139  * Configuration items
2140  */
2141 static const CfgItem PagersCfgItems[] = {
2142    CFG_ITEM_BOOL(Conf_pagers, enable, 1),
2143    CFG_ITEM_BOOL(Conf_pagers, zoom, 1),
2144    CFG_ITEM_BOOL(Conf_pagers, title, 1),
2145    CFG_ITEM_BOOL(Conf_pagers, hiq, 1),
2146    CFG_ITEM_INT(Conf_pagers, mode, PAGER_MODE_LIVE),
2147    CFG_ITEM_INT(Conf_pagers, scanspeed, 10),
2148    CFG_ITEM_INT(Conf_pagers, sel_button, 2),
2149    CFG_ITEM_INT(Conf_pagers, win_button, 1),
2150    CFG_ITEM_INT(Conf_pagers, menu_button, 3),
2151 };
2152 
2153 /*
2154  * Module descriptor
2155  */
2156 extern const EModule ModPagers;
2157 
2158 const EModule       ModPagers = {
2159    "pagers", "pg",
2160    PagersSighan,
2161    MOD_ITEMS(PagersIpcArray),
2162    MOD_ITEMS(PagersCfgItems)
2163 };
2164