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