387 lines
11 KiB
C
387 lines
11 KiB
C
/*
|
|
* mouse.c
|
|
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of the nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "wmfs.h"
|
|
|
|
Window prevwin;
|
|
|
|
/** Draw the border when a client in dragging/resizing with mouse
|
|
*/
|
|
static void
|
|
mouse_dragborder(Geo geo, GC g)
|
|
{
|
|
XDrawRectangle(dpy, ROOT, g,
|
|
geo.x - (BORDH >> 1),
|
|
geo.y - (TBARH - (BORDH >> 1)),
|
|
geo.width + BORDH,
|
|
geo.height + TBARH);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
mouse_cfactor_border(Client *c, int f[4], GC g)
|
|
{
|
|
int e;
|
|
|
|
mouse_dragborder(cfactor_geo(c->wrgeo, f, &e), g);
|
|
|
|
return;
|
|
}
|
|
|
|
/** Move a client in tile grid with the mouse
|
|
*\param c Client double pointer
|
|
*/
|
|
static void
|
|
mouse_move_tile_client(Client **c)
|
|
{
|
|
Client *sc;
|
|
Window w;
|
|
int d;
|
|
|
|
if(!((*c)->flags & (TileFlag | LMaxFlag)))
|
|
return;
|
|
|
|
XQueryPointer(dpy, ROOT, &w, &w, &d, &d, &d, &d, (uint*)&d);
|
|
|
|
if(((sc = client_gb_win(w)) || (sc = client_gb_frame(w)) || (sc = client_gb_titlebar(w)))
|
|
&& (*c)->win != sc->win && !((*c)->flags & HideFlag) && !(sc->flags & HideFlag) && (sc->flags & TileFlag))
|
|
{
|
|
client_swap(sc, *c);
|
|
client_focus(sc);
|
|
swap_ptr((void**)c, (void**)&sc);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/** Move a client from one tag to another with dah mouse
|
|
*\param c client pointer
|
|
*/
|
|
static void
|
|
mouse_move_tag_client(Client *c)
|
|
{
|
|
Window w;
|
|
int i, d, s;
|
|
|
|
if(!(c->flags & (TileFlag | LMaxFlag)))
|
|
return;
|
|
|
|
s = c->screen;
|
|
|
|
XQueryPointer(dpy, infobar[selscreen].tags_board->win, &w, &w, &d, &d, &d, &d, (uint*)&d);
|
|
|
|
if(w == prevwin)
|
|
return;
|
|
|
|
prevwin = w;
|
|
|
|
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
|
|
if(infobar[selscreen].tags[i]->win == w
|
|
&& tags[selscreen][i].layout.func != freelayout)
|
|
{
|
|
tag_transfert(c, i);
|
|
|
|
if(s != c->screen)
|
|
arrange(c->screen, True);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** Move the client with the mouse
|
|
* \param c Client pointer
|
|
*/
|
|
static void
|
|
mouse_move(Client *c)
|
|
{
|
|
int ocx, ocy, mx, my;
|
|
int dint;
|
|
uint duint;
|
|
Window dw;
|
|
Geo geo = c->geo;
|
|
XGCValues xgc;
|
|
GC gci;
|
|
XEvent ev;
|
|
|
|
if(c->flags & (MaxFlag | FSSFlag))
|
|
return;
|
|
|
|
ocx = c->geo.x;
|
|
ocy = c->geo.y;
|
|
|
|
if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync,
|
|
None, cursor[CurMove], CurrentTime) != GrabSuccess)
|
|
return;
|
|
|
|
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag))
|
|
XGrabServer(dpy);
|
|
|
|
/* Set the GC for the rectangle */
|
|
xgc.function = GXinvert;
|
|
xgc.subwindow_mode = IncludeInferiors;
|
|
xgc.line_width = BORDH;
|
|
gci = XCreateGC(dpy, ROOT, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
|
|
|
|
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag))
|
|
mouse_dragborder(c->geo, gci);
|
|
|
|
XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint);
|
|
|
|
do
|
|
{
|
|
XMaskEvent(dpy, MouseMask | SubstructureRedirectMask, &ev);
|
|
screen_get_sel();
|
|
|
|
if(ev.type == MotionNotify)
|
|
{
|
|
mouse_move_tile_client(&c);
|
|
mouse_move_tag_client(c);
|
|
|
|
/* To move a client normally, in freelayout */
|
|
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag))
|
|
{
|
|
mouse_dragborder(geo, gci);
|
|
|
|
geo.x = (ocx + (ev.xmotion.x - mx));
|
|
geo.y = (ocy + (ev.xmotion.y - my));
|
|
|
|
/*
|
|
* Need to draw 2 times the same rectangle because
|
|
* it is draw with the revert color; revert + revert = normal
|
|
*/
|
|
mouse_dragborder(geo, gci);
|
|
}
|
|
}
|
|
else if((ev.type == MapRequest || ev.type == ConfigureRequest))
|
|
HANDLE_EVENT(&ev);
|
|
}
|
|
while(ev.type != ButtonRelease);
|
|
|
|
/* One time again to delete all the trace on the window */
|
|
if(!(c->flags & (TileFlag | LMaxFlag)))
|
|
{
|
|
mouse_dragborder(geo, gci);
|
|
client_moveresize(c, geo, False);
|
|
frame_update(c);
|
|
XUngrabServer(dpy);
|
|
}
|
|
client_update_attributes(c);
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
XFreeGC(dpy, gci);
|
|
|
|
return;
|
|
}
|
|
|
|
/** Resize a client with the mouse
|
|
* \param c Client pointer
|
|
*/
|
|
|
|
void
|
|
mouse_resize(Client *c)
|
|
{
|
|
Geo geo = c->geo, ogeo = c->geo;
|
|
Position pos = Right;
|
|
XEvent ev;
|
|
Window w;
|
|
int d, u, omx, omy;
|
|
XGCValues xgc;
|
|
GC gci;
|
|
int f[4] = { 0 };
|
|
|
|
if(c->flags & (MaxFlag | LMaxFlag | FSSFlag))
|
|
return;
|
|
|
|
XQueryPointer(dpy, ROOT, &w, &w, &omx, &omy, &d, &d, (uint *)&u);
|
|
|
|
if((omx - c->geo.x) < (c->geo.width >> 1))
|
|
pos = Left;
|
|
|
|
if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync, None,
|
|
cursor[((c->flags & TileFlag) ? CurResize : ((pos == Right) ? CurRightResize : CurLeftResize))],
|
|
CurrentTime) != GrabSuccess)
|
|
return;
|
|
|
|
if(!(c->flags & TileFlag))
|
|
XGrabServer(dpy);
|
|
|
|
/* Set the GC for the rectangle */
|
|
xgc.function = GXinvert;
|
|
xgc.subwindow_mode = IncludeInferiors;
|
|
xgc.line_width = BORDH;
|
|
gci = XCreateGC(dpy, ROOT, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
|
|
|
|
if(!(c->flags & TileFlag))
|
|
{
|
|
if(pos == Right)
|
|
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geo.width + conf.client.borderheight, c->geo.height);
|
|
else
|
|
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, 0, c->geo.height);
|
|
mouse_dragborder(c->geo, gci);
|
|
}
|
|
else
|
|
mouse_cfactor_border(c, f, gci);
|
|
|
|
do
|
|
{
|
|
XMaskEvent(dpy, MouseMask | SubstructureRedirectMask, &ev);
|
|
|
|
if(ev.type == MotionNotify)
|
|
{
|
|
/* To resize client in tile mode with cfactor */
|
|
if(c->flags & TileFlag)
|
|
{
|
|
mouse_cfactor_border(c, f, gci);
|
|
|
|
if(omx >= c->frame_geo.x + (c->frame_geo.width >> 1))
|
|
f[Right] = ev.xmotion.x_root - omx;
|
|
else
|
|
f[Left] = omx - ev.xmotion.x_root;
|
|
|
|
if(omy >= c->frame_geo.y + (c->frame_geo.height >> 1))
|
|
f[Bottom] = ev.xmotion.y_root - omy;
|
|
else
|
|
f[Top] = omy - ev.xmotion.y_root;
|
|
|
|
mouse_cfactor_border(c, f, gci);
|
|
}
|
|
/* Free mode */
|
|
else if(!(c->flags & TileFlag))
|
|
{
|
|
mouse_dragborder(geo, gci);
|
|
|
|
if(pos == Right)
|
|
{
|
|
geo.width = ((ev.xmotion.x - c->geo.x < c->minw) ? c->minw : ev.xmotion.x - c->geo.x);
|
|
geo.height = ((ev.xmotion.y - c->geo.y < c->minh) ? c->minh : ev.xmotion.y - c->geo.y);
|
|
}
|
|
else
|
|
{
|
|
geo.x = (geo.width != c->maxw) ? c->geo.x - (c->geo.x - ev.xmotion.x) : geo.x;
|
|
geo.width = ((c->geo.width + (c->geo.x - geo.x) < c->minw)
|
|
? c->minw && (geo.x = (c->geo.x + c->geo.width) - c->minw)
|
|
: c->geo.width + (c->geo.x - geo.x));
|
|
geo.height = ((ev.xmotion.y - c->geo.y <= c->minh) ? c->minh : ev.xmotion.y - c->geo.y);
|
|
}
|
|
|
|
client_geo_hints(&geo, c);
|
|
|
|
mouse_dragborder((ogeo = geo), gci);
|
|
|
|
XSync(dpy, False);
|
|
}
|
|
}
|
|
}
|
|
while(ev.type != ButtonRelease);
|
|
|
|
if(!(c->flags & TileFlag))
|
|
{
|
|
mouse_dragborder(ogeo, gci);
|
|
client_moveresize(c, geo, True);
|
|
frame_update(c);
|
|
XUngrabServer(dpy);
|
|
}
|
|
else
|
|
{
|
|
mouse_cfactor_border(c, f, gci);
|
|
cfactor_multi_set(c, f);
|
|
}
|
|
|
|
client_update_attributes(c);
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
XFreeGC(dpy, gci);
|
|
|
|
return;
|
|
}
|
|
|
|
/** Grab buttons
|
|
* \param c Client pointer
|
|
* \param focused For know if c is or not focused
|
|
*/
|
|
void
|
|
mouse_grabbuttons(Client *c, bool focused)
|
|
{
|
|
size_t i;
|
|
uint but[] = {Button1, Button2, Button3, Button4, Button5};
|
|
|
|
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
|
|
if(focused)
|
|
for(i = 0; i < LEN(but); ++i)
|
|
{
|
|
XGrabButton(dpy, but[i], conf.client.mod, c->win, False,
|
|
ButtonMask, GrabModeAsync,GrabModeSync, None, None);
|
|
XGrabButton(dpy, but[i], conf.client.mod|LockMask, c->win, False,
|
|
ButtonMask, GrabModeAsync,GrabModeSync, None, None);
|
|
XGrabButton(dpy, but[i], conf.client.mod|numlockmask, c->win, False,
|
|
ButtonMask, GrabModeAsync,GrabModeSync, None, None);
|
|
XGrabButton(dpy, but[i], conf.client.mod|LockMask|numlockmask, c->win, False,
|
|
ButtonMask, GrabModeAsync,GrabModeSync, None, None);
|
|
}
|
|
else
|
|
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
|
|
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
|
|
|
|
return;
|
|
}
|
|
|
|
/** Move the selected client
|
|
* \param cmd uicb_t type unused
|
|
*/
|
|
void
|
|
uicb_mouse_move(uicb_t cmd)
|
|
{
|
|
(void)cmd;
|
|
CHECK(sel);
|
|
|
|
mouse_move(sel);
|
|
|
|
return;
|
|
}
|
|
|
|
/** Reisze the selected client
|
|
* \param cmd uicb_t type unused
|
|
*/
|
|
void
|
|
uicb_mouse_resize(uicb_t cmd)
|
|
{
|
|
(void)cmd;
|
|
CHECK(sel);
|
|
|
|
mouse_resize(sel);
|
|
|
|
return;
|
|
}
|
|
|
|
|