dwm-meillo

annotate main.c @ 79:aabebd6e61f3

fixed XSync handling and finished man page
author Anselm R. Garbe <garbeam@wmii.de>
date Sat, 15 Jul 2006 18:51:44 +0200
parents 0d71fb80b592
children 052fe7498930
rev   line source
garbeam@0 1 /*
garbeam@0 2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
garbeam@0 3 * See LICENSE file for license details.
garbeam@0 4 */
garbeam@0 5
garbeam@76 6 #include "dwm.h"
garbeam@76 7
garbeam@59 8 #include <errno.h>
garbeam@0 9 #include <stdio.h>
garbeam@0 10 #include <stdlib.h>
garbeam@57 11 #include <string.h>
garbeam@59 12 #include <unistd.h>
garbeam@0 13 #include <X11/cursorfont.h>
garbeam@0 14 #include <X11/Xatom.h>
garbeam@0 15 #include <X11/Xproto.h>
garbeam@0 16
garbeam@0 17 Display *dpy;
garbeam@5 18 Window root, barwin;
garbeam@77 19 Atom wmatom[WMLast], netatom[NetLast];
garbeam@0 20 Cursor cursor[CurLast];
garbeam@5 21 Bool running = True;
garbeam@77 22 Bool issel = True;
garbeam@3 23
garbeam@31 24 int tsel = Tdev; /* default tag */
garbeam@57 25 int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
garbeam@57 26 char stext[1024];
garbeam@3 27
garbeam@34 28 DC dc = {0};
garbeam@50 29 Client *clients = NULL;
garbeam@50 30 Client *sel = NULL;
garbeam@0 31
garbeam@75 32 static Bool otherwm;
garbeam@75 33 static int (*xerrorxlib)(Display *, XErrorEvent *);
garbeam@0 34
garbeam@76 35 /* static functions */
garbeam@76 36
garbeam@0 37 static void
garbeam@76 38 cleanup()
garbeam@76 39 {
garbeam@76 40 while(sel) {
garbeam@76 41 resize(sel, True);
garbeam@76 42 unmanage(sel);
garbeam@76 43 }
garbeam@76 44 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
garbeam@76 45 }
garbeam@0 46
garbeam@0 47 static void
garbeam@75 48 scan()
garbeam@0 49 {
garbeam@0 50 unsigned int i, num;
garbeam@0 51 Window *wins;
garbeam@0 52 XWindowAttributes wa;
garbeam@0 53 Window d1, d2;
garbeam@0 54
garbeam@0 55 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
garbeam@0 56 for(i = 0; i < num; i++) {
garbeam@0 57 if(!XGetWindowAttributes(dpy, wins[i], &wa))
garbeam@0 58 continue;
garbeam@0 59 if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
garbeam@0 60 continue;
garbeam@0 61 if(wa.map_state == IsViewable)
garbeam@10 62 manage(wins[i], &wa);
garbeam@0 63 }
garbeam@0 64 }
garbeam@0 65 if(wins)
garbeam@0 66 XFree(wins);
garbeam@0 67 }
garbeam@0 68
garbeam@13 69 static int
garbeam@13 70 win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
garbeam@13 71 {
garbeam@13 72 Atom real;
garbeam@13 73 int format;
garbeam@13 74 unsigned long res, extra;
garbeam@13 75 int status;
garbeam@13 76
garbeam@13 77 status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
garbeam@13 78 &res, &extra, prop);
garbeam@13 79
garbeam@13 80 if(status != Success || *prop == 0) {
garbeam@13 81 return 0;
garbeam@13 82 }
garbeam@13 83 if(res == 0) {
garbeam@13 84 free((void *) *prop);
garbeam@13 85 }
garbeam@13 86 return res;
garbeam@13 87 }
garbeam@13 88
garbeam@76 89 /*
garbeam@76 90 * Startup Error handler to check if another window manager
garbeam@76 91 * is already running.
garbeam@76 92 */
garbeam@76 93 static int
garbeam@76 94 xerrorstart(Display *dsply, XErrorEvent *ee)
garbeam@76 95 {
garbeam@76 96 otherwm = True;
garbeam@76 97 return -1;
garbeam@76 98 }
garbeam@76 99
garbeam@76 100 /* extern functions */
garbeam@76 101
garbeam@13 102 int
garbeam@75 103 getproto(Window w)
garbeam@13 104 {
garbeam@30 105 unsigned char *protocols;
garbeam@13 106 long res;
garbeam@13 107 int protos = 0;
garbeam@13 108 int i;
garbeam@13 109
garbeam@77 110 res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L, &protocols);
garbeam@13 111 if(res <= 0) {
garbeam@13 112 return protos;
garbeam@13 113 }
garbeam@13 114 for(i = 0; i < res; i++) {
garbeam@77 115 if(protocols[i] == wmatom[WMDelete])
garbeam@13 116 protos |= WM_PROTOCOL_DELWIN;
garbeam@13 117 }
garbeam@13 118 free((char *) protocols);
garbeam@13 119 return protos;
garbeam@13 120 }
garbeam@13 121
garbeam@13 122 void
garbeam@74 123 sendevent(Window w, Atom a, long value)
garbeam@13 124 {
garbeam@13 125 XEvent e;
garbeam@13 126
garbeam@13 127 e.type = ClientMessage;
garbeam@13 128 e.xclient.window = w;
garbeam@13 129 e.xclient.message_type = a;
garbeam@13 130 e.xclient.format = 32;
garbeam@13 131 e.xclient.data.l[0] = value;
garbeam@13 132 e.xclient.data.l[1] = CurrentTime;
garbeam@13 133 XSendEvent(dpy, w, False, NoEventMask, &e);
garbeam@79 134 XSync(dpy, False);
garbeam@13 135 }
garbeam@13 136
garbeam@76 137 void
garbeam@76 138 quit(Arg *arg)
garbeam@75 139 {
garbeam@76 140 running = False;
garbeam@75 141 }
garbeam@75 142
garbeam@75 143 /*
garbeam@0 144 * There's no way to check accesses to destroyed windows, thus
garbeam@0 145 * those cases are ignored (especially on UnmapNotify's).
garbeam@0 146 * Other types of errors call Xlib's default error handler, which
garbeam@0 147 * calls exit().
garbeam@0 148 */
garbeam@10 149 int
garbeam@75 150 xerror(Display *dpy, XErrorEvent *ee)
garbeam@0 151 {
garbeam@75 152 if(ee->error_code == BadWindow
garbeam@75 153 || (ee->request_code == X_SetInputFocus
garbeam@75 154 && ee->error_code == BadMatch)
garbeam@75 155 || (ee->request_code == X_PolyText8
garbeam@75 156 && ee->error_code == BadDrawable)
garbeam@75 157 || (ee->request_code == X_PolyFillRectangle
garbeam@75 158 && ee->error_code == BadDrawable)
garbeam@75 159 || (ee->request_code == X_PolySegment
garbeam@75 160 && ee->error_code == BadDrawable)
garbeam@75 161 || (ee->request_code == X_ConfigureWindow
garbeam@75 162 && ee->error_code == BadMatch)
garbeam@75 163 || (ee->request_code == X_GrabKey
garbeam@75 164 && ee->error_code == BadAccess))
garbeam@0 165 return 0;
garbeam@34 166 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
garbeam@75 167 ee->request_code, ee->error_code);
garbeam@75 168 return xerrorxlib(dpy, ee); /* may call exit() */
garbeam@27 169 }
garbeam@27 170
garbeam@0 171 int
garbeam@0 172 main(int argc, char *argv[])
garbeam@0 173 {
garbeam@59 174 int i, n;
garbeam@59 175 fd_set rd;
garbeam@0 176 XSetWindowAttributes wa;
garbeam@0 177 unsigned int mask;
garbeam@65 178 Bool readstdin = True;
garbeam@0 179 Window w;
garbeam@5 180 XEvent ev;
garbeam@0 181
garbeam@0 182 for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
garbeam@0 183 switch (argv[i][1]) {
garbeam@0 184 case 'v':
garbeam@77 185 fprintf(stdout, "%s",
garbeam@77 186 "dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n");
garbeam@0 187 exit(0);
garbeam@0 188 break;
garbeam@0 189 default:
garbeam@76 190 eprint("usage: dwm [-v]\n");
garbeam@0 191 break;
garbeam@0 192 }
garbeam@0 193 }
garbeam@0 194
garbeam@0 195 dpy = XOpenDisplay(0);
garbeam@0 196 if(!dpy)
garbeam@75 197 eprint("dwm: cannot connect X server\n");
garbeam@0 198
garbeam@0 199 screen = DefaultScreen(dpy);
garbeam@0 200 root = RootWindow(dpy, screen);
garbeam@0 201
garbeam@0 202 /* check if another WM is already running */
garbeam@75 203 otherwm = False;
garbeam@75 204 XSetErrorHandler(xerrorstart);
garbeam@0 205 /* this causes an error if some other WM is running */
garbeam@0 206 XSelectInput(dpy, root, SubstructureRedirectMask);
garbeam@78 207 XSync(dpy, False);
garbeam@0 208
garbeam@75 209 if(otherwm)
garbeam@75 210 eprint("dwm: another window manager is already running\n");
garbeam@0 211
garbeam@78 212 XSetErrorHandler(NULL);
garbeam@75 213 xerrorxlib = XSetErrorHandler(xerror);
garbeam@0 214
garbeam@0 215 /* init atoms */
garbeam@77 216 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
garbeam@77 217 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
garbeam@77 218 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
garbeam@77 219 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
garbeam@77 220 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
garbeam@77 221 PropModeReplace, (unsigned char *) netatom, NetLast);
garbeam@0 222
garbeam@0 223 /* init cursors */
garbeam@0 224 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
garbeam@0 225 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
garbeam@0 226 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
garbeam@0 227
garbeam@73 228 grabkeys();
garbeam@0 229
garbeam@5 230 /* style */
garbeam@74 231 dc.bg = getcolor(BGCOLOR);
garbeam@74 232 dc.fg = getcolor(FGCOLOR);
garbeam@74 233 dc.border = getcolor(BORDERCOLOR);
garbeam@74 234 setfont(FONT);
garbeam@5 235
garbeam@57 236 sx = sy = 0;
garbeam@57 237 sw = DisplayWidth(dpy, screen);
garbeam@57 238 sh = DisplayHeight(dpy, screen);
garbeam@57 239 mw = (sw * MASTERW) / 100;
garbeam@5 240
garbeam@57 241 wa.override_redirect = 1;
garbeam@57 242 wa.background_pixmap = ParentRelative;
garbeam@58 243 wa.event_mask = ButtonPressMask | ExposureMask;
garbeam@57 244
garbeam@57 245 bx = by = 0;
garbeam@57 246 bw = sw;
garbeam@57 247 dc.h = bh = dc.font.height + 4;
garbeam@57 248 barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen),
garbeam@57 249 CopyFromParent, DefaultVisual(dpy, screen),
garbeam@57 250 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
garbeam@57 251 XDefineCursor(dpy, barwin, cursor[CurNormal]);
garbeam@57 252 XMapRaised(dpy, barwin);
garbeam@57 253
garbeam@60 254 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
garbeam@60 255 dc.gc = XCreateGC(dpy, root, 0, 0);
garbeam@74 256 drawstatus();
garbeam@60 257
garbeam@57 258 issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
garbeam@21 259
garbeam@9 260 wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
garbeam@9 261 | LeaveWindowMask;
garbeam@0 262 wa.cursor = cursor[CurNormal];
garbeam@57 263
garbeam@0 264 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
garbeam@0 265
garbeam@57 266 strcpy(stext, "dwm-"VERSION);
garbeam@75 267 scan();
garbeam@3 268
garbeam@59 269 /* main event loop, reads status text from stdin as well */
garbeam@61 270 Mainloop:
garbeam@5 271 while(running) {
garbeam@59 272 FD_ZERO(&rd);
garbeam@65 273 if(readstdin)
garbeam@65 274 FD_SET(STDIN_FILENO, &rd);
garbeam@59 275 FD_SET(ConnectionNumber(dpy), &rd);
garbeam@59 276
garbeam@59 277 i = select(ConnectionNumber(dpy) + 1, &rd, 0, 0, 0);
garbeam@59 278 if(i == -1 && errno == EINTR)
garbeam@59 279 continue;
garbeam@59 280 if(i < 0)
garbeam@75 281 eprint("select failed\n");
garbeam@59 282 else if(i > 0) {
garbeam@64 283 if(FD_ISSET(ConnectionNumber(dpy), &rd)) {
garbeam@64 284 while(XPending(dpy)) {
garbeam@64 285 XNextEvent(dpy, &ev);
garbeam@64 286 if(handler[ev.type])
garbeam@64 287 (handler[ev.type])(&ev); /* call handler */
garbeam@64 288 }
garbeam@59 289 }
garbeam@65 290 if(readstdin && FD_ISSET(STDIN_FILENO, &rd)) {
garbeam@59 291 i = n = 0;
garbeam@60 292 for(;;) {
garbeam@60 293 if((i = getchar()) == EOF) {
garbeam@65 294 /* broken pipe/end of producer */
garbeam@65 295 readstdin = False;
garbeam@65 296 strcpy(stext, "broken pipe");
garbeam@60 297 goto Mainloop;
garbeam@60 298 }
garbeam@60 299 if(i == '\n' || n >= sizeof(stext) - 1)
garbeam@60 300 break;
garbeam@59 301 stext[n++] = i;
garbeam@60 302 }
garbeam@59 303 stext[n] = 0;
garbeam@74 304 drawstatus();
garbeam@59 305 }
garbeam@59 306 }
garbeam@5 307 }
garbeam@0 308
garbeam@0 309 cleanup();
garbeam@0 310 XCloseDisplay(dpy);
garbeam@0 311
garbeam@0 312 return 0;
garbeam@0 313 }