X-Git-Url: https://jasonwoof.com/gitweb/?p=dwm.git;a=blobdiff_plain;f=dwm.c;h=fa48fb00fa46a4a8b01bc7940c92aec9ee6f2bf1;hp=241c090b7c8262eac9b8ac79a211e602c633ffda;hb=33883da028e2eae2cc5c70b445e0d78434d11ac9;hpb=a75a352db611b268cdcc02e8d7e93cb73c46face diff --git a/dwm.c b/dwm.c index 241c090..fa48fb0 100644 --- a/dwm.c +++ b/dwm.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMWindowTypeDialog, NetClientList, NetSupportingWMCheck, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + ClkClientWin, ClkRootWin, ClkAnywhere, ClkLast }; /* clicks */ typedef union { int i; @@ -179,6 +180,7 @@ static void grabbuttons(Client *c, Bool focused); static void grabkeys(void); static void incnmaster(const Arg *arg); static void keypress(XEvent *e); +static void keyrelease(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); @@ -200,6 +202,7 @@ static void restack(Monitor *m); static void run(void); static void scan(void); static Bool sendevent(Client *c, Atom proto); +static void send_key_event(int type, KeyCode key, unsigned int state); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); @@ -209,6 +212,7 @@ static void setmfact(const Arg *arg); static void setup(void); static void showhide(Client *c); static void sigchld(int unused); +static void kbspawn(const Arg *arg); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -240,6 +244,14 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +typedef struct { + KeyCode keycode; + unsigned int state; + int type; +} BufferedKey; +static BufferedKey key_buffer[200]; +static int key_buffer_len = 0; +static Bool key_buffering = False; static const char broken[] = "broken"; static char stext[256]; static int screen; @@ -257,6 +269,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { [Expose] = expose, [FocusIn] = focusin, [KeyPress] = keypress, + [KeyRelease] = keyrelease, [MappingNotify] = mappingnotify, [MapRequest] = maprequest, [MotionNotify] = motionnotify, @@ -358,6 +371,9 @@ applyrules(Client *c) { && (!r->instance || strstr(instance, r->instance))) { c->isfloating = r->isfloating; + if(r->isfloating) { + c->x = -1; c->y = -2; // secret code for centered + } c->tags |= r->tags; c->screen_hog = r->screen_hog; for(m = mons; m && m->num != r->monitor; m = m->next); @@ -482,11 +498,23 @@ attachstack(Client *c) { void buttonpress(XEvent *e) { - unsigned int i, x, click; + unsigned int i, click; Arg arg = {0}; Client *c; Monitor *m; XButtonPressedEvent *ev = &e->xbutton; + Bool called = False; + + for(i = 0; i < LENGTH(buttons); i++) { + if(buttons[i].click == ClkAnywhere && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { + buttons[i].func(&buttons[i].arg); + called = True; + } + } + if (called) { + return; + } click = ClkRootWin; /* focus monitor if necessary */ @@ -496,29 +524,21 @@ buttonpress(XEvent *e) { focus(NULL); } if(ev->window == selmon->barwin) { - i = x = 0; - do - x += TEXTW(tags[i]); - while(ev->x >= x && ++i < LENGTH(tags)); - if(i < LENGTH(tags)) { - click = ClkTagBar; - arg.ui = 1 << i; - } - else if(ev->x < x + blw) - click = ClkLtSymbol; - else if(ev->x > selmon->ww - TEXTW(stext)) - click = ClkStatusText; - else - click = ClkWinTitle; - } - else if((c = wintoclient(ev->window))) { + return; + } else if((c = wintoclient(ev->window))) { focus(c); click = ClkClientWin; } - for(i = 0; i < LENGTH(buttons); i++) + 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); + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { + if (click == ClkTagBar && buttons[i].arg.i == 0) { + buttons[i].func(&arg); + } else { + buttons[i].func(&buttons[i].arg); + } + } + } } void @@ -752,10 +772,11 @@ detachstack(Client *c) { for(i = nextvisible(c->mon->clients); i && i != c; i = nextvisible(i->next)) next_sel = i; // failing that, find first visible window (besides c) - if (!next_sel) + if (!next_sel) { for(i = nextvisible(c->mon->clients); i && i == c; i = nextvisible(i->next)); if (i != c) next_sel = i; + } c->mon->sel = next_sel; } if (prev) { @@ -1029,34 +1050,25 @@ grabbuttons(Client *c, Bool focused) { XUngrabButton(dpy, AnyButton, AnyModifier, c->win); if(focused) { for(i = 0; i < LENGTH(buttons); i++) - if(buttons[i].click == ClkClientWin) + if(buttons[i].click == ClkClientWin || buttons[i].click == ClkAnywhere) for(j = 0; j < LENGTH(modifiers); j++) XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); - } - else + } else { XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); + } } } void grabkeys(void) { updatenumlockmask(); - { - unsigned int i, j; - unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; - KeyCode code; - - XUngrabKey(dpy, AnyKey, AnyModifier, root); - for(i = 0; i < LENGTH(keys); i++) - if((code = XKeysymToKeycode(dpy, keys[i].keysym))) - for(j = 0; j < LENGTH(modifiers); j++) - XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, - True, GrabModeAsync, GrabModeAsync); - } + //XUngrabKey(dpy, AnyKey, AnyModifier, root); + // FIXME key grabbing causes FocusOut events, which confuses programs (they only get keypresses when they don't have focus) + XGrabKey(dpy, AnyKey, AnyModifier, root, True, GrabModeAsync, GrabModeAsync); } void @@ -1077,18 +1089,88 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) { #endif /* XINERAMA */ void +send_key_event(int type, KeyCode key, unsigned int state) { + int mask; + if (type == KeyPress) { + mask = KeyPressMask; + } else { + mask = KeyReleaseMask; + } + XKeyEvent event; + if(!selmon->sel) { + return; + } + event.type = type; + event.display = dpy; + event.root = root; + event.window = selmon->sel->win; + event.subwindow = None; + event.same_screen = True; + event.x = 1; + event.y = 1; + event.x_root = 1; + event.y_root = 1; + event.time = CurrentTime; + event.state = state; // modifiers + event.keycode = key; + event.same_screen = True; + XSendEvent(event.display, event.window, True, mask, (XEvent *)&event); +} + +void keypress(XEvent *e) { unsigned int i; KeySym keysym; XKeyEvent *ev; + Bool called = False; ev = &e->xkey; + // fprintf(stderr, "key DOWN %i\n", ev->keycode); keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); for(i = 0; i < LENGTH(keys); i++) if(keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) - && keys[i].func) + && keys[i].func) { keys[i].func(&(keys[i].arg)); + called = True; + } + if(!called) { + if(key_buffering) { + if(key_buffer_len == LENGTH(key_buffer)) { + // buffer full, bail + key_buffer_len = 0; + key_buffering = False; + } else { + key_buffer[key_buffer_len].keycode = (KeyCode)ev->keycode; + key_buffer[key_buffer_len].state = ev->state; + key_buffer[key_buffer_len].type = KeyPress; + key_buffer_len += 1; + } + } else { + send_key_event(KeyPress, (KeyCode)ev->keycode, ev->state); + } + } +} + +void +keyrelease(XEvent *e) { + XKeyEvent *ev; + ev = &e->xkey; + // fprintf(stderr, "key UP %i\n", ev->keycode); + if(key_buffering) { + if(key_buffer_len == LENGTH(key_buffer)) { + // buffer full, bail + key_buffer_len = 0; + key_buffering = False; + } else { + key_buffer[key_buffer_len].keycode = (KeyCode)ev->keycode; + key_buffer[key_buffer_len].state = ev->state; + key_buffer[key_buffer_len].type = KeyRelease; + key_buffer_len += 1; + } + } else { + send_key_event(KeyRelease, (KeyCode)ev->keycode, ev->state); + } } void @@ -1111,6 +1193,7 @@ manage(Window w, XWindowAttributes *wa) { Client *c, *t = NULL; Window trans = None; XWindowChanges wc; + int i; if(!(c = calloc(1, sizeof(Client)))) die("fatal: could not malloc() %u bytes\n", sizeof(Client)); @@ -1126,8 +1209,13 @@ manage(Window w, XWindowAttributes *wa) { applyrules(c); } /* geometry */ - c->x = c->oldx = wa->x; - c->y = c->oldy = wa->y; + if(c->x == -1 && c->y == -2) { // secret code for centered + c->x = c->oldx = (c->mon->ww - wa->width) / 2; + c->y = c->oldy = (c->mon->wh - wa->height) / 2; + } else { + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + } c->w = c->oldw = wa->width; c->h = c->oldh = wa->height; c->oldbw = wa->border_width; @@ -1167,11 +1255,19 @@ manage(Window w, XWindowAttributes *wa) { arrange(c->mon); XMapWindow(dpy, c->win); focus(c); + if(key_buffering) { + for(i = 0; i < key_buffer_len; ++i) { + send_key_event(key_buffer[i].type, key_buffer[i].keycode, key_buffer[i].state); + } + key_buffer_len = 0; + key_buffering = False; + } } void mappingnotify(XEvent *e) { XMappingEvent *ev = &e->xmapping; + // fprintf(stderr, "MapNotify\n"); XRefreshKeyboardMapping(ev); if(ev->request == MappingKeyboard) @@ -1183,10 +1279,14 @@ maprequest(XEvent *e) { static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + // fprintf(stderr, "MapRequest\n"); if(!XGetWindowAttributes(dpy, ev->window, &wa)) return; - if(wa.override_redirect) + if(wa.override_redirect) { + key_buffer_len = 0; + key_buffering = False; return; + } if(!wintoclient(ev->window)) manage(ev->window, &wa); } @@ -1482,9 +1582,14 @@ run(void) { XEvent ev; /* main event loop */ XSync(dpy, False); - while(running && !XNextEvent(dpy, &ev)) - if(handler[ev.type]) + while(running && !XNextEvent(dpy, &ev)) { + if(handler[ev.type]) { + // fprintf(stderr, "handling event type %i\n", ev.type); handler[ev.type](&ev); /* call handler */ + } else { + // fprintf(stderr, "evt type %i\n", ev.type); + } + } } void @@ -1658,6 +1763,7 @@ setup(void) { netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); netatom[NetSupportingWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); + XInternAtom(dpy, "_MOTIF_WM_HINTS", False); /* clients may request borderless/fullscreen */ /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1710,6 +1816,13 @@ sigchld(int unused) { } void +kbspawn(const Arg *arg) { + key_buffering = True; + key_buffer_len = 0; + spawn(arg); +} + +void spawn(const Arg *arg) { int tag = 0, i; if(arg->v == termcmd) {