From d20d7a88902659b28369b56ab5d1447b775fb7a1 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Wed, 31 Jan 2024 01:07:09 -0500 Subject: Initial commit. --- xdeadzone.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 xdeadzone.c (limited to 'xdeadzone.c') 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 +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3