Compare commits

...

228 Commits
0.1 ... 0.9

Author SHA1 Message Date
a1682b8927 prepared dwm-0.9 2006-08-15 10:11:29 +02:00
24d91e3b8a extended cleanup 2006-08-15 09:37:12 +02:00
ce04a66528 applied Sanders changes to config.arg.h 2006-08-15 08:38:19 +02:00
df74b26e5d applied jk_to_tab patch 2006-08-15 08:25:11 +02:00
b6ad663f87 changed main event loop 2006-08-15 07:31:42 +02:00
ee31e38dc7 removed NUMLOCKMASK, added dynamically calculated numlockmask instead 2006-08-14 19:18:02 +02:00
442334641e added Sander to LICENSE (since he has contributed/revised big portions) 2006-08-14 18:47:13 +02:00
dfa5ea6360 applied viewsel.patch 2006-08-14 18:46:07 +02:00
3e06edeb5d applied sanders man page patch, removed button2 from bar click 2006-08-14 18:14:08 +02:00
78b050c13c applied sanders tag()/toggletag() fixes 2006-08-14 17:50:48 +02:00
4ad20ffc2c fixed 2006-08-14 17:48:54 +02:00
57e6e3bb80 added missing arrange 2006-08-14 17:14:22 +02:00
19da197f58 changed replacetag into toggletag 2006-08-14 16:59:18 +02:00
666fae97e6 added some flicker prevention 2006-08-14 16:37:55 +02:00
823fb1118a remove unnecessary XSync 2006-08-14 16:26:06 +02:00
db1d62e184 changed order of selecting input at root window 2006-08-14 16:21:16 +02:00
d26ffc7fa3 removed finished message 2006-08-14 16:11:54 +02:00
0f3acce042 added mappingnotify event for kb refreshes 2006-08-14 16:08:52 +02:00
9eef9f7b02 removed unneecessary crap 2006-08-14 15:43:04 +02:00
aff4c787f4 applied the saner patch (removed the pathetic one) 2006-08-14 15:33:23 +02:00
fe3dfbbe90 pplied Sanders appendtag patch 2006-08-14 15:31:58 +02:00
2ffdc1936c some other small fixes 2006-08-14 15:11:02 +02:00
0fe52c63ea removed ungrabkeys again (because of sander's mail) 2006-08-14 11:38:43 +02:00
28a52197c4 fixed string cutting 2006-08-14 10:58:03 +02:00
2c0d1cc87b fixed a core dump 2006-08-14 10:49:22 +02:00
375a251d16 implemented ungrabkeys() which is called in cleanup() 2006-08-14 10:24:38 +02:00
d4b7a9a373 implemented restack behavior (floats are on top in tiled mode) 2006-08-14 10:18:24 +02:00
4d67199a4b fixed string cutting in draw.c 2006-08-14 08:52:15 +02:00
95766d6241 applied Sanders LD and resize patches 2006-08-14 08:43:19 +02:00
4cb78a170c removed viewnext/viewprev 2006-08-14 08:38:26 +02:00
2c66b422e7 supplying NULL args in select 2006-08-14 07:40:20 +02:00
e571de83e9 reducing ConnectionNumber calls to a bare minimum 2006-08-14 07:23:46 +02:00
4bb89e2cb1 updated man page, added CAVEATS section 2006-08-13 18:04:42 +02:00
349cadacf6 made shortcuts like proposed by Sander, renamed viewextend to toggleview (more clear) 2006-08-13 17:58:06 +02:00
292ccc4c43 implemented viewextend and added M-S-C-n shortcuts for extending the current view... updated man page (works great!) nice feature 2006-08-11 19:26:12 +02:00
d7413ffd2d implement multi-tag selection through button3 click on the specific tag 2006-08-11 18:37:41 +02:00
50729a2e73 after some days of experimenting with grey background, I finally give up and switch to white on black ;) 2006-08-11 18:11:39 +02:00
a3e3f0b9ed applied Sanders fixes to dwm.1 2006-08-11 17:12:48 +02:00
45aea23355 fixed dwm.1, added Mod1-Shift-c (was missing for an odd reason) 2006-08-11 12:32:34 +02:00
975b459c17 simplified drawtext 2006-08-11 11:52:55 +02:00
2b35faee06 updated dwm(1) 2006-08-11 10:54:29 +02:00
84818bdbb5 upgraded version info 2006-08-11 10:28:51 +02:00
895902b57a applied Sander's patch as well 2006-08-11 10:05:53 +02:00
7d4184dc5c realized that client focussing through the bar is pretty useless, better is sloppy view focussing for B1/B3 as well instead 2006-08-11 10:00:47 +02:00
8278f0a6be implemented focusprev on button1 press in the bar, and focusnext on button3 press in the bar 2006-08-11 09:16:40 +02:00
d3969634ac simplified unmanage 2006-08-11 08:47:55 +02:00
735ca9ccd6 removed the if(clients) check from popping code 2006-08-11 08:34:42 +02:00
4ee661d908 added dwm favicon 2006-08-10 18:44:19 +02:00
9fce8215b7 applied Sanders zoom_update patch 2006-08-10 17:48:50 +02:00
6521c2dd41 respecting inc hints in floating mode on togglemax 2006-08-10 17:33:11 +02:00
9ee9ce7e14 reverting last patch, that sucks, I don't care about retarded apps like gvim 2006-08-10 16:37:13 +02:00
9d39da6452 togglemax repects inc-hints (this way gvim can be toggle'maxed as well) 2006-08-10 16:35:36 +02:00
0228dcd58f applied grammar correction by ILF 2006-08-10 15:35:02 +02:00
3d35ea99bb Added tag 0.8 for changeset cd15de32e173f8ce97bfe1c9b6607937b59056b4 2006-08-10 15:19:31 +02:00
0680c76a6f prepared 0.8 2006-08-10 15:19:25 +02:00
c3e5f5cc9a updated html 2006-08-10 13:30:39 +02:00
1c620d27d8 fixed the issue reported by sander (gaps at left columns button due to round-offs) 2006-08-10 12:33:44 +02:00
fde45ebed8 applied sumik's multihead patch 2006-08-10 11:26:32 +02:00
4bd0d33f57 applied sander's patch 2006-08-10 11:19:25 +02:00
00255728aa readded border color, this sucks least 2006-08-10 11:12:15 +02:00
4b0328f209 drawing border with fg color 2006-08-10 11:07:27 +02:00
30561a0161 removed unnecessary border color 2006-08-10 10:27:08 +02:00
a4c4998c8b swapping my default colors (bg with fg) 2006-08-10 10:22:15 +02:00
8e053b6476 made terminals darker, that is better indeed 2006-08-10 10:20:26 +02:00
b79b5facb1 disallow zoom on maximized clients 2006-08-10 10:16:12 +02:00
c53f0fca91 added zoom on Mod1-Button1 on managed clients only (there is no moving possible) 2006-08-09 18:37:33 +02:00
c225e1afc2 removed NET_ACTIVE_WINDOW handling 2006-08-08 18:12:18 +02:00
92e55c7c53 implemented NET_ACTIVE_WINDOW support 2006-08-08 17:08:45 +02:00
c86f131681 fixed typo 2006-08-08 12:58:05 +02:00
e943234d09 it always takes a while until one sticks to a colorscheme, but this one feels well 2006-08-08 12:50:11 +02:00
9fc24e371b default colors are best 2006-08-08 12:47:45 +02:00
cac467d52c without borders it looks cleaner 2006-08-08 11:47:29 +02:00
04f17d2669 red is easier to my eyes with ffffaa bg 2006-08-08 11:18:05 +02:00
dff15a02f7 using a better colorscheme (ffffaa is the best background for black) 2006-08-08 11:06:56 +02:00
42277b1110 applied Sanders tiny patches 2006-08-08 09:30:45 +02:00
095f9e143e removed some " 2006-08-07 17:38:14 +02:00
9fbb2ebb90 I really only need 3 tags 2006-08-07 14:12:28 +02:00
dbcf87ce76 added a trailing '.' to shortcut descriptions in dwm(1) 2006-08-07 14:10:22 +02:00
4250c26e9b changed signature of drawtext 2006-08-07 13:54:59 +02:00
e48de30516 applied grabbing-- and shell_minimal 2006-08-07 13:40:31 +02:00
1f0060caa3 updated screenshot section 2006-08-07 12:26:28 +02:00
c732cc90ab changed font size, I'm not blind... 2006-08-07 12:21:17 +02:00
4e2c5b5f25 small fix of a comment 2006-08-07 12:12:56 +02:00
d9386a0c07 typo fix 2006-08-07 11:58:46 +02:00
66e16c92d3 applied Sanders man page/Makefile patch 2006-08-07 11:57:05 +02:00
6a8e176df1 settle with grey 2006-08-07 11:10:19 +02:00
632c7f3410 next version is 0.8 2006-08-07 10:32:36 +02:00
045f1840e0 made my colors tasting better with the background 2006-08-07 10:28:21 +02:00
45d16d090b status box should have a border in my eyes 2006-08-07 09:47:13 +02:00
525c5ff4d8 next attempt for w on black switch 2006-08-07 09:41:43 +02:00
5952157c3b Added tag 0.7 for changeset 3fb41412e2492f66476d92ce8f007a8b48fb1d2a 2006-08-07 08:55:39 +02:00
f777d21899 prepared dwm.html 2006-08-07 08:51:43 +02:00
82064af2d7 added stripping to dwm target in Makefile 2006-08-07 08:46:11 +02:00
d54444cfd7 changed getproto, maybe that might fix the killclient issue reported on the list 2006-08-07 08:19:58 +02:00
525ef3c178 applied endless loop prevention on zoom() 2006-08-07 08:05:04 +02:00
5ef6ef1bac updated man page 2006-08-07 07:36:36 +02:00
f4208e7cac small fix of the last commit 2006-08-05 14:57:26 +02:00
ecc95c903b using -Os again, zoom is ignored in floating mode or on floating clients 2006-08-05 14:56:32 +02:00
a207949b65 mouse grab needs also to grab for combinations of numlock/lockmask 2006-08-05 14:02:25 +02:00
86d12249dd slight fix 2006-08-05 13:10:09 +02:00
b098c94ed4 small performance tweak ;) 2006-08-04 18:34:40 +02:00
6a39a496d0 fixed xterm font change (all other related apps should work fine with this fix as well) 2006-08-04 18:25:40 +02:00
3d73084b5e fixed view-change bug reported on the list 2006-08-04 18:17:02 +02:00
12b1d439e4 no need for -g anymore, regexp matching works now 2006-08-04 17:04:50 +02:00
1076161bf3 fixed dmenu link (thx to deifl) 2006-08-04 15:47:50 +02:00
e21d93b7bd switched to regexp matching for Rules 2006-08-04 14:40:32 +02:00
f504aea132 fixed a bug in dmenu call 2006-08-04 13:42:40 +02:00
9955ddc978 using execl now, argv changed, using cmd and const char defs directly in the KEYS struct 2006-08-04 12:00:55 +02:00
0dfe729f90 added dmenu to dwm.html 2006-08-04 10:36:22 +02:00
8f698bd4cc small stylistic fix 2006-08-04 10:27:16 +02:00
99b126d0af removed CONFIG 2006-08-03 17:08:43 +02:00
a2d56f6dce make config.h not a time dependence 2006-08-03 15:36:13 +02:00
db876f9fb0 removed rm config.h from clean 2006-08-03 15:29:28 +02:00
05a618b06e added gmake compliance 2006-08-03 15:21:08 +02:00
72608f0d5a s/tag2/two/g 2006-08-03 15:09:52 +02:00
bba044de4f applied Jukka's diff 2006-08-03 15:05:34 +02:00
4d55eee754 applied Sanders Makefile patch 2006-08-03 13:50:37 +02:00
d41b232b52 stylistic chnage 2006-08-03 12:21:00 +02:00
b35575574b removed TLast tag enum, now tags is simple defined as char *[] array, the rest is calculated correctly, rules take an int array for the tags 2006-08-03 12:12:26 +02:00
666b4563a0 hotfix of settags 2006-08-03 11:38:26 +02:00
7315bb08ad using SRC instead of *.c 2006-08-03 11:27:29 +02:00
f80688f1c7 changed the files included in make dist 2006-08-03 10:59:20 +02:00
dc5c070c44 applied Sanders doc changes, added a PHONY line and changed the output of config.h creation somewhat 2006-08-03 10:58:29 +02:00
8cc7f3bace changed Client->tags and Rule->tags to be Bool (I'll also try to remove the TLast enum) 2006-08-03 10:55:07 +02:00
5d3fd3707b implemented the idea presented by Sander for dwm target 2006-08-02 17:49:21 +02:00
1bf0c4a8e7 changing MASTERW value from 52 to 60 (in both, default and arg), I feel this is better now 2006-08-02 17:19:22 +02:00
863656d2bc fixed a type in README, and patched config.mk 2006-08-02 17:12:00 +02:00
f1a34ae1e4 updated dwm.html 2006-08-02 16:54:58 +02:00
3000cad507 Added tag 0.6 for changeset c11f86db4550cac5d0a648a3fe4d6d3b9a4fcf7e 2006-08-02 16:52:21 +02:00
0f8249f262 removed config.h (stupid hg) 2006-08-02 16:52:02 +02:00
b515765216 removed the CONFIG variable from config.mk, renamed config.h into config.default.h, after first clone/extract one needs to copy config.default.h to config.h, that is easier than always heavy typing make CONFIG=blafasel 2006-08-02 16:46:59 +02:00
85e6d59956 added Acroread.* and MPlayer.* to config.arg.h rules 2006-08-02 16:38:21 +02:00
95e8d12b71 made fullscreen apps working fine in floating mode (there is no sane way to make them work in tiled mode, thus I switch to floating mode if I run such kind of app), also fixed the xterm issue reported by Sander 2006-08-02 16:32:05 +02:00
a55f0e12fe new stuff 2006-08-02 13:05:04 +02:00
0cf3ba0eab dwm is now exit, if stdin is closed due broken pipe 2006-08-02 12:33:24 +02:00
1d85225952 implemented focus on enterwindow on titlebars 2006-08-02 11:28:27 +02:00
3af6434085 applied Sanders patches (numlock2) 2006-08-02 11:13:32 +02:00
57871415c1 reverting to old resize policy 2006-08-02 10:48:58 +02:00
52021851d1 new resize stuff (using XConfigureWindow instead of XSendEvent) 2006-08-02 10:43:21 +02:00
080a38d62d renamed WM_PROTOCOL_DELWIN into PROTODELWIN 2006-08-01 16:44:23 +02:00
ab7a11c0c7 renamed ARRANGE into DEFMODE 2006-08-01 16:39:20 +02:00
d8675f6f30 small fixes to dwm.html 2006-08-01 16:35:54 +02:00
eff4478c2d simplified README 2006-08-01 16:29:25 +02:00
81683351f0 removed 1 missing LOC 2006-08-01 16:20:29 +02:00
b38905b004 removed 5LOC 2006-08-01 16:20:03 +02:00
d9a6a3b5d2 removed artefacts of single-linked list (thanx to Jukka, I must have been mad) 2006-08-01 16:14:17 +02:00
7c2e3bb67d cleaned config.*h to prevent some confusion 2006-08-01 15:29:37 +02:00
b01a51a844 saved 2LOC 2006-08-01 15:16:29 +02:00
77f8c075c4 uppercasing all define'd values (uppercase-prefixed should only be enum field qualifiers) 2006-08-01 14:46:01 +02:00
33b4821cd6 fixed config.h files 2006-08-01 14:03:29 +02:00
a73a882806 centralized/externalized configuration to config.h 2006-08-01 13:59:13 +02:00
57416beefe applied Cedric's NumLock patch 2006-08-01 12:41:38 +02:00
1b63f832c5 applied Jukkas prev/next patch with XK_{h,l} 2006-08-01 12:39:14 +02:00
7b5638f61d applied Sanders patches 2006-08-01 12:32:33 +02:00
937cabfa0a committed a patch which fixes the hints of Jukka 2006-08-01 11:49:19 +02:00
deba5069e5 updated html 2006-07-21 21:15:39 +02:00
956113b295 Added tag 0.5 for changeset 22213b9a2114167ee8ba019a012e27da0422a61a 2006-07-21 21:15:11 +02:00
db98a7d60f prepared 0.5 2006-07-21 21:15:08 +02:00
0464e42231 some cleanups/fixes inspired by Jukka Salmi's feedback 2006-07-21 18:34:10 +02:00
4970ef938e simplified main.c, switching back to single urxvt usage 2006-07-21 14:11:38 +02:00
f85b163899 s/sleep 5/sleep 2/ 2006-07-21 11:54:14 +02:00
2b66f7afb1 changed the status info README hint (more simple now, no extra script necessary) 2006-07-21 11:48:28 +02:00
67b3083dfd s/0.5/0.6/ - my steps are wider than the reality 2006-07-21 10:18:12 +02:00
0c7bcc24cb applied sanders maxfix patch 2006-07-21 10:07:41 +02:00
98c6a92eb5 added a note how to achieve status info in the bar 2006-07-21 09:59:11 +02:00
ba59bc8b9f preparing 0.6 which will be available in the evening after sanders patch approx. 2006-07-21 09:39:44 +02:00
cd8d8e1208 sanitization of several clunky stuff, removed heretag (rarely of use), simplified pop(), changed shortcuts to always contain MODKEY 2006-07-21 07:37:52 +02:00
04eb016e78 applied sanders no_sizehints for tiled mode patch (thx!) 2006-07-20 19:09:11 +02:00
0a4342098b serious mistake in pop() (forgot to set c->prev to NULL on pop) 2006-07-20 18:23:43 +02:00
72707c2fae using double-linked list in order to get correct prev focus handling 2006-07-20 16:54:20 +02:00
06dc514bc7 added yet another CUTOMIZE tag 2006-07-20 15:40:41 +02:00
2b5553b1eb cleaned the CUSTOMIZE flags 2006-07-20 15:17:52 +02:00
4688ad181d made status bar drawing more robust, implemented togglemax and togglemode, works quite well 2006-07-20 15:07:35 +02:00
dc5d967ee6 cleaned up code 2006-07-20 12:18:06 +02:00
fe3756c8e1 Added tag 0.4 for changeset eb3165734f00fe7f7da8aeebaed00e60a57caac9 2006-07-20 10:48:22 +02:00
01b151f5f8 prepared 0.4 2006-07-20 10:48:19 +02:00
8bb4a93f2b using O3 instead of Os, binary size still < 40kb 2006-07-20 10:26:36 +02:00
5ec04b7726 fixed version in man page 2006-07-20 10:15:05 +02:00
3657eaedf3 yet another html patch 2006-07-20 10:12:41 +02:00
9291283a18 updated html 2006-07-20 10:10:58 +02:00
eccd02def2 makefile now sets permissions for executables and man pages 2006-07-20 09:45:47 +02:00
11737233a7 removed c->f{x,y,w,h} and c->t{x,y,w,h} in favor for the new rule handling remembering two kinds of geometries is unnecessary, removed the randomized (x,y) setting on dofloat startup, was kind too random und unpredictable 2006-07-20 07:26:23 +02:00
bcaf6a7a0f implemented regexp matching for rules 2006-07-19 17:42:08 +02:00
f95eed34b4 applied Jukka's patch with s/ModKeyMask/MODKEY/g 2006-07-19 16:38:39 +02:00
1eaffa372f removed TODO, because dwm is nearly finished 2006-07-19 15:03:53 +02:00
b1697e8d5f reapplied my default keybindings 2006-07-19 14:54:19 +02:00
801d11c7e7 alternate dwm.png 2006-07-19 14:49:19 +02:00
1b855fccd7 Added tag 0.3 for changeset 7e66082e5092fb0bccd18a3695a0bec52c80fdb2 2006-07-19 14:44:44 +02:00
d34b4c7b9a some changes in the html page 2006-07-19 14:44:24 +02:00
1f9614f82e prepared 0.3 2006-07-19 14:43:17 +02:00
4491bdda69 fixed the bug mentioned by Sander 2006-07-19 14:11:27 +02:00
8af1d97332 refactored Sanders code somewhat 2006-07-19 13:52:31 +02:00
79cd408844 implemented fallback for too many clients in stacked mode 2006-07-19 13:36:04 +02:00
18be893b66 and another fix... 2006-07-19 13:30:18 +02:00
0fb1842fd0 yet another typo fix 2006-07-19 13:29:45 +02:00
f522930a99 fixed a typo 2006-07-19 13:24:58 +02:00
aebd745f72 floating clients get random (x,y) offsets now 2006-07-19 13:22:49 +02:00
c53980cddc applied Sanders resize patch, fixed lower bug 2006-07-19 11:31:04 +02:00
95e56ffc0d changed CFLAGs 2006-07-18 17:54:55 +02:00
f1294353f2 firefox instance is different now 2006-07-18 15:10:57 +02:00
6649dcce6d changed occurrences of wmii.de into 10kloc.org in dwm.html, because 10kloc.org is already working 2006-07-18 13:01:33 +02:00
58f2fe3f6a implemened distinguishing float/managed geometries of clients (works quite well) 2006-07-18 12:36:57 +02:00
0aaa9a21f3 pop on heretag 2006-07-18 11:45:32 +02:00
4f8b08d330 added heretag command which allows to tag a client of a foreign tag with current tag 2006-07-18 11:38:31 +02:00
849e631510 using EXIT_stuff in exit() now 2006-07-18 08:18:54 +02:00
789717d109 simplified Makefile 2006-07-17 18:49:13 +02:00
605630c145 added new stuff 2006-07-17 16:46:42 +02:00
1e7e57dad3 updated html 2006-07-17 11:56:27 +02:00
eb184e02ea patched dwm 2006-07-17 11:36:07 +02:00
ed41473634 updated README 2006-07-17 10:09:57 +02:00
ee5ba14431 Added tag 0.2 for changeset 0a6472e2203994bc5738d40a340d26f7ec9d6062 2006-07-17 10:00:59 +02:00
b706893e0a updated html 2006-07-17 10:00:55 +02:00
bf35794507 ordered variables in structs and source files alphabetically 2006-07-17 09:12:29 +02:00
e743836541 slight change to dwm.1 2006-07-17 08:37:37 +02:00
0c3544d42f simplified man page 2006-07-16 23:26:50 +02:00
94f7c2707b another XSync 2006-07-16 12:29:50 +02:00
901b3ed9b7 several additions in mouse handling ;) 2006-07-16 00:47:40 +02:00
e6cbe9c11e fixed XSync handling and finished man page 2006-07-15 18:51:44 +02:00
f60c597d65 changing XFlush into XSync 2006-07-15 18:11:14 +02:00
c09bf8da07 sanitized other stuff 2006-07-15 17:19:19 +02:00
adaa28a6e6 proceeded with cleaning up, sorting functions, etc 2006-07-15 17:00:56 +02:00
dba23062ba rearranged several stuff 2006-07-15 16:30:50 +02:00
c0705eeb65 sanitized names 2006-07-14 22:54:09 +02:00
29355bd382 rearranged 2006-07-14 22:33:38 +02:00
91a1f6926e I prefer the tiled/floating indicator on the right side 2006-07-14 18:59:25 +02:00
54775e0b3e bar shows if currently is tiled (Mod1-space) or floating (Mod1-Shift-space) mode 2006-07-14 18:55:50 +02:00
59b4a5e4ca draw bar on exposure ;) 2006-07-14 18:46:12 +02:00
82384e385e Added tag 0.1 for changeset d31b5ad96b0ba7b5b0a30928fcf000428339a577 2006-07-14 18:40:36 +02:00
21 changed files with 1685 additions and 1270 deletions

8
.hgtags Normal file
View File

@ -0,0 +1,8 @@
d31b5ad96b0ba7b5b0a30928fcf000428339a577 0.1
0a6472e2203994bc5738d40a340d26f7ec9d6062 0.2
7e66082e5092fb0bccd18a3695a0bec52c80fdb2 0.3
eb3165734f00fe7f7da8aeebaed00e60a57caac9 0.4
22213b9a2114167ee8ba019a012e27da0422a61a 0.5
c11f86db4550cac5d0a648a3fe4d6d3b9a4fcf7e 0.6
3fb41412e2492f66476d92ce8f007a8b48fb1d2a 0.7
cd15de32e173f8ce97bfe1c9b6607937b59056b4 0.8

View File

@ -1,6 +1,7 @@
MIT/X Consortium License
(C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
(C)opyright MMVI Sander van Dijk <a dot h dot vandijk at gmail dot com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View File

@ -3,53 +3,60 @@
include config.mk
SRC = bar.c client.c dev.c draw.c event.c main.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
all: config dwm
@echo finished
all: options dwm
config:
options:
@echo dwm build options:
@echo "LIBS = ${LIBS}"
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
@echo "LD = ${LD}"
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
${OBJ}: dwm.h
${OBJ}: dwm.h config.h config.mk
config.h:
@echo creating $@ from config.default.h
@cp config.default.h $@
dwm: ${OBJ}
@echo LD $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
@${LD} -o $@ ${OBJ} ${LDFLAGS}
@strip $@
clean:
rm -f dwm *.o core
@echo cleaning
@rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
cp -R Makefile README LICENSE config.mk *.h *.c ${MAN1} dwm-${VERSION}
tar -cf dwm-${VERSION}.tar dwm-${VERSION}
gzip dwm-${VERSION}.tar
rm -rf dwm-${VERSION}
@echo creating dist tarball
@mkdir -p dwm-${VERSION}
@cp -R LICENSE Makefile README config.*.h config.mk \
dwm.1 dwm.h ${SRC} dwm-${VERSION}
@tar -cf dwm-${VERSION}.tar dwm-${VERSION}
@gzip dwm-${VERSION}.tar
@rm -rf dwm-${VERSION}
install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
@echo installed executable files to ${DESTDIR}${PREFIX}/bin
@cp -f dwm ${DESTDIR}${PREFIX}/bin
@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1
@echo installed manual pages to ${DESTDIR}${MANPREFIX}/man1
@sed 's/VERSION/${VERSION}/g' < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall:
for i in ${BIN}; do \
rm -f ${DESTDIR}${PREFIX}/bin/`basename $$i`; \
done
for i in ${MAN1}; do \
rm -f ${DESTDIR}${MANPREFIX}/man1/`basename $$i`; \
done
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/dwm
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/dwm.1
.PHONY: all options clean dist install uninstall

22
README
View File

@ -1,7 +1,6 @@
dwm - dynamic window manager
----------------------------
dwm is an extremly fast, small, and dynamic X11 window manager.
dwm is an extremely fast, small, and dynamic X11 window manager.
Requirements
@ -11,8 +10,8 @@ In order to build dwm you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup. dwm is installed into
the /usr/local namespace by default.
Edit config.mk to match your local setup (dwm is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dwm (if
necessary as root):
@ -31,10 +30,19 @@ the DISPLAY environment variable is set correctly, e.g.:
DISPLAY=foo.bar:1 exec dwm
This will start dwm on display :1 of the host foo.bar.
(This will start dwm on display :1 of the host foo.bar.)
In order to display status info in the bar, you can do something
like this in your .xinitrc:
while true
do
echo `date` `uptime | sed 's/.*://; s/,//g'`
sleep 1
done | dwm
Configuration
-------------
The configuration of dwm is done by customizing the wm.h source file. To
customize the key bindings edit dev.c.
The configuration of dwm is done by creating a custom config.h
and (re)compiling the source code.

1
TODO
View File

@ -1 +0,0 @@
- improve mouse based resizals with quadrant approach (then I think we have feature completeness already)

46
bar.c
View File

@ -1,46 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
void
barclick(XButtonPressedEvent *e)
{
int x = 0;
Arg a;
for(a.i = 0; a.i < TLast; a.i++) {
x += textw(tags[a.i]) + dc.font.height;
if(e->x < x) {
view(&a);
return;
}
}
}
void
draw_bar()
{
int i;
dc.x = dc.y = 0;
dc.w = bw;
drawtext(NULL, False, False);
dc.w = 0;
for(i = 0; i < TLast; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]) + dc.font.height;
drawtext(tags[i], i == tsel, True);
}
if(sel) {
dc.x += dc.w;
dc.w = textw(sel->name) + dc.font.height;
drawtext(sel->name, True, True);
}
dc.w = textw(stext) + dc.font.height;
dc.x = bx + bw - dc.w;
drawtext(stext, False, False);
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XFlush(dpy);
}

838
client.c
View File

@ -2,274 +2,321 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "dwm.h"
void (*arrange)(Arg *) = tiling;
static Rule rule[] = {
/* class instance tags floating */
{ "Firefox-bin", "Gecko", { [Twww] = "www" }, False },
};
static Client *
next(Client *c)
{
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
void
zoom(Arg *arg)
{
Client **l, *c;
if(!sel)
return;
if(sel == next(clients) && sel->next) {
if((c = next(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
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;
craise(sel);
resize(sel, False);
}
void
view(Arg *arg)
{
Client *c;
tsel = arg->i;
arrange(NULL);
for(c = clients; c; c = next(c->next))
draw_client(c);
draw_bar();
}
void
tappend(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
arrange(NULL);
}
void
ttrunc(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
tappend(arg);
}
/* static functions */
static void
ban_client(Client *c)
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);
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);
else
XMoveResizeWindow(dpy, c->title, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
static int
xerrordummy(Display *dsply, XErrorEvent *ee)
{
return 0;
}
/* extern functions */
void
ban(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
floating(Arg *arg)
focus(Client *c)
{
Client *c;
Client *old = sel;
arrange = floating;
for(c = clients; c; c = c->next) {
if(c->tags[tsel])
resize(c, True);
else
ban_client(c);
}
if(sel && !sel->tags[tsel]) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
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) {
craise(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_client(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
void
prevc(Arg *arg)
{
Client *c;
if(!sel)
if (!issel)
return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
craise(c);
focus(c);
}
if(sel && sel->ismax)
togglemax(NULL);
sel = c;
if(old && old != c)
drawtitle(old);
drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
}
void
nextc(Arg *arg)
focusnext(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = next(sel->next)))
c = next(clients);
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
craise(c);
c->revert = sel;
focus(c);
restack();
}
}
void
ckill(Arg *arg)
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();
}
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
Client *
getctitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
void
gravitate(Client *c, Bool invert)
{
int dx = 0, dy = 0;
switch(c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
dy = c->border;
break;
case EastGravity:
case CenterGravity:
case WestGravity:
dy = -(c->h / 2) + c->border;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
dy = -(c->h);
break;
}
switch (c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case WestGravity:
case SouthWestGravity:
dx = c->border;
break;
case NorthGravity:
case CenterGravity:
case SouthGravity:
dx = -(c->w / 2) + c->border;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
dx = -(c->w + c->border);
break;
}
if(invert) {
dx = -dx;
dy = -dy;
}
c->x += dx;
c->y += dy;
}
void
killclient(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
if(sel->proto & PROTODELWIN)
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
static void
resize_title(Client *c)
void
manage(Window w, XWindowAttributes *wa)
{
int i;
Client *c;
Window trans;
XSetWindowAttributes twa;
c->tw = 0;
for(i = 0; i < TLast; i++)
if(c->tags[i])
c->tw += textw(c->tags[i]) + dc.font.height;
c->tw += textw(c->name) + dc.font.height;
if(c->tw > c->w)
c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 2;
c->ty = c->y;
XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool));
c->win = w;
c->x = c->tx = wa->x;
c->y = c->ty = wa->y;
c->w = c->tw = wa->width;
c->h = wa->height;
c->th = bh;
c->border = 0;
setsize(c);
if(c->h != sh && c->y < bh)
c->y = c->ty = bh;
c->proto = getproto(c->win);
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans);
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask | EnterWindowMask;
c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
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);
XMapWindow(dpy, c->win);
XMapWindow(dpy, c->title);
if(isvisible(c))
focus(c);
}
void
update_name(Client *c)
resize(Client *c, Bool sizehints, Corner sticky)
{
XTextProperty name;
int n;
char **list = NULL;
int bottom = c->y + c->h;
int right = c->x + c->w;
/*XConfigureEvent e;*/
XWindowChanges wc;
name.nitems = 0;
c->name[0] = 0;
XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
if(!name.nitems)
XGetWMName(dpy, c->win, &name);
if(!name.nitems)
return;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
if(sizehints) {
if(c->incw)
c->w -= (c->w - c->basew) % c->incw;
if(c->inch)
c->h -= (c->h - c->baseh) % c->inch;
if(c->minw && c->w < c->minw)
c->w = c->minw;
if(c->minh && c->h < c->minh)
c->h = c->minh;
if(c->maxw && c->w > c->maxw)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
}
XFree(name.value);
resize_title(c);
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)
c->y = bottom - c->h;
resizetitle(c);
wc.x = c->x;
wc.y = c->y;
wc.width = c->w;
wc.height = c->h;
if(c->w == sw && c->h == sh)
wc.border_width = 0;
else
wc.border_width = 1;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
XSync(dpy, False);
}
void
update_size(Client *c)
setsize(Client *c)
{
XSizeHints size;
long msize;
XSizeHints size;
if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
size.flags = PSize;
c->flags = size.flags;
@ -304,313 +351,116 @@ update_size(Client *c)
}
void
craise(Client *c)
settitle(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
char **list = NULL;
int n;
XTextProperty name;
name.nitems = 0;
c->name[0] = 0;
XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
if(!name.nitems)
XGetWMName(dpy, c->win, &name);
if(!name.nitems)
return;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
}
XFree(name.value);
resizetitle(c);
}
void
lower(Client *c)
togglemax(Arg *arg)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
void
focus(Client *c)
{
Client *old = sel;
int ox, oy, ow, oh;
XEvent ev;
XFlush(dpy);
sel = c;
if(old && old != c)
draw_client(old);
draw_client(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XFlush(dpy);
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];
if(!sel)
return;
if((sel->ismax = !sel->ismax)) {
ox = sel->x;
oy = sel->y;
ow = sel->w;
oh = sel->h;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2;
sel->h = sh - 2 - bh;
restack();
resize(sel, arrange == dofloat, TopLeft);
sel->x = ox;
sel->y = oy;
sel->w = ow;
sel->h = oh;
}
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)
{
Client *c, **l;
XSetWindowAttributes twa;
Window trans;
c = emallocz(sizeof(Client));
c->win = w;
c->tx = c->x = wa->x;
c->ty = c->y = wa->y;
if(c->y < bh)
c->ty = c->y += bh;
c->tw = c->w = wa->width;
c->h = wa->height;
c->th = bh;
c->border = 1;
c->proto = win_proto(c->win);
update_size(c);
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans);
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask;
c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
update_name(c);
init_tags(c);
for(l = &clients; *l; l = &(*l)->next);
c->next = *l; /* *l == nil */
*l = c;
XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
if(!c->floating)
c->floating = trans
|| ((c->maxw == c->minw) && (c->maxh == c->minh));
arrange(NULL);
/* mapping the window now prevents flicker */
if(c->tags[tsel]) {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
focus(c);
}
else {
ban_client(c);
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
}
}
void
gravitate(Client *c, Bool invert)
{
int dx = 0, dy = 0;
switch(c->grav) {
case StaticGravity:
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
dy = c->border;
break;
case EastGravity:
case CenterGravity:
case WestGravity:
dy = -(c->h / 2) + c->border;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
dy = -c->h;
break;
default:
break;
}
switch (c->grav) {
case StaticGravity:
case NorthWestGravity:
case WestGravity:
case SouthWestGravity:
dx = c->border;
break;
case NorthGravity:
case CenterGravity:
case SouthGravity:
dx = -(c->w / 2) + c->border;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
dx = -(c->w + c->border);
break;
default:
break;
}
if(invert) {
dx = -dx;
dy = -dy;
}
c->x += dx;
c->y += dy;
}
void
resize(Client *c, Bool inc)
{
XConfigureEvent e;
if(inc) {
if(c->incw)
c->w -= (c->w - c->basew) % c->incw;
if(c->inch)
c->h -= (c->h - c->baseh) % c->inch;
}
if(c->x > sw) /* might happen on restart */
c->x = sw - c->w;
if(c->y > sh)
c->ty = c->y = sh - c->h;
if(c->minw && c->w < c->minw)
c->w = c->minw;
if(c->minh && c->h < c->minh)
c->h = c->minh;
if(c->maxw && c->w > c->maxw)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
resize_title(c);
XSetWindowBorderWidth(dpy, c->win, 1);
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
e.type = ConfigureNotify;
e.event = c->win;
e.window = c->win;
e.x = c->x;
e.y = c->y;
e.width = c->w;
e.height = c->h;
e.border_width = c->border;
e.above = None;
e.override_redirect = False;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
XFlush(dpy);
}
static int
dummy_error_handler(Display *dsply, XErrorEvent *err)
{
return 0;
else
resize(sel, False, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
unmanage(Client *c)
{
Client **l;
XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler);
XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title);
for(l = &clients; *l && *l != c; l = &(*l)->next);
*l = c->next;
for(l = &clients; *l; l = &(*l)->next)
if((*l)->revert == c)
(*l)->revert = NULL;
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 = sel->revert ? sel->revert : clients;
sel = getnext(clients);
free(c->tags);
free(c);
XFlush(dpy);
XSetErrorHandler(error_handler);
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
arrange(NULL);
if(sel)
focus(sel);
}
Client *
gettitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
arrange(NULL);
}
void
draw_client(Client *c)
zoom(Arg *arg)
{
int i;
if(c == sel) {
draw_bar();
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
Client *c;
if(!sel || (arrange != dotile) || sel->isfloat || sel->ismax)
return;
if(sel == getnext(clients)) {
if((c = getnext(sel->next)))
sel = c;
else
return;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]) + dc.font.height;
drawtext(c->tags[i], False, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name) + dc.font.height;
drawtext(c->name, False, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc,
0, 0, c->tw, c->th, 0, 0);
XFlush(dpy);
/* 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);
}

54
config.arg.h Normal file
View File

@ -0,0 +1,54 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "work", "net", "fnord", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 0 /* index */
#define FONT "-*-terminus-medium-*-*-*-12-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0d121d"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#3f484d"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
/* modifier key function arguments */ \
{ MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec urxvt +sb -tr -bg black -fg '#eeeeee' -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`" } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \
{ 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|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
{ MODKEY, XK_3, view, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
};
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
{ "Firefox.*", "net", False }, \
{ "Gimp.*", NULL, True}, \
{ "MPlayer.*", NULL, True}, \
{ "Acroread.*", NULL, True}, \
};

56
config.default.h Normal file
View File

@ -0,0 +1,56 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "0", "1", "2", "3", "4", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 1 /* index */
#define FONT "fixed"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
/* modifier key function arguments */ \
{ MODKEY|ShiftMask, XK_Return, spawn, { .cmd = "exec xterm" } }, \
{ MODKEY, XK_Tab, focusnext, { 0 } }, \
{ 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|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|ShiftMask, XK_q, quit, { 0 } }, \
};
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
{ "Firefox.*", "2", False }, \
{ "Gimp.*", NULL, True}, \
};

View File

@ -1,31 +1,25 @@
# Customize to fit your system
# dwm version
VERSION = 0.9
# Customize below to fit your system
# paths
PREFIX = /usr/local
CONFPREFIX = ${PREFIX}/etc
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
VERSION = 0.1
# includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11
INCS = -I/usr/lib -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
# Linux/BSD
CFLAGS = -Os -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
-DVERSION=\"${VERSION}\"
# flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
# -DVERSION=\"${VERSION}\"
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS}
# Solaris
#CFLAGS = -fast -xtarget=ultra ${INCLUDES} -DVERSION=\"${VERSION}\"
#LIBS += -lnsl -lsocket
AR = ar cr
# compiler and linker
CC = cc
RANLIB = ranlib
LD = ${CC}

151
dev.c
View File

@ -1,151 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/keysym.h>
/********** 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 };
static 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
update_keys(void)
{
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;
}
}
#define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
void
mresize(Client *c)
{
XEvent ev;
int ocx, ocy;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
switch(ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XFlush(dpy);
c->w = abs(ocx - ev.xmotion.x);
c->h = abs(ocy - ev.xmotion.y);
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
resize(c, True);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
void
mmove(Client *c)
{
XEvent ev;
int x1, y1, ocx, ocy, di;
unsigned int dui;
Window dummy;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
switch (ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XFlush(dpy);
c->x = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}

164
draw.c
View File

@ -2,18 +2,37 @@
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
#include <string.h>
#include <X11/Xlocale.h>
#include "dwm.h"
/* static */
static unsigned int
textnw(const char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
static void
drawborder(void)
drawtext(const char *text, Bool invert)
{
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);
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;
@ -27,28 +46,12 @@ drawborder(void)
points[4].x = 0;
points[4].y = -(dc.h - 1);
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious);
}
void
drawtext(const char *text, Bool invert, Bool border)
{
int x, y, w, h;
unsigned int len;
static char buf[256];
XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
XSetForeground(dpy, dc.gc, invert ? dc.fg : dc.bg);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
w = 0;
if(border)
drawborder();
if(!text)
return;
len = strlen(text);
w = 0;
olen = len = strlen(text);
if(len >= sizeof(buf))
len = sizeof(buf) - 1;
memcpy(buf, text, len);
@ -61,6 +64,14 @@ drawtext(const char *text, Bool invert, Bool border)
/* shorten text if necessary */
while(len && (w = textnw(buf, len)) > dc.w - h)
buf[--len] = 0;
if(len < olen) {
if(len > 1)
buf[len - 1] = '.';
if(len > 2)
buf[len - 2] = '.';
if(len > 3)
buf[len - 3] = '.';
}
if(w > dc.w)
return; /* too long */
@ -79,35 +90,94 @@ drawtext(const char *text, Bool invert, Bool border)
}
}
unsigned long
initcolor(const char *colstr)
/* extern */
void
drawall()
{
Client *c;
for(c = clients; c; c = getnext(c->next))
drawtitle(c);
drawstatus();
}
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]);
else
drawtext(tags[i], !seltag[i]);
}
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)) {
dc.x = x;
drawtext(sel->name, istile);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XSync(dpy, False);
}
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);
return;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
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);
XSync(dpy, False);
}
unsigned long
getcolor(const char *colstr)
{
XColor color;
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color);
return color.pixel;
}
unsigned int
textnw(char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
unsigned int
textw(char *text)
{
return textnw(text, strlen(text));
}
void
initfont(const char *fontstr)
setfont(const char *fontstr)
{
char **missing, *def;
int i, n;
@ -150,9 +220,15 @@ initfont(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;
}
dc.font.height = dc.font.ascent + dc.font.descent;
}
unsigned int
textw(const char *text)
{
return textnw(text, strlen(text)) + dc.font.height;
}

186
dwm.1
View File

@ -1,98 +1,148 @@
.TH DWM 1 dwm-0.1
.TH DWM 1 dwm-VERSION
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
.SS Overview
.B dwm
is a dynamic window manager for X11.
.SS Options
is a dynamic window manager for X11. 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
In tiling mode windows are managed in a master and stacking column. The master
column contains the window which currently needs most attention, whereas the
stacking column contains all other windows. In floating mode windows can be
resized and moved freely. Dialog windows are always managed floating,
regardless of the mode selected.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
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.
.SH OPTIONS
.TP
.B \-v
prints version information to stdout, then exits.
.SS Status text
.B dwm
reads from stdin to display status text if provided.
.SS Default Key Bindings
.TP 16
.I Key
.I Action
prints version information to standard output, then exits.
.SH USAGE
.SS Status bar
.TP
.B Mod1-Return
Zoom
.B window
to the
.B master
track
.B Standard input
is read and displayed in the status text area.
.TP
.B Mod1-k
Focus previous
.B window
.B Button1
click on a tag label views all windows with that
.BR tag .
.TP
.B Mod1-j
Focus next
.B window
.TP
.B Mod1-m
Maximize current
.B window
.TP
.B Mod1-[0..n]
Focus
.B nth
tag
.TP
.B Mod1-space
(Re-)arrange
.B all
windows tiled
.TP
.B Mod1-Shift-space
(Re-)arrange
.B all
windows floating
.TP
.B Mod1-Shift-[0..n]
Apply
.B nth
tag to current
.B window
.TP
.B Mod1-Shift-q
Quit
.B dwm
.B Button3
click on a tag label adds/removes all windows with that
.B tag
to/from the view.
.SS Keyboard commands
.TP
.B Mod1-Shift-Return
Start
.B terminal
.BR xterm (1).
.TP
.B Mod1-Shift-w
Start
.B web browser
.B Mod1-Tab
Focus next
.BR window .
.TP
.B Mod1-Shift-l
Lock
.B screen
.B Mod1-Shift-Tab
Focus previous
.BR window .
.TP
.B Control-[0..n]
Append
.B nth
tag to cureent
.B Mod1-Return
Zoom current
.B window
.SS Default Mouse Bindings
to the
.B master
column
.RB ( tiling
mode only).
.TP
.B Mod1-m
Maximize current
.BR window .
.TP
.B Mod1-Shift-[0..n]
Apply
.B nth tag
to current
.BR window .
.TP
.B Mod1-Control-Shift-[0..n]
Add/remove
.B nth tag
to/from current
.BR window .
.TP
.B Mod1-Shift-c
Close focused
.B window.
.TP
.B Mod1-space
Toggle between
.B tiled
and
.B floating
mode (affects
.BR "all windows" ).
.TP
.B Mod1-[0..n]
View all windows with
.BR "tag n" .
.TP
.B Mod1-Control-[0..n]
Add/remove all windows with
.B tag n
to/from the view.
.TP
.B Mod1-Shift-q
Quit
.B dwm.
.SS Mouse commands
.TP
.B Mod1-Button1
Moves current
Move current
.B window
while dragging
.RB ( floating
mode only).
.TP
.B Mod1-Button2
Lowers current
Zoom current
.B window
to the
.B master
column
.RB ( tiling
mode only).
.TP
.B Mod1-Button3
Resizes current
Resize current
.B window
while dragging
.RB ( floating
mode only).
.SH CUSTOMIZATION
.B dwm
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
.B broken pipe
when
.B dwm
has been started by
.BR xdm (1),
because it closes standard output before executing
.BR dwm .
.SH SEE ALSO
.BR dmenu (1)

169
dwm.h
View File

@ -3,153 +3,136 @@
* See LICENSE file for license details.
*/
#include "config.h"
#include <X11/Xlib.h>
/********** CUSTOMIZE **********/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
#define MASTERW 52 /* percent */
#define WM_PROTOCOL_DELWIN 1
/* tags */
enum { Tscratch, Tdev, Twww, Twork, TLast };
/********** CUSTOMIZE **********/
/* mask shorthands, used in event.c and client.c */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define PROTODELWIN 1
typedef union Arg Arg;
typedef struct DC DC;
typedef struct Client Client;
typedef struct DC DC;
typedef struct Fnt Fnt;
typedef struct Key Key;
typedef struct Rule Rule;
union Arg {
const char **argv;
const char *cmd;
int i;
};
/* atoms */
enum { WMProtocols, WMDelete, WMLast };
enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };
/* cursor */
enum { CurNormal, CurResize, CurMove, CurInput, CurLast };
enum { CurNormal, CurResize, CurMove, CurLast };
/* windowcorners */
typedef enum { TopLeft, TopRight, BotLeft, BotRight } Corner;
struct Fnt {
XFontStruct *xfont;
XFontSet set;
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
};
struct DC { /* draw context */
GC gc;
Drawable drawable;
int x, y, w, h;
Fnt font;
unsigned long bg;
unsigned long fg;
unsigned long border;
Drawable drawable;
Fnt font;
GC gc;
};
struct Client {
char name[256];
char *tags[TLast];
int proto;
int x, y, w, h;
int tx, ty, tw, th;
int tx, ty, tw, th; /* title */
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
unsigned int border;
long flags;
Bool floating;
unsigned int border;
Bool isfloat;
Bool ismax;
Bool *tags;
Client *next;
Client *prev;
Window win;
Window title;
Client *next;
Client *revert;
};
struct Rule {
const char *class;
const char *instance;
char *tags[TLast];
Bool floating;
};
struct Key {
unsigned long mod;
KeySym keysym;
void (*func)(Arg *arg);
Arg arg;
};
extern Display *dpy;
extern Window root, barwin;
extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
extern Bool running, issel;
extern const char *tags[];
extern char stext[1024];
extern int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern unsigned int ntags, numlockmask;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern char *tags[TLast], stext[1024];
extern DC dc;
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, *seltag;
extern Client *clients, *sel;
/* bar.c */
extern void draw_bar();
extern void barclick(XButtonPressedEvent *e);
extern Cursor cursor[CurLast];
extern DC dc;
extern Display *dpy;
extern Window root, barwin;
/* client.c */
extern void manage(Window w, XWindowAttributes *wa);
extern void unmanage(Client *c);
extern Client *getclient(Window w);
extern void ban(Client *c);
extern void focus(Client *c);
extern void update_name(Client *c);
extern void draw_client(Client *c);
extern void resize(Client *c, Bool inc);
extern void update_size(Client *c);
extern Client *gettitle(Window w);
extern void craise(Client *c);
extern void lower(Client *c);
extern void ckill(Arg *arg);
extern void nextc(Arg *arg);
extern void prevc(Arg *arg);
extern void max(Arg *arg);
extern void floating(Arg *arg);
extern void tiling(Arg *arg);
extern void ttrunc(Arg *arg);
extern void tappend(Arg *arg);
extern void view(Arg *arg);
extern void zoom(Arg *arg);
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);
extern void killclient(Arg *arg);
extern void manage(Window w, XWindowAttributes *wa);
extern void resize(Client *c, Bool sizehints, Corner sticky);
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 drawtext(const char *text, Bool invert, Bool border);
extern unsigned long initcolor(const char *colstr);
extern void initfont(const char *fontstr);
extern unsigned int textnw(char *text, unsigned int len);
extern unsigned int textw(char *text);
extern unsigned int texth(void);
extern void drawall();
extern void drawstatus();
extern void drawtitle(Client *c);
extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(const char *text);
/* dev.c */
extern void update_keys(void);
extern void keypress(XEvent *e);
extern void mresize(Client *c);
extern void mmove(Client *c);
/* event.c */
extern void grabkeys();
extern void procevent();
/* main.c */
extern int error_handler(Display *dsply, XErrorEvent *e);
extern void send_message(Window w, Atom a, long value);
extern int win_proto(Window w);
extern int getproto(Window w);
extern void quit(Arg *arg);
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 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 error(const char *errstr, ...);
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);

111
dwm.html
View File

@ -4,6 +4,7 @@
<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;
@ -21,86 +22,106 @@
<p>
dwm is a dynamic window manager for X11.
</p>
<h3>Philosophy</h3>
<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.
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>
<h3>Differences to wmii</h3
<h4>Differences to ion, larswm, and wmii</h4>
<p>
In contrast to wmii, dwm is only a window manager, and nothing else.
Hence, it is much smaller, faster and simpler.
In contrast to ion, larswm, and wmii, dwm is much smaller, faster and simpler.
</p>
<ul>
<li>
dwm has no 9P support, no menu, no editable tagbars,
no shell-based configuration and remote control and comes without
any additional tools like printing the selection or warping the
mouse.
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.
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>
dwm is based on tagging and dynamic window management (however simpler
than wmii or larswm).
</li>
<li>
dwm don't distinguishes between layers, there is no floating or
managed layer. Wether the clients of currently selected tag are
managed or not, you can re-arrange all clients on the fly. Popup-
and fixed-size windows are treated unmanaged.
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.
estate to clients. Small titlebars are only drawn in front of
unfocused clients.
</li>
<li>
dwm reads from <b>stdin</b> to print arbitrary status text (like the
date, load, battery charge). That's much simpler than larsremote,
wmiir and what not...
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>
garbeam <b>does not</b> want any feedback to dwm. If you ask for support,
feature requests, or if you report bugs, they will be <b>ignored</b>
with a high chance. dwm is only intended to fit garbeams needs.
However you are free to download and distribute/relicense it, with the
conditions of the <a href="http://wmii.de/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
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>
<h3>Screenshot</h3>
<p>
<a href="http://wmii.de/shots/dwm-20060714.png">Click here for a screenshot</a> (20060714)
</p>
<h3>Development</h3>
<p>
dwm is actively developed in parallel to wmii. You can <a href="http://wmii.de/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://wmii.de/cgi-bin/hgwebdir.cgi/dwm</code>
</p>
<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://wmii.de/download/dwm-0.1.tar.gz">dwm 0.1</a> (12kb) (20060714)</li>
<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 garbeam.
if you like dwm and the dwm logo, which has been designed by Anselm.
</p>
<p><small>--Anselm (20060714)</small></p>
<p><small>--Anselm</small></p>
</body>
</html>

BIN
dwm.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 373 B

345
event.c
View File

@ -2,63 +2,140 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include <fcntl.h>
#include <stdio.h>
#include "dwm.h"
#include <stdlib.h>
#include <string.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include "dwm.h"
/* static */
/* local functions */
static void buttonpress(XEvent *e);
static void configurerequest(XEvent *e);
static void destroynotify(XEvent *e);
static void enternotify(XEvent *e);
static void leavenotify(XEvent *e);
static void expose(XEvent *e);
static void keymapnotify(XEvent *e);
static void maprequest(XEvent *e);
static void propertynotify(XEvent *e);
static void unmapnotify(XEvent *e);
typedef struct {
unsigned long mod;
KeySym keysym;
void (*func)(Arg *arg);
Arg arg;
} Key;
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[LeaveNotify] = leavenotify,
[Expose] = expose,
[KeyPress] = keypress,
[KeymapNotify] = keymapnotify,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
KEYS
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
static void
movemouse(Client *c)
{
int x1, y1, ocx, ocy, di;
unsigned int dui;
Window dummy;
XEvent ev;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch (ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
c->x = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False, TopLeft);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
resizemouse(Client *c)
{
int ocx, ocy;
int nw, nh;
Corner sticky;
XEvent ev;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch(ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
if((nw = abs(ocx - ev.xmotion.x)))
c->w = abs(ocx - ev.xmotion.x);
if((nh = abs(ocy - ev.xmotion.y)))
c->h = abs(ocy - ev.xmotion.y);
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
else
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
buttonpress(XEvent *e)
{
XButtonPressedEvent *ev = &e->xbutton;
int x;
Arg a;
Client *c;
XButtonPressedEvent *ev = &e->xbutton;
if(barwin == ev->window)
barclick(ev);
if(barwin == ev->window) {
x = 0;
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);
return;
}
}
}
else if((c = getclient(ev->window))) {
craise(c);
focus(c);
switch(ev->button) {
default:
break;
case Button1:
mmove(c);
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
restack(c);
movemouse(c);
}
break;
case Button2:
lower(c);
zoom(NULL);
break;
case Button3:
mresize(c);
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
restack(c);
resizemouse(c);
}
break;
}
}
@ -67,11 +144,12 @@ buttonpress(XEvent *e)
static void
configurerequest(XEvent *e)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
unsigned long newmask;
Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XEvent synev;
XWindowChanges wc;
ev->value_mask &= ~CWSibling;
if((c = getclient(ev->window))) {
gravitate(c, True);
if(ev->value_mask & CWX)
@ -83,22 +161,46 @@ configurerequest(XEvent *e)
if(ev->value_mask & CWHeight)
c->h = ev->height;
if(ev->value_mask & CWBorderWidth)
c->border = 1;
c->border = ev->border_width;
gravitate(c, False);
resize(c, True);
wc.x = c->x;
wc.y = c->y;
wc.width = c->w;
wc.height = c->h;
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);
}
XSync(dpy, False);
if(c->isfloat)
resize(c, False, TopLeft);
else
arrange(NULL);
}
else {
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.border_width = ev->border_width;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XSync(dpy, False);
}
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.border_width = 1;
wc.sibling = None;
wc.stack_mode = Above;
ev->value_mask &= ~CWStackMode;
ev->value_mask |= CWBorderWidth;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XFlush(dpy);
}
static void
@ -114,16 +216,53 @@ destroynotify(XEvent *e)
static void
enternotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
Client *c;
XCrossingEvent *ev = &e->xcrossing;
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return;
if((c = getclient(ev->window)))
if((c = getclient(ev->window)) || (c = getctitle(ev->window)))
focus(c);
else if(ev->window == root)
else if(ev->window == root) {
issel = True;
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
drawall();
}
}
static void
expose(XEvent *e)
{
Client *c;
XExposeEvent *ev = &e->xexpose;
if(ev->count == 0) {
if(barwin == ev->window)
drawstatus();
else if((c = getctitle(ev->window)))
drawtitle(c);
}
}
static void
keypress(XEvent *e)
{
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeySym keysym;
XKeyEvent *ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++) {
if(keysym == key[i].keysym &&
CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
{
if(key[i].func)
key[i].func(&key[i].arg);
return;
}
}
}
static void
@ -131,33 +270,27 @@ leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
}
static void
expose(XEvent *e)
{
XExposeEvent *ev = &e->xexpose;
Client *c;
if(ev->count == 0) {
if((c = gettitle(ev->window)))
draw_client(c);
if((ev->window == root) && !ev->same_screen) {
issel = False;
drawall();
}
}
static void
keymapnotify(XEvent *e)
mappingnotify(XEvent *e)
{
update_keys();
XMappingEvent *ev = &e->xmapping;
XRefreshKeyboardMapping(ev);
if(ev->request == MappingKeyboard)
grabkeys();
}
static void
maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
@ -175,32 +308,32 @@ maprequest(XEvent *e)
static void
propertynotify(XEvent *e)
{
XPropertyEvent *ev = &e->xproperty;
Window trans;
Client *c;
Window trans;
XPropertyEvent *ev = &e->xproperty;
if(ev->state == PropertyDelete)
return; /* ignore */
if((c = getclient(ev->window))) {
if(ev->atom == wm_atom[WMProtocols]) {
c->proto = win_proto(c->win);
if(ev->atom == wmatom[WMProtocols]) {
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->isfloat && (c->isfloat = (trans != 0)))
arrange(NULL);
break;
case XA_WM_NORMAL_HINTS:
update_size(c);
setsize(c);
break;
}
if(ev->atom == XA_WM_NAME || ev->atom == net_atom[NetWMName]) {
update_name(c);
draw_client(c);
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
settitle(c);
drawtitle(c);
}
}
}
@ -214,3 +347,53 @@ unmapnotify(XEvent *e)
if((c = getclient(ev->window)))
unmanage(c);
}
/* extern */
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[LeaveNotify] = leavenotify,
[Expose] = expose,
[KeyPress] = keypress,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
void
grabkeys()
{
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeyCode code;
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for(i = 0; i < len; i++) {
code = XKeysymToKeycode(dpy, key[i].keysym);
XGrabKey(dpy, code, key[i].mod, root, True,
GrabModeAsync, GrabModeAsync);
XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
GrabModeAsync, GrabModeAsync);
XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
GrabModeAsync, GrabModeAsync);
XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
GrabModeAsync, GrabModeAsync);
}
}
void
procevent()
{
XEvent ev;
while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
}

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

337
main.c
View File

@ -3,62 +3,50 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include "dwm.h"
/* static */
/********** CUSTOMIZE **********/
char *tags[TLast] = {
[Tscratch] = "scratch",
[Tdev] = "dev",
[Twww] = "www",
[Twork] = "work",
};
/********** CUSTOMIZE **********/
/* X structs */
Display *dpy;
Window root, barwin;
Atom wm_atom[WMLast], net_atom[NetLast];
Cursor cursor[CurLast];
Bool running = True;
Bool issel;
int tsel = Tdev; /* default tag */
int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
char stext[1024];
DC dc = {0};
Client *clients = NULL;
Client *sel = NULL;
static Bool other_wm_running;
static const char version[] =
"dwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
static int (*x_error_handler) (Display *, XErrorEvent *);
static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm;
static void
usage() { error("usage: dwm [-v]\n"); }
cleanup()
{
while(sel) {
resize(sel, True, TopLeft);
unmanage(sel);
}
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
else
XFreeFont(dpy, dc.font.xfont);
XUngrabKey(dpy, AnyKey, AnyModifier, root);
XDestroyWindow(dpy, barwin);
XFreePixmap(dpy, dc.drawable);
XFreeGC(dpy, dc.gc);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XSync(dpy, False);
}
static void
scan_wins()
scan()
{
unsigned int i, num;
Window *wins;
Window *wins, d1, d2;
XWindowAttributes wa;
Window d1, d2;
wins = NULL;
if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
for(i = 0; i < num; i++) {
if(!XGetWindowAttributes(dpy, wins[i], &wa))
@ -76,10 +64,9 @@ scan_wins()
static int
win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
{
Atom real;
int format;
int status, format;
unsigned long res, extra;
int status;
Atom real;
status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
&res, &extra, prop);
@ -93,28 +80,56 @@ win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
return res;
}
int
win_proto(Window w)
/*
* 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)
{
unsigned char *protocols;
long res;
int protos = 0;
int i;
long res;
Atom *protocols;
res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &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] == wm_atom[WMDelete])
protos |= WM_PROTOCOL_DELWIN;
if(protocols[i] == wmatom[WMDelete])
protos |= PROTODELWIN;
}
free((char *) protocols);
return protos;
}
void
send_message(Window w, Atom a, long value)
sendevent(Window w, Atom a, long value)
{
XEvent e;
@ -125,56 +140,7 @@ send_message(Window w, Atom a, long value)
e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e);
XFlush(dpy);
}
/*
* 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
error_handler(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_error_handler(dpy, error); /* may call exit() */
}
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int
startup_error_handler(Display *dpy, XErrorEvent *error)
{
other_wm_running = True;
return -1;
}
static void
cleanup()
{
while(sel) {
resize(sel, True);
unmanage(sel);
}
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XSync(dpy, False);
}
void
@ -183,82 +149,117 @@ 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, n;
fd_set rd;
XSetWindowAttributes wa;
int i, j, xfd;
unsigned int mask;
Bool readstdin = True;
fd_set rd;
Bool readin = True;
Window w;
XEvent ev;
XModifierKeymap *modmap;
XSetWindowAttributes wa;
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) {
case 'v':
fprintf(stdout, "%s", version);
exit(0);
break;
default:
usage();
break;
}
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)
error("dwm: cannot connect X server\n");
eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
/* check if another WM is already running */
other_wm_running = False;
XSetErrorHandler(startup_error_handler);
/* this causes an error if some other WM is running */
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other window manager is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XFlush(dpy);
XSync(dpy, False);
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_error_handler = XSetErrorHandler(error_handler);
XSync(dpy, False);
XSetErrorHandler(NULL);
xerrorxlib = XSetErrorHandler(xerror);
XSync(dpy, False);
/* init atoms */
wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) net_atom, NetLast);
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
/* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
update_keys();
modmap = XGetModifierMapping(dpy);
for (i = 0; i < 8; i++) {
for (j = 0; j < modmap->max_keypermod; j++) {
if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i);
}
}
XFree(modmap);
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask;
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
grabkeys();
initrregs();
for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags);
seltag[DEFTAG] = True;
/* style */
dc.bg = initcolor(BGCOLOR);
dc.fg = initcolor(FGCOLOR);
dc.border = initcolor(BORDERCOLOR);
initfont(FONT);
dc.bg = getcolor(BGCOLOR);
dc.fg = getcolor(FGCOLOR);
dc.border = getcolor(BORDERCOLOR);
setfont(FONT);
sx = sy = 0;
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
mw = (sw * MASTERW) / 100;
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask | ExposureMask;
bx = by = 0;
bw = sw;
dc.h = bh = dc.font.height + 4;
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask | ExposureMask;
barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
@ -267,59 +268,39 @@ main(int argc, char *argv[])
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
draw_bar();
strcpy(stext, "dwm-"VERSION);
drawstatus();
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
| LeaveWindowMask;
wa.cursor = cursor[CurNormal];
scan();
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
strcpy(stext, "dwm-"VERSION);
scan_wins();
/* main event loop, reads status text from stdin as well */
Mainloop:
/* main event loop, also reads status text from stdin */
XSync(dpy, False);
procevent();
while(running) {
FD_ZERO(&rd);
if(readstdin)
if(readin)
FD_SET(STDIN_FILENO, &rd);
FD_SET(ConnectionNumber(dpy), &rd);
i = select(ConnectionNumber(dpy) + 1, &rd, 0, 0, 0);
FD_SET(xfd, &rd);
i = select(xfd + 1, &rd, NULL, NULL, NULL);
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)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
}
if(readstdin && FD_ISSET(STDIN_FILENO, &rd)) {
i = n = 0;
for(;;) {
if((i = getchar()) == EOF) {
/* broken pipe/end of producer */
readstdin = False;
strcpy(stext, "broken pipe");
goto Mainloop;
}
if(i == '\n' || n >= sizeof(stext) - 1)
break;
stext[n++] = i;
}
stext[n] = 0;
draw_bar();
if(readin && FD_ISSET(STDIN_FILENO, &rd)) {
readin = NULL != fgets(stext, sizeof(stext), stdin);
if(readin)
stext[strlen(stext) - 1] = 0;
else
strcpy(stext, "broken pipe");
drawstatus();
}
}
procevent();
}
cleanup();
XCloseDisplay(dpy);

326
tag.c Normal file
View File

@ -0,0 +1,326 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xutil.h>
typedef struct {
const char *clpattern;
const char *tpattern;
Bool isfloat;
} Rule;
typedef struct {
regex_t *clregex;
regex_t *tregex;
} RReg;
/* static */
TAGS
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)
{
for(; c && !isvisible(c); c = c->next);
return c;
}
Client *
getprev(Client *c)
{
for(; c && !isvisible(c); c = c->prev);
return c;
}
void
initrregs()
{
unsigned int i;
regex_t *reg;
if(rreg)
return;
len = sizeof(rule) / sizeof(rule[0]);
rreg = emallocz(len * sizeof(RReg));
for(i = 0; i < len; i++) {
if(rule[i].clpattern) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].clpattern, 0))
free(reg);
else
rreg[i].clregex = reg;
}
if(rule[i].tpattern) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].tpattern, 0))
free(reg);
else
rreg[i].tregex = reg;
}
}
}
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()
{
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];
unsigned int i, j;
regmatch_t tmp;
Bool matched = False;
XClassHint ch;
if(XGetClassHint(dpy, c->win, &ch)) {
snprintf(classinst, sizeof(classinst), "%s:%s",
ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "");
for(i = 0; !matched && i < len; i++)
if(rreg[i].clregex && !regexec(rreg[i].clregex, classinst, 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)) {
matched = True;
c->tags[j] = True;
}
}
}
if(ch.res_class)
XFree(ch.res_class);
if(ch.res_name)
XFree(ch.res_name);
}
if(!matched)
for(i = 0; i < ntags; i++)
c->tags[i] = seltag[i];
}
void
tag(Arg *arg)
{
unsigned int i;
if(!sel)
return;
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;
arrange(NULL);
}
void
toggletag(Arg *arg)
{
unsigned int i;
if(!sel)
return;
sel->tags[arg->i] = !sel->tags[arg->i];
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;
arrange(NULL);
}

55
util.c
View File

@ -2,37 +2,48 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "dwm.h"
void
error(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
/* static */
static void
bad_malloc(unsigned int size)
{
fprintf(stderr, "fatal: could not malloc() %d bytes\n",
(int) size);
exit(1);
eprint("fatal: could not malloc() %u bytes\n", size);
}
/* extern */
void *
emallocz(unsigned int size)
{
void *res = calloc(1, size);
if(!res)
bad_malloc(size);
return res;
}
void
eprint(const char *errstr, ...)
{
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
void *
erealloc(void *ptr, unsigned int size)
{
void *res = realloc(ptr, size);
if(!res)
bad_malloc(size);
return res;
@ -41,19 +52,23 @@ emallocz(unsigned int size)
void
spawn(Arg *arg)
{
char **argv = (char **)arg->argv;
if(!argv || !argv[0])
static char *shell = NULL;
if(!shell && !(shell = getenv("SHELL")))
shell = "/bin/sh";
if(!arg->cmd)
return;
if(fork() == 0) {
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(argv[0], argv);
fprintf(stderr, "dwm: execvp %s", argv[0]);
execl(shell, shell, "-c", arg->cmd, NULL);
fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg->cmd);
perror(" failed");
}
exit (0);
exit(0);
}
wait(0);
}