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