You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
9.2 KiB
Diff

From 15f09e0e690328cb7bfd35b577435cba7b2e4859 Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Mon, 12 Jun 2023 15:17:51 +0200
Subject: [PATCH] Banish patch - behaviour similiar to xbanish and unclutter
---
config.mk | 6 ++-
dwm.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 149 insertions(+), 7 deletions(-)
diff --git a/config.mk b/config.mk
index ef8acf7..ae0a7f3 100644
--- a/config.mk
+++ b/config.mk
@@ -14,6 +14,10 @@ X11LIB = /usr/X11R6/lib
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
+# Banish: dependency on libxi and libxfixes for mouse related features
+XINPUTLIBS = -lXi
+XFIXESLIBS = -lXfixes
+
# freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
@@ -23,7 +27,7 @@ FREETYPEINC = /usr/include/freetype2
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XINPUTLIBS} ${XFIXESLIBS}
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
diff --git a/dwm.c b/dwm.c
index e5efb6a..bb7760b 100644
--- a/dwm.c
+++ b/dwm.c
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <time.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
@@ -39,6 +40,8 @@
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/XInput2.h>
#include <X11/Xft/Xft.h>
#include "drw.h"
@@ -49,6 +52,8 @@
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+#define INTERSECTC(X,Y,W,H,Z) (MAX(0, MIN((X)+(W),(Z)->x+(Z)->w) - MAX((X),(Z)->x)) \
+ * MAX(0, MIN((Y)+(H),(Z)->y+(Z)->h) - MAX((Y),(Z)->y)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
@@ -169,12 +174,14 @@ static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
+static void genericevent(XEvent *e);
static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
+static void hidecursor(const Arg *arg);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
@@ -185,9 +192,11 @@ static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
+static unsigned long long now(void);
static void pop(Client *c);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
+static Client *recttoclient(int x, int y, int w, int h, int include_floating);
static Monitor *recttomon(int x, int y, int w, int h);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
@@ -204,6 +213,7 @@ static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void seturgent(Client *c, int urg);
+static void showcursor(const Arg *arg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
@@ -244,6 +254,14 @@ static int bh; /* bar height */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
+static int cursor_hidden = 0;
+/* mouse_x and mouse_y are used to store the actual co-ordinates of the mouse cursor when
+ * hidden. These can be manipulated freely, e.g. when using the warp patch, to set a new
+ * cursor position for when the cursor is to be revealed again. */
+static int mouse_x = 0;
+static int mouse_y = 0;
+static int xi_opcode;
+static unsigned long long last_button_press = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ClientMessage] = clientmessage,
@@ -252,6 +270,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[Expose] = expose,
+ [GenericEvent] = genericevent,
[FocusIn] = focusin,
[KeyPress] = keypress,
[MappingNotify] = mappingnotify,
@@ -432,7 +451,20 @@ buttonpress(XEvent *e)
selmon = m;
focus(NULL);
}
- if (ev->window == selmon->barwin) {
+
+ c = wintoclient(ev->window);
+
+ if (!c && cursor_hidden) {
+ c = recttoclient(mouse_x, mouse_y, 1, 1, 1);
+ showcursor(NULL);
+ }
+
+ if (c) {
+ focus(c);
+ restack(selmon);
+ XAllowEvents(dpy, ReplayPointer, CurrentTime);
+ click = ClkClientWin;
+ } else if (ev->window == selmon->barwin) {
i = x = 0;
do
x += TEXTW(tags[i]);
@@ -446,16 +478,14 @@ buttonpress(XEvent *e)
click = ClkStatusText;
else
click = ClkWinTitle;
- } else if ((c = wintoclient(ev->window))) {
- focus(c);
- restack(selmon);
- XAllowEvents(dpy, ReplayPointer, CurrentTime);
- click = ClkClientWin;
}
+
for (i = 0; i < LENGTH(buttons); i++)
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+
+ last_button_press = now();
}
void
@@ -765,6 +795,9 @@ enternotify(XEvent *e)
Monitor *m;
XCrossingEvent *ev = &e->xcrossing;
+ if (cursor_hidden)
+ return;
+
if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
return;
c = wintoclient(ev->window);
@@ -862,6 +895,36 @@ focusstack(const Arg *arg)
}
}
+void
+genericevent(XEvent *e)
+{
+ if (e->xcookie.extension != xi_opcode)
+ return;
+
+ if (!XGetEventData(dpy, &e->xcookie))
+ return;
+
+ switch (e->xcookie.evtype) {
+ case XI_RawMotion:
+ if (cursor_hidden)
+ showcursor(NULL);
+ break;
+ case XI_RawTouchBegin:
+ case XI_RawTouchEnd:
+ case XI_RawTouchUpdate:
+ if (!cursor_hidden)
+ hidecursor(NULL);
+ break;
+ case XI_RawKeyRelease:
+ if (now() - last_button_press > 2000 && !cursor_hidden) {
+ hidecursor(NULL);
+ }
+ break;
+ }
+
+ XFreeEventData(dpy, &e->xcookie);
+}
+
Atom
getatomprop(Client *c, Atom prop)
{
@@ -885,6 +948,12 @@ getrootptr(int *x, int *y)
unsigned int dui;
Window dummy;
+ if (cursor_hidden) {
+ *x = mouse_x;
+ *y = mouse_y;
+ return 1;
+ }
+
return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
}
@@ -968,6 +1037,20 @@ grabkeys(void)
}
}
+void
+hidecursor(const Arg *arg)
+{
+ if (cursor_hidden)
+ return;
+
+ XFixesHideCursor(dpy, root);
+ if (getrootptr(&mouse_x, &mouse_y)) {
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->mx + selmon->mw, selmon->my);
+ }
+
+ cursor_hidden = 1;
+}
+
void
incnmaster(const Arg *arg)
{
@@ -1200,6 +1283,13 @@ nexttiled(Client *c)
return c;
}
+unsigned long long
+now(void) {
+ struct timespec currentTime;
+ clock_gettime(CLOCK_REALTIME, &currentTime);
+ return currentTime.tv_sec * 1000LL + currentTime.tv_nsec / 1000000LL;
+}
+
void
pop(Client *c)
{
@@ -1252,6 +1342,23 @@ quit(const Arg *arg)
running = 0;
}
+Client *
+recttoclient(int x, int y, int w, int h, int include_floating)
+{
+ Client *c, *r = NULL;
+ int a, area = 1;
+
+ for (c = selmon->stack; c; c = c->snext) {
+ if (!ISVISIBLE(c) || (c->isfloating && !include_floating))
+ continue;
+ if ((a = INTERSECTC(x, y, w, h, c)) >= area) {
+ area = a;
+ r = c;
+ }
+ }
+ return r;
+}
+
Monitor *
recttomon(int x, int y, int w, int h)
{
@@ -1593,6 +1700,25 @@ setup(void)
|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask);
+
+ if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &i, &i)) {
+ fprintf(stderr, "Warning: XInput is not available.");
+ }
+ /* Tell XInput to send us all RawMotion events. */
+ unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)];
+ memset(mask_bytes, 0, sizeof(mask_bytes));
+ XISetMask(mask_bytes, XI_RawMotion);
+ XISetMask(mask_bytes, XI_RawKeyRelease);
+ XISetMask(mask_bytes, XI_RawTouchBegin);
+ XISetMask(mask_bytes, XI_RawTouchEnd);
+ XISetMask(mask_bytes, XI_RawTouchUpdate);
+
+ XIEventMask mask;
+ mask.deviceid = XIAllMasterDevices;
+ mask.mask_len = sizeof(mask_bytes);
+ mask.mask = mask_bytes;
+ XISelectEvents(dpy, root, &mask, 1);
+
grabkeys();
focus(NULL);
}
@@ -1610,6 +1736,18 @@ seturgent(Client *c, int urg)
XFree(wmh);
}
+void
+showcursor(const Arg *arg)
+{
+ if (!cursor_hidden)
+ return;
+
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, mouse_x, mouse_y);
+ XFixesShowCursor(dpy, root);
+
+ cursor_hidden = 0;
+}
+
void
showhide(Client *c)
{
--
2.19.1