1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-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 #include <X11/keysym.h>
28
29 #include "E.h"
30 #include "borders.h"
31 #include "cursors.h"
32 #include "desktops.h"
33 #include "emodule.h"
34 #include "ewins.h"
35 #include "focus.h"
36 #include "grabs.h"
37 #include "groups.h"
38 #include "hints.h"
39 #include "timers.h"
40 #include "xwin.h"
41
42 static struct {
43 Win events;
44 EWin *ewin;
45 char mode;
46 char using_kbd;
47 char nogroup;
48 char grab_server;
49 int start_x, start_y;
50 int cur_x, cur_y;
51 int win_x, win_y, win_w, win_h;
52 int swapcoord_x, swapcoord_y;
53 int resize_detail;
54 } Mode_mr;
55
56 static void _MoveResizeInit(void);
57
58 void
EwinShapeSet(EWin * ewin)59 EwinShapeSet(EWin * ewin)
60 {
61 int bl, br, bt, bb;
62
63 ewin->shape_x = EoGetX(ewin);
64 ewin->shape_y = EoGetY(ewin);
65
66 if (ewin->state.shaded)
67 {
68 EwinBorderGetSize(ewin, &bl, &br, &bt, &bb);
69 ewin->shape_w = EoGetW(ewin) - (bl + br);
70 ewin->shape_h = EoGetH(ewin) - (bt + bb);
71 }
72 else
73 {
74 ewin->shape_w = ewin->client.w;
75 ewin->shape_h = ewin->client.h;
76 }
77 }
78
79 void
MoveResizeMoveStart(EWin * ewin,int kbd,int constrained,int nogroup)80 MoveResizeMoveStart(EWin * ewin, int kbd, int constrained, int nogroup)
81 {
82 EWin **gwins;
83 int i, num, cx, cy;
84
85 if (!ewin || ewin->state.inhibit_move)
86 return;
87
88 _MoveResizeInit();
89
90 Mode_mr.ewin = ewin;
91 Mode_mr.using_kbd = kbd;
92 Mode_mr.nogroup = nogroup;
93
94 cx = Mode.events.cx;
95 cy = Mode.events.cy;
96
97 SoundPlay(SOUND_MOVE_START);
98
99 Mode.mode = MODE_MOVE_PENDING;
100 Mode.constrained = constrained;
101
102 Mode_mr.start_x = Mode_mr.cur_x = cx;
103 Mode_mr.start_y = Mode_mr.cur_y = cy;
104
105 Mode_mr.win_x = Mode_mr.start_x - (EoGetX(ewin) + EoGetX(EoGetDesk(ewin)));
106 Mode_mr.win_y = Mode_mr.start_y - (EoGetY(ewin) + EoGetY(EoGetDesk(ewin)));
107
108 EwinRaise(ewin);
109 gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, nogroup
110 || Mode.move.swap, &num);
111
112 Conf.movres.mode_move = MoveResizeModeValidateMove(Conf.movres.mode_move);
113 Mode_mr.mode = Conf.movres.mode_move;
114 Mode_mr.grab_server = DrawEwinShapeNeedsGrab(Mode_mr.mode);
115
116 for (i = 0; i < num; i++)
117 {
118 EwinShapeSet(gwins[i]);
119 EwinOpFloatAt(gwins[i], OPSRC_USER, EoGetX(gwins[i]), EoGetY(gwins[i]));
120 if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
121 {
122 ewin->state.moving = 1;
123 EwinUpdateOpacity(gwins[i]);
124 }
125 }
126 Efree(gwins);
127
128 if (kbd)
129 GrabKeyboardSet(Mode_mr.events);
130 else
131 GrabPointerSet(Mode_mr.events, ECSR_ACT_MOVE, 1);
132
133 Mode_mr.swapcoord_x = EoGetX(ewin);
134 Mode_mr.swapcoord_y = EoGetY(ewin);
135 }
136
137 static void
_MoveResizeMoveEnd(EWin * ewin)138 _MoveResizeMoveEnd(EWin * ewin)
139 {
140 EWin **gwins;
141 int num, i;
142 Desk *d1, *d2;
143
144 if (ewin && ewin != Mode_mr.ewin)
145 return;
146
147 GrabKeyboardRelease();
148 GrabPointerRelease();
149
150 SoundPlay(SOUND_MOVE_STOP);
151
152 ewin = Mode_mr.ewin;
153 if (!ewin)
154 goto done;
155
156 ewin->state.show_coords = 0;
157
158 gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, Mode_mr.nogroup
159 || Mode.move.swap, &num);
160
161 if (Mode.mode == MODE_MOVE)
162 {
163 for (i = 0; i < num; i++)
164 DrawEwinShape(gwins[i], Mode_mr.mode,
165 gwins[i]->shape_x, gwins[i]->shape_y,
166 gwins[i]->client.w, gwins[i]->client.h, 2);
167 }
168 Mode.mode = MODE_NONE;
169
170 d2 = DesktopAt(Mode.events.mx, Mode.events.my);
171
172 for (i = 0; i < num; i++)
173 {
174 ewin = gwins[i];
175 d1 = EoGetDesk(ewin);
176 if (d2 == d1)
177 EwinOpUnfloatAt(ewin, OPSRC_USER, d2, ewin->shape_x, ewin->shape_y);
178 else
179 EwinOpUnfloatAt(ewin, OPSRC_USER, d2,
180 ewin->shape_x - (EoGetX(d2) - EoGetX(d1)),
181 ewin->shape_y - (EoGetY(d2) - EoGetY(d1)));
182 if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
183 {
184 ewin->state.moving = 0;
185 EwinUpdateOpacity(ewin);
186 }
187 }
188
189 Efree(gwins);
190
191 ESync(ESYNC_MOVRES);
192
193 done:
194 Mode.mode = MODE_NONE;
195 Mode.move.swap = 0;
196 Mode.place.doing_manual = 0;
197 Mode_mr.ewin = NULL;
198
199 if (Mode_mr.grab_server)
200 {
201 FocusEnable(1);
202 EUngrabServer();
203 ModulesSignal(ESIGNAL_ANIMATION_RESUME, NULL);
204 }
205 }
206
207 static void
_MoveResizeMoveSuspend(void)208 _MoveResizeMoveSuspend(void)
209 {
210 EWin *ewin, **lst;
211 int i, num;
212
213 ewin = Mode_mr.ewin;
214 if (!ewin)
215 return;
216
217 if (Mode.mode == MODE_MOVE_PENDING)
218 return;
219
220 /* If non opaque undraw our boxes */
221 if (Mode_mr.grab_server)
222 {
223 lst = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
224 Mode_mr.nogroup, &num);
225 for (i = 0; i < num; i++)
226 {
227 ewin = lst[i];
228 DrawEwinShape(ewin, Mode_mr.mode, ewin->shape_x,
229 ewin->shape_y, ewin->client.w, ewin->client.h, 3);
230 }
231 Efree(lst);
232
233 EUngrabServer();
234 }
235 }
236
237 static void
_MoveResizeMoveResume(void)238 _MoveResizeMoveResume(void)
239 {
240 EWin *ewin, **lst;
241 int i, num;
242 int x, y, dx, dy;
243
244 ewin = Mode_mr.ewin;
245 if (!ewin)
246 return;
247
248 GrabPointerSet(Mode_mr.events, ECSR_ACT_MOVE, 1);
249
250 if (Mode.mode == MODE_MOVE_PENDING)
251 Mode.mode = MODE_MOVE;
252
253 if (Mode_mr.grab_server)
254 EGrabServer();
255
256 dx =
257 Mode.events.mx - Mode_mr.win_x - EoGetX(EoGetDesk(ewin)) - ewin->shape_x;
258 dy =
259 Mode.events.my - Mode_mr.win_y - EoGetY(EoGetDesk(ewin)) - ewin->shape_y;
260
261 /* Redraw any windows that were in "move mode" */
262 lst = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
263 Mode_mr.nogroup, &num);
264 for (i = 0; i < num; i++)
265 {
266 ewin = lst[i];
267
268 if (!EoIsFloating(ewin))
269 continue;
270
271 x = ewin->shape_x + dx;
272 y = ewin->shape_y + dy;
273 DrawEwinShape(ewin, Mode_mr.mode, x, y,
274 ewin->client.w, ewin->client.h, 0);
275 }
276 Efree(lst);
277 }
278
279 #define RD(h, v) (((h) << 8) + (v))
280 #define RD_H(hv) (((hv) >> 8) & 0xff)
281 #define RD_V(hv) (((hv) ) & 0xff)
282
283 void
MoveResizeResizeStart(EWin * ewin,int kbd,int hv)284 MoveResizeResizeStart(EWin * ewin, int kbd, int hv)
285 {
286 int x, y, w, h, ww, hh, cx, cy;
287 unsigned int csr;
288
289 if (!ewin || ewin->state.inhibit_resize)
290 return;
291
292 _MoveResizeInit();
293
294 Mode_mr.ewin = ewin;
295
296 cx = Mode.events.cx;
297 cy = Mode.events.cy;
298
299 SoundPlay(SOUND_RESIZE_START);
300
301 Conf.movres.mode_resize =
302 MoveResizeModeValidateResize(Conf.movres.mode_resize);
303 Mode_mr.mode = Conf.movres.mode_resize;
304 Mode_mr.using_kbd = kbd;
305 Mode_mr.grab_server = DrawEwinShapeNeedsGrab(Mode_mr.mode);
306 if (Mode_mr.grab_server)
307 {
308 EGrabServer();
309 ModulesSignal(ESIGNAL_ANIMATION_SUSPEND, NULL);
310 /* Run idlers (stacking, border updates, ...) before drawing lines */
311 IdlersRun();
312 }
313 if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
314 {
315 ewin->state.resizing = 1;
316 EwinUpdateOpacity(ewin);
317 }
318
319 switch (hv)
320 {
321 default:
322 case MODE_RESIZE:
323 Mode.mode = hv;
324 if (kbd)
325 {
326 Mode_mr.resize_detail = 0;
327 csr = ECSR_ACT_RESIZE_BR;
328 break;
329 }
330 x = cx - EoGetX(ewin);
331 y = cy - EoGetY(ewin);
332 w = EoGetW(ewin) >> 1;
333 h = EoGetH(ewin) >> 1;
334 ww = EoGetW(ewin) / 6;
335 hh = EoGetH(ewin) / 6;
336
337 csr = ECSR_ACT_RESIZE;
338 if ((x < w) && (y < h))
339 {
340 Mode_mr.resize_detail = RD(1, 1);
341 csr = ECSR_ACT_RESIZE_TL;
342 }
343 else if ((x >= w) && (y < h))
344 {
345 Mode_mr.resize_detail = RD(2, 1);
346 csr = ECSR_ACT_RESIZE_TR;
347 }
348 else if ((x < w) && (y >= h))
349 {
350 Mode_mr.resize_detail = RD(1, 2);
351 csr = ECSR_ACT_RESIZE_BL;
352 }
353 else if ((x >= w) && (y >= h))
354 {
355 Mode_mr.resize_detail = RD(2, 2);
356 csr = ECSR_ACT_RESIZE_BR;
357 }
358
359 /* The following four if statements added on 07/22/04 by Josh Holtrop.
360 * They allow strictly horizontal or vertical resizing when the
361 * cursor is towards the middle of an edge of a window. */
362 if ((abs(x - w) < (w >> 1)) && (y < hh))
363 {
364 Mode.mode = MODE_RESIZE_V;
365 Mode_mr.resize_detail = RD(0, 1);
366 csr = ECSR_ACT_RESIZE_V;
367 }
368 else if ((abs(x - w) < (w >> 1)) && (y > (EoGetH(ewin) - hh)))
369 {
370 Mode.mode = MODE_RESIZE_V;
371 Mode_mr.resize_detail = RD(0, 2);
372 csr = ECSR_ACT_RESIZE_V;
373 }
374 else if ((abs(y - h) < (h >> 1)) && (x < ww))
375 {
376 Mode.mode = MODE_RESIZE_H;
377 Mode_mr.resize_detail = RD(1, 0);
378 csr = ECSR_ACT_RESIZE_H;
379 }
380 else if ((abs(y - h) < (h >> 1)) && (x > (EoGetW(ewin) - ww)))
381 {
382 Mode.mode = MODE_RESIZE_H;
383 Mode_mr.resize_detail = RD(2, 0);
384 csr = ECSR_ACT_RESIZE_H;
385 }
386 break;
387
388 case MODE_RESIZE_H:
389 Mode.mode = hv;
390 x = cx - EoGetX(ewin);
391 w = EoGetW(ewin) >> 1;
392 if (x < w)
393 Mode_mr.resize_detail = RD(1, 0);
394 else
395 Mode_mr.resize_detail = RD(2, 0);
396 csr = ECSR_ACT_RESIZE_H;
397 break;
398
399 case MODE_RESIZE_V:
400 Mode.mode = hv;
401 y = cy - EoGetY(ewin);
402 h = EoGetH(ewin) >> 1;
403 if (y < h)
404 Mode_mr.resize_detail = RD(0, 1);
405 else
406 Mode_mr.resize_detail = RD(0, 2);
407 csr = ECSR_ACT_RESIZE_V;
408 break;
409 }
410
411 Mode_mr.start_x = Mode_mr.cur_x = cx;
412 Mode_mr.start_y = Mode_mr.cur_y = cy;
413 Mode_mr.win_x = EoGetX(ewin);
414 Mode_mr.win_y = EoGetY(ewin);
415 Mode_mr.win_w = ewin->client.w;
416 Mode_mr.win_h = ewin->client.h;
417
418 if (kbd)
419 GrabKeyboardSet(Mode_mr.events);
420 else
421 GrabPointerSet(Mode_mr.events, csr, 1);
422
423 EwinShapeSet(ewin);
424 ewin->state.show_coords = 1;
425 DrawEwinShape(ewin, Conf.movres.mode_resize, EoGetX(ewin), EoGetY(ewin),
426 ewin->client.w, ewin->client.h, 0);
427 }
428
429 static void
_MoveResizeResizeEnd(EWin * ewin)430 _MoveResizeResizeEnd(EWin * ewin)
431 {
432 if (ewin && ewin != Mode_mr.ewin)
433 return;
434
435 Mode.mode = MODE_NONE;
436
437 GrabKeyboardRelease();
438 GrabPointerRelease();
439
440 SoundPlay(SOUND_RESIZE_STOP);
441
442 ewin = Mode_mr.ewin;
443 if (!ewin)
444 goto done;
445
446 ewin->state.show_coords = 0;
447 DrawEwinShape(ewin, Conf.movres.mode_resize, ewin->shape_x, ewin->shape_y,
448 ewin->shape_w, ewin->shape_h, 2);
449
450 if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
451 {
452 ewin->state.resizing = 0;
453 EwinUpdateOpacity(ewin);
454 }
455 else
456 {
457 if (ewin->state.shaded)
458 EwinOpMove(ewin, OPSRC_USER, ewin->shape_x, ewin->shape_y);
459 else
460 EwinOpMoveResize(ewin, OPSRC_USER, ewin->shape_x, ewin->shape_y,
461 ewin->shape_w, ewin->shape_h);
462 }
463
464 ESync(ESYNC_MOVRES);
465
466 done:
467 Mode_mr.ewin = NULL;
468 if (Mode_mr.grab_server)
469 {
470 EUngrabServer();
471 ModulesSignal(ESIGNAL_ANIMATION_RESUME, NULL);
472 }
473 }
474
475 static void
_MoveResizeMoveHandleMotion(void)476 _MoveResizeMoveHandleMotion(void)
477 {
478 int dx, dy, dd;
479 EWin *ewin, **gwins, *ewin1;
480 int i, num;
481 int ndx, ndy;
482 int screen_snap_dist;
483 char jumpx, jumpy;
484 int min_dx, max_dx, min_dy, max_dy;
485
486 ewin = Mode_mr.ewin;
487 if (!ewin)
488 return;
489
490 EdgeCheckMotion(Mode.events.mx, Mode.events.my);
491
492 gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
493 Mode_mr.nogroup || Mode.move.swap, &num);
494
495 if (Mode.mode == MODE_MOVE_PENDING)
496 {
497 Mode.mode = MODE_MOVE;
498 if (Mode_mr.grab_server)
499 {
500 EGrabServer();
501 FocusEnable(0);
502 ModulesSignal(ESIGNAL_ANIMATION_SUSPEND, NULL);
503 }
504
505 if (Mode_mr.mode == MR_OPAQUE || num == 1)
506 ewin->state.show_coords = 1;
507
508 for (i = 0; i < num; i++)
509 {
510 ewin1 = gwins[i];
511 DrawEwinShape(ewin1, Mode_mr.mode, EoGetX(ewin1), EoGetY(ewin1),
512 ewin1->client.w, ewin1->client.h, 0);
513 if (Conf.movres.mode_move == MR_OPAQUE)
514 Mode_mr.mode = MR_OPAQUE;
515 }
516 dx = Mode.events.mx - Mode_mr.start_x;
517 dy = Mode.events.my - Mode_mr.start_y;
518 }
519 else if (Mode.mode == MODE_MOVE)
520 {
521 dx = Mode.events.mx - Mode.events.px;
522 dy = Mode.events.my - Mode.events.py;
523 }
524 else
525 {
526 /* It should not be possible to get here. */
527 goto done;
528 }
529
530 jumpx = 0;
531 jumpy = 0;
532 min_dx = dx;
533 min_dy = dy;
534 max_dx = dx;
535 max_dy = dy;
536
537 for (i = 0; i < num; i++)
538 {
539 ndx = dx;
540 ndy = dy;
541 /* make our ewin resist other ewins around the place */
542 SnapEwin(gwins[i], dx, dy, &ndx, &ndy);
543 if ((dx < 0) && (ndx <= 0))
544 {
545 if (ndx > min_dx)
546 min_dx = ndx;
547 if (ndx < max_dx)
548 max_dx = ndx;
549 }
550 else if (ndx >= 0)
551 {
552 if (ndx < min_dx)
553 min_dx = ndx;
554 if (ndx > max_dx)
555 max_dx = ndx;
556 }
557 if ((dy < 0) && (ndy <= 0))
558 {
559 if (ndy > min_dy)
560 min_dy = ndy;
561 if (ndy < max_dy)
562 max_dy = ndy;
563 }
564 else if (ndy >= 0)
565 {
566 if (ndy < min_dy)
567 min_dy = ndy;
568 if (ndy > max_dy)
569 max_dy = ndy;
570 }
571 }
572 if (min_dx == dx)
573 ndx = max_dx;
574 else
575 ndx = min_dx;
576 if (min_dy == dy)
577 ndy = max_dy;
578 else
579 ndy = min_dy;
580
581 screen_snap_dist =
582 Mode.constrained ? (WinGetW(VROOT) +
583 WinGetH(VROOT)) : Conf.snap.screen_snap_dist;
584
585 for (i = 0; i < num; i++)
586 {
587 ewin1 = gwins[i];
588
589 /* jump out of snap horizontally */
590 dd = ewin1->req_x - ewin1->shape_x;
591 if (dd < 0)
592 dd = -dd;
593 if ((ndx != dx) &&
594 (((ewin1->shape_x == 0) &&
595 (dd > screen_snap_dist)) ||
596 ((ewin1->shape_x == (WinGetW(VROOT) - EoGetW(ewin1))) &&
597 (dd > screen_snap_dist)) ||
598 ((ewin1->shape_x != 0) &&
599 (ewin1->shape_x != (WinGetW(VROOT) - EoGetW(ewin1)) &&
600 (dd > Conf.snap.edge_snap_dist)))))
601 {
602 jumpx = 1;
603 ndx = ewin1->req_x - ewin1->shape_x + dx;
604 }
605
606 /* jump out of snap vertically */
607 dd = ewin1->req_y - ewin1->shape_y;
608 if (dd < 0)
609 dd = -dd;
610 if ((ndy != dy) &&
611 (((ewin1->shape_y == 0) &&
612 (dd > screen_snap_dist)) ||
613 ((ewin1->shape_y == (WinGetH(VROOT) - EoGetH(ewin1))) &&
614 (dd > screen_snap_dist)) ||
615 ((ewin1->shape_y != 0) &&
616 (ewin1->shape_y != (WinGetH(VROOT) - EoGetH(ewin1)) &&
617 (dd > Conf.snap.edge_snap_dist)))))
618 {
619 jumpy = 1;
620 ndy = ewin1->req_y - ewin1->shape_y + dy;
621 }
622 }
623
624 for (i = 0; i < num; i++)
625 {
626 ewin1 = gwins[i];
627
628 /* if its opaque move mode check to see if we have to float */
629 /* the window above all desktops (reparent to root) */
630 if (Mode_mr.mode == MR_OPAQUE)
631 {
632 Desk *dsk;
633
634 dsk = EoGetDesk(ewin1);
635 DetermineEwinFloat(ewin1, ndx, ndy);
636 if (dsk != EoGetDesk(ewin1))
637 {
638 ewin1->shape_x += EoGetX(dsk);
639 ewin1->shape_y += EoGetY(dsk);
640 ewin1->req_x += EoGetX(dsk);
641 ewin1->req_y += EoGetY(dsk);
642 }
643 }
644
645 /* draw the new position of the window */
646 DrawEwinShape(ewin1, Mode_mr.mode,
647 ewin1->shape_x + ndx, ewin1->shape_y + ndy,
648 ewin1->client.w, ewin1->client.h, 1);
649
650 /* if we didnt jump the window after a resist at the edge */
651 /* reset the requested x to be the prev. requested + delta */
652 /* if we did jump set requested to current shape position */
653 ewin1->req_x = (jumpx) ? ewin1->shape_x : ewin1->req_x + dx;
654 ewin1->req_y = (jumpy) ? ewin1->shape_y : ewin1->req_y + dy;
655
656 /* swapping of group member locations: */
657 if (Mode.move.swap && GroupsGetSwapmove())
658 {
659 EWin **all_gwins, *ewin2;
660 int j, all_gwins_num;
661
662 all_gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_ANY, 0,
663 &all_gwins_num);
664
665 for (j = 0; j < all_gwins_num; j++)
666 {
667 ewin2 = all_gwins[j];
668
669 if (ewin1 == ewin2)
670 continue;
671
672 /* check for sufficient overlap and avoid flickering */
673 if (((ewin1->shape_x >= ewin2->shape_x &&
674 ewin1->shape_x <= ewin2->shape_x + EoGetW(ewin2) / 2 &&
675 dx <= 0) ||
676 (ewin1->shape_x <= ewin2->shape_x &&
677 ewin1->shape_x + EoGetW(ewin1) / 2 >= ewin2->shape_x &&
678 dx >= 0)) &&
679 ((ewin1->shape_y >= ewin2->shape_y &&
680 ewin1->shape_y <= ewin2->shape_y + EoGetH(ewin2) / 2 &&
681 dy <= 0) ||
682 (EoGetY(ewin1) <= EoGetY(ewin2) &&
683 ewin1->shape_y + EoGetH(ewin1) / 2 >= ewin2->shape_y &&
684 dy >= 0)))
685 {
686 int tmp_swapcoord_x;
687 int tmp_swapcoord_y;
688
689 tmp_swapcoord_x = Mode_mr.swapcoord_x;
690 tmp_swapcoord_y = Mode_mr.swapcoord_y;
691 Mode_mr.swapcoord_x = ewin2->shape_x;
692 Mode_mr.swapcoord_y = ewin2->shape_y;
693 EwinOpMove(ewin2, OPSRC_USER,
694 tmp_swapcoord_x, tmp_swapcoord_y);
695 break;
696 }
697 }
698
699 Efree(all_gwins);
700 }
701 }
702
703 done:
704 Efree(gwins);
705 }
706
707 static void
_MoveResizeResizeHandleMotion(void)708 _MoveResizeResizeHandleMotion(void)
709 {
710 int x, y, w, h;
711 EWin *ewin;
712
713 ewin = Mode_mr.ewin;
714 if (!ewin)
715 return;
716
717 w = ewin->client.w;
718 h = ewin->client.h;
719 x = ewin->shape_x;
720 y = ewin->shape_y;
721
722 switch (RD_H(Mode_mr.resize_detail))
723 {
724 default:
725 break;
726 case 1: /* Left */
727 w = Mode_mr.win_w - (Mode.events.mx - Mode_mr.start_x);
728 ICCCM_SizeMatch(ewin, w, h, &w, &h);
729 x = Mode_mr.win_x + (Mode_mr.win_w - w);
730 break;
731 case 2: /* Right */
732 w = Mode_mr.win_w + (Mode.events.mx - Mode_mr.start_x);
733 ICCCM_SizeMatch(ewin, w, h, &w, &h);
734 break;
735 }
736
737 switch (RD_V(Mode_mr.resize_detail))
738 {
739 default:
740 break;
741 case 1: /* Top */
742 h = Mode_mr.win_h - (Mode.events.my - Mode_mr.start_y);
743 ICCCM_SizeMatch(ewin, w, h, &w, &h);
744 y = Mode_mr.win_y + (Mode_mr.win_h - h);
745 break;
746 case 2: /* Bottom */
747 h = Mode_mr.win_h + (Mode.events.my - Mode_mr.start_y);
748 ICCCM_SizeMatch(ewin, w, h, &w, &h);
749 break;
750 }
751
752 DrawEwinShape(ewin, Conf.movres.mode_resize, x, y, w, h, 1);
753 }
754
755 static void
_MoveResizeHandleKey(unsigned int key)756 _MoveResizeHandleKey(unsigned int key)
757 {
758 EWin *ewin;
759 int resize, delta, end = 0;
760
761 ewin = Mode_mr.ewin;
762 if (!ewin)
763 return;
764
765 resize = Mode.mode == MODE_RESIZE ||
766 Mode.mode == MODE_RESIZE_H || Mode.mode == MODE_RESIZE_V;
767
768 Mode.events.px = Mode_mr.cur_x;
769 Mode.events.py = Mode_mr.cur_y;
770 delta = 5;
771
772 switch (key)
773 {
774 default:
775 return;
776
777 case XK_Escape:
778 Mode_mr.cur_x = Mode_mr.start_x;
779 Mode_mr.cur_y = Mode_mr.start_y;
780 /* FALLTHROUGH */
781 case XK_Return:
782 end = 1;
783 break;
784
785 case XK_Left:
786 if (!RD_H(Mode_mr.resize_detail))
787 Mode_mr.resize_detail |= RD(1, 0);
788 if (resize && ewin->icccm.w_inc > delta)
789 delta = ewin->icccm.w_inc;
790 Mode_mr.cur_x -= delta;
791 break;
792 case XK_Right:
793 if (!RD_H(Mode_mr.resize_detail))
794 Mode_mr.resize_detail |= RD(2, 0);
795 if (resize && ewin->icccm.w_inc > delta)
796 delta = ewin->icccm.w_inc;
797 Mode_mr.cur_x += delta;
798 break;
799 case XK_Up:
800 if (!RD_V(Mode_mr.resize_detail))
801 Mode_mr.resize_detail |= RD(0, 1);
802 if (resize && ewin->icccm.h_inc > delta)
803 delta = ewin->icccm.h_inc;
804 Mode_mr.cur_y -= delta;
805 break;
806 case XK_Down:
807 if (!RD_V(Mode_mr.resize_detail))
808 Mode_mr.resize_detail |= RD(0, 2);
809 if (resize && ewin->icccm.h_inc > delta)
810 delta = ewin->icccm.h_inc;
811 Mode_mr.cur_y += delta;
812 break;
813 }
814
815 Mode_mr.using_kbd = 2;
816 Mode.events.mx = Mode_mr.cur_x;
817 Mode.events.my = Mode_mr.cur_y;
818
819 switch (Mode.mode)
820 {
821 case MODE_MOVE_PENDING:
822 case MODE_MOVE:
823 _MoveResizeMoveHandleMotion();
824 if (end)
825 _MoveResizeMoveEnd(NULL);
826 break;
827
828 case MODE_RESIZE:
829 case MODE_RESIZE_H:
830 case MODE_RESIZE_V:
831 _MoveResizeResizeHandleMotion();
832 if (end)
833 _MoveResizeResizeEnd(NULL);
834 break;
835
836 default:
837 break;
838 }
839 }
840
841 static void
_MoveResizeHandleMotion(void)842 _MoveResizeHandleMotion(void)
843 {
844 switch (Mode.mode)
845 {
846 case MODE_MOVE_PENDING:
847 case MODE_MOVE:
848 _MoveResizeMoveHandleMotion();
849 break;
850
851 case MODE_RESIZE:
852 case MODE_RESIZE_H:
853 case MODE_RESIZE_V:
854 _MoveResizeResizeHandleMotion();
855 break;
856
857 default:
858 break;
859 }
860 }
861
862 void
MoveResizeSuspend(void)863 MoveResizeSuspend(void)
864 {
865 switch (Mode.mode)
866 {
867 case MODE_MOVE_PENDING:
868 case MODE_MOVE:
869 _MoveResizeMoveSuspend();
870 break;
871 }
872 }
873
874 void
MoveResizeResume(void)875 MoveResizeResume(void)
876 {
877 switch (Mode.mode)
878 {
879 case MODE_MOVE_PENDING:
880 case MODE_MOVE:
881 _MoveResizeMoveResume();
882 break;
883 }
884 }
885
886 void
MoveResizeEnd(EWin * ewin)887 MoveResizeEnd(EWin * ewin)
888 {
889 switch (Mode.mode)
890 {
891 case MODE_RESIZE:
892 case MODE_RESIZE_H:
893 case MODE_RESIZE_V:
894 _MoveResizeResizeEnd(ewin);
895 break;
896
897 case MODE_MOVE_PENDING:
898 case MODE_MOVE:
899 _MoveResizeMoveEnd(ewin);
900 break;
901 }
902 }
903
904 static void
_MoveResizeEventHandler(Win win __UNUSED__,XEvent * ev,void * prm __UNUSED__)905 _MoveResizeEventHandler(Win win __UNUSED__, XEvent * ev, void *prm __UNUSED__)
906 {
907 EWin *ewin;
908
909 #if 0
910 Eprintf("%s: type=%2d win=%#lx\n", __func__, ev->type, ev->xany.window);
911 #endif
912 switch (ev->type)
913 {
914 default:
915 break;
916 case KeyPress:
917 _MoveResizeHandleKey(XLookupKeysym(&ev->xkey, 0));
918 break;
919 #if 0
920 case ButtonPress:
921 break;
922 #endif
923 case ButtonRelease:
924 ewin = Mode_mr.ewin;
925 if (!ewin)
926 break;
927 MoveResizeEnd(ewin);
928 BorderCheckState(ewin, ev);
929 break;
930 case MotionNotify:
931 _MoveResizeHandleMotion();
932 break;
933 }
934 }
935
936 static void
_MoveResizeInit(void)937 _MoveResizeInit(void)
938 {
939 if (Mode_mr.events)
940 return;
941 Mode_mr.events = ECreateEventWindow(VROOT, 0, 0, 1, 1);
942 EMapWindow(Mode_mr.events);
943 EventCallbackRegister(Mode_mr.events, _MoveResizeEventHandler, NULL);
944 }
945