paulo@0: /* (C)opyright MMVI-MMVII Anselm R. Garbe paulo@0: * See LICENSE file for license details. paulo@0: */ paulo@0: #include "dwm.h" paulo@0: #include paulo@0: #include paulo@0: #include paulo@0: paulo@0: /* static */ paulo@0: paulo@0: typedef struct { paulo@0: unsigned long mod; paulo@0: KeySym keysym; paulo@0: void (*func)(Arg *arg); paulo@0: Arg arg; paulo@0: } Key; paulo@0: paulo@0: KEYS paulo@0: paulo@0: #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) paulo@0: #define MOUSEMASK (BUTTONMASK | PointerMotionMask) paulo@0: paulo@0: static Client * paulo@0: getclient(Window w) { paulo@0: Client *c; paulo@0: paulo@0: for(c = clients; c && c->win != w; c = c->next); paulo@0: return c; paulo@0: } paulo@0: paulo@0: static void paulo@0: movemouse(Client *c) { paulo@0: int x1, y1, ocx, ocy, di, nx, ny; paulo@0: unsigned int dui; paulo@0: Window dummy; paulo@0: XEvent ev; paulo@0: paulo@0: ocx = nx = c->x; paulo@0: ocy = ny = c->y; paulo@0: if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, paulo@0: None, cursor[CurMove], CurrentTime) != GrabSuccess) paulo@0: return; paulo@0: c->ismax = False; paulo@0: XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); paulo@0: for(;;) { paulo@0: XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); paulo@0: switch (ev.type) { paulo@0: case ButtonRelease: paulo@0: XUngrabPointer(dpy, CurrentTime); paulo@0: return; paulo@0: case ConfigureRequest: paulo@0: case Expose: paulo@0: case MapRequest: paulo@0: handler[ev.type](&ev); paulo@0: break; paulo@0: case MotionNotify: paulo@0: XSync(dpy, False); paulo@0: nx = ocx + (ev.xmotion.x - x1); paulo@0: ny = ocy + (ev.xmotion.y - y1); paulo@0: if(abs(wax + nx) < SNAP) paulo@0: nx = wax; paulo@0: else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP) paulo@0: nx = wax + waw - c->w - 2 * c->border; paulo@0: if(abs(way - ny) < SNAP) paulo@0: ny = way; paulo@0: else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP) paulo@0: ny = way + wah - c->h - 2 * c->border; paulo@0: resize(c, nx, ny, c->w, c->h, False); paulo@0: break; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: resizemouse(Client *c) { paulo@0: int ocx, ocy; paulo@0: int nw, nh; paulo@0: XEvent ev; paulo@0: paulo@0: ocx = c->x; paulo@0: ocy = c->y; paulo@0: if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, paulo@0: None, cursor[CurResize], CurrentTime) != GrabSuccess) paulo@0: return; paulo@0: c->ismax = False; paulo@0: XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1); paulo@0: for(;;) { paulo@0: XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); paulo@0: switch(ev.type) { paulo@0: case ButtonRelease: paulo@0: XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, paulo@0: c->w + c->border - 1, c->h + c->border - 1); paulo@0: XUngrabPointer(dpy, CurrentTime); paulo@0: while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); paulo@0: return; paulo@0: case ConfigureRequest: paulo@0: case Expose: paulo@0: case MapRequest: paulo@0: handler[ev.type](&ev); paulo@0: break; paulo@0: case MotionNotify: paulo@0: XSync(dpy, False); paulo@0: if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0) paulo@0: nw = 1; paulo@0: if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0) paulo@0: nh = 1; paulo@0: resize(c, c->x, c->y, nw, nh, True); paulo@0: break; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: buttonpress(XEvent *e) { paulo@0: int x; paulo@0: Arg a; paulo@0: Client *c; paulo@0: XButtonPressedEvent *ev = &e->xbutton; paulo@0: paulo@0: if(barwin == ev->window) { paulo@0: x = 0; paulo@0: for(a.i = 0; a.i < ntags; a.i++) { paulo@0: x += textw(tags[a.i]); paulo@0: if(ev->x < x) { paulo@0: if(ev->button == Button1) { paulo@0: if(ev->state & MODKEY) paulo@0: tag(&a); paulo@0: else paulo@0: view(&a); paulo@0: } paulo@0: else if(ev->button == Button3) { paulo@0: if(ev->state & MODKEY) paulo@0: toggletag(&a); paulo@0: else paulo@0: toggleview(&a); paulo@0: } paulo@0: return; paulo@0: } paulo@0: } paulo@0: if(ev->x < x + blw) paulo@0: switch(ev->button) { paulo@0: case Button1: paulo@0: a.i = -1; paulo@0: setlayout(&a); paulo@0: break; paulo@0: case Button4: paulo@0: a.i = 1; paulo@0: incnmaster(&a); paulo@0: break; paulo@0: case Button5: paulo@0: a.i = -1; paulo@0: incnmaster(&a); paulo@0: break; paulo@0: } paulo@0: if(ev->x > x + blw) paulo@0: switch(ev->button) { paulo@0: case Button1: zoom(NULL); break; paulo@0: case Button2: toggleversatile(NULL); break; paulo@0: case Button3: killclient(NULL); break; paulo@0: case Button4: focusprev(NULL); break; paulo@0: case Button5: focusnext(NULL); break; paulo@0: } paulo@0: } paulo@0: else if((c = getclient(ev->window))) { paulo@0: focus(c); paulo@0: if(CLEANMASK(ev->state) != MODKEY) paulo@0: return; paulo@0: if(ev->button == Button1 && (lt->arrange == versatile || c->isversatile)) { paulo@0: restack(); paulo@0: movemouse(c); paulo@0: } paulo@0: else if(ev->button == Button2) paulo@0: zoom(NULL); paulo@0: else if(ev->button == Button3 paulo@0: && (lt->arrange == versatile || c->isversatile) && !c->isfixed) paulo@0: { paulo@0: restack(); paulo@0: resizemouse(c); paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: configurerequest(XEvent *e) { paulo@0: Client *c; paulo@0: XConfigureRequestEvent *ev = &e->xconfigurerequest; paulo@0: XWindowChanges wc; paulo@0: paulo@0: if((c = getclient(ev->window))) { paulo@0: c->ismax = False; paulo@0: if(ev->value_mask & CWBorderWidth) paulo@0: c->border = ev->border_width; paulo@0: if(c->isfixed || c->isversatile || (lt->arrange == versatile)) { paulo@0: if(ev->value_mask & CWX) paulo@0: c->x = ev->x; paulo@0: if(ev->value_mask & CWY) paulo@0: c->y = ev->y; paulo@0: if(ev->value_mask & CWWidth) paulo@0: c->w = ev->width; paulo@0: if(ev->value_mask & CWHeight) paulo@0: c->h = ev->height; paulo@0: if((ev->value_mask & (CWX | CWY)) paulo@0: && !(ev->value_mask & (CWWidth | CWHeight))) paulo@0: configure(c); paulo@0: if(isvisible(c)) paulo@0: /* XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); */ paulo@0: resize(c, c->x, c->y, c->w, c->h, False); paulo@0: } paulo@0: else paulo@0: configure(c); paulo@0: } paulo@0: else { paulo@0: wc.x = ev->x; paulo@0: wc.y = ev->y; paulo@0: wc.width = ev->width; paulo@0: wc.height = ev->height; paulo@0: wc.border_width = ev->border_width; paulo@0: wc.sibling = ev->above; paulo@0: wc.stack_mode = ev->detail; paulo@0: XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); paulo@0: } paulo@0: XSync(dpy, False); paulo@0: } paulo@0: paulo@0: static void paulo@0: destroynotify(XEvent *e) { paulo@0: Client *c; paulo@0: XDestroyWindowEvent *ev = &e->xdestroywindow; paulo@0: paulo@0: if((c = getclient(ev->window))) paulo@0: unmanage(c); paulo@0: } paulo@0: paulo@0: static void paulo@0: enternotify(XEvent *e) { paulo@0: Client *c; paulo@0: XCrossingEvent *ev = &e->xcrossing; paulo@0: paulo@0: if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) paulo@0: return; paulo@0: if((c = getclient(ev->window)) && isvisible(c)) paulo@0: focus(c); paulo@0: else if(ev->window == root) { paulo@0: selscreen = True; paulo@0: for(c = stack; c && !isvisible(c); c = c->snext); paulo@0: focus(c); paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: expose(XEvent *e) { paulo@0: XExposeEvent *ev = &e->xexpose; paulo@0: paulo@0: if(ev->count == 0) { paulo@0: if(barwin == ev->window) paulo@0: drawstatus(); paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: keypress(XEvent *e) { paulo@0: static unsigned int len = sizeof key / sizeof key[0]; paulo@0: unsigned int i; paulo@0: KeySym keysym; paulo@0: XKeyEvent *ev = &e->xkey; paulo@0: paulo@0: keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); paulo@0: for(i = 0; i < len; i++) paulo@0: if(keysym == key[i].keysym paulo@0: && CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) paulo@0: { paulo@0: if(key[i].func) paulo@0: key[i].func(&key[i].arg); paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: leavenotify(XEvent *e) { paulo@0: XCrossingEvent *ev = &e->xcrossing; paulo@0: paulo@0: if((ev->window == root) && !ev->same_screen) { paulo@0: selscreen = False; paulo@0: focus(NULL); paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: mappingnotify(XEvent *e) { paulo@0: XMappingEvent *ev = &e->xmapping; paulo@0: paulo@0: XRefreshKeyboardMapping(ev); paulo@0: if(ev->request == MappingKeyboard) paulo@0: grabkeys(); paulo@0: } paulo@0: paulo@0: static void paulo@0: maprequest(XEvent *e) { paulo@0: static XWindowAttributes wa; paulo@0: XMapRequestEvent *ev = &e->xmaprequest; paulo@0: paulo@0: if(!XGetWindowAttributes(dpy, ev->window, &wa)) paulo@0: return; paulo@0: if(wa.override_redirect) paulo@0: return; paulo@0: if(!getclient(ev->window)) paulo@0: manage(ev->window, &wa); paulo@0: } paulo@0: paulo@0: static void paulo@0: propertynotify(XEvent *e) { paulo@0: Client *c; paulo@0: Window trans; paulo@0: XPropertyEvent *ev = &e->xproperty; paulo@0: paulo@0: if(ev->state == PropertyDelete) paulo@0: return; /* ignore */ paulo@0: if((c = getclient(ev->window))) { paulo@0: switch (ev->atom) { paulo@0: default: break; paulo@0: case XA_WM_TRANSIENT_FOR: paulo@0: XGetTransientForHint(dpy, c->win, &trans); paulo@0: if(!c->isversatile && (c->isversatile = (getclient(trans) != NULL))) paulo@0: lt->arrange(); paulo@0: break; paulo@0: case XA_WM_NORMAL_HINTS: paulo@0: updatesizehints(c); paulo@0: break; paulo@0: } paulo@0: if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { paulo@0: updatetitle(c); paulo@0: if(c == sel) paulo@0: drawstatus(); paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void paulo@0: unmapnotify(XEvent *e) { paulo@0: Client *c; paulo@0: XUnmapEvent *ev = &e->xunmap; paulo@0: paulo@0: if((c = getclient(ev->window))) paulo@0: unmanage(c); paulo@0: } paulo@0: paulo@0: /* extern */ paulo@0: paulo@0: void (*handler[LASTEvent]) (XEvent *) = { paulo@0: [ButtonPress] = buttonpress, paulo@0: [ConfigureRequest] = configurerequest, paulo@0: [DestroyNotify] = destroynotify, paulo@0: [EnterNotify] = enternotify, paulo@0: [LeaveNotify] = leavenotify, paulo@0: [Expose] = expose, paulo@0: [KeyPress] = keypress, paulo@0: [MappingNotify] = mappingnotify, paulo@0: [MapRequest] = maprequest, paulo@0: [PropertyNotify] = propertynotify, paulo@0: [UnmapNotify] = unmapnotify paulo@0: }; paulo@0: paulo@0: void paulo@0: grabkeys(void) { paulo@0: static unsigned int len = sizeof key / sizeof key[0]; paulo@0: unsigned int i; paulo@0: KeyCode code; paulo@0: paulo@0: XUngrabKey(dpy, AnyKey, AnyModifier, root); paulo@0: for(i = 0; i < len; i++) { paulo@0: code = XKeysymToKeycode(dpy, key[i].keysym); paulo@0: XGrabKey(dpy, code, key[i].mod, root, True, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, code, key[i].mod | LockMask, root, True, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: } paulo@0: }