JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
07e12aa3420d62739ba5287ae494d6fb71c74c34
[dwm.git] / main.c
1 /*
2  * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3  * See LICENSE file for license details.
4  */
5
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9
10 #include <X11/cursorfont.h>
11 #include <X11/Xatom.h>
12 #include <X11/Xproto.h>
13
14 #include "dwm.h"
15
16 /********** CUSTOMIZE **********/
17
18 char *tags[TLast] = {
19         [Tscratch] = "scratch",
20         [Tdev] = "dev",
21         [Tirc] = "irc",
22         [Twww] = "www",
23         [Twork] = "work",
24 };
25
26 /********** CUSTOMIZE **********/
27
28 /* X structs */
29 Display *dpy;
30 Window root, barwin;
31 Atom wm_atom[WMLast], net_atom[NetLast];
32 Cursor cursor[CurLast];
33 Bool running = True;
34 Bool issel;
35
36 char stext[1024];
37 int tsel = Tdev; /* default tag */
38 int screen, sx, sy, sw, sh, th;
39
40 DC dc = {0};
41 Client *clients = NULL;
42 Client *sel = NULL;
43
44 static Bool other_wm_running;
45 static const char version[] =
46         "dwm - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
47 static int (*x_error_handler) (Display *, XErrorEvent *);
48
49 static void
50 usage() {       error("usage: dwm [-v]\n"); }
51
52 static void
53 scan_wins()
54 {
55         unsigned int i, num;
56         Window *wins;
57         XWindowAttributes wa;
58         Window d1, d2;
59
60         if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
61                 for(i = 0; i < num; i++) {
62                         if(!XGetWindowAttributes(dpy, wins[i], &wa))
63                                 continue;
64                         if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
65                                 continue;
66                         if(wa.map_state == IsViewable)
67                                 manage(wins[i], &wa);
68                 }
69         }
70         if(wins)
71                 XFree(wins);
72 }
73
74 static int
75 win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
76 {
77         Atom real;
78         int format;
79         unsigned long res, extra;
80         int status;
81
82         status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
83                         &res, &extra, prop);
84
85         if(status != Success || *prop == 0) {
86                 return 0;
87         }
88         if(res == 0) {
89                 free((void *) *prop);
90         }
91         return res;
92 }
93
94 int
95 win_proto(Window w)
96 {
97         unsigned char *protocols;
98         long res;
99         int protos = 0;
100         int i;
101
102         res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols);
103         if(res <= 0) {
104                 return protos;
105         }
106         for(i = 0; i < res; i++) {
107                 if(protocols[i] == wm_atom[WMDelete])
108                         protos |= WM_PROTOCOL_DELWIN;
109         }
110         free((char *) protocols);
111         return protos;
112 }
113
114 void
115 send_message(Window w, Atom a, long value)
116 {
117         XEvent e;
118
119         e.type = ClientMessage;
120         e.xclient.window = w;
121         e.xclient.message_type = a;
122         e.xclient.format = 32;
123         e.xclient.data.l[0] = value;
124         e.xclient.data.l[1] = CurrentTime;
125         XSendEvent(dpy, w, False, NoEventMask, &e);
126         XFlush(dpy);
127 }
128
129 /*
130  * There's no way to check accesses to destroyed windows, thus
131  * those cases are ignored (especially on UnmapNotify's).
132  * Other types of errors call Xlib's default error handler, which
133  * calls exit().
134  */
135 int
136 error_handler(Display *dpy, XErrorEvent *error)
137 {
138         if(error->error_code == BadWindow
139                         || (error->request_code == X_SetInputFocus
140                                 && error->error_code == BadMatch)
141                         || (error->request_code == X_PolyText8
142                                 && error->error_code == BadDrawable)
143                         || (error->request_code == X_PolyFillRectangle
144                                 && error->error_code == BadDrawable)
145                         || (error->request_code == X_PolySegment
146                                 && error->error_code == BadDrawable)
147                         || (error->request_code == X_ConfigureWindow
148                                 && error->error_code == BadMatch)
149                         || (error->request_code == X_GrabKey
150                                 && error->error_code == BadAccess))
151                 return 0;
152         fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
153                         error->request_code, error->error_code);
154         return x_error_handler(dpy, error); /* may call exit() */
155 }
156
157 /*
158  * Startup Error handler to check if another window manager
159  * is already running.
160  */
161 static int
162 startup_error_handler(Display *dpy, XErrorEvent *error)
163 {
164         other_wm_running = True;
165         return -1;
166 }
167
168 static void
169 cleanup()
170 {
171         while(sel) {
172                 resize(sel);
173                 unmanage(sel);
174         }
175         XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
176 }
177
178 void
179 quit(Arg *arg)
180 {
181         running = False;
182 }
183
184 int
185 main(int argc, char *argv[])
186 {
187         int i;
188         XSetWindowAttributes wa;
189         unsigned int mask;
190         Window w;
191         XEvent ev;
192
193         /* command line args */
194         for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
195                 switch (argv[i][1]) {
196                 case 'v':
197                         fprintf(stdout, "%s", version);
198                         exit(0);
199                         break;
200                 default:
201                         usage();
202                         break;
203                 }
204         }
205
206         dpy = XOpenDisplay(0);
207         if(!dpy)
208                 error("dwm: cannot connect X server\n");
209
210         screen = DefaultScreen(dpy);
211         root = RootWindow(dpy, screen);
212
213         /* check if another WM is already running */
214         other_wm_running = False;
215         XSetErrorHandler(startup_error_handler);
216         /* this causes an error if some other WM is running */
217         XSelectInput(dpy, root, SubstructureRedirectMask);
218         XFlush(dpy);
219
220         if(other_wm_running)
221                 error("dwm: another window manager is already running\n");
222
223         sx = sy = 0;
224         sw = DisplayWidth(dpy, screen);
225         sh = DisplayHeight(dpy, screen);
226         issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
227
228         XSetErrorHandler(0);
229         x_error_handler = XSetErrorHandler(error_handler);
230
231         /* init atoms */
232         wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
233         wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
234         net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
235         net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
236
237         XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
238                         PropModeReplace, (unsigned char *) net_atom, NetLast);
239
240
241         /* init cursors */
242         cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
243         cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
244         cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
245
246         update_keys();
247
248         /* style */
249         dc.bg = initcolor(BGCOLOR);
250         dc.fg = initcolor(FGCOLOR);
251         dc.border = initcolor(BORDERCOLOR);
252         initfont(FONT);
253
254         th = dc.font.height + 4;
255
256         dc.drawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen));
257         dc.gc = XCreateGC(dpy, root, 0, 0);
258
259         wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
260                                         | LeaveWindowMask;
261         wa.cursor = cursor[CurNormal];
262         XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
263
264         scan_wins();
265
266         while(running) {
267                 XNextEvent(dpy, &ev);
268                 if(handler[ev.type])
269                         (handler[ev.type])(&ev); /* call handler */
270         }
271
272         cleanup();
273         XCloseDisplay(dpy);
274
275         return 0;
276 }