1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2015 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "config.h"
25 
26 #include <X11/Xlib.h>
27 
28 #include "E.h"
29 #include "desktops.h"
30 #include "eobj.h"
31 #include "ewins.h"
32 #include "menus.h"		/* FIXME - Should not be here */
33 #include "timers.h"
34 #include "xwin.h"
35 
36 static EObj        *w1 = NULL, *w2 = NULL, *w3 = NULL, *w4 = NULL;
37 static Timer       *edge_timer = NULL;
38 
39 static int
EdgeTimeout(void * data)40 EdgeTimeout(void *data)
41 {
42    int                 val;
43    int                 ax, ay, aw, ah, dx, dy, dax, day;
44    EWin               *ewin;
45 
46    if (MenusActive())
47       goto done;
48    if (Conf.desks.edge_flip_mode == EDGE_FLIP_OFF)
49       goto done;
50 
51    /* Quit if pointer has left screen */
52    if (!EQueryPointer(NULL, NULL, NULL, NULL, NULL))
53       goto done;
54 
55    /* Quit if in fullscreen window */
56    ewin = GetEwinPointerInClient();
57    if (ewin && ewin->state.fullscreen)
58       goto done;
59 
60    DeskCurrentGetArea(&ax, &ay);
61    DesksGetAreaSize(&aw, &ah);
62    val = PTR2INT(data);
63    dx = 0;
64    dy = 0;
65    dax = 0;
66    day = 0;
67    switch (val)
68      {
69      case 0:
70 	if (ax == 0 && !Conf.desks.areas_wraparound)
71 	   goto done;
72 	dx = WinGetW(VROOT) - 2;
73 	dax = -1;
74 	break;
75      case 1:
76 	if (ax == (aw - 1) && !Conf.desks.areas_wraparound)
77 	   goto done;
78 	dx = -(WinGetW(VROOT) - 2);
79 	dax = 1;
80 	break;
81      case 2:
82 	if (ay == 0 && !Conf.desks.areas_wraparound)
83 	   goto done;
84 	dy = WinGetH(VROOT) - 2;
85 	day = -1;
86 	break;
87      case 3:
88 	if (ay == (ah - 1) && !Conf.desks.areas_wraparound)
89 	   goto done;
90 	dy = -(WinGetH(VROOT) - 2);
91 	day = 1;
92 	break;
93      default:
94 	break;
95      }
96    if (aw == 1)
97       dx = 0;
98    if (ah == 1)
99       dy = 0;
100    Mode.events.px = Mode.events.mx;
101    Mode.events.py = Mode.events.my;
102    Mode.events.mx = Mode.events.cx += dx;
103    Mode.events.my = Mode.events.cy += dy;
104    EWarpPointer(VROOT, Mode.events.mx, Mode.events.my);
105    DeskCurrentMoveAreaBy(dax, day);
106    Mode.events.px = Mode.events.mx;
107    Mode.events.py = Mode.events.my;
108 
109  done:
110    edge_timer = NULL;
111    return 0;
112 }
113 
114 static void
EdgeEvent(int dir)115 EdgeEvent(int dir)
116 {
117    static int          lastdir = -1;
118 
119 #if 0
120    Eprintf("%s: %d -> %d\n", __func__, lastdir, dir);
121 #endif
122    if (lastdir == dir || Conf.desks.edge_flip_mode == EDGE_FLIP_OFF)
123       return;
124 
125    if (Conf.desks.edge_flip_mode == EDGE_FLIP_MOVE && Mode.mode != MODE_MOVE)
126       return;
127 
128    TIMER_DEL(edge_timer);
129    if (dir >= 0)
130      {
131 	if (Conf.desks.edge_flip_resistance <= 0)
132 	   Conf.desks.edge_flip_resistance = 1;
133 	TIMER_ADD(edge_timer, 10 * Conf.desks.edge_flip_resistance,
134 		  EdgeTimeout, INT2PTR(dir));
135      }
136    lastdir = dir;
137 }
138 
139 static void
EdgeHandleEvents(Win win __UNUSED__,XEvent * ev,void * prm)140 EdgeHandleEvents(Win win __UNUSED__, XEvent * ev, void *prm)
141 {
142    int                 dir;
143 
144    dir = PTR2INT(prm);
145 
146    switch (ev->type)
147      {
148      default:
149 	break;
150 
151      case EnterNotify:
152 	EdgeEvent(dir);
153 	break;
154 
155      case LeaveNotify:
156 	EdgeEvent(-1);
157 	break;
158      }
159 }
160 
161 void
EdgeCheckMotion(int x,int y)162 EdgeCheckMotion(int x, int y)
163 {
164    int                 dir;
165 
166    if (x == 0)
167       dir = 0;
168    else if (x == WinGetW(VROOT) - 1)
169       dir = 1;
170    else if (y == 0)
171       dir = 2;
172    else if (y == WinGetH(VROOT) - 1)
173       dir = 3;
174    else
175       dir = -1;
176    EdgeEvent(dir);
177 }
178 
179 static void
EdgeWindowShow(int which,int on)180 EdgeWindowShow(int which, int on)
181 {
182    EObj               *eo;
183    int                 x, y, w, h;
184 
185    x = y = 0;
186    w = h = 1;
187 
188    switch (which)
189      {
190      default:
191      case 1:			/* Left */
192 	eo = w1;
193 	h = WinGetH(VROOT);
194 	break;
195      case 2:			/* Right */
196 	eo = w2;
197 	x = WinGetW(VROOT) - 1;
198 	h = WinGetH(VROOT);
199 	break;
200      case 3:			/* Top */
201 	eo = w3;
202 	w = WinGetW(VROOT);
203 	break;
204      case 4:			/* Bottom */
205 	eo = w4;
206 	y = WinGetH(VROOT) - 1;
207 	w = WinGetW(VROOT);
208 	break;
209      }
210 
211    if (on)
212      {
213 	EobjMoveResize(eo, x, y, w, h);
214 	EobjMap(eo, 0);
215      }
216    else
217      {
218 	EobjUnmap(eo);
219      }
220 }
221 
222 void
EdgeWindowsShow(void)223 EdgeWindowsShow(void)
224 {
225    int                 ax, ay, cx, cy;
226 
227    if (Conf.desks.edge_flip_mode == EDGE_FLIP_OFF)
228      {
229 	EdgeWindowsHide();
230 	return;
231      }
232 
233    if (!w1)
234      {
235 	w1 = EobjWindowCreate(EOBJ_TYPE_EVENT,
236 			      0, 0, 1, WinGetH(VROOT), 0, "Edge-L");
237 	w2 = EobjWindowCreate(EOBJ_TYPE_EVENT,
238 			      WinGetW(VROOT) - 1, 0, 1, WinGetH(VROOT),
239 			      0, "Edge-R");
240 	w3 = EobjWindowCreate(EOBJ_TYPE_EVENT,
241 			      0, 0, WinGetW(VROOT), 1, 0, "Edge-T");
242 	w4 = EobjWindowCreate(EOBJ_TYPE_EVENT,
243 			      0, WinGetH(VROOT) - 1, WinGetW(VROOT), 1,
244 			      0, "Edge-B");
245 	ESelectInput(EobjGetWin(w1), EnterWindowMask | LeaveWindowMask);
246 	ESelectInput(EobjGetWin(w2), EnterWindowMask | LeaveWindowMask);
247 	ESelectInput(EobjGetWin(w3), EnterWindowMask | LeaveWindowMask);
248 	ESelectInput(EobjGetWin(w4), EnterWindowMask | LeaveWindowMask);
249 	EventCallbackRegister(EobjGetWin(w1), EdgeHandleEvents, (void *)0);
250 	EventCallbackRegister(EobjGetWin(w2), EdgeHandleEvents, (void *)1);
251 	EventCallbackRegister(EobjGetWin(w3), EdgeHandleEvents, (void *)2);
252 	EventCallbackRegister(EobjGetWin(w4), EdgeHandleEvents, (void *)3);
253      }
254    DeskCurrentGetArea(&cx, &cy);
255    DesksGetAreaSize(&ax, &ay);
256 
257    EdgeWindowShow(1, cx != 0 || Conf.desks.areas_wraparound);
258    EdgeWindowShow(2, cx != (ax - 1) || Conf.desks.areas_wraparound);
259    EdgeWindowShow(3, cy != 0 || Conf.desks.areas_wraparound);
260    EdgeWindowShow(4, cy != (ay - 1) || Conf.desks.areas_wraparound);
261 }
262 
263 void
EdgeWindowsHide(void)264 EdgeWindowsHide(void)
265 {
266    if (!w1)
267       return;
268 
269    EobjUnmap(w1);
270    EobjUnmap(w2);
271    EobjUnmap(w3);
272    EobjUnmap(w4);
273 }
274