Mercurial > hg > index.fcgi > dwm > dwm-3.6.1-11pba
comparison main.c @ 1:ba504f41828f
add prev/next control to view_tags() and setlayouts()
author | paulo@localhost |
---|---|
date | Mon, 23 Mar 2009 00:14:48 -0700 |
parents | |
children | faa4cb9d7bd6 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8f2deb0d9790 |
---|---|
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> | |
2 * See LICENSE file for license details. | |
3 */ | |
4 | |
5 #include "dwm.h" | |
6 #include <errno.h> | |
7 #include <locale.h> | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 #include <unistd.h> | |
12 #include <sys/select.h> | |
13 #include <X11/cursorfont.h> | |
14 #include <X11/keysym.h> | |
15 #include <X11/Xatom.h> | |
16 #include <X11/Xproto.h> | |
17 | |
18 /* extern */ | |
19 | |
20 char stext[256]; | |
21 int screen, sx, sy, sw, sh, wax, way, waw, wah; | |
22 unsigned int bh, ntags, numlockmask; | |
23 Atom wmatom[WMLast], netatom[NetLast]; | |
24 Bool *seltag; | |
25 Bool selscreen = True; | |
26 Client *clients = NULL; | |
27 Client *sel = NULL; | |
28 Client *stack = NULL; | |
29 Cursor cursor[CurLast]; | |
30 Display *dpy; | |
31 DC dc = {0}; | |
32 Window root, barwin; | |
33 | |
34 /* static */ | |
35 | |
36 static int (*xerrorxlib)(Display *, XErrorEvent *); | |
37 static Bool otherwm, readin; | |
38 static Bool running = True; | |
39 | |
40 static void | |
41 cleanup(void) { | |
42 close(STDIN_FILENO); | |
43 while(stack) { | |
44 if(stack->isbanned) | |
45 XMoveWindow(dpy, stack->win, stack->x, stack->y); | |
46 unmanage(stack); | |
47 } | |
48 if(dc.font.set) | |
49 XFreeFontSet(dpy, dc.font.set); | |
50 else | |
51 XFreeFont(dpy, dc.font.xfont); | |
52 XUngrabKey(dpy, AnyKey, AnyModifier, root); | |
53 XFreePixmap(dpy, dc.drawable); | |
54 XFreeGC(dpy, dc.gc); | |
55 XDestroyWindow(dpy, barwin); | |
56 XFreeCursor(dpy, cursor[CurNormal]); | |
57 XFreeCursor(dpy, cursor[CurResize]); | |
58 XFreeCursor(dpy, cursor[CurMove]); | |
59 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); | |
60 XSync(dpy, False); | |
61 free(seltag); | |
62 } | |
63 | |
64 static unsigned long | |
65 initcolor(const char *colstr) { | |
66 Colormap cmap = DefaultColormap(dpy, screen); | |
67 XColor color; | |
68 | |
69 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | |
70 eprint("error, cannot allocate color '%s'\n", colstr); | |
71 return color.pixel; | |
72 } | |
73 | |
74 static void | |
75 initfont(const char *fontstr) { | |
76 char *def, **missing; | |
77 int i, n; | |
78 | |
79 missing = NULL; | |
80 if(dc.font.set) | |
81 XFreeFontSet(dpy, dc.font.set); | |
82 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); | |
83 if(missing) { | |
84 while(n--) | |
85 fprintf(stderr, "missing fontset: %s\n", missing[n]); | |
86 XFreeStringList(missing); | |
87 } | |
88 if(dc.font.set) { | |
89 XFontSetExtents *font_extents; | |
90 XFontStruct **xfonts; | |
91 char **font_names; | |
92 dc.font.ascent = dc.font.descent = 0; | |
93 font_extents = XExtentsOfFontSet(dc.font.set); | |
94 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); | |
95 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { | |
96 if(dc.font.ascent < (*xfonts)->ascent) | |
97 dc.font.ascent = (*xfonts)->ascent; | |
98 if(dc.font.descent < (*xfonts)->descent) | |
99 dc.font.descent = (*xfonts)->descent; | |
100 xfonts++; | |
101 } | |
102 } | |
103 else { | |
104 if(dc.font.xfont) | |
105 XFreeFont(dpy, dc.font.xfont); | |
106 dc.font.xfont = NULL; | |
107 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) | |
108 eprint("error, cannot load font: '%s'\n", fontstr); | |
109 dc.font.ascent = dc.font.xfont->ascent; | |
110 dc.font.descent = dc.font.xfont->descent; | |
111 } | |
112 dc.font.height = dc.font.ascent + dc.font.descent; | |
113 } | |
114 | |
115 static void | |
116 scan(void) { | |
117 unsigned int i, num; | |
118 Window *wins, d1, d2; | |
119 XWindowAttributes wa; | |
120 | |
121 wins = NULL; | |
122 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { | |
123 for(i = 0; i < num; i++) { | |
124 if(!XGetWindowAttributes(dpy, wins[i], &wa) | |
125 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) | |
126 continue; | |
127 if(wa.map_state == IsViewable) | |
128 manage(wins[i], &wa); | |
129 } | |
130 } | |
131 if(wins) | |
132 XFree(wins); | |
133 } | |
134 | |
135 static void | |
136 setup(void) { | |
137 int i, j; | |
138 unsigned int mask; | |
139 Window w; | |
140 XModifierKeymap *modmap; | |
141 XSetWindowAttributes wa; | |
142 | |
143 /* init atoms */ | |
144 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); | |
145 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); | |
146 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); | |
147 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); | |
148 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | |
149 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, | |
150 PropModeReplace, (unsigned char *) netatom, NetLast); | |
151 /* init cursors */ | |
152 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); | |
153 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); | |
154 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); | |
155 /* init modifier map */ | |
156 numlockmask = 0; | |
157 modmap = XGetModifierMapping(dpy); | |
158 for (i = 0; i < 8; i++) | |
159 for (j = 0; j < modmap->max_keypermod; j++) { | |
160 if(modmap->modifiermap[i * modmap->max_keypermod + j] | |
161 == XKeysymToKeycode(dpy, XK_Num_Lock)) | |
162 numlockmask = (1 << i); | |
163 } | |
164 XFreeModifiermap(modmap); | |
165 /* select for events */ | |
166 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | |
167 | EnterWindowMask | LeaveWindowMask; | |
168 wa.cursor = cursor[CurNormal]; | |
169 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); | |
170 grabkeys(); | |
171 compileregs(); | |
172 for(ntags = 0; tags[ntags]; ntags++); | |
173 seltag = emallocz(sizeof(Bool) * ntags); | |
174 seltag[0] = True; | |
175 /* style */ | |
176 dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR); | |
177 dc.norm[ColBG] = initcolor(NORMBGCOLOR); | |
178 dc.norm[ColFG] = initcolor(NORMFGCOLOR); | |
179 dc.sel[ColBorder] = initcolor(SELBORDERCOLOR); | |
180 dc.sel[ColBG] = initcolor(SELBGCOLOR); | |
181 dc.sel[ColFG] = initcolor(SELFGCOLOR); | |
182 initfont(FONT); | |
183 /* geometry */ | |
184 sx = sy = 0; | |
185 sw = DisplayWidth(dpy, screen); | |
186 sh = DisplayHeight(dpy, screen); | |
187 initlayouts(); | |
188 /* bar */ | |
189 dc.h = bh = dc.font.height + 2; | |
190 wa.override_redirect = 1; | |
191 wa.background_pixmap = ParentRelative; | |
192 wa.event_mask = ButtonPressMask | ExposureMask; | |
193 barwin = XCreateWindow(dpy, root, sx, sy + (TOPBAR ? 0 : sh - bh), sw, bh, 0, | |
194 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), | |
195 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | |
196 XDefineCursor(dpy, barwin, cursor[CurNormal]); | |
197 XMapRaised(dpy, barwin); | |
198 strcpy(stext, "dwm-"VERSION); | |
199 /* windowarea */ | |
200 wax = sx; | |
201 way = sy + (TOPBAR ? bh : 0); | |
202 wah = sh - bh; | |
203 waw = sw; | |
204 /* pixmap for everything */ | |
205 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); | |
206 dc.gc = XCreateGC(dpy, root, 0, 0); | |
207 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); | |
208 /* multihead support */ | |
209 selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); | |
210 } | |
211 | |
212 /* | |
213 * Startup Error handler to check if another window manager | |
214 * is already running. | |
215 */ | |
216 static int | |
217 xerrorstart(Display *dsply, XErrorEvent *ee) { | |
218 otherwm = True; | |
219 return -1; | |
220 } | |
221 | |
222 /* extern */ | |
223 | |
224 void | |
225 sendevent(Window w, Atom a, long value) { | |
226 XEvent e; | |
227 | |
228 e.type = ClientMessage; | |
229 e.xclient.window = w; | |
230 e.xclient.message_type = a; | |
231 e.xclient.format = 32; | |
232 e.xclient.data.l[0] = value; | |
233 e.xclient.data.l[1] = CurrentTime; | |
234 XSendEvent(dpy, w, False, NoEventMask, &e); | |
235 XSync(dpy, False); | |
236 } | |
237 | |
238 void | |
239 quit(Arg *arg) { | |
240 readin = running = False; | |
241 } | |
242 | |
243 /* There's no way to check accesses to destroyed windows, thus those cases are | |
244 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs | |
245 * default error handler, which may call exit. | |
246 */ | |
247 int | |
248 xerror(Display *dpy, XErrorEvent *ee) { | |
249 if(ee->error_code == BadWindow | |
250 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) | |
251 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) | |
252 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) | |
253 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) | |
254 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) | |
255 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) | |
256 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) | |
257 return 0; | |
258 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", | |
259 ee->request_code, ee->error_code); | |
260 return xerrorxlib(dpy, ee); /* may call exit */ | |
261 } | |
262 | |
263 int | |
264 main(int argc, char *argv[]) { | |
265 char *p; | |
266 int r, xfd; | |
267 fd_set rd; | |
268 XEvent ev; | |
269 | |
270 if(argc == 2 && !strncmp("-v", argv[1], 3)) | |
271 eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n"); | |
272 else if(argc != 1) | |
273 eprint("usage: dwm [-v]\n"); | |
274 setlocale(LC_CTYPE, ""); | |
275 if(!(dpy = XOpenDisplay(0))) | |
276 eprint("dwm: cannot open display\n"); | |
277 xfd = ConnectionNumber(dpy); | |
278 screen = DefaultScreen(dpy); | |
279 root = RootWindow(dpy, screen); | |
280 otherwm = False; | |
281 XSetErrorHandler(xerrorstart); | |
282 /* this causes an error if some other window manager is running */ | |
283 XSelectInput(dpy, root, SubstructureRedirectMask); | |
284 XSync(dpy, False); | |
285 if(otherwm) | |
286 eprint("dwm: another window manager is already running\n"); | |
287 | |
288 XSync(dpy, False); | |
289 XSetErrorHandler(NULL); | |
290 xerrorxlib = XSetErrorHandler(xerror); | |
291 XSync(dpy, False); | |
292 setup(); | |
293 drawstatus(); | |
294 scan(); | |
295 | |
296 /* main event loop, also reads status text from stdin */ | |
297 XSync(dpy, False); | |
298 readin = True; | |
299 while(running) { | |
300 FD_ZERO(&rd); | |
301 if(readin) | |
302 FD_SET(STDIN_FILENO, &rd); | |
303 FD_SET(xfd, &rd); | |
304 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { | |
305 if(errno == EINTR) | |
306 continue; | |
307 eprint("select failed\n"); | |
308 } | |
309 if(FD_ISSET(STDIN_FILENO, &rd)) { | |
310 switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { | |
311 case -1: | |
312 strncpy(stext, strerror(errno), sizeof stext - 1); | |
313 stext[sizeof stext - 1] = '\0'; | |
314 readin = False; | |
315 break; | |
316 case 0: | |
317 strncpy(stext, "EOF", 4); | |
318 readin = False; | |
319 break; | |
320 default: | |
321 for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); | |
322 for(; p >= stext && *p != '\n'; --p); | |
323 if(p > stext) | |
324 strncpy(stext, p + 1, sizeof stext); | |
325 } | |
326 drawstatus(); | |
327 } | |
328 if(FD_ISSET(xfd, &rd)) | |
329 while(XPending(dpy)) { | |
330 XNextEvent(dpy, &ev); | |
331 if(handler[ev.type]) | |
332 (handler[ev.type])(&ev); /* call handler */ | |
333 } | |
334 } | |
335 cleanup(); | |
336 XCloseDisplay(dpy); | |
337 return 0; | |
338 } |