/* 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; }