Compare commits

...

142 Commits
0.9 ... 1.4

Author SHA1 Message Date
57c49fe867 prepared dwm-1.4 update 2006-09-06 12:18:57 +02:00
c60de1acd4 drawstatus even if no client exists 2006-09-06 12:10:43 +02:00
69b738c097 sanders solution is convincing and elegant 2006-09-06 11:54:16 +02:00
da0b2a2f31 seems to preserve floating client z-layer order (even with reorder() calls) 2006-09-06 11:46:35 +02:00
2378a558a2 Added tag 1.4 for changeset a6b8994af16491220db0199623bd57d061e06143 2006-09-06 10:54:10 +02:00
f18ed615ae small fix 2006-09-06 10:03:21 +02:00
f6656fffb4 made args mode symbols the default ones (the default ones look too ugly) 2006-09-06 09:23:34 +02:00
aaad7bfd15 moved transient_for tag inheritance to settags 2006-09-06 09:21:17 +02:00
0915da8842 no, reodering floating clients definately breaks the manage() policy which attaches all clients zoomed (otherwise higher-weight clients couldn't be attached zoomed, which sucks) 2006-09-06 09:13:31 +02:00
0d0e8bde13 no, ordering floating clients at the end seems better 2006-09-05 19:26:34 +02:00
838a1ff950 fix 2006-09-05 18:43:15 +02:00
e1315fd40c this makes sure the issue mentioned by sander 2006-09-05 18:04:22 +02:00
52a3ab1042 fixing zoom 2006-09-05 17:10:48 +02:00
a82e7b765e fixing two off-by-ones 2006-09-05 16:11:52 +02:00
0ed0fa4d5b ach ich will auch Alt-s 2006-09-05 16:05:09 +02:00
ec85fddb9a applied checking existance of >2 tiles patch (proposed by sander) to zoom and resizecol 2006-09-05 16:00:09 +02:00
3a1343a245 renamed resizetile into resizecol 2006-09-05 13:52:23 +02:00
9066ee2eb4 well ok, added Mod-s to default bindings (however, I don't need it) 2006-09-05 13:27:43 +02:00
40bd21ce63 s/growcol/resizetile/g 2006-09-05 13:25:42 +02:00
4633fbec61 right, multihead issue is not involved with growcol 2006-09-05 13:21:59 +02:00
25060031a5 hotfix 2006-09-05 13:20:29 +02:00
c7ae6334b7 applied a fix related to Sanders remark to growcol 2006-09-05 13:19:18 +02:00
eac04882b4 sanders toggletag patch is much more elegant 2006-09-05 09:37:45 +02:00
6499fc4f93 I really need column growing, now pushing upstream 2006-09-05 09:02:37 +02:00
04f27a5438 don't access sel in restack without checking for NULL (multihead crashing bug) 2006-09-05 08:37:34 +02:00
1b3903d6e9 fixing c->weight handling 2006-09-05 08:24:00 +02:00
cc05093b0d removed some useless tags 2006-09-04 19:19:37 +02:00
6436dd4438 after 1.3 2006-09-04 17:52:46 +02:00
26c50c780e Added tag 1.3 for changeset f5f5cbf016a94b48a8fe9c47f0736e96d166d5d4 2006-09-04 17:52:16 +02:00
01d13b0c49 retagged 2006-09-04 17:52:12 +02:00
f15f45a9f8 simplified manage 2006-09-04 17:39:33 +02:00
1b2e149cb4 removed html crap 2006-09-04 17:37:31 +02:00
6136640ec9 Added tag 1.3 for changeset dd44dc937e8b0a46abf1a15a333dba5304e4fe89 2006-09-04 17:21:18 +02:00
95d8423823 hotfixing with sanders hint 2006-09-04 17:21:15 +02:00
de6411c338 Added tag 1.3 for changeset 6413ea66b1c2496cfc2173fe58df67cb965eb1da 2006-09-04 17:18:01 +02:00
e316cf53f6 fixing the issue that new clients appear lowered 2006-09-04 17:02:13 +02:00
c107db57db removed unused vars 2006-09-04 12:23:41 +02:00
d39d00057c reducing focus calls (sanders patch) 2006-09-04 10:10:08 +02:00
26157e6973 applied Sanders max_and_focus.patch 2006-09-04 08:55:49 +02:00
6d22782e8f simplified buttonpress 2006-09-01 15:31:59 +02:00
1836b6740d applied sanders patch 2006-09-01 10:32:50 +02:00
924a088812 reorder was misssing in Ross version of viewall 2006-08-31 18:08:28 +02:00
bab575c868 changed shortcut into Mod1-0 2006-08-31 18:04:34 +02:00
daae3bba50 added viewall to mainstream (only Ross Mohns version, not the toggle) 2006-08-31 18:02:38 +02:00
05fbbbd8dc implemented Button2 press on tags for toggletag on the focused client 2006-08-31 17:49:04 +02:00
4c368bcd24 applied sanders patch to remove unnecessary commit() 2006-08-31 08:48:04 +02:00
9927b9e642 small fix in config.arg.h 2006-08-30 13:00:30 +02:00
1b492dffc8 Added tag 1.2 for changeset e3179ce2b90451d2807cd53b589d768412b8666b 2006-08-30 12:39:35 +02:00
140be1b4b3 prepared 1.2 2006-08-30 12:39:27 +02:00
79259acc12 now using Salmi's menu command 2006-08-30 11:21:56 +02:00
5a3bea2d69 removed a warning reported by Jukka 2006-08-30 11:15:58 +02:00
30d928591d simplified configurerequest 2006-08-29 19:24:28 +02:00
70a3e62257 now dwm enforces max screen size also in tiled mode on non-floating clients which are maximized 2006-08-29 18:05:02 +02:00
6828fba7a0 fixed 2006-08-29 17:33:27 +02:00
aa1bda8164 configurenotify remembers max geom now, and restores this if necessary, however it accepts to touch the max size on configurerequest, this shouldn't break fillscreen apps (tested with mplayer) 2006-08-29 17:31:55 +02:00
157ea539a2 applied patch similiar proposed by dave tweed 2006-08-29 17:11:37 +02:00
c3c94c0e0a improved selection policy 2006-08-29 15:28:29 +02:00
9d73909075 still something wrong with reorder() 2006-08-29 13:40:09 +02:00
016c54196e this algorithm seems to keep order for any scenario 2006-08-29 09:57:57 +02:00
5056bb952d fix client position in list also on tag and toggletag 2006-08-29 09:25:14 +02:00
8a6679b3b4 added attach/detach functions which don't attach at the begin of list, but at the slot of a first match of the tags of a client 2006-08-29 09:23:44 +02:00
7b6d5ff298 removed crappy variables 2006-08-28 14:32:51 +02:00
846850914d changed config.arg.h - I really need the 4th tag 2006-08-28 12:27:00 +02:00
4e6c513ac2 updated html page 2006-08-28 10:21:40 +02:00
db9cda6a7d Added tag 1.1 for changeset 44a55e6e46bf6c231780b09d919977d6f01083de 2006-08-28 10:19:55 +02:00
a50b15a9e9 added a comment to spawn 2006-08-28 08:17:27 +02:00
0a25fe9188 applied sanders focus_ patches 2006-08-28 08:06:50 +02:00
2dd5212a79 applied sanders somepatches.patch 2006-08-28 08:02:29 +02:00
00e95e1f38 oh frking dear big font... 2006-08-25 18:14:55 +02:00
0a0759132c term enlightened 2006-08-25 18:05:18 +02:00
5cf362c7d0 switching to darker colorscheme with larger font 2006-08-25 18:03:56 +02:00
413be1112a patched arg.h 2006-08-25 17:42:58 +02:00
8233dc8568 new stuff 2006-08-25 17:34:03 +02:00
afa8b3bcd9 switching to dark colors again 2006-08-25 17:31:57 +02:00
c518345f40 updated man page of dwm 2006-08-25 16:21:45 +02:00
afe6ac9923 changed order of options 2006-08-25 16:15:13 +02:00
e995c1b532 trying a different configuration 2006-08-25 15:48:44 +02:00
e36929292e removed small 1px gap, somehow without it things feel better 2006-08-25 15:37:00 +02:00
03128f78df oops 2006-08-25 15:24:18 +02:00
7d4a5e654c fixed typo 2006-08-25 15:21:49 +02:00
41ba7a7984 s/TILED/TILE/g 2006-08-25 15:16:20 +02:00
aa471f2d65 removed a bunch of lines, made mode symbols configurable 2006-08-25 15:12:32 +02:00
d37dfa1bed changed symbols for float/tiled mode, added mouse-driven mode toggle to buttonpress() 2006-08-25 15:06:38 +02:00
9f35cc52fe small fix to separate client title from right-most tag 2006-08-25 14:46:01 +02:00
f1fe19bc2b restored config.arg.h 2006-08-25 13:02:07 +02:00
b55bd709ee new color stuff/new rendering stuff 2006-08-25 12:59:45 +02:00
9833610356 back to 3 colors 2006-08-25 07:54:49 +02:00
de7fc0011e fixed 2006-08-24 12:07:10 +02:00
2e0c767d74 3->4 colors 2006-08-24 12:04:56 +02:00
a5379e901c Added tag 1.0 for changeset bbc98e77ae89a7c9232a5be0835f60ea00d8036e 2006-08-24 10:28:50 +02:00
a039d51d5f prepared dwm-1.0 2006-08-24 10:25:05 +02:00
60b3dceccf yet another fix 2006-08-24 10:20:00 +02:00
c2ac851b90 small man page fix 2006-08-24 10:18:42 +02:00
c976bc6c2c found less intrusive way 2006-08-24 09:41:41 +02:00
2e834e941f changing tag indicator through underline 2006-08-24 09:25:10 +02:00
77e5f3167c black on light is really better, I notice this after all 2006-08-23 19:05:03 +02:00
7e597ae204 updated man page 2006-08-23 18:50:46 +02:00
c39df91ab9 applied tag drawing change to man page 2006-08-23 14:40:44 +02:00
af1158d105 implemented right tag drawing in the status bar and titlebars 2006-08-23 14:38:25 +02:00
b739721d9e removed a blank line 2006-08-23 13:04:43 +02:00
7711ab6707 eliminated sentinel warning 2006-08-23 12:28:39 +02:00
d370c32f69 small fix of man page 2006-08-23 12:10:55 +02:00
d6a6eca71d implemented class:inst:title matching 2006-08-23 12:08:37 +02:00
39ffc18635 applied zero_to_five patch 2006-08-23 12:03:25 +02:00
3e972ec84d tags appear in the left again 2006-08-23 11:33:50 +02:00
b5159dfd2f separated setup stuff into main.c:setup() - this makes main() more readable 2006-08-23 10:21:57 +02:00
07c2659806 updated man page 2006-08-22 19:56:29 +02:00
dc83b9e988 titlebars contain tags in the right now 2006-08-22 19:55:20 +02:00
8b4bc8270a fixed default key bindings (indexes of tags were screwed up) 2006-08-22 18:08:25 +02:00
0ff80653d3 rearranged getproto 2006-08-22 17:40:21 +02:00
352e1b4c81 removed winprop (merged into getproto) 2006-08-22 17:38:59 +02:00
aa13727067 separated several functions into view.c 2006-08-22 16:50:21 +02:00
595028614b removed DEFTAG 2006-08-22 16:42:29 +02:00
6a3ae5e26a removed badmalloc (thx for the pointer to Uriel) 2006-08-22 16:06:11 +02:00
8c334ee078 rxvt is quite slow under OpenBSD 2006-08-22 10:06:11 +02:00
f60fe2a4f9 font fix 2006-08-22 10:01:32 +02:00
b112257bf2 slight change of my config.h 2006-08-22 09:57:32 +02:00
eb88adcd8a fixed 2006-08-22 09:49:48 +02:00
950a1ab5af windows which have set transient_for hint inherit the transient_for window tags now 2006-08-21 17:35:37 +02:00
1b9fe55025 after switching to OpenBSD again, I switched back to a saner color scheme 2006-08-21 17:41:09 +02:00
2272df9d31 applied Sanders focus_* patches, removed the unnecessary clean-prefix from the new function names 2006-08-21 09:03:14 +02:00
08d85d6d66 small renamings of two static functions 2006-08-21 07:33:18 +02:00
b43989207a small changes to dwm.1, rearranged order within main event loop 2006-08-21 07:31:15 +02:00
2eebebf262 applied Sanders patch 2006-08-18 13:40:34 +02:00
8c1fffe106 made a new client position strategy similiar to that one proposed by Sander, but which takes top bar into account 2006-08-18 08:39:33 +02:00
5e9acbc952 fixed a bug reported by sander 2006-08-17 10:06:36 +02:00
a420ceab50 applied the shorter xprop command 2006-08-17 09:44:17 +02:00
0e1c649dca centering apps only if transient_for is not(!) set 2006-08-17 09:37:43 +02:00
67c2124fa9 fixed issue Sander reported 2006-08-17 09:35:44 +02:00
a635743c6d corrected order of cleanup code 2006-08-16 19:25:29 +02:00
b5c2412d84 condition was insufficient 2006-08-16 17:58:18 +02:00
ad2e77d635 fixed issue reported by sander 2006-08-16 17:56:04 +02:00
a20b10d01f added general centralization rule for new clients (works around various borken apps) 2006-08-16 15:57:36 +02:00
4cc0551948 removed leading ; 2006-08-16 15:31:24 +02:00
56130c3689 added sample command to config.default.h to highlight how to query class:instance info with a one-liner of shell commands 2006-08-16 15:00:14 +02:00
14f7380308 applied another config.mk patch made by sander 2006-08-16 12:36:32 +02:00
727449d1e7 we close stdin as well 2006-08-16 09:31:41 +02:00
80bf2aa559 simplified sort | uniq into sort -u (on my boxes all sort support -u) 2006-08-16 09:05:58 +02:00
b9cd0c4331 fixing small bug in config.mk 2006-08-15 16:54:54 +02:00
f77a87137c adding forgetten whitespace 2006-08-15 10:45:14 +02:00
65dfe8fdce added gmane archive to dwm.html 2006-08-15 10:44:15 +02:00
e3bb595d77 Added tag 0.9 for changeset fae61afa861755636c4a1070694209ace8efbb6c 2006-08-15 10:25:30 +02:00
17 changed files with 817 additions and 800 deletions

View File

@ -6,3 +6,8 @@ eb3165734f00fe7f7da8aeebaed00e60a57caac9 0.4
c11f86db4550cac5d0a648a3fe4d6d3b9a4fcf7e 0.6
3fb41412e2492f66476d92ce8f007a8b48fb1d2a 0.7
cd15de32e173f8ce97bfe1c9b6607937b59056b4 0.8
fae61afa861755636c4a1070694209ace8efbb6c 0.9
bbc98e77ae89a7c9232a5be0835f60ea00d8036e 1.0
44a55e6e46bf6c231780b09d919977d6f01083de 1.1
e3179ce2b90451d2807cd53b589d768412b8666b 1.2
f5f5cbf016a94b48a8fe9c47f0736e96d166d5d4 1.3

View File

@ -3,7 +3,7 @@
include config.mk
SRC = client.c draw.c event.c main.c tag.c util.c
SRC = client.c draw.c event.c main.c tag.c util.c view.c
OBJ = ${SRC:.c=.o}
all: options dwm

2
README
View File

@ -1,6 +1,6 @@
dwm - dynamic window manager
----------------------------
dwm is an extremely fast, small, and dynamic X11 window manager.
dwm is an extremely fast, small, and dynamic window manager for X.
Requirements

235
client.c
View File

@ -10,24 +10,57 @@
/* static functions */
static void
grabbuttons(Client *c, Bool focus)
{
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
if(focus) {
XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
}
else
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
}
static void
resizetitle(Client *c)
{
int i;
c->tw = 0;
for(i = 0; i < ntags; i++)
if(c->tags[i])
c->tw += textw(tags[i]);
c->tw += textw(c->name);
c->tw = textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 2;
c->ty = c->y;
if(isvisible(c))
XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->title, c->tx + 2 * sw, c->ty, c->tw, c->th);
XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
@ -43,57 +76,35 @@ void
ban(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
}
void
focus(Client *c)
{
Client *old = sel;
Client *old;
if (!issel)
if(!issel)
return;
if(sel && sel->ismax)
togglemax(NULL);
sel = c;
if(old && old != c)
drawtitle(old);
drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
}
void
focusnext(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
focus(c);
restack();
}
}
void
focusprev(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
sel = c;
else if(sel != c) {
if(maximized)
togglemax(NULL);
old = sel;
sel = c;
if(old) {
grabbuttons(old, False);
drawtitle(old);
}
}
if(c) {
focus(c);
restack();
grabbuttons(c, True);
drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
}
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}
Client *
@ -113,7 +124,7 @@ getctitle(Window w)
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
if(c->twin == w)
return c;
return NULL;
}
@ -187,6 +198,7 @@ killclient(Arg *arg)
void
manage(Window w, XWindowAttributes *wa)
{
unsigned int i;
Client *c;
Window trans;
XSetWindowAttributes twa;
@ -203,8 +215,14 @@ manage(Window w, XWindowAttributes *wa)
c->border = 0;
setsize(c);
if(c->x + c->w + 2 > sw)
c->x = sw - c->w - 2;
if(c->x < 0)
c->x = 0;
if(c->y + c->h + 2 > sh)
c->y = sh - c->h - 2;
if(c->h != sh && c->y < bh)
c->y = c->ty = bh;
c->y = bh;
c->proto = getproto(c->win);
XSelectInput(dpy, c->win,
@ -214,57 +232,30 @@ manage(Window w, XWindowAttributes *wa)
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask | EnterWindowMask;
c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
grabbuttons(c, False);
settags(c, getclient(trans));
if(!c->isfloat)
c->isfloat = trans
|| (c->maxw && c->minw &&
c->maxw == c->minw && c->maxh == c->minh);
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
settags(c);
if(!c->isfloat)
c->isfloat = trans
|| (c->maxw && c->minw &&
c->maxw == c->minw && c->maxh == c->minh);
settitle(c);
if(isvisible(c))
sel = c;
arrange(NULL);
ban(c);
XMapWindow(dpy, c->win);
XMapWindow(dpy, c->title);
XMapWindow(dpy, c->twin);
if(isvisible(c))
focus(c);
arrange(NULL);
}
void
@ -272,7 +263,6 @@ resize(Client *c, Bool sizehints, Corner sticky)
{
int bottom = c->y + c->h;
int right = c->x + c->w;
/*XConfigureEvent e;*/
XWindowChanges wc;
if(sizehints) {
@ -289,10 +279,6 @@ resize(Client *c, Bool sizehints, Corner sticky)
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
}
if(c->x > right) /* might happen on restart */
c->x = right - c->w;
if(c->y > bottom)
c->y = bottom - c->h;
if(sticky == TopRight || sticky == BotRight)
c->x = right - c->w;
if(sticky == BotLeft || sticky == BotRight)
@ -382,12 +368,13 @@ void
togglemax(Arg *arg)
{
int ox, oy, ow, oh;
Client *c;
XEvent ev;
if(!sel)
return;
if((sel->ismax = !sel->ismax)) {
if((maximized = !maximized)) {
ox = sel->x;
oy = sel->y;
ow = sel->w;
@ -398,6 +385,9 @@ togglemax(Arg *arg)
sel->h = sh - 2 - bh;
restack();
for(c = getnext(clients); c; c = getnext(c->next))
if(c != sel)
ban(c);
resize(sel, arrange == dofloat, TopLeft);
sel->x = ox;
@ -406,61 +396,36 @@ togglemax(Arg *arg)
sel->h = oh;
}
else
resize(sel, False, TopLeft);
arrange(NULL);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
unmanage(Client *c)
{
Client *tc, *fc;
Window trans;
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title);
detach(c);
if(sel == c) {
XGetTransientForHint(dpy, c->win, &trans);
if(trans && (tc = getclient(trans)) && isvisible(tc))
fc = tc;
else
fc = getnext(clients);
focus(fc);
}
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->twin);
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
if(sel == c)
sel = getnext(clients);
free(c->tags);
free(c);
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
if(sel)
focus(sel);
arrange(NULL);
}
void
zoom(Arg *arg)
{
Client *c;
if(!sel || (arrange != dotile) || sel->isfloat || sel->ismax)
return;
if(sel == getnext(clients)) {
if((c = getnext(sel->next)))
sel = c;
else
return;
}
/* pop */
sel->prev->next = sel->next;
if(sel->next)
sel->next->prev = sel->prev;
sel->prev = NULL;
clients->prev = sel;
sel->next = clients;
clients = sel;
focus(sel);
arrange(NULL);
}

View File

@ -4,14 +4,20 @@
*/
#define TAGS \
const char *tags[] = { "work", "net", "fnord", NULL };
const char *tags[] = { "dev", "work", "net", "fnord", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 0 /* index */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-*-*-*-12-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0d121d"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#3f484d"
#define SELBGCOLOR "#333366"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333333"
#define NORMFGCOLOR "#dddddd"
#define STATUSBGCOLOR "#222222"
#define STATUSFGCOLOR "#9999cc"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
@ -19,34 +25,42 @@ const char *tags[] = { "work", "net", "fnord", NULL };
static Key key[] = { \
/* modifier key function arguments */ \
{ MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec urxvt +sb -tr -bg black -fg '#eeeeee' -fn '"FONT"'" } }, \
{ .cmd = "exec uxterm -bg '#111111' -fg '#eeeeee' -cr '#eeeeee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \
{ .cmd = "exec `ls -lL /usr/bin /usr/local/bin 2>/dev/null | " \
"awk 'NF>2 && $1 ~ /^[^d].*x/ {print $NF}' | sort | uniq | dmenu`" } }, \
{ .cmd = "exe=\"$(IFS=:; for dir in $PATH; do " \
"for file in \"$dir\"/*; do [ -x \"$file\" ] && echo \"${file##*/}\"; done; " \
"done | sort -u | dmenu)\" && exec \"$exe\"" } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY, XK_0, viewall, { 0 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
{ MODKEY, XK_3, view, { .i = 2 } }, \
{ MODKEY, XK_4, view, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
};
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
/* class:instance:title regex tags regex isfloat */ \
{ "Firefox.*", "net", False }, \
{ "Gimp.*", NULL, True}, \
{ "MPlayer.*", NULL, True}, \

View File

@ -4,14 +4,20 @@
*/
#define TAGS \
const char *tags[] = { "0", "1", "2", "3", "4", NULL };
const char *tags[] = { "1", "2", "3", "4", "5", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 1 /* index */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "fixed"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333366"
#define NORMFGCOLOR "#cccccc"
#define STATUSBGCOLOR "#dddddd"
#define STATUSFGCOLOR "#222222"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
@ -23,34 +29,39 @@ static Key key[] = { \
{ MODKEY|ShiftMask, XK_Tab, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY|ShiftMask, XK_0, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_4, tag, { .i = 4 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_0, toggletag, { .i = 0 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 1 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 2 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 3 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 4 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_5, tag, { .i = 4 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_5, toggletag, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY, XK_0, view, { .i = 0 } }, \
{ MODKEY, XK_1, view, { .i = 1 } }, \
{ MODKEY, XK_2, view, { .i = 2 } }, \
{ MODKEY, XK_3, view, { .i = 3 } }, \
{ MODKEY, XK_4, view, { .i = 4 } }, \
{ MODKEY|ControlMask, XK_0, toggleview, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_4, toggleview, { .i = 4 } }, \
{ MODKEY, XK_0, viewall, { 0 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
{ MODKEY, XK_3, view, { .i = 2 } }, \
{ MODKEY, XK_4, view, { .i = 3 } }, \
{ MODKEY, XK_5, view, { .i = 4 } }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
};
/* Query class:instance:title for regex matching info with following command:
* xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
/* class:instance:title regex tags regex isfloat */ \
{ "Firefox.*", "2", False }, \
{ "Gimp.*", NULL, True}, \
};

View File

@ -1,5 +1,5 @@
# dwm version
VERSION = 0.9
VERSION = 1.4
# Customize below to fit your system
@ -11,7 +11,7 @@ X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# includes and libs
INCS = -I/usr/lib -I${X11INC}
INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
# flags

95
draw.c
View File

@ -22,30 +22,16 @@ textnw(const char *text, unsigned int len)
}
static void
drawtext(const char *text, Bool invert)
drawtext(const char *text, unsigned long col[ColLast], Bool highlight)
{
int x, y, w, h;
static char buf[256];
unsigned int len, olen;
XGCValues gcv;
XPoint points[5];
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
XSetForeground(dpy, dc.gc, invert ? dc.fg : dc.bg);
XSetForeground(dpy, dc.gc, col[ColBG]);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
XSetForeground(dpy, dc.gc, dc.border);
points[0].x = dc.x;
points[0].y = dc.y;
points[1].x = dc.w - 1;
points[1].y = 0;
points[2].x = 0;
points[2].y = dc.h - 1;
points[3].x = -(dc.w - 1);
points[3].y = 0;
points[4].x = 0;
points[4].y = -(dc.h - 1);
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious);
if(!text)
return;
@ -75,18 +61,21 @@ drawtext(const char *text, Bool invert)
if(w > dc.w)
return; /* too long */
gcv.foreground = invert ? dc.bg : dc.fg;
gcv.background = invert ? dc.fg : dc.bg;
gcv.foreground = col[ColFG];
if(dc.font.set) {
XChangeGC(dpy, dc.gc, GCForeground | GCBackground, &gcv);
XmbDrawImageString(dpy, dc.drawable, dc.font.set, dc.gc,
x, y, buf, len);
XChangeGC(dpy, dc.gc, GCForeground, &gcv);
XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
}
else {
gcv.font = dc.font.xfont->fid;
XChangeGC(dpy, dc.gc, GCForeground | GCBackground | GCFont, &gcv);
XDrawImageString(dpy, dc.drawable, dc.gc, x, y, buf, len);
XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}
if(highlight) {
r.x = dc.x + 2;
r.y = dc.y + 2;
r.width = r.height = 3;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
@ -106,28 +95,36 @@ void
drawstatus()
{
int i, x;
Bool istile = arrange == dotile;
dc.x = dc.y = 0;
dc.w = bw;
drawtext(NULL, !istile);
dc.w = 0;
for(i = 0; i < ntags; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]);
if(istile)
drawtext(tags[i], seltag[i]);
if(seltag[i])
drawtext(tags[i], dc.sel, sel && sel->tags[i]);
else
drawtext(tags[i], !seltag[i]);
drawtext(tags[i], dc.norm, sel && sel->tags[i]);
dc.x += dc.w;
}
dc.w = bmw;
drawtext(arrange == dotile ? TILESYMBOL : FLOATSYMBOL, dc.status, False);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = bx + bw - dc.w;
drawtext(stext, !istile);
if(sel && ((dc.w = dc.x - x) >= bh)) {
if(dc.x < x) {
dc.x = x;
drawtext(sel->name, istile);
dc.w = bw - x;
}
drawtext(stext, dc.status, False);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
if(sel)
drawtext(sel->name, dc.sel, False);
else
drawtext(NULL, dc.norm, False);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XSync(dpy, False);
@ -136,33 +133,19 @@ drawstatus()
void
drawtitle(Client *c)
{
int i;
Bool istile = arrange == dotile;
if(c == sel && issel) {
drawstatus();
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
XUnmapWindow(dpy, c->twin);
XSetWindowBorder(dpy, c->win, dc.sel[ColBG]);
return;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.norm[ColBG]);
XMapWindow(dpy, c->twin);
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < ntags; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(tags[i]);
drawtext(tags[i], !istile);
}
}
dc.x += dc.w;
dc.w = c->tw - dc.x;
drawtext(c->name, !istile);
XCopyArea(dpy, dc.drawable, c->title, dc.gc, 0, 0, c->tw, c->th, 0, 0);
dc.w = c->tw;
drawtext(c->name, dc.norm, False);
XCopyArea(dpy, dc.drawable, c->twin, dc.gc, 0, 0, c->tw, c->th, 0, 0);
XSync(dpy, False);
}

59
dwm.1
View File

@ -6,7 +6,7 @@ dwm \- dynamic window manager
.RB [ \-v ]
.SH DESCRIPTION
.B dwm
is a dynamic window manager for X11. It manages windows in tiling and floating
is a dynamic window manager for X. It manages windows in tiling and floating
modes. Either mode can be applied dynamically, optimizing the environment for
the application in use and the task performed.
.P
@ -21,11 +21,13 @@ tags. Selecting a certain tag for viewing will display all windows with that
tag.
.P
.B dwm
has a small status bar which displays the text read from standard
input, if written. Besides that, it displays all available tags, and the title
of the focused window. It draws a 1-pixel border around windows to
indicate the focus state. Unfocused windows contain a small bar in front of
them displaying their tags and title.
contains a small status bar which displays all available tags, the mode, the
title of the focused window, and the text read from standard input. The tags of
the focused window are highlighted with a small point.
.P
.B dwm
draws a 1-pixel border around windows to indicate the focus state.
Unfocused windows contain a small bar in front of them displaying their title.
.SH OPTIONS
.TP
.B \-v
@ -38,12 +40,29 @@ is read and displayed in the status text area.
.TP
.B Button1
click on a tag label views all windows with that
.BR tag .
.BR tag ,
click on the mode label toggles between
.B tiled
and
.B floating
mode.
.TP
.B Button3
click on a tag label adds/removes all windows with that
.B tag
to/from the view.
.TP
.B Mod1-Button1
click on a tag label applies that
.B tag
to the focused
.BR window .
.TP
.B Mod1-Button3
click on a tag label adds/removes that
.B tag
to/from the focused
.BR window .
.SS Keyboard commands
.TP
.B Mod1-Shift-Return
@ -71,13 +90,25 @@ mode only).
Maximize current
.BR window .
.TP
.B Mod1-Shift-[0..n]
.B Mod1-g
Grow current
.BR column
.RB ( tiling
mode only).
.TP
.B Mod1-s
Shrink current
.BR column
.RB ( tiling
mode only).
.TP
.B Mod1-Shift-[1..n]
Apply
.B nth tag
to current
.BR window .
.TP
.B Mod1-Control-Shift-[0..n]
.B Mod1-Control-Shift-[1..n]
Add/remove
.B nth tag
to/from current
@ -95,11 +126,15 @@ and
mode (affects
.BR "all windows" ).
.TP
.B Mod1-[0..n]
.B Mod1-[1..n]
View all windows with
.BR "tag n" .
.TP
.B Mod1-Control-[0..n]
.B Mod1-0
View all windows with any
.BR "tag" .
.TP
.B Mod1-Control-[1..n]
Add/remove all windows with
.B tag n
to/from the view.
@ -136,7 +171,7 @@ mode only).
is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.
.SH CAVEATS
The status bar displays
The status bar may display
.B broken pipe
when
.B dwm

65
dwm.h
View File

@ -11,15 +11,10 @@
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define PROTODELWIN 1
typedef union Arg Arg;
typedef struct Client Client;
typedef struct DC DC;
typedef struct Fnt Fnt;
union Arg {
typedef union {
const char *cmd;
int i;
};
} Arg;
/* atoms */
enum { NetSupported, NetWMName, NetLast };
@ -28,27 +23,31 @@ enum { WMProtocols, WMDelete, WMLast };
/* cursor */
enum { CurNormal, CurResize, CurMove, CurLast };
/* windowcorners */
/* color */
enum { ColFG, ColBG, ColLast };
/* window corners */
typedef enum { TopLeft, TopRight, BotLeft, BotRight } Corner;
struct Fnt {
typedef struct {
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
};
} Fnt;
struct DC { /* draw context */
typedef struct { /* draw context */
int x, y, w, h;
unsigned long bg;
unsigned long fg;
unsigned long border;
unsigned long norm[ColLast];
unsigned long sel[ColLast];
unsigned long status[ColLast];
Drawable drawable;
Fnt font;
GC gc;
};
} DC;
typedef struct Client Client;
struct Client {
char name[256];
int proto;
@ -57,24 +56,23 @@ struct Client {
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
long flags;
unsigned int border;
unsigned int border, weight;
Bool isfloat;
Bool ismax;
Bool *tags;
Client *next;
Client *prev;
Window win;
Window title;
Window twin;
};
extern const char *tags[];
extern char stext[1024];
extern int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
extern unsigned int ntags, numlockmask;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, *seltag;
extern Bool running, issel, maximized, *seltag;
extern Client *clients, *sel;
extern Cursor cursor[CurLast];
extern DC dc;
@ -84,8 +82,6 @@ extern Window root, barwin;
/* client.c */
extern void ban(Client *c);
extern void focus(Client *c);
extern void focusnext(Arg *arg);
extern void focusprev(Arg *arg);
extern Client *getclient(Window w);
extern Client *getctitle(Window w);
extern void gravitate(Client *c, Bool invert);
@ -96,7 +92,6 @@ extern void setsize(Client *c);
extern void settitle(Client *c);
extern void togglemax(Arg *arg);
extern void unmanage(Client *c);
extern void zoom(Arg *arg);
/* draw.c */
extern void drawall();
@ -117,22 +112,30 @@ extern void sendevent(Window w, Atom a, long value);
extern int xerror(Display *dsply, XErrorEvent *ee);
/* tag.c */
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern void initrregs();
extern Bool isvisible(Client *c);
extern Client *getnext(Client *c);
extern Client *getprev(Client *c);
extern void restack();
extern void settags(Client *c);
extern void settags(Client *c, Client *trans);
extern void tag(Arg *arg);
extern void togglemode(Arg *arg);
extern void toggletag(Arg *arg);
extern void toggleview(Arg *arg);
extern void view(Arg *arg);
/* util.c */
extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void *erealloc(void *ptr, unsigned int size);
extern void spawn(Arg *arg);
/* view.c */
extern void detach(Client *c);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern void focusnext(Arg *arg);
extern void focusprev(Arg *arg);
extern Bool isvisible(Client *c);
extern void resizecol(Arg *arg);
extern void restack();
extern void togglemode(Arg *arg);
extern void toggleview(Arg *arg);
extern void view(Arg *arg);
extern void viewall(Arg *arg);
extern void zoom(Arg *arg);

127
dwm.html
View File

@ -1,127 +0,0 @@
<html>
<head>
<title>dwm - dynamic window manager</title>
<meta name="author" content="Anselm R. Garbe">
<meta name="generator" content="ed">
<meta name="copyright" content="(C)opyright 2006 by Anselm R. Garbe">
<link rel="dwm icon" href="favicon.ico" type="image/x-icon" />
<style type="text/css">
body {
color: #000000;
font-family: sans-serif;
margin: 20px 20px 20px 20px;
}
</style>
</head>
<body>
<center>
<img src="dwm.png"/><br />
<h3>dynamic window manager</h3>
</center>
<h3>Description</h3>
<p>
dwm is a dynamic window manager for X11.
</p>
<h4>Background</h4>
<p>
As founder and main developer of wmii I came to the conclusion that
wmii is too clunky for my needs. I don't need so many funky features
and all this hype about remote control through a 9P service, I only
want to manage my windows in a simple, but dynamic way. wmii never got
finished because I listened to users, who proposed arbitrary ideas I
considered useful. This resulted in an extreme <a
href="http://www.jwz.org/doc/cadt.html">CADT</a> development model,
which was a mistake. Thus the philosophy of dwm is simply <i>to fit my
needs</i> (maybe yours as well). That's it.
</p>
<h4>Differences to ion, larswm, and wmii</h4>
<p>
In contrast to ion, larswm, and wmii, dwm is much smaller, faster and simpler.
</p>
<ul>
<li>
dwm has no Lua integration, no 9P support, no editable
tagbars, no shell-based configuration, no remote control, and comes
without any additional tools like printing the selection or warping
the mouse.
</li>
<li>
dwm is only a single binary, it's source code is intended to never
exceed 2000 SLOC.
</li>
<li>
dwm is based on tagging and dynamic window management (however
simpler than ion, wmii or larswm). It manages windows in
tiling and floating modes. Either mode can be applied dynamically,
depending on the application in use and the task performed.
</li>
<li>
dwm doesn't distinguishes between layers, there is no floating or
tiled layer. Wether the clients of currently selected tag are in
tiled mode or not, you can re-arrange all clients on the fly.
Popup- and fixed-size windows are treated floating, however.
</li>
<li>
dwm is customized through editing its source code, that makes it
extremely fast and secure - it does not process any input data
which hasn't been known at compile time, except window title names
and status text read from standard input. You don't have to learn
Lua/sh/ruby or some weird configuration file format (like X
resource files), beside C to customize it for your needs,
you <b>only</b> have to learn C (at least editing header files).
</li>
<li>
Because dwm is customized through editing its source code, it's
pointless to make binary packages of it. This keeps its userbase
small and elitist. No novices asking stupid questions.
</li>
<li>
dwm uses 1-pixel borders to provide the maximum of screen real
estate to clients. Small titlebars are only drawn in front of
unfocused clients.
</li>
<li>
dwm reads from standard input to print arbitrary status text (like
the date, load, battery charge). That's much simpler than
larsremote, wmiir and what not...
</li>
<li>
It can be downloaded and distributed under the conditions
of the <a href="http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
</li>
<li>
Optionally you can install <b>dmenu</b> to extend dwm with a wmii-alike menu.
</li>
</ul>
<h4>Links</h4>
<ul>
<li><a href="http://10kloc.org/cgi-bin/man/man2html?query=dwm">Man page</a></li>
<li><a href="http://10kloc.org/shots/dwm-20060810a.png">Screenshot of tiled mode</a> (20060810)</li>
<li><a href="http://10kloc.org/shots/dwm-20060810b.png">Screenshotof floating mode</a> (20060810)</li>
<li><a href="http://10kloc.org/download/poster.ps">A4 poster (PostScript)</a></li>
<li>Mailing List: <a href="http://10kloc.org/cgi-bin/mailman/listinfo/dwm">dwm at wmii dot de</a> <a href="http://10kloc.org/pipermail/dwm/">(Archives)</a></li>
<li>IRC channel: <code>#dwm</code> at <code>irc.oftc.net</code></li>
</ul>
<h3>Download</h3>
<ul>
<li><a href="http://10kloc.org/download/dwm-0.9.tar.gz">dwm 0.9</a> (15kb) (20060815)</li>
<li><a href="http://10kloc.org/download/dmenu-0.4.tar.gz">dmenu 0.4</a> (7kb) (20060815)</li>
</ul>
<h3>Development</h3>
<p>
dwm is actively developed in parallel to wmii. You can <a href="http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm">browse</a> its source code repository or get a copy using <a href="http://www.selenic.com/mercurial/">Mercurial</a> with following command:
</p>
<p>
<code>hg clone http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm</code>
</p>
<p>
<code>hg clone http://10kloc.org/cgi-bin/hgwebdir.cgi/dmenu</code>
</p>
<h3>Miscellaneous</h3>
<p>
You can purchase this <a href="https://www.spreadshirt.net/shop.php?op=article&article_id=3298632&view=403">tricot</a>
if you like dwm and the dwm logo, which has been designed by Anselm.
</p>
<p><small>--Anselm</small></p>
</body>
</html>

87
event.c
View File

@ -109,48 +109,75 @@ buttonpress(XEvent *e)
for(a.i = 0; a.i < ntags; a.i++) {
x += textw(tags[a.i]);
if(ev->x < x) {
if(ev->button == Button1)
view(&a);
else if(ev->button == Button3)
toggleview(&a);
if(ev->button == Button1) {
if(ev->state & MODKEY)
tag(&a);
else
view(&a);
}
else if(ev->button == Button3) {
if(ev->state & MODKEY)
toggletag(&a);
else
toggleview(&a);
}
return;
}
}
if(ev->x < x + bmw) {
if(ev->button == Button1)
togglemode(NULL);
}
}
else if((c = getclient(ev->window))) {
focus(c);
switch(ev->button) {
default:
break;
case Button1:
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
restack(c);
movemouse(c);
}
break;
case Button2:
if(maximized || CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
restack(c);
movemouse(c);
}
else if(ev->button == Button2)
zoom(NULL);
break;
case Button3:
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
restack(c);
resizemouse(c);
}
break;
else if(ev->button == Button3 && (arrange == dofloat || c->isfloat)) {
restack(c);
resizemouse(c);
}
}
}
static void
synconfig(Client *c, int x, int y, int w, int h, unsigned int border)
{
XEvent synev;
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = x;
synev.xconfigure.y = y;
synev.xconfigure.width = w;
synev.xconfigure.height = h;
synev.xconfigure.border_width = border;
synev.xconfigure.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
static void
configurerequest(XEvent *e)
{
unsigned long newmask;
Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XEvent synev;
XWindowChanges wc;
if((c = getclient(ev->window))) {
if((c == sel) && !c->isfloat && (arrange != dofloat) && maximized) {
synconfig(c, sx, sy + bh, sw - 2, sh - 2 - bh, ev->border_width);
XSync(dpy, False);
return;
}
gravitate(c, True);
if(ev->value_mask & CWX)
c->x = ev->x;
@ -170,20 +197,8 @@ configurerequest(XEvent *e)
newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
if(newmask)
XConfigureWindow(dpy, c->win, newmask, &wc);
else {
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = c->x;
synev.xconfigure.y = c->y;
synev.xconfigure.width = c->w;
synev.xconfigure.height = c->h;
synev.xconfigure.border_width = c->border;
synev.xconfigure.above = None;
/* Send synthetic ConfigureNotify */
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
else
synconfig(c, c->x, c->y, c->w, c->h, c->border);
XSync(dpy, False);
if(c->isfloat)
resize(c, False, TopLeft);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

311
main.c
View File

@ -15,14 +15,32 @@
#include <X11/Xatom.h>
#include <X11/Xproto.h>
/* extern */
char stext[1024];
Bool *seltag;
int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
unsigned int ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
Bool maximized = False;
Client *clients = NULL;
Client *sel = NULL;
Cursor cursor[CurLast];
Display *dpy;
DC dc = {0};
Window root, barwin;
/* static */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm;
static Bool otherwm, readin;
static void
cleanup()
{
close(STDIN_FILENO);
while(sel) {
resize(sel, True, TopLeft);
unmanage(sel);
@ -32,11 +50,12 @@ cleanup()
else
XFreeFont(dpy, dc.font.xfont);
XUngrabKey(dpy, AnyKey, AnyModifier, root);
XDestroyWindow(dpy, barwin);
XFreePixmap(dpy, dc.drawable);
XFreeGC(dpy, dc.gc);
XDestroyWindow(dpy, barwin);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XSync(dpy, False);
free(seltag);
}
static void
@ -61,155 +80,15 @@ scan()
XFree(wins);
}
static int
win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
static void
setup()
{
int status, format;
unsigned long res, extra;
Atom real;
status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
&res, &extra, prop);
if(status != Success || *prop == 0) {
return 0;
}
if(res == 0) {
free((void *) *prop);
}
return res;
}
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int
xerrorstart(Display *dsply, XErrorEvent *ee)
{
otherwm = True;
return -1;
}
/* extern */
char stext[1024];
Bool *seltag;
int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
unsigned int ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
Client *clients = NULL;
Client *sel = NULL;
Cursor cursor[CurLast];
Display *dpy;
DC dc = {0};
Window root, barwin;
int
getproto(Window w)
{
int protos = 0;
int i;
long res;
Atom *protocols;
res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L,
((unsigned char **)&protocols));
if(res <= 0) {
return protos;
}
for(i = 0; i < res; i++) {
if(protocols[i] == wmatom[WMDelete])
protos |= PROTODELWIN;
}
free((char *) protocols);
return protos;
}
void
sendevent(Window w, Atom a, long value)
{
XEvent e;
e.type = ClientMessage;
e.xclient.window = w;
e.xclient.message_type = a;
e.xclient.format = 32;
e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e);
XSync(dpy, False);
}
void
quit(Arg *arg)
{
running = False;
}
/*
* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which calls exit().
*/
int
xerror(Display *dpy, XErrorEvent *ee)
{
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
main(int argc, char *argv[])
{
int i, j, xfd;
int i, j;
unsigned int mask;
fd_set rd;
Bool readin = True;
Window w;
XModifierKeymap *modmap;
XSetWindowAttributes wa;
if(argc == 2 && !strncmp("-v", argv[1], 3)) {
fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
}
else if(argc != 1)
eprint("usage: dwm [-v]\n");
dpy = XOpenDisplay(0);
if(!dpy)
eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other window manager is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XSync(dpy, False);
if(otherwm)
eprint("dwm: another window manager is already running\n");
XSync(dpy, False);
XSetErrorHandler(NULL);
xerrorxlib = XSetErrorHandler(xerror);
XSync(dpy, False);
/* init atoms */
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
@ -241,14 +120,18 @@ main(int argc, char *argv[])
for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags);
seltag[DEFTAG] = True;
seltag[0] = True;
/* style */
dc.bg = getcolor(BGCOLOR);
dc.fg = getcolor(FGCOLOR);
dc.border = getcolor(BORDERCOLOR);
dc.norm[ColBG] = getcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR);
dc.status[ColBG] = getcolor(STATUSBGCOLOR);
dc.status[ColFG] = getcolor(STATUSFGCOLOR);
setfont(FONT);
bmw = textw(FLOATSYMBOL) > textw(TILESYMBOL) ? textw(FLOATSYMBOL) : textw(TILESYMBOL);
sx = sy = 0;
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
@ -256,7 +139,7 @@ main(int argc, char *argv[])
bx = by = 0;
bw = sw;
dc.h = bh = dc.font.height + 4;
dc.h = bh = dc.font.height + 2;
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask | ExposureMask;
@ -268,28 +151,138 @@ main(int argc, char *argv[])
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
strcpy(stext, "dwm-"VERSION);
drawstatus();
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
strcpy(stext, "dwm-"VERSION);
}
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int
xerrorstart(Display *dsply, XErrorEvent *ee)
{
otherwm = True;
return -1;
}
/* extern */
int
getproto(Window w)
{
int i, format, protos, status;
unsigned long extra, res;
Atom *protocols, real;
protos = 0;
status = XGetWindowProperty(dpy, w, wmatom[WMProtocols], 0L, 20L, False,
XA_ATOM, &real, &format, &res, &extra, (unsigned char **)&protocols);
if(status != Success || protocols == 0)
return protos;
for(i = 0; i < res; i++)
if(protocols[i] == wmatom[WMDelete])
protos |= PROTODELWIN;
free(protocols);
return protos;
}
void
sendevent(Window w, Atom a, long value)
{
XEvent e;
e.type = ClientMessage;
e.xclient.window = w;
e.xclient.message_type = a;
e.xclient.format = 32;
e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e);
XSync(dpy, False);
}
void
quit(Arg *arg)
{
readin = running = False;
}
/*
* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which calls exit().
*/
int
xerror(Display *dpy, XErrorEvent *ee)
{
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
main(int argc, char *argv[])
{
int r, xfd;
fd_set rd;
if(argc == 2 && !strncmp("-v", argv[1], 3)) {
fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
}
else if(argc != 1)
eprint("usage: dwm [-v]\n");
dpy = XOpenDisplay(0);
if(!dpy)
eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other window manager is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XSync(dpy, False);
if(otherwm)
eprint("dwm: another window manager is already running\n");
XSync(dpy, False);
XSetErrorHandler(NULL);
xerrorxlib = XSetErrorHandler(xerror);
XSync(dpy, False);
setup();
drawstatus();
scan();
/* main event loop, also reads status text from stdin */
XSync(dpy, False);
procevent();
readin = True;
while(running) {
FD_ZERO(&rd);
if(readin)
FD_SET(STDIN_FILENO, &rd);
FD_SET(xfd, &rd);
i = select(xfd + 1, &rd, NULL, NULL, NULL);
if(i == -1 && errno == EINTR)
r = select(xfd + 1, &rd, NULL, NULL, NULL);
if((r == -1) && (errno == EINTR))
continue;
if(i < 0)
eprint("select failed\n");
else if(i > 0) {
if(r > 0) {
if(readin && FD_ISSET(STDIN_FILENO, &rd)) {
readin = NULL != fgets(stext, sizeof(stext), stdin);
if(readin)
@ -299,6 +292,8 @@ main(int argc, char *argv[])
drawstatus();
}
}
else if(r < 0)
eprint("select failed\n");
procevent();
}
cleanup();

209
tag.c
View File

@ -30,98 +30,8 @@ RULES
static RReg *rreg = NULL;
static unsigned int len = 0;
void (*arrange)(Arg *) = DEFMODE;
/* extern */
void
dofloat(Arg *arg)
{
Client *c;
for(c = clients; c; c = c->next) {
c->ismax = False;
if(isvisible(c)) {
resize(c, True, TopLeft);
}
else
ban(c);
}
if(!sel || !isvisible(sel))
sel = getnext(clients);
if(sel) {
focus(sel);
restack();
}
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}
void
dotile(Arg *arg)
{
int h, i, n, w;
Client *c;
w = sw - mw;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
c->ismax = False;
if(isvisible(c)) {
if(c->isfloat) {
resize(c, True, TopLeft);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2;
c->h = sh - 2 - bh;
}
else if(i == 0) {
c->x = sx;
c->y = sy + bh;
c->w = mw - 2;
c->h = sh - 2 - bh;
}
else if(h > bh) {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2;
if(i + 1 == n)
c->h = sh - c->y - 2;
else
c->h = h - 2;
}
else { /* fallback if h < bh */
c->x = sx + mw;
c->y = sy + bh;
c->w = w - 2;
c->h = sh - 2 - bh;
}
resize(c, False, TopLeft);
i++;
}
else
ban(c);
}
if(!sel || !isvisible(sel))
sel = getnext(clients);
if(sel)
focus(sel);
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
restack();
}
Client *
getnext(Client *c)
{
@ -165,84 +75,25 @@ initrregs()
}
}
Bool
isvisible(Client *c)
{
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void
restack()
settags(Client *c, Client *trans)
{
static unsigned int nwins = 0;
static Window *wins = NULL;
unsigned int f, fi, m, mi, n;
Client *c;
XEvent ev;
for(f = 0, m = 0, c = clients; c; c = c->next)
if(isvisible(c)) {
if(c->isfloat || arrange == dofloat)
f++;
else
m++;
}
if(!(n = 2 * (f + m))) {
drawstatus();
return;
}
if(nwins < n) {
nwins = n;
wins = erealloc(wins, nwins * sizeof(Window));
}
fi = 0;
mi = 2 * f;
if(sel->isfloat || arrange == dofloat) {
wins[fi++] = sel->title;
wins[fi++] = sel->win;
}
else {
wins[mi++] = sel->title;
wins[mi++] = sel->win;
}
for(c = clients; c; c = c->next)
if(isvisible(c) && c != sel) {
if(c->isfloat || arrange == dofloat) {
wins[fi++] = c->title;
wins[fi++] = c->win;
}
else {
wins[mi++] = c->title;
wins[mi++] = c->win;
}
}
XRestackWindows(dpy, wins, n);
drawall();
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
settags(Client *c)
{
char classinst[256];
char prop[512];
unsigned int i, j;
regmatch_t tmp;
Bool matched = False;
Bool matched = trans != NULL;
XClassHint ch;
if(XGetClassHint(dpy, c->win, &ch)) {
snprintf(classinst, sizeof(classinst), "%s:%s",
if(matched) {
for(i = 0; i < ntags; i++)
c->tags[i] = trans->tags[i];
}
else if(XGetClassHint(dpy, c->win, &ch)) {
snprintf(prop, sizeof(prop), "%s:%s:%s",
ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "");
ch.res_name ? ch.res_name : "", c->name);
for(i = 0; !matched && i < len; i++)
if(rreg[i].clregex && !regexec(rreg[i].clregex, classinst, 1, &tmp, 0)) {
if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) {
c->isfloat = rule[i].isfloat;
for(j = 0; rreg[i].tregex && j < ntags; j++) {
if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) {
@ -259,6 +110,7 @@ settags(Client *c)
if(!matched)
for(i = 0; i < ntags; i++)
c->tags[i] = seltag[i];
for(c->weight = 0; c->weight < ntags && !c->tags[c->weight]; c->weight++);
}
void
@ -272,15 +124,7 @@ tag(Arg *arg)
for(i = 0; i < ntags; i++)
sel->tags[i] = False;
sel->tags[arg->i] = True;
settitle(sel);
if(!isvisible(sel))
arrange(NULL);
}
void
togglemode(Arg *arg)
{
arrange = arrange == dofloat ? dotile : dofloat;
sel->weight = arg->i;
arrange(NULL);
}
@ -296,31 +140,6 @@ toggletag(Arg *arg)
for(i = 0; i < ntags && !sel->tags[i]; i++);
if(i == ntags)
sel->tags[arg->i] = True;
settitle(sel);
if(!isvisible(sel))
arrange(NULL);
}
void
toggleview(Arg *arg)
{
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
arrange(NULL);
}
void
view(Arg *arg)
{
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = False;
seltag[arg->i] = True;
sel->weight = (i == ntags) ? arg->i : i;
arrange(NULL);
}

15
util.c
View File

@ -9,14 +9,6 @@
#include <sys/wait.h>
#include <unistd.h>
/* static */
static void
bad_malloc(unsigned int size)
{
eprint("fatal: could not malloc() %u bytes\n", size);
}
/* extern */
void *
@ -25,7 +17,7 @@ emallocz(unsigned int size)
void *res = calloc(1, size);
if(!res)
bad_malloc(size);
eprint("fatal: could not malloc() %u bytes\n", size);
return res;
}
@ -45,7 +37,7 @@ erealloc(void *ptr, unsigned int size)
{
void *res = realloc(ptr, size);
if(!res)
bad_malloc(size);
eprint("fatal: could not malloc() %u bytes\n", size);
return res;
}
@ -59,12 +51,13 @@ spawn(Arg *arg)
if(!arg->cmd)
return;
/* the double-fork construct avoids zombie processes */
if(fork() == 0) {
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execl(shell, shell, "-c", arg->cmd, NULL);
execl(shell, shell, "-c", arg->cmd, (char *)NULL);
fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg->cmd);
perror(" failed");
}

306
view.c Normal file
View File

@ -0,0 +1,306 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
/* static */
static Client *
minclient()
{
Client *c, *min;
for(min = c = clients; c; c = c->next)
if(c->weight < min->weight)
min = c;
return min;
}
static void
reorder()
{
Client *c, *newclients, *tail;
newclients = tail = NULL;
while((c = minclient())) {
detach(c);
if(tail) {
c->prev = tail;
tail->next = c;
tail = c;
}
else
tail = newclients = c;
}
clients = newclients;
}
static Client *
nexttiled(Client *c)
{
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
}
/* extern */
void (*arrange)(Arg *) = DEFMODE;
void
detach(Client *c)
{
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
c->next = c->prev = NULL;
}
void
dofloat(Arg *arg)
{
Client *c;
maximized = False;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
resize(c, True, TopLeft);
}
else
ban(c);
}
if(!sel || !isvisible(sel))
focus(getnext(clients));
restack();
}
void
dotile(Arg *arg)
{
int h, i, n, w;
Client *c;
maximized = False;
w = sw - mw;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
if(isvisible(c)) {
if(c->isfloat) {
resize(c, True, TopLeft);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2;
c->h = sh - 2 - bh;
}
else if(i == 0) {
c->x = sx;
c->y = sy + bh;
c->w = mw - 2;
c->h = sh - 2 - bh;
}
else if(h > bh) {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2;
if(i + 1 == n)
c->h = sh - c->y - 2;
else
c->h = h - 2;
}
else { /* fallback if h < bh */
c->x = sx + mw;
c->y = sy + bh;
c->w = w - 2;
c->h = sh - 2 - bh;
}
resize(c, False, TopLeft);
i++;
}
else
ban(c);
}
if(!sel || !isvisible(sel))
focus(getnext(clients));
restack();
}
void
focusnext(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
focus(c);
restack();
}
}
void
focusprev(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
}
if(c) {
focus(c);
restack();
}
}
Bool
isvisible(Client *c)
{
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void
resizecol(Arg *arg)
{
unsigned int n;
Client *c;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
return;
if(sel == getnext(clients)) {
if(mw + arg->i > sw - 100 || mw + arg->i < 100)
return;
mw += arg->i;
}
else {
if(mw - arg->i > sw - 100 || mw - arg->i < 100)
return;
mw -= arg->i;
}
arrange(NULL);
}
void
restack()
{
Client *c;
XEvent ev;
if(!sel) {
drawstatus();
return;
}
if(sel->isfloat || arrange == dofloat) {
XRaiseWindow(dpy, sel->win);
XRaiseWindow(dpy, sel->twin);
}
if(arrange != dofloat)
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
XLowerWindow(dpy, c->twin);
XLowerWindow(dpy, c->win);
}
drawall();
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
togglemode(Arg *arg)
{
arrange = (arrange == dofloat) ? dotile : dofloat;
if(sel)
arrange(NULL);
else
drawstatus();
}
void
toggleview(Arg *arg)
{
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
reorder();
arrange(NULL);
}
void
view(Arg *arg)
{
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = False;
seltag[arg->i] = True;
reorder();
arrange(NULL);
}
void
viewall(Arg *arg)
{
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = True;
reorder();
arrange(NULL);
}
void
zoom(Arg *arg)
{
unsigned int n;
Client *c;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
return;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
detach(c);
c->next = clients;
clients->prev = c;
clients = c;
focus(c);
arrange(NULL);
}