1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2007-2020 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 "shapewin.h"
33 #include "xwin.h"
34 
35 #define MR_MODES_MOVE           0x47	/* MR_OPAQUE through MR_BOX and MR_TECH_OPAQUE */
36 #define MR_MODES_RESIZE         0x47	/* MR_OPAQUE through MR_BOX and MR_TECH_OPAQUE */
37 
38 static Font         font = NoXID;	/* Used in mode 1 (technical) */
39 
40 static void
draw_h_arrow(EX_Drawable dr,GC gc,int x1,int x2,int y1)41 draw_h_arrow(EX_Drawable dr, GC gc, int x1, int x2, int y1)
42 {
43    char                str[32];
44 
45    if (x2 - x1 >= 12)
46      {
47 	XDrawLine(disp, dr, gc, x1, y1, x1 + 6, y1 - 3);
48 	XDrawLine(disp, dr, gc, x1, y1, x1 + 6, y1 + 3);
49 	XDrawLine(disp, dr, gc, x2, y1, x2 - 6, y1 - 3);
50 	XDrawLine(disp, dr, gc, x2, y1, x2 - 6, y1 + 3);
51      }
52    if (x2 >= x1)
53      {
54 	XDrawLine(disp, dr, gc, x1, y1, x2, y1);
55 	Esnprintf(str, sizeof(str), "%i", x2 - x1 + 1);
56 	XDrawString(disp, dr, gc, (x1 + x2) / 2, y1 - 10, str, strlen(str));
57      }
58 }
59 
60 static void
draw_v_arrow(EX_Drawable dr,GC gc,int y1,int y2,int x1)61 draw_v_arrow(EX_Drawable dr, GC gc, int y1, int y2, int x1)
62 {
63    char                str[32];
64 
65    if (y2 - y1 >= 12)
66      {
67 	XDrawLine(disp, dr, gc, x1, y1, x1 + 3, y1 + 6);
68 	XDrawLine(disp, dr, gc, x1, y1, x1 - 3, y1 + 6);
69 	XDrawLine(disp, dr, gc, x1, y2, x1 + 3, y2 - 6);
70 	XDrawLine(disp, dr, gc, x1, y2, x1 - 3, y2 - 6);
71      }
72    if (y2 >= y1)
73      {
74 	XDrawLine(disp, dr, gc, x1, y1, x1, y2);
75 	Esnprintf(str, sizeof(str), "%i", y2 - y1 + 1);
76 	XDrawString(disp, dr, gc, x1 + 10, (y1 + y2) / 2, str, strlen(str));
77      }
78 }
79 
80 void
do_draw_technical(EX_Drawable dr,GC gc,int a,int b,int c,int d,int bl,int br,int bt,int bb)81 do_draw_technical(EX_Drawable dr, GC gc,
82 		  int a, int b, int c, int d, int bl, int br, int bt, int bb)
83 {
84    if (!font)
85       font = XLoadFont(disp, "-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*");
86    XSetFont(disp, gc, font);
87 
88    if (c < 3)
89       c = 3;
90    if (d < 3)
91       d = 3;
92 
93    draw_h_arrow(dr, gc, a + bl, a + bl + c - 1, b + bt + d - 16);
94    draw_h_arrow(dr, gc, 0, a - 1, b + bt + (d / 2));
95    draw_h_arrow(dr, gc, a + c + bl + br, WinGetW(VROOT) - 1, b + bt + (d / 2));
96    draw_v_arrow(dr, gc, b + bt, b + bt + d - 1, a + bl + 16);
97    draw_v_arrow(dr, gc, 0, b - 1, a + bl + (c / 2));
98    draw_v_arrow(dr, gc, b + d + bt + bb, WinGetH(VROOT) - 1, a + bl + (c / 2));
99 
100    XDrawLine(disp, dr, gc, a, 0, a, WinGetH(VROOT));
101    XDrawLine(disp, dr, gc, a + c + bl + br - 1, 0,
102 	     a + c + bl + br - 1, WinGetH(VROOT));
103    XDrawLine(disp, dr, gc, 0, b, WinGetW(VROOT), b);
104    XDrawLine(disp, dr, gc, 0, b + d + bt + bb - 1,
105 	     WinGetW(VROOT), b + d + bt + bb - 1);
106 
107    XDrawRectangle(disp, dr, gc, a + bl + 1, b + bt + 1, c - 3, d - 3);
108 }
109 
110 static void
do_draw_boxy(EX_Drawable dr,GC gc,int a,int b,int c,int d,int bl,int br,int bt,int bb)111 do_draw_boxy(EX_Drawable dr, GC gc,
112 	     int a, int b, int c, int d, int bl, int br, int bt, int bb)
113 {
114    if (c < 3)
115       c = 3;
116    if (d < 3)
117       d = 3;
118    XDrawRectangle(disp, dr, gc, a, b, c + bl + br - 1, d + bt + bb - 1);
119    XDrawRectangle(disp, dr, gc, a + bl + 1, b + bt + 1, c - 3, d - 3);
120 }
121 
122 typedef struct {
123    EX_Window           root;
124    GC                  gc;
125    int                 xo, yo, wo, ho;
126    int                 bl, br, bt, bb;
127    ShapeWin           *shwin;
128 } ShapeData;
129 
130 static void
_ShapeDrawNograb_tech_box(EWin * ewin,int md,int firstlast,int xn,int yn,int wn,int hn)131 _ShapeDrawNograb_tech_box(EWin * ewin, int md, int firstlast,
132 			  int xn, int yn, int wn, int hn)
133 {
134    ShapeData          *psd = (ShapeData *) ewin->shape_data;
135 
136    if (firstlast == 0 && !psd->shwin)
137       psd->shwin = ShapewinCreate(md);
138    if (!psd->shwin)
139       return;
140 
141    ShapewinShapeSet(psd->shwin, md, xn, yn, wn, hn,
142 		    psd->bl, psd->br, psd->bt, psd->bb);
143    EoMap(psd->shwin, 0);
144 
145    CoordsShow(ewin);
146 
147    if (firstlast == 2)
148      {
149 	ShapewinDestroy(psd->shwin);
150 	psd->shwin = NULL;
151      }
152 }
153 
154 typedef void        (DrawFunc) (EX_Drawable dr, GC gc,
155 				int a, int b, int c, int d,
156 				int bl, int br, int bt, int bb);
157 
158 static DrawFunc    *const draw_functions[] = {
159    do_draw_technical, do_draw_boxy,
160    NULL, NULL,
161    NULL, do_draw_technical,
162 };
163 
164 static void
_ShapeDrawNontranslucent(EWin * ewin,int md,int firstlast,int xn,int yn,int wn,int hn)165 _ShapeDrawNontranslucent(EWin * ewin, int md, int firstlast,
166 			 int xn, int yn, int wn, int hn)
167 {
168    ShapeData          *psd = (ShapeData *) ewin->shape_data;
169    DrawFunc           *drf;
170 
171    if (firstlast == 0)
172      {
173 	XGCValues           gcv;
174 
175 	gcv.function = GXxor;
176 	gcv.foreground = Dpy.pixel_white;
177 	if (gcv.foreground == 0)
178 	   gcv.foreground = Dpy.pixel_black;
179 	gcv.subwindow_mode = IncludeInferiors;
180 	psd->gc = EXCreateGC(psd->root,
181 			     GCFunction | GCForeground | GCSubwindowMode, &gcv);
182      }
183 
184    drf = draw_functions[md - 1];
185 
186    if (firstlast > 0)
187       drf(psd->root, psd->gc, psd->xo, psd->yo, psd->wo, psd->ho,
188 	  psd->bl, psd->br, psd->bt, psd->bb);
189 
190    CoordsShow(ewin);
191 
192    if (firstlast < 2)
193       drf(psd->root, psd->gc, xn, yn, wn, hn,
194 	  psd->bl, psd->br, psd->bt, psd->bb);
195 
196    if (firstlast == 2)
197      {
198 	EXFreeGC(psd->gc);
199 	psd->gc = NULL;
200      }
201 }
202 
203 void
DrawEwinShape(EWin * ewin,int md,int x,int y,int w,int h,int firstlast)204 DrawEwinShape(EWin * ewin, int md, int x, int y, int w, int h, int firstlast)
205 {
206    ShapeData          *psd;
207    int                 dx, dy;
208 
209    /* Quit if no change */
210    if (firstlast == 1 &&
211        (x == ewin->shape_x && y == ewin->shape_y &&
212 	(ewin->state.shaded || (w == ewin->shape_w && h == ewin->shape_h))))
213       return;
214 
215    if ((md == MR_OPAQUE) || (md == MR_TECH_OPAQUE))
216      {
217 	EwinOpMoveResize(ewin, OPSRC_USER, x, y, w, h);
218 	EwinShapeSet(ewin);
219 	CoordsShow(ewin);
220 	if (md == MR_OPAQUE)
221 	   goto done;
222      }
223 
224    if (firstlast == 0)
225      {
226 	EwinShapeSet(ewin);
227 
228 	psd = (ShapeData *) ewin->shape_data;
229 	if (!psd)
230 	  {
231 	     psd = ECALLOC(ShapeData, 1);
232 	     if (!psd)
233 		goto done;
234 	     ewin->shape_data = psd;
235 	     psd->root = WinGetXwin(VROOT);
236 	     EwinBorderGetSize(ewin, &psd->bl, &psd->br, &psd->bt, &psd->bb);
237 	  }
238      }
239    psd = (ShapeData *) ewin->shape_data;
240    if (!psd)
241       goto done;
242 
243    dx = EoGetX(EoGetDesk(ewin));
244    dy = EoGetY(EoGetDesk(ewin));
245    ewin->shape_x = x;
246    ewin->shape_y = y;
247    x += dx;
248    y += dy;
249 
250    if (!ewin->state.shaded)
251      {
252 	ewin->shape_w = w;
253 	ewin->shape_h = h;
254      }
255    else
256      {
257 	w = ewin->shape_w;
258 	h = ewin->shape_h;
259      }
260 
261    if (((md <= MR_BOX) || (md == MR_TECH_OPAQUE)) &&
262        Conf.movres.avoid_server_grab)
263      {
264 	_ShapeDrawNograb_tech_box(ewin, md, firstlast, x, y, w, h);
265 	goto done;
266      }
267 
268    switch (md)
269      {
270      case MR_TECHNICAL:
271      case MR_TECH_OPAQUE:
272      case MR_BOX:
273 	_ShapeDrawNontranslucent(ewin, md, firstlast, x, y, w, h);
274 	break;
275      default:
276 	/* Fall back to opaque mode */
277 	Conf.movres.mode_move = MR_OPAQUE;
278 	break;
279      }
280 
281    psd->xo = x;
282    psd->yo = y;
283    psd->wo = w;
284    psd->ho = h;
285 
286  done:
287    if (firstlast == 0 || firstlast == 2 || firstlast == 4)
288      {
289 	ewin->req_x = ewin->shape_x;
290 	ewin->req_y = ewin->shape_y;
291 	if (firstlast == 2)
292 	  {
293 	     CoordsHide();
294 	     EFREE_NULL(ewin->shape_data);
295 	  }
296      }
297 }
298 
299 void
DrawEwinShapeEnd(EWin * ewin)300 DrawEwinShapeEnd(EWin * ewin)
301 {
302    ShapeData          *psd = (ShapeData *) ewin->shape_data;
303 
304    if (!psd)
305       return;
306    if (psd->shwin)
307       ShapewinDestroy(psd->shwin);
308    Efree(psd);
309    ewin->shape_data = NULL;
310 }
311 
312 int
DrawEwinShapeNeedsGrab(int mode)313 DrawEwinShapeNeedsGrab(int mode)
314 {
315    if (mode == MR_OPAQUE)
316       return 0;
317    if ((mode <= MR_BOX) || (mode == MR_TECH_OPAQUE))
318       return !Conf.movres.avoid_server_grab;
319    return 1;
320 }
321 
322 static int
_MoveResizeModeValidate(unsigned int valid,int md)323 _MoveResizeModeValidate(unsigned int valid, int md)
324 {
325    if (md & ~0x1f)
326       return MR_OPAQUE;
327    if (valid & (1U << md))
328       return md;
329    return MR_OPAQUE;
330 }
331 
332 int
MoveResizeModeValidateMove(int md)333 MoveResizeModeValidateMove(int md)
334 {
335    return _MoveResizeModeValidate(MR_MODES_MOVE, md);
336 }
337 
338 int
MoveResizeModeValidateResize(int md)339 MoveResizeModeValidateResize(int md)
340 {
341    return _MoveResizeModeValidate(MR_MODES_RESIZE, md);
342 }
343