aboutsummaryrefslogtreecommitdiff
path: root/xdeadzone.c
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-01-31 01:07:09 -0500
committerB. Watson <urchlay@slackware.uk>2024-01-31 01:07:09 -0500
commitd20d7a88902659b28369b56ab5d1447b775fb7a1 (patch)
tree97d3c76b7193e40215afc4b423943f3eca1ea029 /xdeadzone.c
downloadxdeadzone-d20d7a88902659b28369b56ab5d1447b775fb7a1.tar.gz
Initial commit.
Diffstat (limited to 'xdeadzone.c')
-rw-r--r--xdeadzone.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/xdeadzone.c b/xdeadzone.c
new file mode 100644
index 0000000..ab36f8c
--- /dev/null
+++ b/xdeadzone.c
@@ -0,0 +1,197 @@
+/*
+ xdeadzone - create a window and don't allow the mouse pointer to enter it.
+
+ Operation is simple: set up our window, wait for events, and if we get
+ an EnterNotify event, warp the pointer out of our window.
+*/
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef VERSION
+# define VERSION "UnknownVersion"
+#endif
+
+#define NAME "XDeadZone"
+
+/* define this to print some debug info at runtime. */
+// #define DEBUG
+
+#ifdef DEBUG
+# define DBG(x) x
+#else
+# define DBG(x)
+#endif
+
+const char *exe_name;
+
+void set_exe_name(const char *p) {
+ exe_name = p;
+ while(*p) {
+ if(*p == '/') exe_name = p + 1;
+ p++;
+ }
+}
+
+void banner(void) {
+ printf(NAME " " VERSION "\n");
+}
+
+void usage(const int ret) {
+ banner();
+ printf(
+ "Usage:\n %s "
+ "[-nw | -ne | -sw | -se | -abs xpos ypos] [width] [height]"
+ "\n",
+ exe_name);
+ exit(ret);
+}
+
+void errmsg(const char *msg) {
+ fprintf(stderr, "%s: %s\n", exe_name, msg);
+ usage(1);
+}
+
+int streq(const char *s1, const char *s2) {
+ return !strcmp(s1, s2);
+}
+
+int main(int argc, char **argv) {
+ Display *d;
+ Window w;
+ XEvent ev;
+ Atom dock_atom;
+ XWindowAttributes attr;
+ XSetWindowAttributes setattr;
+
+ int x = 0, y = 0, width = 0, height = 0;
+
+ set_exe_name(argv[0]);
+
+ if(argc < 2)
+ usage(1);
+
+ if(argc == 2) {
+ if(streq(argv[1], "--help")) {
+ usage(0);
+ } else if(streq(argv[1], "--version")) {
+ banner();
+ exit(0);
+ } else {
+ usage(1);
+ }
+ }
+
+ if(streq(argv[1], "-abs")) {
+ if(argc != 6)
+ errmsg("wrong number of arguments for -abs");
+ x = atoi(argv[2]);
+ y = atoi(argv[3]);
+ width = atoi(argv[4]);
+ height = atoi(argv[5]);
+ } else {
+ if(argc != 4)
+ errmsg("wrong number of arguments for non-abs mode");
+ width = atoi(argv[2]);
+ height = atoi(argv[3]);
+ if(streq(argv[1], "-nw")) {
+ x = 0; y = 0;
+ } else if(streq(argv[1], "-ne")) {
+ x = -width; y = 0;
+ } else if(streq(argv[1], "-sw")) {
+ x = 0; y = -height;
+ } else if(streq(argv[1], "-se")) {
+ x = -width; y = -height;
+ } else {
+ errmsg("invalid first argument (not -abs/-nw/-ne/-sw/-se)");
+ }
+ }
+
+ if(width <= 0 || height <= 0)
+ errmsg("width and height must be positive and non-zero");
+
+ if(!(d = XOpenDisplay(NULL)))
+ errmsg("can't open X display");
+
+ XGetWindowAttributes(d, DefaultRootWindow(d), &attr);
+ if(x < 0) x = attr.width + x;
+ if(y < 0) y = attr.height + y;
+
+ DBG(printf("X size %d x %d, x %d, y %d, width %d, height %d\n",
+ attr.width, attr.height, x, y, width, height));
+
+ /* Create window with override_redirect enabled, to tell the window
+ manager not to decorate it with a titlebar or resize frame.
+ Also, we really only care about EnterNotify events.
+ Set the window to solid white, to make it easy to see during testing.
+ In actual use, the window won't be visible, it'll be in the dead zone,
+ right?
+ */
+ setattr.override_redirect = True;
+ setattr.background_pixel = WhitePixel(d, DefaultScreen(d));
+ setattr.event_mask = EnterWindowMask;
+
+ w = XCreateWindow(d,
+ DefaultRootWindow(d),
+ x, y, width, height, 0,
+ CopyFromParent,
+ InputOutput,
+ CopyFromParent,
+ CWBackPixel | CWOverrideRedirect | CWEventMask,
+ &setattr);
+
+ DBG(printf("window created\n"));
+
+ XStoreName(d, w, NAME);
+
+ /* On most window managers, this makes the window stay on top and
+ be present on all virtual desktops. Tested, works with WindowMaker, Fvwm2,
+ KDE5, XFCE4, BlackBox, and FluxBox. On all but Fvwm2, it also
+ disappears the titlebar and resize frame... but we already took
+ care of that with override_redirect, above.
+ ref: http://standards.freedesktop.org/wm-spec/wm-spec-latest.html
+ */
+ dock_atom = XInternAtom(d, "_NET_WM_WINDOW_TYPE_DOCK", False);
+ XChangeProperty(d,
+ w,
+ XInternAtom(d, "_NET_WM_WINDOW_TYPE", False),
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *) &dock_atom,
+ 1);
+
+ XMapWindow(d, w);
+
+ /* Have to do this after it's mapped, since the window manager might have
+ ignored the x and y in the XCreateWindow(). */
+ XMoveWindow(d, w, x, y);
+
+ while(1) {
+ XNextEvent(d, &ev);
+ if(ev.type == EnterNotify) {
+ /* warp down if at top of screen */
+ int new_y = (y == 0 ? y + height : y - 1);
+
+ DBG(printf("Got EnterNotify, coords %d, %d, new Y is %d\n",
+ ev.xcrossing.x_root, ev.xcrossing.y_root, new_y));
+ XWarpPointer(d,
+ None,
+ DefaultRootWindow(d),
+ 0, 0, 0, 0,
+ ev.xcrossing.x_root,
+ new_y);
+ }
+ }
+
+ /* We should never get here (the loop above never exits).
+ The only way out is for us or the X server to be killed. */
+ XUnmapWindow(d, w);
+ XDestroyWindow(d, w);
+ XCloseDisplay(d);
+
+ return 0;
+}