dwm

dynamic window manager
git clone git://git.suckless.org/dwm
Log | Files | Refs | README | LICENSE

commit dba23062bad40afb1a90f60b6897cf9e1ca5035b
parent c0705eeb65733e8c5091e47d5bdc701a0779a949
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Sat, 15 Jul 2006 16:30:50 +0200

rearranged several stuff

Diffstat:
MMakefile | 2+-
Mclient.c | 145+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mdraw.c | 37++++++++++++++++++++++++-------------
Mdwm.h | 36++++++++++++++++++++++--------------
Mevent.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Dkey.c | 192-------------------------------------------------------------------------------
Mmain.c | 112++++++++++++++++++++++++++++++++++++++++----------------------------------------
Dscreen.c | 100-------------------------------------------------------------------------------
Atag.c | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.c | 2+-
10 files changed, 442 insertions(+), 444 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = client.c draw.c event.c key.c main.c screen.c util.c +SRC = client.c draw.c event.c main.c tag.c util.c OBJ = ${SRC:.c=.o} MAN1 = dwm.1 BIN = dwm diff --git a/client.c b/client.c @@ -11,18 +11,6 @@ #include "dwm.h" -static Rule rule[] = { - /* class instance tags floating */ - { "Firefox-bin", "Gecko", { [Twww] = "www" }, False }, -}; - -Client * -getnext(Client *c) -{ - for(; c && !c->tags[tsel]; c = c->next); - return c; -} - void ban(Client *c) { @@ -31,7 +19,7 @@ ban(Client *c) } static void -resize_title(Client *c) +resizetitle(Client *c) { int i; @@ -72,7 +60,7 @@ settitle(Client *c) } } XFree(name.value); - resize_title(c); + resizetitle(c); } void @@ -143,42 +131,6 @@ focus(Client *c) while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); } -static void -init_tags(Client *c) -{ - XClassHint ch; - static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0; - unsigned int i, j; - Bool matched = False; - - if(!len) { - c->tags[tsel] = tags[tsel]; - return; - } - - if(XGetClassHint(dpy, c->win, &ch)) { - if(ch.res_class && ch.res_name) { - for(i = 0; i < len; i++) - if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class)) - && !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance))) - { - for(j = 0; j < TLast; j++) - c->tags[j] = rule[i].tags[j]; - c->floating = rule[i].floating; - matched = True; - break; - } - } - if(ch.res_class) - XFree(ch.res_class); - if(ch.res_name) - XFree(ch.res_name); - } - - if(!matched) - c->tags[tsel] = tags[tsel]; -} - void manage(Window w, XWindowAttributes *wa) { @@ -196,7 +148,7 @@ manage(Window w, XWindowAttributes *wa) c->h = wa->height; c->th = bh; c->border = 1; - c->proto = proto(c->win); + c->proto = getproto(c->win); setsize(c); XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | EnterWindowMask); @@ -211,7 +163,7 @@ manage(Window w, XWindowAttributes *wa) CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); settitle(c); - init_tags(c); + settags(c); for(l = &clients; *l; l = &(*l)->next); c->next = *l; /* *l == nil */ @@ -224,8 +176,8 @@ manage(Window w, XWindowAttributes *wa) XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask, GrabModeAsync, GrabModeSync, None, None); - if(!c->floating) - c->floating = trans + if(!c->dofloat) + c->dofloat = trans || ((c->maxw == c->minw) && (c->maxh == c->minh)); arrange(NULL); @@ -321,7 +273,7 @@ resize(Client *c, Bool inc) c->w = c->maxw; if(c->maxh && c->h > c->maxh) c->h = c->maxh; - resize_title(c); + resizetitle(c); XSetWindowBorderWidth(dpy, c->win, 1); XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); e.type = ConfigureNotify; @@ -339,7 +291,7 @@ resize(Client *c, Bool inc) } static int -dummy_xerror(Display *dsply, XErrorEvent *err) +xerrordummy(Display *dsply, XErrorEvent *ee) { return 0; } @@ -350,7 +302,7 @@ unmanage(Client *c) Client **l; XGrabServer(dpy); - XSetErrorHandler(dummy_xerror); + XSetErrorHandler(xerrordummy); XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XDestroyWindow(dpy, c->title); @@ -374,7 +326,7 @@ unmanage(Client *c) } Client * -gettitle(Window w) +getctitle(Window w) { Client *c; for(c = clients; c; c = c->next) @@ -392,3 +344,80 @@ getclient(Window w) return c; return NULL; } + +void +zoom(Arg *arg) +{ + Client **l, *c; + + if(!sel) + return; + + if(sel == getnext(clients) && sel->next) { + if((c = getnext(sel->next))) + sel = c; + } + + for(l = &clients; *l && *l != sel; l = &(*l)->next); + *l = sel->next; + + sel->next = clients; /* pop */ + clients = sel; + arrange(NULL); + focus(sel); +} + +void +maximize(Arg *arg) +{ + if(!sel) + return; + sel->x = sx; + sel->y = sy + bh; + sel->w = sw - 2 * sel->border; + sel->h = sh - 2 * sel->border - bh; + higher(sel); + resize(sel, False); +} + +void +focusprev(Arg *arg) +{ + Client *c; + + if(!sel) + return; + + if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) { + higher(c); + focus(c); + } +} + +void +focusnext(Arg *arg) +{ + Client *c; + + if(!sel) + return; + + if(!(c = getnext(sel->next))) + c = getnext(clients); + if(c) { + higher(c); + c->revert = sel; + focus(c); + } +} + +void +killclient(Arg *arg) +{ + if(!sel) + return; + if(sel->proto & WM_PROTOCOL_DELWIN) + sendevent(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]); + else + XKillClient(dpy, sel->win); +} diff --git a/draw.c b/draw.c @@ -11,33 +11,42 @@ #include "dwm.h" void +drawall() +{ + Client *c; + + for(c = clients; c; c = getnext(c->next)) + drawtitle(c); + drawstatus(); +} + +void drawstatus() { int i; + Bool istile = arrange == dotile; dc.x = dc.y = 0; dc.w = bw; - drawtext(NULL, False, False); + drawtext(NULL, !istile, False); - if(arrange == floating) { - dc.w = textw("~"); - drawtext("~", False, False); - } - else - dc.w = 0; + dc.w = 0; for(i = 0; i < TLast; i++) { dc.x += dc.w; dc.w = textw(tags[i]); - drawtext(tags[i], i == tsel, True); + if(istile) + drawtext(tags[i], (i == tsel), True); + else + drawtext(tags[i], (i != tsel), True); } if(sel) { dc.x += dc.w; dc.w = textw(sel->name); - drawtext(sel->name, True, True); + drawtext(sel->name, istile, True); } dc.w = textw(stext); dc.x = bx + bw - dc.w; - drawtext(stext, False, False); + drawtext(stext, !istile, False); XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0); XFlush(dpy); @@ -47,6 +56,8 @@ void drawtitle(Client *c) { int i; + Bool istile = arrange == dotile; + if(c == sel) { drawstatus(); XUnmapWindow(dpy, c->title); @@ -64,12 +75,12 @@ drawtitle(Client *c) if(c->tags[i]) { dc.x += dc.w; dc.w = textw(c->tags[i]); - drawtext(c->tags[i], False, True); + drawtext(c->tags[i], !istile, True); } } dc.x += dc.w; dc.w = textw(c->name); - drawtext(c->name, False, True); + drawtext(c->name, !istile, True); XCopyArea(dpy, dc.drawable, c->title, dc.gc, 0, 0, c->tw, c->th, 0, 0); XFlush(dpy); @@ -215,7 +226,7 @@ setfont(const char *fontstr) if (!dc.font.xfont) dc.font.xfont = XLoadQueryFont(dpy, "fixed"); if (!dc.font.xfont) - error("error, cannot init 'fixed' font\n"); + eprint("error, cannot init 'fixed' font\n"); dc.font.ascent = dc.font.xfont->ascent; dc.font.descent = dc.font.xfont->descent; } diff --git a/dwm.h b/dwm.h @@ -66,7 +66,7 @@ struct Client { int grav; unsigned int border; long flags; - Bool floating; + Bool dofloat; Window win; Window title; Client *next; @@ -77,7 +77,7 @@ struct Rule { const char *class; const char *instance; char *tags[TLast]; - Bool floating; + Bool dofloat; }; struct Key { @@ -103,6 +103,7 @@ extern DC dc; extern Client *clients, *sel; /* client.c */ +extern void ban(Client *c); extern void manage(Window w, XWindowAttributes *wa); extern void unmanage(Client *c); extern Client *getclient(Window w); @@ -110,14 +111,18 @@ extern void focus(Client *c); extern void settitle(Client *c); extern void resize(Client *c, Bool inc); extern void setsize(Client *c); -extern Client *gettitle(Window w); +extern Client *getctitle(Window w); extern void higher(Client *c); extern void lower(Client *c); extern void gravitate(Client *c, Bool invert); -extern void ban(Client *c); -extern Client *getnext(Client *c); +extern void zoom(Arg *arg); +extern void maximize(Arg *arg); +extern void focusprev(Arg *arg); +extern void focusnext(Arg *arg); +extern void killclient(Arg *arg); /* draw.c */ +extern void drawall(); extern void drawstatus(); extern void drawtitle(Client *c); extern void drawtext(const char *text, Bool invert, Bool border); @@ -127,22 +132,25 @@ extern unsigned int textnw(char *text, unsigned int len); extern unsigned int textw(char *text); extern unsigned int texth(void); -/* key.c */ +/* event.c */ extern void grabkeys(); -extern void keypress(XEvent *e); /* main.c */ -extern int xerror(Display *dsply, XErrorEvent *e); -extern void sendevent(Window w, Atom a, long value); -extern int proto(Window w); extern void quit(Arg *arg); +extern int xerror(Display *dsply, XErrorEvent *ee); +extern void sendevent(Window w, Atom a, long value); +extern int getproto(Window w); -/* screen.c */ -extern void floating(Arg *arg); -extern void tiling(Arg *arg); +/* tag.c */ +extern Client *getnext(Client *c); +extern void settags(Client *c); +extern void dofloat(Arg *arg); +extern void dotile(Arg *arg); extern void view(Arg *arg); +extern void appendtag(Arg *arg); +extern void replacetag(Arg *arg); /* util.c */ -extern void error(const char *errstr, ...); +extern void eprint(const char *errstr, ...); extern void *emallocz(unsigned int size); extern void spawn(Arg *arg); diff --git a/event.c b/event.c @@ -16,6 +16,44 @@ #define ButtonMask (ButtonPressMask | ButtonReleaseMask) #define MouseMask (ButtonMask | PointerMotionMask) +/********** CUSTOMIZE **********/ + +const char *term[] = { + "urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-fn", + "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*",NULL +}; +const char *browse[] = { "firefox", NULL }; +const char *xlock[] = { "xlock", NULL }; + +Key key[] = { + /* modifier key function arguments */ + { Mod1Mask, XK_Return, zoom, { 0 } }, + { Mod1Mask, XK_k, focusprev, { 0 } }, + { Mod1Mask, XK_j, focusnext, { 0 } }, + { Mod1Mask, XK_m, maximize, { 0 } }, + { Mod1Mask, XK_0, view, { .i = Tscratch } }, + { Mod1Mask, XK_1, view, { .i = Tdev } }, + { Mod1Mask, XK_2, view, { .i = Twww } }, + { Mod1Mask, XK_3, view, { .i = Twork } }, + { Mod1Mask, XK_space, dotile, { 0 } }, + { Mod1Mask|ShiftMask, XK_space, dofloat, { 0 } }, + { Mod1Mask|ShiftMask, XK_0, replacetag, { .i = Tscratch } }, + { Mod1Mask|ShiftMask, XK_1, replacetag, { .i = Tdev } }, + { Mod1Mask|ShiftMask, XK_2, replacetag, { .i = Twww } }, + { Mod1Mask|ShiftMask, XK_3, replacetag, { .i = Twork } }, + { Mod1Mask|ShiftMask, XK_c, killclient, { 0 } }, + { Mod1Mask|ShiftMask, XK_q, quit, { 0 } }, + { Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } }, + { Mod1Mask|ShiftMask, XK_w, spawn, { .argv = browse } }, + { Mod1Mask|ShiftMask, XK_l, spawn, { .argv = xlock } }, + { ControlMask, XK_0, appendtag, { .i = Tscratch } }, + { ControlMask, XK_1, appendtag, { .i = Tdev } }, + { ControlMask, XK_2, appendtag, { .i = Twww } }, + { ControlMask, XK_3, appendtag, { .i = Twork } }, +}; + +/********** CUSTOMIZE **********/ + /* local functions */ static void buttonpress(XEvent *e); static void configurerequest(XEvent *e); @@ -23,6 +61,7 @@ static void destroynotify(XEvent *e); static void enternotify(XEvent *e); static void leavenotify(XEvent *e); static void expose(XEvent *e); +static void keypress(XEvent *e); static void maprequest(XEvent *e); static void propertynotify(XEvent *e); static void unmapnotify(XEvent *e); @@ -40,8 +79,40 @@ void (*handler[LASTEvent]) (XEvent *) = { [UnmapNotify] = unmapnotify }; +void +grabkeys() +{ + static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; + unsigned int i; + KeyCode code; + + for(i = 0; i < len; i++) { + code = XKeysymToKeycode(dpy, key[i].keysym); + XUngrabKey(dpy, code, key[i].mod, root); + XGrabKey(dpy, code, key[i].mod, root, True, + GrabModeAsync, GrabModeAsync); + } +} + +static void +keypress(XEvent *e) +{ + XKeyEvent *ev = &e->xkey; + static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; + unsigned int i; + KeySym keysym; + + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for(i = 0; i < len; i++) + if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { + if(key[i].func) + key[i].func(&key[i].arg); + return; + } +} + static void -mresize(Client *c) +resizemouse(Client *c) { XEvent ev; int ocx, ocy; @@ -75,7 +146,7 @@ mresize(Client *c) } static void -mmove(Client *c) +movemouse(Client *c) { XEvent ev; int x1, y1, ocx, ocy, di; @@ -117,7 +188,7 @@ buttonpress(XEvent *e) Client *c; if(barwin == ev->window) { - x = (arrange == floating) ? textw("~") : 0; + x = (arrange == dofloat) ? textw("~") : 0; for(a.i = 0; a.i < TLast; a.i++) { x += textw(tags[a.i]); if(ev->x < x) { @@ -127,20 +198,20 @@ buttonpress(XEvent *e) } } else if((c = getclient(ev->window))) { - if(arrange == tiling && !c->floating) + if(arrange == dotile && !c->dofloat) return; higher(c); switch(ev->button) { default: break; case Button1: - mmove(c); + movemouse(c); break; case Button2: lower(c); break; case Button3: - mresize(c); + resizemouse(c); break; } } @@ -226,7 +297,7 @@ expose(XEvent *e) if(ev->count == 0) { if(barwin == ev->window) drawstatus(); - else if((c = gettitle(ev->window))) + else if((c = getctitle(ev->window))) drawtitle(c); } } @@ -262,14 +333,14 @@ propertynotify(XEvent *e) if((c = getclient(ev->window))) { if(ev->atom == wm_atom[WMProtocols]) { - c->proto = proto(c->win); + c->proto = getproto(c->win); return; } switch (ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(dpy, c->win, &trans); - if(!c->floating && (c->floating = (trans != 0))) + if(!c->dofloat && (c->dofloat = (trans != 0))) arrange(NULL); break; case XA_WM_NORMAL_HINTS: diff --git a/key.c b/key.c @@ -1,192 +0,0 @@ -/* - * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> - -#include "dwm.h" - -static void ckill(Arg *arg); -static void nextc(Arg *arg); -static void prevc(Arg *arg); -static void max(Arg *arg); -static void ttrunc(Arg *arg); -static void tappend(Arg *arg); -static void zoom(Arg *arg); - -/********** CUSTOMIZE **********/ - -const char *term[] = { - "urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-fn", - "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*",NULL -}; -const char *browse[] = { "firefox", NULL }; -const char *xlock[] = { "xlock", NULL }; - -Key key[] = { - /* modifier key function arguments */ - { Mod1Mask, XK_Return, zoom, { 0 } }, - { Mod1Mask, XK_k, prevc, { 0 } }, - { Mod1Mask, XK_j, nextc, { 0 } }, - { Mod1Mask, XK_m, max, { 0 } }, - { Mod1Mask, XK_0, view, { .i = Tscratch } }, - { Mod1Mask, XK_1, view, { .i = Tdev } }, - { Mod1Mask, XK_2, view, { .i = Twww } }, - { Mod1Mask, XK_3, view, { .i = Twork } }, - { Mod1Mask, XK_space, tiling, { 0 } }, - { Mod1Mask|ShiftMask, XK_space, floating, { 0 } }, - { Mod1Mask|ShiftMask, XK_0, ttrunc, { .i = Tscratch } }, - { Mod1Mask|ShiftMask, XK_1, ttrunc, { .i = Tdev } }, - { Mod1Mask|ShiftMask, XK_2, ttrunc, { .i = Twww } }, - { Mod1Mask|ShiftMask, XK_3, ttrunc, { .i = Twork } }, - { Mod1Mask|ShiftMask, XK_c, ckill, { 0 } }, - { Mod1Mask|ShiftMask, XK_q, quit, { 0 } }, - { Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } }, - { Mod1Mask|ShiftMask, XK_w, spawn, { .argv = browse } }, - { Mod1Mask|ShiftMask, XK_l, spawn, { .argv = xlock } }, - { ControlMask, XK_0, tappend, { .i = Tscratch } }, - { ControlMask, XK_1, tappend, { .i = Tdev } }, - { ControlMask, XK_2, tappend, { .i = Twww } }, - { ControlMask, XK_3, tappend, { .i = Twork } }, -}; - -/********** CUSTOMIZE **********/ - -void -grabkeys() -{ - static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; - unsigned int i; - KeyCode code; - - for(i = 0; i < len; i++) { - code = XKeysymToKeycode(dpy, key[i].keysym); - XUngrabKey(dpy, code, key[i].mod, root); - XGrabKey(dpy, code, key[i].mod, root, True, - GrabModeAsync, GrabModeAsync); - } -} - -void -keypress(XEvent *e) -{ - XKeyEvent *ev = &e->xkey; - static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; - unsigned int i; - KeySym keysym; - - keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); - for(i = 0; i < len; i++) - if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { - if(key[i].func) - key[i].func(&key[i].arg); - return; - } -} - -static void -zoom(Arg *arg) -{ - Client **l, *c; - - if(!sel) - return; - - if(sel == getnext(clients) && sel->next) { - if((c = getnext(sel->next))) - sel = c; - } - - for(l = &clients; *l && *l != sel; l = &(*l)->next); - *l = sel->next; - - sel->next = clients; /* pop */ - clients = sel; - arrange(NULL); - focus(sel); -} - -static void -max(Arg *arg) -{ - if(!sel) - return; - sel->x = sx; - sel->y = sy + bh; - sel->w = sw - 2 * sel->border; - sel->h = sh - 2 * sel->border - bh; - higher(sel); - resize(sel, False); -} - -static void -tappend(Arg *arg) -{ - if(!sel) - return; - - sel->tags[arg->i] = tags[arg->i]; - arrange(NULL); -} - -static void -ttrunc(Arg *arg) -{ - int i; - if(!sel) - return; - - for(i = 0; i < TLast; i++) - sel->tags[i] = NULL; - tappend(arg); -} - -static void -prevc(Arg *arg) -{ - Client *c; - - if(!sel) - return; - - if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) { - higher(c); - focus(c); - } -} - -static void -nextc(Arg *arg) -{ - Client *c; - - if(!sel) - return; - - if(!(c = getnext(sel->next))) - c = getnext(clients); - if(c) { - higher(c); - c->revert = sel; - focus(c); - } -} - -static void -ckill(Arg *arg) -{ - if(!sel) - return; - if(sel->proto & WM_PROTOCOL_DELWIN) - sendevent(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]); - else - XKillClient(dpy, sel->win); -} - diff --git a/main.c b/main.c @@ -43,16 +43,16 @@ DC dc = {0}; Client *clients = NULL; Client *sel = NULL; -static Bool other_wm_running; +static Bool otherwm; static const char version[] = "dwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n"; -static int (*x_xerror) (Display *, XErrorEvent *); +static int (*xerrorxlib)(Display *, XErrorEvent *); static void -usage() { error("usage: dwm [-v]\n"); } +usage() { eprint("usage: dwm [-v]\n"); } static void -scan_wins() +scan() { unsigned int i, num; Window *wins; @@ -73,6 +73,22 @@ scan_wins() XFree(wins); } +static void +cleanup() +{ + while(sel) { + resize(sel, True); + unmanage(sel); + } + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +} + +void +quit(Arg *arg) +{ + running = False; +} + static int win_property(Window w, Atom a, Atom t, long l, unsigned char **prop) { @@ -94,7 +110,7 @@ win_property(Window w, Atom a, Atom t, long l, unsigned char **prop) } int -proto(Window w) +getproto(Window w) { unsigned char *protocols; long res; @@ -129,58 +145,42 @@ sendevent(Window w, Atom a, long value) } /* - * There's no way to check accesses to destroyed windows, thus - * those cases are ignored (especially on UnmapNotify's). - * Other types of errors call Xlib's default error handler, which - * calls exit(). - */ -int -xerror(Display *dpy, XErrorEvent *error) -{ - if(error->error_code == BadWindow - || (error->request_code == X_SetInputFocus - && error->error_code == BadMatch) - || (error->request_code == X_PolyText8 - && error->error_code == BadDrawable) - || (error->request_code == X_PolyFillRectangle - && error->error_code == BadDrawable) - || (error->request_code == X_PolySegment - && error->error_code == BadDrawable) - || (error->request_code == X_ConfigureWindow - && error->error_code == BadMatch) - || (error->request_code == X_GrabKey - && error->error_code == BadAccess)) - return 0; - fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", - error->request_code, error->error_code); - return x_xerror(dpy, error); /* may call exit() */ -} - -/* * Startup Error handler to check if another window manager * is already running. */ static int -startup_xerror(Display *dpy, XErrorEvent *error) +xerrorstart(Display *dsply, XErrorEvent *ee) { - other_wm_running = True; + otherwm = True; return -1; } -static void -cleanup() -{ - while(sel) { - resize(sel, True); - unmanage(sel); - } - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); -} - -void -quit(Arg *arg) +/* + * There's no way to check accesses to destroyed windows, thus + * those cases are ignored (especially on UnmapNotify's). + * Other types of errors call Xlib's default error handler, which + * calls exit(). + */ +int +xerror(Display *dpy, XErrorEvent *ee) { - running = False; + if(ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus + && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 + && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle + && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment + && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow + && ee->error_code == BadMatch) + || (ee->request_code == X_GrabKey + && ee->error_code == BadAccess)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit() */ } int @@ -208,23 +208,23 @@ main(int argc, char *argv[]) dpy = XOpenDisplay(0); if(!dpy) - error("dwm: cannot connect X server\n"); + eprint("dwm: cannot connect X server\n"); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); /* check if another WM is already running */ - other_wm_running = False; - XSetErrorHandler(startup_xerror); + otherwm = False; + XSetErrorHandler(xerrorstart); /* this causes an error if some other WM is running */ XSelectInput(dpy, root, SubstructureRedirectMask); XFlush(dpy); - if(other_wm_running) - error("dwm: another window manager is already running\n"); + if(otherwm) + eprint("dwm: another window manager is already running\n"); XSetErrorHandler(0); - x_xerror = XSetErrorHandler(xerror); + xerrorxlib = XSetErrorHandler(xerror); /* init atoms */ wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); @@ -278,7 +278,7 @@ main(int argc, char *argv[]) XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); strcpy(stext, "dwm-"VERSION); - scan_wins(); + scan(); /* main event loop, reads status text from stdin as well */ Mainloop: @@ -292,7 +292,7 @@ Mainloop: if(i == -1 && errno == EINTR) continue; if(i < 0) - error("select failed\n"); + eprint("select failed\n"); else if(i > 0) { if(FD_ISSET(ConnectionNumber(dpy), &rd)) { while(XPending(dpy)) { diff --git a/screen.c b/screen.c @@ -1,100 +0,0 @@ -/* - * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include "dwm.h" - -void (*arrange)(Arg *) = tiling; - -void -view(Arg *arg) -{ - Client *c; - - tsel = arg->i; - arrange(NULL); - - for(c = clients; c; c = getnext(c->next)) - drawtitle(c); - drawstatus(); -} - -void -floating(Arg *arg) -{ - Client *c; - - arrange = floating; - for(c = clients; c; c = c->next) { - if(c->tags[tsel]) - resize(c, True); - else - ban(c); - } - if(sel && !sel->tags[tsel]) { - if((sel = getnext(clients))) { - higher(sel); - focus(sel); - } - } - drawstatus(); -} - -void -tiling(Arg *arg) -{ - Client *c; - int n, i, w, h; - - w = sw - mw; - arrange = tiling; - for(n = 0, c = clients; c; c = c->next) - if(c->tags[tsel] && !c->floating) - n++; - - if(n > 1) - h = (sh - bh) / (n - 1); - else - h = sh - bh; - - for(i = 0, c = clients; c; c = c->next) { - if(c->tags[tsel]) { - if(c->floating) { - higher(c); - resize(c, True); - continue; - } - if(n == 1) { - c->x = sx; - c->y = sy + bh; - c->w = sw - 2 * c->border; - c->h = sh - 2 * c->border - bh; - } - else if(i == 0) { - c->x = sx; - c->y = sy + bh; - c->w = mw - 2 * c->border; - c->h = sh - 2 * c->border - bh; - } - else { - c->x = sx + mw; - c->y = sy + (i - 1) * h + bh; - c->w = w - 2 * c->border; - c->h = h - 2 * c->border; - } - resize(c, False); - i++; - } - else - ban(c); - } - if(!sel || (sel && !sel->tags[tsel])) { - if((sel = getnext(clients))) { - higher(sel); - focus(sel); - } - } - drawstatus(); -} - diff --git a/tag.c b/tag.c @@ -0,0 +1,171 @@ +/* + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> + +#include "dwm.h" + +static Rule rule[] = { + /* class instance tags dofloat */ + { "Firefox-bin", "Gecko", { [Twww] = "www" }, False }, +}; + +void (*arrange)(Arg *) = dotile; + +Client * +getnext(Client *c) +{ + for(; c && !c->tags[tsel]; c = c->next); + return c; +} + +void +settags(Client *c) +{ + XClassHint ch; + static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0; + unsigned int i, j; + Bool matched = False; + + if(!len) { + c->tags[tsel] = tags[tsel]; + return; + } + + if(XGetClassHint(dpy, c->win, &ch)) { + if(ch.res_class && ch.res_name) { + for(i = 0; i < len; i++) + if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class)) + && !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance))) + { + for(j = 0; j < TLast; j++) + c->tags[j] = rule[i].tags[j]; + c->dofloat = rule[i].dofloat; + matched = True; + break; + } + } + if(ch.res_class) + XFree(ch.res_class); + if(ch.res_name) + XFree(ch.res_name); + } + + if(!matched) + c->tags[tsel] = tags[tsel]; +} + +void +view(Arg *arg) +{ + tsel = arg->i; + arrange(NULL); + drawall(); +} + +void +dofloat(Arg *arg) +{ + Client *c; + + arrange = dofloat; + for(c = clients; c; c = c->next) { + if(c->tags[tsel]) + resize(c, True); + else + ban(c); + } + if(sel && !sel->tags[tsel]) { + if((sel = getnext(clients))) { + higher(sel); + focus(sel); + } + } + drawall(); +} + +void +dotile(Arg *arg) +{ + Client *c; + int n, i, w, h; + + w = sw - mw; + arrange = dotile; + for(n = 0, c = clients; c; c = c->next) + if(c->tags[tsel] && !c->dofloat) + n++; + + if(n > 1) + h = (sh - bh) / (n - 1); + else + h = sh - bh; + + for(i = 0, c = clients; c; c = c->next) { + if(c->tags[tsel]) { + if(c->dofloat) { + higher(c); + resize(c, True); + continue; + } + if(n == 1) { + c->x = sx; + c->y = sy + bh; + c->w = sw - 2 * c->border; + c->h = sh - 2 * c->border - bh; + } + else if(i == 0) { + c->x = sx; + c->y = sy + bh; + c->w = mw - 2 * c->border; + c->h = sh - 2 * c->border - bh; + } + else { + c->x = sx + mw; + c->y = sy + (i - 1) * h + bh; + c->w = w - 2 * c->border; + c->h = h - 2 * c->border; + } + resize(c, False); + i++; + } + else + ban(c); + } + if(!sel || (sel && !sel->tags[tsel])) { + if((sel = getnext(clients))) { + higher(sel); + focus(sel); + } + } + drawall(); +} + +void +appendtag(Arg *arg) +{ + if(!sel) + return; + + sel->tags[arg->i] = tags[arg->i]; + arrange(NULL); +} + +void +replacetag(Arg *arg) +{ + int i; + if(!sel) + return; + + for(i = 0; i < TLast; i++) + sel->tags[i] = NULL; + appendtag(arg); +} + diff --git a/util.c b/util.c @@ -13,7 +13,7 @@ #include "dwm.h" void -error(const char *errstr, ...) { +eprint(const char *errstr, ...) { va_list ap; va_start(ap, errstr); vfprintf(stderr, errstr, ap);