1152 lines
30 KiB
C
1152 lines
30 KiB
C
/*
|
|
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
|
|
* Copyright (C) 2004-2023 Kim Woelders
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
* and software packages that this Software was used.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/keysym.h>
|
|
|
|
#include "E.h"
|
|
#include "borders.h"
|
|
#include "cursors.h"
|
|
#include "desktops.h"
|
|
#include "emodule.h"
|
|
#include "ewins.h"
|
|
#include "focus.h"
|
|
#include "grabs.h"
|
|
#include "groups.h"
|
|
#include "hints.h"
|
|
#include "screen.h"
|
|
#include "timers.h"
|
|
#include "xwin.h"
|
|
|
|
static struct {
|
|
Win events;
|
|
EWin *ewin;
|
|
char mode;
|
|
char using_kbd;
|
|
char nogroup;
|
|
char grab_server;
|
|
int start_x, start_y;
|
|
int cur_x, cur_y;
|
|
int win_x, win_y, win_w, win_h;
|
|
int resize_detail;
|
|
} Mode_mr;
|
|
|
|
static void _MoveResizeInit(void);
|
|
|
|
void
|
|
EwinShapeSet(EWin *ewin)
|
|
{
|
|
int bl, br, bt, bb;
|
|
|
|
ewin->shape_x = EoGetX(ewin);
|
|
ewin->shape_y = EoGetY(ewin);
|
|
|
|
if (ewin->state.shaded)
|
|
{
|
|
EwinBorderGetSize(ewin, &bl, &br, &bt, &bb);
|
|
ewin->shape_w = EoGetW(ewin) - (bl + br);
|
|
ewin->shape_h = EoGetH(ewin) - (bt + bb);
|
|
}
|
|
else
|
|
{
|
|
ewin->shape_w = ewin->client.w;
|
|
ewin->shape_h = ewin->client.h;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeGrabsSet(int kbd, unsigned int csr)
|
|
{
|
|
if (kbd)
|
|
GrabKeyboardSet(Mode_mr.events);
|
|
GrabPointerSet(Mode_mr.events, csr, 1);
|
|
}
|
|
|
|
void
|
|
MoveResizeMoveStart(EWin *ewin, int kbd, int nogroup)
|
|
{
|
|
EWin **gwins;
|
|
int i, num, cx, cy;
|
|
|
|
if (!ewin || ewin->state.inhibit_move)
|
|
return;
|
|
|
|
_MoveResizeInit();
|
|
|
|
Mode_mr.ewin = ewin;
|
|
Mode_mr.using_kbd = kbd;
|
|
Mode_mr.nogroup = nogroup;
|
|
|
|
cx = Mode.events.cx;
|
|
cy = Mode.events.cy;
|
|
|
|
SoundPlay(SOUND_MOVE_START);
|
|
|
|
Mode.mode = MODE_MOVE_PENDING;
|
|
|
|
Mode_mr.start_x = Mode_mr.cur_x = cx;
|
|
Mode_mr.start_y = Mode_mr.cur_y = cy;
|
|
|
|
Mode_mr.win_x = Mode_mr.start_x - (EoGetX(ewin) + EoGetX(EoGetDesk(ewin)));
|
|
Mode_mr.win_y = Mode_mr.start_y - (EoGetY(ewin) + EoGetY(EoGetDesk(ewin)));
|
|
|
|
EwinRaise(ewin);
|
|
gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, nogroup, &num);
|
|
|
|
Conf.movres.mode_move = MoveResizeModeValidateMove(Conf.movres.mode_move);
|
|
Mode_mr.mode = Conf.movres.mode_move;
|
|
Mode_mr.grab_server = DrawEwinShapeNeedsGrab(Mode_mr.mode);
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
EwinShapeSet(gwins[i]);
|
|
EwinOpFloatAt(gwins[i], OPSRC_USER, EoGetX(gwins[i]), EoGetY(gwins[i]));
|
|
if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
|
|
{
|
|
ewin->state.moving = 1;
|
|
EwinUpdateOpacity(gwins[i]);
|
|
}
|
|
}
|
|
Efree(gwins);
|
|
|
|
_MoveResizeGrabsSet(kbd, ECSR_ACT_MOVE);
|
|
}
|
|
|
|
static void
|
|
_MoveResizeMoveEnd(EWin *ewin)
|
|
{
|
|
EWin **gwins;
|
|
int num, i;
|
|
Desk *d1, *d2;
|
|
|
|
if (ewin && ewin != Mode_mr.ewin)
|
|
return;
|
|
|
|
GrabKeyboardRelease();
|
|
GrabPointerRelease();
|
|
|
|
SoundPlay(SOUND_MOVE_STOP);
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
goto done;
|
|
|
|
ewin->state.show_coords = 0;
|
|
|
|
gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
|
|
Mode_mr.nogroup, &num);
|
|
|
|
if (Mode.mode == MODE_MOVE)
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
DrawEwinShape(gwins[i], Mode_mr.mode,
|
|
gwins[i]->shape_x, gwins[i]->shape_y,
|
|
gwins[i]->client.w, gwins[i]->client.h, 2);
|
|
}
|
|
Mode.mode = MODE_NONE;
|
|
|
|
d2 = DesktopAt(Mode.events.mx, Mode.events.my);
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ewin = gwins[i];
|
|
d1 = EoGetDesk(ewin);
|
|
if (d2 == d1)
|
|
EwinOpUnfloatAt(ewin, OPSRC_USER, d2, ewin->shape_x, ewin->shape_y);
|
|
else
|
|
EwinOpUnfloatAt(ewin, OPSRC_USER, d2,
|
|
ewin->shape_x - (EoGetX(d2) - EoGetX(d1)),
|
|
ewin->shape_y - (EoGetY(d2) - EoGetY(d1)));
|
|
if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
|
|
{
|
|
ewin->state.moving = 0;
|
|
EwinUpdateOpacity(ewin);
|
|
}
|
|
}
|
|
|
|
Efree(gwins);
|
|
|
|
ESync(ESYNC_MOVRES);
|
|
|
|
done:
|
|
Mode.mode = MODE_NONE;
|
|
Mode.place.doing_manual = NULL;
|
|
Mode_mr.ewin = NULL;
|
|
|
|
if (Mode_mr.grab_server)
|
|
{
|
|
FocusEnable(1);
|
|
EUngrabServer();
|
|
ModulesSignal(ESIGNAL_ANIMATION_RESUME, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeMoveSuspend(void)
|
|
{
|
|
EWin *ewin, **lst;
|
|
int i, num;
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
return;
|
|
|
|
if (Mode.mode == MODE_MOVE_PENDING)
|
|
return;
|
|
|
|
/* If non opaque undraw our boxes */
|
|
if (Mode_mr.grab_server)
|
|
{
|
|
lst = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
|
|
Mode_mr.nogroup, &num);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ewin = lst[i];
|
|
DrawEwinShape(ewin, Mode_mr.mode, ewin->shape_x,
|
|
ewin->shape_y, ewin->client.w, ewin->client.h, 3);
|
|
}
|
|
Efree(lst);
|
|
|
|
EUngrabServer();
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeMoveResume(void)
|
|
{
|
|
EWin *ewin, **lst;
|
|
int i, num;
|
|
int x, y, dx, dy;
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
return;
|
|
|
|
GrabPointerSet(Mode_mr.events, ECSR_ACT_MOVE, 1);
|
|
|
|
if (Mode.mode == MODE_MOVE_PENDING)
|
|
Mode.mode = MODE_MOVE;
|
|
|
|
if (Mode_mr.grab_server)
|
|
EGrabServer();
|
|
|
|
dx = Mode.events.mx - Mode_mr.win_x - EoGetX(EoGetDesk(ewin)) -
|
|
ewin->shape_x;
|
|
dy = Mode.events.my - Mode_mr.win_y - EoGetY(EoGetDesk(ewin)) -
|
|
ewin->shape_y;
|
|
|
|
/* Redraw any windows that were in "move mode" */
|
|
lst = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
|
|
Mode_mr.nogroup, &num);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ewin = lst[i];
|
|
|
|
if (!EoIsFloating(ewin))
|
|
continue;
|
|
|
|
x = ewin->shape_x + dx;
|
|
y = ewin->shape_y + dy;
|
|
DrawEwinShape(ewin, Mode_mr.mode, x, y,
|
|
ewin->client.w, ewin->client.h, 0);
|
|
}
|
|
Efree(lst);
|
|
}
|
|
|
|
#define RD(h, v) (((h) << 8) + (v))
|
|
#define RD_H(hv) (((hv) >> 8) & 0xff)
|
|
#define RD_V(hv) (((hv) ) & 0xff)
|
|
|
|
void
|
|
MoveResizeResizeStart(EWin *ewin, int kbd, int hv)
|
|
{
|
|
int x, y, w, h, ww, hh, cx, cy;
|
|
unsigned int csr;
|
|
|
|
if (!ewin || ewin->state.inhibit_resize)
|
|
return;
|
|
|
|
_MoveResizeInit();
|
|
|
|
Mode_mr.ewin = ewin;
|
|
|
|
cx = Mode.events.cx;
|
|
cy = Mode.events.cy;
|
|
|
|
SoundPlay(SOUND_RESIZE_START);
|
|
|
|
Conf.movres.mode_resize =
|
|
MoveResizeModeValidateResize(Conf.movres.mode_resize);
|
|
Mode_mr.mode = Conf.movres.mode_resize;
|
|
Mode_mr.using_kbd = kbd;
|
|
Mode_mr.grab_server = DrawEwinShapeNeedsGrab(Mode_mr.mode);
|
|
if (Mode_mr.grab_server)
|
|
{
|
|
EGrabServer();
|
|
ModulesSignal(ESIGNAL_ANIMATION_SUSPEND, NULL);
|
|
/* Run idlers (stacking, border updates, ...) before drawing lines */
|
|
IdlersRun();
|
|
}
|
|
if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
|
|
{
|
|
ewin->state.resizing = 1;
|
|
EwinUpdateOpacity(ewin);
|
|
}
|
|
|
|
switch (hv)
|
|
{
|
|
default:
|
|
case MODE_RESIZE:
|
|
Mode.mode = hv;
|
|
if (kbd)
|
|
{
|
|
Mode_mr.resize_detail = 0;
|
|
csr = ECSR_ACT_RESIZE;
|
|
break;
|
|
}
|
|
x = cx - EoGetX(ewin);
|
|
y = cy - EoGetY(ewin);
|
|
w = EoGetW(ewin) >> 1;
|
|
h = EoGetH(ewin) >> 1;
|
|
ww = EoGetW(ewin) / 6;
|
|
hh = EoGetH(ewin) / 6;
|
|
|
|
csr = ECSR_ACT_RESIZE;
|
|
if ((x < w) && (y < h))
|
|
{
|
|
Mode_mr.resize_detail = RD(1, 1);
|
|
csr = ECSR_ACT_RESIZE_TL;
|
|
}
|
|
else if ((x >= w) && (y < h))
|
|
{
|
|
Mode_mr.resize_detail = RD(2, 1);
|
|
csr = ECSR_ACT_RESIZE_TR;
|
|
}
|
|
else if ((x < w) && (y >= h))
|
|
{
|
|
Mode_mr.resize_detail = RD(1, 2);
|
|
csr = ECSR_ACT_RESIZE_BL;
|
|
}
|
|
else if ((x >= w) && (y >= h))
|
|
{
|
|
Mode_mr.resize_detail = RD(2, 2);
|
|
csr = ECSR_ACT_RESIZE_BR;
|
|
}
|
|
|
|
/* The following four if statements added on 07/22/04 by Josh Holtrop.
|
|
* They allow strictly horizontal or vertical resizing when the
|
|
* cursor is towards the middle of an edge of a window. */
|
|
if ((abs(x - w) < (w >> 1)) && (y < hh))
|
|
{
|
|
Mode.mode = MODE_RESIZE_V;
|
|
Mode_mr.resize_detail = RD(0, 1);
|
|
csr = ECSR_ACT_RESIZE_V;
|
|
}
|
|
else if ((abs(x - w) < (w >> 1)) && (y > (EoGetH(ewin) - hh)))
|
|
{
|
|
Mode.mode = MODE_RESIZE_V;
|
|
Mode_mr.resize_detail = RD(0, 2);
|
|
csr = ECSR_ACT_RESIZE_V;
|
|
}
|
|
else if ((abs(y - h) < (h >> 1)) && (x < ww))
|
|
{
|
|
Mode.mode = MODE_RESIZE_H;
|
|
Mode_mr.resize_detail = RD(1, 0);
|
|
csr = ECSR_ACT_RESIZE_H;
|
|
}
|
|
else if ((abs(y - h) < (h >> 1)) && (x > (EoGetW(ewin) - ww)))
|
|
{
|
|
Mode.mode = MODE_RESIZE_H;
|
|
Mode_mr.resize_detail = RD(2, 0);
|
|
csr = ECSR_ACT_RESIZE_H;
|
|
}
|
|
break;
|
|
|
|
case MODE_RESIZE_H:
|
|
Mode.mode = hv;
|
|
x = cx - EoGetX(ewin);
|
|
w = EoGetW(ewin) >> 1;
|
|
if (x < w)
|
|
Mode_mr.resize_detail = RD(1, 0);
|
|
else
|
|
Mode_mr.resize_detail = RD(2, 0);
|
|
csr = ECSR_ACT_RESIZE_H;
|
|
break;
|
|
|
|
case MODE_RESIZE_V:
|
|
Mode.mode = hv;
|
|
y = cy - EoGetY(ewin);
|
|
h = EoGetH(ewin) >> 1;
|
|
if (y < h)
|
|
Mode_mr.resize_detail = RD(0, 1);
|
|
else
|
|
Mode_mr.resize_detail = RD(0, 2);
|
|
csr = ECSR_ACT_RESIZE_V;
|
|
break;
|
|
}
|
|
|
|
Mode_mr.start_x = Mode_mr.cur_x = cx;
|
|
Mode_mr.start_y = Mode_mr.cur_y = cy;
|
|
Mode_mr.win_x = EoGetX(ewin);
|
|
Mode_mr.win_y = EoGetY(ewin);
|
|
Mode_mr.win_w = ewin->client.w;
|
|
Mode_mr.win_h = ewin->client.h;
|
|
|
|
_MoveResizeGrabsSet(kbd, csr);
|
|
|
|
EwinShapeSet(ewin);
|
|
ewin->state.show_coords = 1;
|
|
DrawEwinShape(ewin, Conf.movres.mode_resize, EoGetX(ewin), EoGetY(ewin),
|
|
ewin->client.w, ewin->client.h, 0);
|
|
}
|
|
|
|
static void
|
|
_MoveResizeResizeEnd(EWin *ewin)
|
|
{
|
|
if (ewin && ewin != Mode_mr.ewin)
|
|
return;
|
|
|
|
Mode.mode = MODE_NONE;
|
|
|
|
GrabKeyboardRelease();
|
|
GrabPointerRelease();
|
|
|
|
SoundPlay(SOUND_RESIZE_STOP);
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
goto done;
|
|
|
|
ewin->state.show_coords = 0;
|
|
DrawEwinShape(ewin, Conf.movres.mode_resize, ewin->shape_x, ewin->shape_y,
|
|
ewin->shape_w, ewin->shape_h, 2);
|
|
|
|
if ((Mode_mr.mode == MR_OPAQUE) || (Mode_mr.mode == MR_TECH_OPAQUE))
|
|
{
|
|
ewin->state.resizing = 0;
|
|
EwinUpdateOpacity(ewin);
|
|
}
|
|
else
|
|
{
|
|
if (ewin->state.shaded)
|
|
EwinOpMove(ewin, OPSRC_USER, ewin->shape_x, ewin->shape_y);
|
|
else
|
|
EwinOpMoveResize(ewin, OPSRC_USER, ewin->shape_x, ewin->shape_y,
|
|
ewin->shape_w, ewin->shape_h);
|
|
}
|
|
|
|
ESync(ESYNC_MOVRES);
|
|
|
|
done:
|
|
Mode_mr.ewin = NULL;
|
|
if (Mode_mr.grab_server)
|
|
{
|
|
EUngrabServer();
|
|
ModulesSignal(ESIGNAL_ANIMATION_RESUME, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_SnapEwin(EWin *ewin, int dx, int dy, int *new_dx, int *new_dy)
|
|
{
|
|
EWin *const *lst1;
|
|
EWin **lst, **gwins, *e;
|
|
int gnum, num, i, j, k, odx, ody;
|
|
static char last_res = 0;
|
|
int top_bound, bottom_bound, left_bound, right_bound;
|
|
int top_strut, bottom_strut, left_strut, right_strut;
|
|
Area area;
|
|
|
|
if (!ewin)
|
|
return;
|
|
|
|
if (!Conf.snap.enable)
|
|
{
|
|
*new_dx = dx;
|
|
*new_dy = dy;
|
|
return;
|
|
}
|
|
|
|
ScreenGetGeometry(ewin->shape_x, ewin->shape_y, &area);
|
|
left_bound = area.x;
|
|
top_bound = area.y;
|
|
right_bound = left_bound + area.w;
|
|
bottom_bound = top_bound + area.h;
|
|
|
|
left_strut = left_bound + Conf.place.screen_struts.left;
|
|
right_strut = right_bound - Conf.place.screen_struts.right;
|
|
top_strut = top_bound + Conf.place.screen_struts.top;
|
|
bottom_strut = bottom_bound - Conf.place.screen_struts.bottom;
|
|
|
|
/* Find the list of windows to check against */
|
|
lst1 = EwinListGetAll(&num);
|
|
if (!lst1)
|
|
return;
|
|
|
|
lst = EMALLOC(EWin *, num);
|
|
if (!lst)
|
|
return;
|
|
|
|
gwins =
|
|
ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, Mode.nogroup,
|
|
&gnum);
|
|
if (gwins)
|
|
{
|
|
for (j = k = 0; j < num; j++)
|
|
{
|
|
e = lst1[j];
|
|
if (e == ewin) /* Skip self */
|
|
continue;
|
|
if (!EoIsSticky(e) && EoGetDesk(ewin) != EoGetDesk(e))
|
|
continue; /* Skip if other desk */
|
|
if (EoIsFloating(e) || e->state.iconified || e->props.ignorearrange)
|
|
continue;
|
|
for (i = 0; i < gnum; i++)
|
|
{
|
|
if (lst1[j] == gwins[i])
|
|
goto skip; /* Skip group members */
|
|
}
|
|
lst[k++] = e; /* Add to list */
|
|
skip:
|
|
;
|
|
}
|
|
num = k;
|
|
Efree(gwins);
|
|
}
|
|
else
|
|
{
|
|
num = 0; /* We should never go here */
|
|
}
|
|
|
|
odx = dx;
|
|
ody = dy;
|
|
if (dx < 0)
|
|
{
|
|
if (IN_BELOW(ewin->shape_x + dx, left_bound,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_x >= left_bound))
|
|
{
|
|
dx = left_bound - ewin->shape_x;
|
|
}
|
|
else if (left_strut > left_bound &&
|
|
IN_BELOW(ewin->shape_x + dx, left_strut,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_x >= left_strut))
|
|
{
|
|
dx = left_strut - ewin->shape_x;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
e = lst[i];
|
|
if (IN_BELOW(ewin->shape_x + dx,
|
|
EoGetX(e) + EoGetW(e) - 1,
|
|
Conf.snap.edge_snap_dist) &&
|
|
SPANS_COMMON(ewin->shape_y, EoGetH(ewin),
|
|
EoGetY(e), EoGetH(e)) &&
|
|
(ewin->shape_x >= (EoGetX(e) + EoGetW(e))))
|
|
{
|
|
dx = (EoGetX(e) + EoGetW(e)) - ewin->shape_x;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((ewin->req_x - ewin->shape_x) > 0)
|
|
dx = 0;
|
|
}
|
|
else if (dx > 0)
|
|
{
|
|
if (IN_ABOVE(ewin->shape_x + EoGetW(ewin) + dx, right_bound,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_x + EoGetW(ewin) <= right_bound))
|
|
{
|
|
dx = right_bound - (ewin->shape_x + EoGetW(ewin));
|
|
}
|
|
else if (right_strut < right_bound &&
|
|
IN_ABOVE(ewin->shape_x + EoGetW(ewin) + dx, right_strut,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_x + EoGetW(ewin) <= right_strut))
|
|
{
|
|
dx = right_strut - (ewin->shape_x + EoGetW(ewin));
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
e = lst[i];
|
|
if (IN_ABOVE(ewin->shape_x + EoGetW(ewin) + dx - 1,
|
|
EoGetX(e), Conf.snap.edge_snap_dist) &&
|
|
SPANS_COMMON(ewin->shape_y, EoGetH(ewin),
|
|
EoGetY(e), EoGetH(e)) &&
|
|
((ewin->shape_x + EoGetW(ewin)) <= EoGetX(e)))
|
|
{
|
|
dx = EoGetX(e) - (ewin->shape_x + EoGetW(ewin));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((ewin->req_x - ewin->shape_x) < 0)
|
|
dx = 0;
|
|
}
|
|
|
|
if (dy < 0)
|
|
{
|
|
if (IN_BELOW(ewin->shape_y + dy, top_bound,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_y >= top_bound))
|
|
{
|
|
dy = top_bound - ewin->shape_y;
|
|
}
|
|
else if (top_strut > top_bound &&
|
|
IN_BELOW(ewin->shape_y + dy, top_strut,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_y >= top_strut))
|
|
{
|
|
dy = top_strut - ewin->shape_y;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
e = lst[i];
|
|
if (IN_BELOW(ewin->shape_y + dy,
|
|
EoGetY(e) + EoGetH(e) - 1,
|
|
Conf.snap.edge_snap_dist) &&
|
|
SPANS_COMMON(ewin->shape_x, EoGetW(ewin),
|
|
EoGetX(e), EoGetW(e)) &&
|
|
(ewin->shape_y >= (EoGetY(e) + EoGetH(e))))
|
|
{
|
|
dy = (EoGetY(e) + EoGetH(e)) - ewin->shape_y;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((ewin->req_y - ewin->shape_y) > 0)
|
|
dy = 0;
|
|
}
|
|
else if (dy > 0)
|
|
{
|
|
if (IN_ABOVE(ewin->shape_y + EoGetH(ewin) + dy, bottom_bound,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_y + EoGetH(ewin) <= bottom_bound))
|
|
{
|
|
dy = bottom_bound - (ewin->shape_y + EoGetH(ewin));
|
|
}
|
|
else if (bottom_strut < bottom_bound &&
|
|
IN_ABOVE(ewin->shape_y + EoGetH(ewin) + dy, bottom_strut,
|
|
Conf.snap.screen_snap_dist) &&
|
|
(ewin->shape_y + EoGetH(ewin) <= bottom_strut))
|
|
{
|
|
dy = bottom_strut - (ewin->shape_y + EoGetH(ewin));
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
e = lst[i];
|
|
if (IN_ABOVE(ewin->shape_y + EoGetH(ewin) + dy - 1,
|
|
EoGetY(e), Conf.snap.edge_snap_dist) &&
|
|
SPANS_COMMON(ewin->shape_x, EoGetW(ewin),
|
|
EoGetX(e), EoGetW(e)) &&
|
|
(ewin->shape_y + EoGetH(ewin) <= EoGetY(e)))
|
|
{
|
|
dy = EoGetY(e) - (ewin->shape_y + EoGetH(ewin));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((ewin->req_y - ewin->shape_y) < 0)
|
|
dy = 0;
|
|
}
|
|
|
|
Efree(lst);
|
|
|
|
if ((odx != dx) || (ody != dy))
|
|
{
|
|
if (!last_res)
|
|
{
|
|
/* SoundPlay(SOUND_MOVE_RESIST); */
|
|
last_res = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
last_res = 0;
|
|
}
|
|
*new_dx = dx;
|
|
*new_dy = dy;
|
|
}
|
|
|
|
static void
|
|
_MoveResizeMoveHandleMotion(void)
|
|
{
|
|
int dx, dy, dd;
|
|
EWin *ewin, **gwins, *ewin1;
|
|
int i, num;
|
|
int ndx, ndy;
|
|
char jumpx, jumpy;
|
|
int min_dx, max_dx, min_dy, max_dy;
|
|
int at_screen_edge;
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
return;
|
|
|
|
EdgeCheckMotion(Mode.events.mx, Mode.events.my);
|
|
|
|
gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE,
|
|
Mode_mr.nogroup, &num);
|
|
|
|
if (Mode.mode == MODE_MOVE_PENDING)
|
|
{
|
|
Mode.mode = MODE_MOVE;
|
|
if (Mode_mr.grab_server)
|
|
{
|
|
EGrabServer();
|
|
FocusEnable(0);
|
|
ModulesSignal(ESIGNAL_ANIMATION_SUSPEND, NULL);
|
|
}
|
|
|
|
if (Mode_mr.mode == MR_OPAQUE || num == 1)
|
|
ewin->state.show_coords = 1;
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ewin1 = gwins[i];
|
|
DrawEwinShape(ewin1, Mode_mr.mode, EoGetX(ewin1), EoGetY(ewin1),
|
|
ewin1->client.w, ewin1->client.h, 0);
|
|
if (Conf.movres.mode_move == MR_OPAQUE)
|
|
Mode_mr.mode = MR_OPAQUE;
|
|
}
|
|
dx = Mode.events.mx - Mode_mr.start_x;
|
|
dy = Mode.events.my - Mode_mr.start_y;
|
|
}
|
|
else if (Mode.mode == MODE_MOVE)
|
|
{
|
|
dx = Mode.events.mx - Mode.events.px;
|
|
dy = Mode.events.my - Mode.events.py;
|
|
}
|
|
else
|
|
{
|
|
/* It should not be possible to get here. */
|
|
goto done;
|
|
}
|
|
|
|
jumpx = 0;
|
|
jumpy = 0;
|
|
min_dx = dx;
|
|
min_dy = dy;
|
|
max_dx = dx;
|
|
max_dy = dy;
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ndx = dx;
|
|
ndy = dy;
|
|
/* make our ewin resist other ewins around the place */
|
|
_SnapEwin(gwins[i], dx, dy, &ndx, &ndy);
|
|
if ((dx < 0) && (ndx <= 0))
|
|
{
|
|
if (ndx > min_dx)
|
|
min_dx = ndx;
|
|
if (ndx < max_dx)
|
|
max_dx = ndx;
|
|
}
|
|
else if (ndx >= 0)
|
|
{
|
|
if (ndx < min_dx)
|
|
min_dx = ndx;
|
|
if (ndx > max_dx)
|
|
max_dx = ndx;
|
|
}
|
|
if ((dy < 0) && (ndy <= 0))
|
|
{
|
|
if (ndy > min_dy)
|
|
min_dy = ndy;
|
|
if (ndy < max_dy)
|
|
max_dy = ndy;
|
|
}
|
|
else if (ndy >= 0)
|
|
{
|
|
if (ndy < min_dy)
|
|
min_dy = ndy;
|
|
if (ndy > max_dy)
|
|
max_dy = ndy;
|
|
}
|
|
}
|
|
if (min_dx == dx)
|
|
ndx = max_dx;
|
|
else
|
|
ndx = min_dx;
|
|
if (min_dy == dy)
|
|
ndy = max_dy;
|
|
else
|
|
ndy = min_dy;
|
|
|
|
/* Loop over windows, top to bottom */
|
|
for (i = num - 1; i >= 0; i--)
|
|
{
|
|
ewin1 = gwins[i];
|
|
|
|
/* jump out of snap horizontally */
|
|
dd = ewin1->req_x - ewin1->shape_x;
|
|
if (dd < 0)
|
|
dd = -dd;
|
|
if (ndx != dx)
|
|
{
|
|
at_screen_edge =
|
|
ewin1->shape_x == 0 ||
|
|
ewin1->shape_x + EoGetW(ewin1) == WinGetW(VROOT);
|
|
|
|
if (at_screen_edge)
|
|
{
|
|
if (dd > Conf.snap.screen_snap_dist)
|
|
{
|
|
jumpx = 1;
|
|
ndx = ewin1->req_x - ewin1->shape_x + dx;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (dd > Conf.snap.edge_snap_dist)
|
|
{
|
|
jumpx = 1;
|
|
ndx = ewin1->req_x - ewin1->shape_x + dx;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* jump out of snap vertically */
|
|
dd = ewin1->req_y - ewin1->shape_y;
|
|
if (dd < 0)
|
|
dd = -dd;
|
|
if (ndy != dy)
|
|
{
|
|
at_screen_edge =
|
|
ewin1->shape_y == 0 ||
|
|
ewin1->shape_y + EoGetH(ewin1) == WinGetH(VROOT);
|
|
|
|
if (at_screen_edge)
|
|
{
|
|
if (dd > Conf.snap.screen_snap_dist)
|
|
{
|
|
jumpy = 1;
|
|
ndy = ewin1->req_y - ewin1->shape_y + dy;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (dd > Conf.snap.edge_snap_dist)
|
|
{
|
|
jumpy = 1;
|
|
ndy = ewin1->req_y - ewin1->shape_y + dy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ewin1 = gwins[i];
|
|
|
|
/* if its opaque move mode check to see if we have to float */
|
|
/* the window above all desktops (reparent to root) */
|
|
if (Mode_mr.mode == MR_OPAQUE)
|
|
{
|
|
Desk *dsk;
|
|
|
|
dsk = EoGetDesk(ewin1);
|
|
DetermineEwinFloat(ewin1, ndx, ndy);
|
|
if (dsk != EoGetDesk(ewin1))
|
|
{
|
|
ewin1->shape_x += EoGetX(dsk);
|
|
ewin1->shape_y += EoGetY(dsk);
|
|
ewin1->req_x += EoGetX(dsk);
|
|
ewin1->req_y += EoGetY(dsk);
|
|
}
|
|
}
|
|
|
|
/* draw the new position of the window */
|
|
DrawEwinShape(ewin1, Mode_mr.mode,
|
|
ewin1->shape_x + ndx, ewin1->shape_y + ndy,
|
|
ewin1->client.w, ewin1->client.h, 1);
|
|
|
|
/* if we didnt jump the window after a resist at the edge */
|
|
/* reset the requested x to be the prev. requested + delta */
|
|
/* if we did jump set requested to current shape position */
|
|
ewin1->req_x = (jumpx) ? ewin1->shape_x : ewin1->req_x + dx;
|
|
ewin1->req_y = (jumpy) ? ewin1->shape_y : ewin1->req_y + dy;
|
|
}
|
|
|
|
done:
|
|
Efree(gwins);
|
|
}
|
|
|
|
static void
|
|
_MoveResizeResizeHandleMotion(void)
|
|
{
|
|
int x, y, w, h;
|
|
EWin *ewin;
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
return;
|
|
|
|
w = ewin->client.w;
|
|
h = ewin->client.h;
|
|
x = ewin->shape_x;
|
|
y = ewin->shape_y;
|
|
|
|
switch (RD_H(Mode_mr.resize_detail))
|
|
{
|
|
default:
|
|
break;
|
|
case 1: /* Left */
|
|
w = Mode_mr.win_w - (Mode.events.mx - Mode_mr.start_x);
|
|
ICCCM_SizeMatch(ewin, w, h, &w, &h);
|
|
x = Mode_mr.win_x + (Mode_mr.win_w - w);
|
|
break;
|
|
case 2: /* Right */
|
|
w = Mode_mr.win_w + (Mode.events.mx - Mode_mr.start_x);
|
|
ICCCM_SizeMatch(ewin, w, h, &w, &h);
|
|
break;
|
|
}
|
|
|
|
switch (RD_V(Mode_mr.resize_detail))
|
|
{
|
|
default:
|
|
break;
|
|
case 1: /* Top */
|
|
h = Mode_mr.win_h - (Mode.events.my - Mode_mr.start_y);
|
|
ICCCM_SizeMatch(ewin, w, h, &w, &h);
|
|
y = Mode_mr.win_y + (Mode_mr.win_h - h);
|
|
break;
|
|
case 2: /* Bottom */
|
|
h = Mode_mr.win_h + (Mode.events.my - Mode_mr.start_y);
|
|
ICCCM_SizeMatch(ewin, w, h, &w, &h);
|
|
break;
|
|
}
|
|
|
|
DrawEwinShape(ewin, Conf.movres.mode_resize, x, y, w, h, 1);
|
|
}
|
|
|
|
static void
|
|
_MoveResizeHandleKey(unsigned int key)
|
|
{
|
|
EWin *ewin;
|
|
int resize, delta, end = 0;
|
|
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
return;
|
|
|
|
resize = Mode.mode == MODE_RESIZE ||
|
|
Mode.mode == MODE_RESIZE_H || Mode.mode == MODE_RESIZE_V;
|
|
|
|
Mode.events.px = Mode_mr.cur_x;
|
|
Mode.events.py = Mode_mr.cur_y;
|
|
delta = 5;
|
|
|
|
switch (key)
|
|
{
|
|
default:
|
|
return;
|
|
|
|
case XK_Escape:
|
|
Mode_mr.cur_x = Mode_mr.start_x;
|
|
Mode_mr.cur_y = Mode_mr.start_y;
|
|
/* FALLTHROUGH */
|
|
case XK_Return:
|
|
end = 1;
|
|
break;
|
|
|
|
case XK_Left:
|
|
if (!RD_H(Mode_mr.resize_detail))
|
|
Mode_mr.resize_detail |= RD(1, 0);
|
|
if (resize && ewin->icccm.w_inc > delta)
|
|
delta = ewin->icccm.w_inc;
|
|
Mode_mr.cur_x -= delta;
|
|
break;
|
|
case XK_Right:
|
|
if (!RD_H(Mode_mr.resize_detail))
|
|
Mode_mr.resize_detail |= RD(2, 0);
|
|
if (resize && ewin->icccm.w_inc > delta)
|
|
delta = ewin->icccm.w_inc;
|
|
Mode_mr.cur_x += delta;
|
|
break;
|
|
case XK_Up:
|
|
if (!RD_V(Mode_mr.resize_detail))
|
|
Mode_mr.resize_detail |= RD(0, 1);
|
|
if (resize && ewin->icccm.h_inc > delta)
|
|
delta = ewin->icccm.h_inc;
|
|
Mode_mr.cur_y -= delta;
|
|
break;
|
|
case XK_Down:
|
|
if (!RD_V(Mode_mr.resize_detail))
|
|
Mode_mr.resize_detail |= RD(0, 2);
|
|
if (resize && ewin->icccm.h_inc > delta)
|
|
delta = ewin->icccm.h_inc;
|
|
Mode_mr.cur_y += delta;
|
|
break;
|
|
}
|
|
|
|
Mode_mr.using_kbd = 2;
|
|
Mode.events.mx = Mode_mr.cur_x;
|
|
Mode.events.my = Mode_mr.cur_y;
|
|
|
|
switch (Mode.mode)
|
|
{
|
|
case MODE_MOVE_PENDING:
|
|
case MODE_MOVE:
|
|
_MoveResizeMoveHandleMotion();
|
|
if (end)
|
|
_MoveResizeMoveEnd(NULL);
|
|
break;
|
|
|
|
case MODE_RESIZE:
|
|
case MODE_RESIZE_H:
|
|
case MODE_RESIZE_V:
|
|
_MoveResizeResizeHandleMotion();
|
|
if (end)
|
|
_MoveResizeResizeEnd(NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeHandleMotion(void)
|
|
{
|
|
switch (Mode.mode)
|
|
{
|
|
case MODE_MOVE_PENDING:
|
|
case MODE_MOVE:
|
|
_MoveResizeMoveHandleMotion();
|
|
break;
|
|
|
|
case MODE_RESIZE:
|
|
case MODE_RESIZE_H:
|
|
case MODE_RESIZE_V:
|
|
_MoveResizeResizeHandleMotion();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
MoveResizeSuspend(void)
|
|
{
|
|
switch (Mode.mode)
|
|
{
|
|
case MODE_MOVE_PENDING:
|
|
case MODE_MOVE:
|
|
_MoveResizeMoveSuspend();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
MoveResizeResume(void)
|
|
{
|
|
switch (Mode.mode)
|
|
{
|
|
case MODE_MOVE_PENDING:
|
|
case MODE_MOVE:
|
|
_MoveResizeMoveResume();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
MoveResizeEnd(EWin *ewin)
|
|
{
|
|
switch (Mode.mode)
|
|
{
|
|
case MODE_RESIZE:
|
|
case MODE_RESIZE_H:
|
|
case MODE_RESIZE_V:
|
|
_MoveResizeResizeEnd(ewin);
|
|
break;
|
|
|
|
case MODE_MOVE_PENDING:
|
|
case MODE_MOVE:
|
|
_MoveResizeMoveEnd(ewin);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeEventHandler(Win win __UNUSED__, XEvent *ev, void *prm __UNUSED__)
|
|
{
|
|
EWin *ewin;
|
|
|
|
#if 0
|
|
Eprintf("%s: type=%2d win=%#lx\n", __func__, ev->type, ev->xany.window);
|
|
#endif
|
|
switch (ev->type)
|
|
{
|
|
default:
|
|
break;
|
|
case KeyPress:
|
|
_MoveResizeHandleKey(XLookupKeysym(&ev->xkey, 0));
|
|
break;
|
|
#if 0
|
|
case ButtonPress:
|
|
break;
|
|
#endif
|
|
case ButtonRelease:
|
|
if (Mode_mr.using_kbd)
|
|
break;
|
|
ewin = Mode_mr.ewin;
|
|
if (!ewin)
|
|
break;
|
|
MoveResizeEnd(ewin);
|
|
BorderCheckState(ewin, ev);
|
|
break;
|
|
case MotionNotify:
|
|
if (Mode_mr.using_kbd)
|
|
break;
|
|
_MoveResizeHandleMotion();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_MoveResizeInit(void)
|
|
{
|
|
if (Mode_mr.events)
|
|
return;
|
|
Mode_mr.events = ECreateEventWindow(VROOT, 0, 0, 1, 1);
|
|
EMapWindow(Mode_mr.events);
|
|
EventCallbackRegister(Mode_mr.events, _MoveResizeEventHandler, NULL);
|
|
}
|