JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
changed how manage client works
[dwm.git] / wm.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 "wm.h"
15
16 /* X structs */
17 Display *dpy;
18 Window root, barwin;
19 Atom net_atom[NetLast];
20 Cursor cursor[CurLast];
21 XRectangle rect, barrect;
22 Bool running = True;
23
24 char *bartext, tag[256];
25 int screen, sel_screen;
26
27 Brush brush = {0};
28 Client *clients = NULL;
29
30 enum { WM_PROTOCOL_DELWIN = 1 };
31
32 static Bool other_wm_running;
33 static char version[] = "gridwm - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
34 static int (*x_error_handler) (Display *, XErrorEvent *);
35
36 static void
37 usage()
38 {
39         fputs("usage: gridwm [-v]\n", stderr);
40         exit(1);
41 }
42
43 static void
44 scan_wins()
45 {
46         unsigned int i, num;
47         Window *wins;
48         XWindowAttributes wa;
49         Window d1, d2;
50
51         if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
52                 for(i = 0; i < num; i++) {
53                         if(!XGetWindowAttributes(dpy, wins[i], &wa))
54                                 continue;
55                         if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
56                                 continue;
57                         if(wa.map_state == IsViewable)
58                                 manage(wins[i], &wa);
59                 }
60         }
61         if(wins)
62                 XFree(wins);
63 }
64
65 /*
66  * There's no way to check accesses to destroyed windows, thus
67  * those cases are ignored (especially on UnmapNotify's).
68  * Other types of errors call Xlib's default error handler, which
69  * calls exit().
70  */
71 int
72 error_handler(Display *dpy, XErrorEvent *error)
73 {
74         if(error->error_code == BadWindow
75                         || (error->request_code == X_SetInputFocus
76                                 && error->error_code == BadMatch)
77                         || (error->request_code == X_PolyText8
78                                 && error->error_code == BadDrawable)
79                         || (error->request_code == X_PolyFillRectangle
80                                 && error->error_code == BadDrawable)
81                         || (error->request_code == X_PolySegment
82                                 && error->error_code == BadDrawable)
83                         || (error->request_code == X_ConfigureWindow
84                                 && error->error_code == BadMatch)
85                         || (error->request_code == X_GrabKey
86                                 && error->error_code == BadAccess))
87                 return 0;
88         fprintf(stderr, "gridwm: fatal error: request code=%d, error code=%d\n",
89                         error->request_code, error->error_code);
90         return x_error_handler(dpy, error); /* may call exit() */
91 }
92
93 /*
94  * Startup Error handler to check if another window manager
95  * is already running.
96  */
97 static int
98 startup_error_handler(Display *dpy, XErrorEvent *error)
99 {
100         other_wm_running = True;
101         return -1;
102 }
103
104 static void
105 cleanup()
106 {
107         /*
108         Client *c;
109         for(c=client; c; c=c->next)
110                 reparent_client(c, root, c->sel->rect.x, c->sel->rect.y);
111         XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
112         */
113 }
114
115 int
116 main(int argc, char *argv[])
117 {
118         int i;
119         XSetWindowAttributes wa;
120         unsigned int mask;
121         Window w;
122         XEvent ev;
123
124         /* command line args */
125         for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
126                 switch (argv[i][1]) {
127                 case 'v':
128                         fprintf(stdout, "%s", version);
129                         exit(0);
130                         break;
131                 default:
132                         usage();
133                         break;
134                 }
135         }
136
137         dpy = XOpenDisplay(0);
138         if(!dpy)
139                 error("gridwm: cannot connect X server\n");
140
141         screen = DefaultScreen(dpy);
142         root = RootWindow(dpy, screen);
143
144         /* check if another WM is already running */
145         other_wm_running = False;
146         XSetErrorHandler(startup_error_handler);
147         /* this causes an error if some other WM is running */
148         XSelectInput(dpy, root, SubstructureRedirectMask);
149         XFlush(dpy);
150
151         if(other_wm_running)
152                 error("gridwm: another window manager is already running\n");
153
154         rect.x = rect.y = 0;
155         rect.width = DisplayWidth(dpy, screen);
156         rect.height = DisplayHeight(dpy, screen);
157         sel_screen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
158
159         XSetErrorHandler(0);
160         x_error_handler = XSetErrorHandler(error_handler);
161
162         /* init atoms */
163         net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
164         net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
165
166         XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
167                         PropModeReplace, (unsigned char *) net_atom, NetLast);
168
169
170         /* init cursors */
171         cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
172         cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
173         cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
174
175         update_keys();
176
177         brush.drawable = XCreatePixmap(dpy, root, rect.width, rect.height,
178                         DefaultDepth(dpy, screen));
179         brush.gc = XCreateGC(dpy, root, 0, 0);
180
181         /* style */
182         loadcolors(dpy, screen, &brush, BGCOLOR, FGCOLOR, BORDERCOLOR);
183         loadfont(dpy, &brush.font, FONT);
184
185         wa.override_redirect = 1;
186         wa.background_pixmap = ParentRelative;
187         wa.event_mask = ExposureMask;
188
189         barrect = rect;
190         barrect.height = labelheight(&brush.font);
191         barrect.y = rect.height - barrect.height;
192         barwin = XCreateWindow(dpy, root, barrect.x, barrect.y,
193                         barrect.width, barrect.height, 0, DefaultDepth(dpy, screen),
194                         CopyFromParent, DefaultVisual(dpy, screen),
195                         CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
196         bartext = NULL;
197         XDefineCursor(dpy, barwin, cursor[CurNormal]);
198         XMapRaised(dpy, barwin);
199         draw_bar();
200
201         wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
202                                         | LeaveWindowMask;
203         wa.cursor = cursor[CurNormal];
204         XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
205
206         scan_wins();
207
208         while(running) {
209                 XNextEvent(dpy, &ev);
210                 if(handler[ev.type])
211                         (handler[ev.type]) (&ev); /* call handler */
212         }
213
214         cleanup();
215         XCloseDisplay(dpy);
216
217         return 0;
218 }