diff --git a/Makefile.in b/Makefile.in index 807eb82..f1c3a90 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,7 @@ SRCS= \ src/util.c \ src/fifo.c \ src/status.c \ + src/mouse.c \ src/wmfs.c diff --git a/src/client.c b/src/client.c index e74e415..086b26a 100644 --- a/src/client.c +++ b/src/client.c @@ -12,6 +12,7 @@ #include "barwin.h" #include "draw.h" #include "screen.h" +#include "mouse.h" #define CLIENT_MOUSE_MOD Mod1Mask @@ -148,6 +149,17 @@ client_gb_pos(struct tag *t, int x, int y) return NULL; } +struct client* +client_gb_titlebar(Window w) +{ + struct client *c = SLIST_FIRST(&W->h.client); + + while(c && c->titlebar->win != w) + c = SLIST_NEXT(c, next); + + return c; +} + /* * Get client left/right/top/bottom of selected client */ @@ -719,6 +731,10 @@ client_frame_new(struct client *c) /* TODO: Refer to titlebar config */ barwin_mousebind_new(c->titlebar, Button1, false, g, uicb_client_focus_with_wid, cmd); + barwin_mousebind_new(c->titlebar, Button1, false, g, + uicb_mouse_move, cmd); + barwin_mousebind_new(c->titlebar, Button3, false, g, + uicb_mouse_resize, cmd); } XReparentWindow(W->dpy, c->win, c->frame, c->border, c->tbarw); diff --git a/src/client.h b/src/client.h index 0cd2ab1..eb82b55 100644 --- a/src/client.h +++ b/src/client.h @@ -17,6 +17,7 @@ inline void client_configure(struct client *c); struct client *client_gb_win(Window w); struct client *client_gb_frame(Window w); struct client *client_gb_pos(struct tag *t, int x, int y); +struct client *client_gb_titlebar(Window w); struct client *client_next_with_pos(struct client *bc, enum position p); void client_swap2(struct client *c1, struct client *c2); void client_swap(struct client *c, enum position p); diff --git a/src/config.h b/src/config.h index f3111d0..6456cd4 100644 --- a/src/config.h +++ b/src/config.h @@ -15,6 +15,7 @@ #include "tag.h" #include "client.h" #include "status.h" +#include "mouse.h" #define THEME_DEFAULT (SLIST_FIRST(&W->h.theme)) @@ -69,6 +70,10 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] = /* Status */ { "status" , uicb_status }, + /* Mouse */ + { "mouse_resize", uicb_mouse_resize }, + { "mouse_move", uicb_mouse_move }, + { NULL, NULL } }; diff --git a/src/mouse.c b/src/mouse.c new file mode 100644 index 0000000..ff561c5 --- /dev/null +++ b/src/mouse.c @@ -0,0 +1,135 @@ +/* + * wmfs2 by Martin Duquesnoy { for(i = 2011; i < 2111; ++i) ©(i); } + * For license, see COPYING. + */ + +#include "wmfs.h" +#include "mouse.h" +#include "client.h" +#include "draw.h" + +#define _REV_BORDER() \ + do { \ + SLIST_FOREACH(gc, &c->tag->clients, tnext) \ + draw_reversed_rect(W->root, &gc->tgeo); \ + } while(/* CONSTCOND */ 0); +static void +mouse_resize(struct client *c) +{ + struct client *gc; + XEvent ev; + Window w; + int d, u, ox, oy, ix, iy; + + XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u); + XGrabServer(W->dpy); + + _REV_BORDER(); + + if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER)) + c = c->tabmaster; + + ix = ox; + iy = oy; + + do + { + XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev); + + if(ev.type != MotionNotify) + continue; + + _REV_BORDER(); + + if(ix >= c->geo.x + (c->geo.w >> 1)) + _fac_resize(c, Right, ev.xmotion.x_root - ox); + else + _fac_resize(c, Left, ox - ev.xmotion.x_root); + + if(iy >= c->geo.y + (c->geo.h >> 1)) + _fac_resize(c, Bottom, ev.xmotion.y_root - oy); + else + _fac_resize(c, Top, oy - ev.xmotion.y_root); + + ox = ev.xmotion.x_root; + oy = ev.xmotion.y_root; + + _REV_BORDER(); + + XSync(W->dpy, false); + + } while(ev.type != ButtonRelease); + + _REV_BORDER(); + + client_apply_tgeo(c->tag); + layout_save_set(c->tag); + + XUngrabServer(W->dpy); +} + +#define _REV_SBORDER(c) draw_reversed_rect(W->root, &(c)->geo); +void +mouse_move(struct client *c) +{ + struct client *c2 = NULL, *last = c; + XEvent ev; + Window w; + int d, u; + + XGrabServer(W->dpy); + + if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER)) + c = c->tabmaster; + + _REV_SBORDER(c); + + do + { + XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev); + + if(ev.type != MotionNotify) + continue; + + XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u); + + if(!(c2 = client_gb_win(w))) + if(!(c2 = client_gb_frame(w))) + c2 = client_gb_titlebar(w); + + if(c2 && c2 != last) + { + _REV_SBORDER(last); + _REV_SBORDER(c2); + last = c2; + } + + XSync(W->dpy, false); + + } while(ev.type != ButtonRelease); + + if(c2 && c2 != c) + client_swap2(c, c2); + + XUngrabServer(W->dpy); +} + +void +uicb_mouse_resize(Uicb cmd) +{ + (void)cmd; + + if(mouse_check_client(W->client)) + if(W->client) + mouse_resize(W->client); +} + +void +uicb_mouse_move(Uicb cmd) +{ + (void)cmd; + + if(mouse_check_client(W->client)) + if(W->client) + mouse_move(W->client); +} diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 0000000..69fbd6e --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,28 @@ +/* + * wmfs2 by Martin Duquesnoy { for(i = 2011; i < 2111; ++i) ©(i); } + * For license, see COPYING. + */ + +#ifndef MOUSE_H +#define MOUSE_H + +#include "client.h" + +void uicb_mouse_resize(Uicb); +void uicb_mouse_move(Uicb); + +static inline bool +mouse_check_client(struct client *c) +{ + Window w; + int d; + + XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&d); + + if(c == client_gb_win(w) || c == client_gb_titlebar(w) || c == client_gb_frame(w)) + return true; + + return false; +} + +#endif /* MOUSE_H */