cosmetic
[awesome.git] / awesome.c
blob5f62d76868b73a4235370b32d088025903ebb8bc
1 /*
2 * awesome.c - awesome main functions
3 *
4 * Copyright © 2007 Julien Danjou <julien@danjou.info>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
22 #include <errno.h>
23 #include <locale.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <sys/select.h>
27 #include <X11/cursorfont.h>
28 #include <X11/keysym.h>
29 #include <X11/Xatom.h>
30 #include <X11/Xproto.h>
31 #include <X11/Xutil.h>
33 #include "awesome.h"
34 #include "event.h"
35 #include "layout.h"
36 #include "tag.h"
38 Client *clients = NULL;
39 Client *sel = NULL;
40 Client *stack = NULL;
41 Cursor cursor[CurLast];
42 DC dc;
44 /* static */
46 static int (*xerrorxlib) (Display *, XErrorEvent *);
47 static Bool readin = True, running = True;
49 static void
50 cleanup(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
52 close(STDIN_FILENO);
53 while(stack)
55 unban(stack);
56 unmanage(stack, drawcontext, NormalState, awesomeconf);
58 if(drawcontext->font.set)
59 XFreeFontSet(disp, drawcontext->font.set);
60 else
61 XFreeFont(disp, drawcontext->font.xfont);
62 XUngrabKey(disp, AnyKey, AnyModifier, DefaultRootWindow(disp));
63 XFreePixmap(disp, drawcontext->drawable);
64 XFreeGC(disp, drawcontext->gc);
65 XDestroyWindow(disp, awesomeconf->statusbar.window);
66 XFreeCursor(disp, cursor[CurNormal]);
67 XFreeCursor(disp, cursor[CurResize]);
68 XFreeCursor(disp, cursor[CurMove]);
69 XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
70 XSync(disp, False);
73 static long
74 getstate(Display *disp, Window w)
76 int format, status;
77 long result = -1;
78 unsigned char *p = NULL;
79 unsigned long n, extra;
80 Atom real;
81 status = XGetWindowProperty(disp, w, XInternAtom(disp, "WM_STATE", False),
82 0L, 2L, False, XInternAtom(disp, "WM_STATE", False),
83 &real, &format, &n, &extra, (unsigned char **) &p);
84 if(status != Success)
85 return -1;
86 if(n != 0)
87 result = *p;
88 XFree(p);
89 return result;
92 static void
93 scan(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
95 unsigned int i, num;
96 Window *wins, d1, d2;
97 XWindowAttributes wa;
99 wins = NULL;
100 if(XQueryTree(disp, DefaultRootWindow(disp), &d1, &d2, &wins, &num))
101 for(i = 0; i < num; i++)
103 if(!XGetWindowAttributes(disp, wins[i], &wa)
104 || wa.override_redirect || XGetTransientForHint(disp, wins[i], &d1))
105 continue;
106 if(wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState)
107 manage(disp, drawcontext, wins[i], &wa, awesomeconf);
109 /* now the transients */
110 for(i = 0; i < num; i++)
112 if(!XGetWindowAttributes(disp, wins[i], &wa))
113 continue;
114 if(XGetTransientForHint(disp, wins[i], &d1)
115 && (wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState))
116 manage(disp, drawcontext, wins[i], &wa, awesomeconf);
118 if(wins)
119 XFree(wins);
124 enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
125 Atom netatom[NetWMName];
126 /** Setup everything before running
127 * \param disp Display ref
128 * \param awesomeconf awesome config ref
129 * \todo clean things...
131 static void
132 setup(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
134 XSetWindowAttributes wa;
136 netatom[NetSupported] = XInternAtom(disp, "_NET_SUPPORTED", False);
137 netatom[NetWMName] = XInternAtom(disp, "_NET_WM_NAME", False);
138 XChangeProperty(disp, DefaultRootWindow(disp), netatom[NetSupported],
139 XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast);
140 /* init cursors */
141 cursor[CurNormal] = XCreateFontCursor(disp, XC_left_ptr);
142 cursor[CurResize] = XCreateFontCursor(disp, XC_sizing);
143 cursor[CurMove] = XCreateFontCursor(disp, XC_fleur);
144 /* select for events */
145 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
146 | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
147 wa.cursor = cursor[CurNormal];
148 XChangeWindowAttributes(disp, DefaultRootWindow(disp), CWEventMask | CWCursor, &wa);
149 XSelectInput(disp, DefaultRootWindow(disp), wa.event_mask);
150 grabkeys(disp, awesomeconf);
151 compileregs(awesomeconf->rules, awesomeconf->nrules);
152 /* bar */
153 drawcontext->h = awesomeconf->statusbar.height = drawcontext->font.height + 2;
154 wa.override_redirect = 1;
155 wa.background_pixmap = ParentRelative;
156 wa.event_mask = ButtonPressMask | ExposureMask;
157 awesomeconf->statusbar.window = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, 0,
158 DefaultDepth(disp, DefaultScreen(disp)), CopyFromParent,
159 DefaultVisual(disp, DefaultScreen(disp)),
160 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
161 XDefineCursor(disp, awesomeconf->statusbar.window, cursor[CurNormal]);
162 updatebarpos(disp, awesomeconf->statusbar);
163 XMapRaised(disp, awesomeconf->statusbar.window);
164 /* pixmap for everything */
165 drawcontext->drawable = XCreatePixmap(disp, DefaultRootWindow(disp), DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, DefaultDepth(disp, DefaultScreen(disp)));
166 drawcontext->gc = XCreateGC(disp, DefaultRootWindow(disp), 0, 0);
167 XSetLineAttributes(disp, drawcontext->gc, 1, LineSolid, CapButt, JoinMiter);
168 if(!drawcontext->font.set)
169 XSetFont(disp, drawcontext->gc, drawcontext->font.xfont->fid);
170 loadawesomeprops(disp, awesomeconf);
174 * Startup Error handler to check if another window manager
175 * is already running.
177 static int __attribute__ ((noreturn))
178 xerrorstart(Display * dsply __attribute__ ((unused)), XErrorEvent * ee __attribute__ ((unused)))
180 eprint("awesome: another window manager is already running\n");
183 /* extern */
185 void
186 uicb_quit(Display *disp __attribute__ ((unused)),
187 awesome_config *awesomeconf __attribute__((unused)),
188 const char *arg __attribute__ ((unused)))
190 readin = running = False;
194 get_windows_area_x(Statusbar statusbar __attribute__ ((unused)))
196 return 0;
200 get_windows_area_y(Statusbar statusbar)
202 if(statusbar.position == BarTop)
203 return statusbar.height;
205 return 0;
209 get_windows_area_height(Display *disp, Statusbar statusbar)
211 if(statusbar.position == BarTop || statusbar.position == BarBot)
212 return DisplayHeight(disp, DefaultScreen(disp)) - statusbar.height;
214 return DisplayHeight(disp, DefaultScreen(disp));
218 get_windows_area_width(Display *disp,
219 Statusbar statusbar __attribute__ ((unused)))
221 return DisplayWidth(disp, DefaultScreen(disp));
224 void
225 updatebarpos(Display *disp, Statusbar statusbar)
227 XEvent ev;
229 switch (statusbar.position)
231 default:
232 XMoveWindow(disp, statusbar.window, 0, 0);
233 break;
234 case BarBot:
235 XMoveWindow(disp, statusbar.window, 0, get_windows_area_width(disp, statusbar) - statusbar.height);
236 break;
237 case BarOff:
238 XMoveWindow(disp, statusbar.window, 0, 0 - statusbar.height);
239 break;
241 XSync(disp, False);
242 while(XCheckMaskEvent(disp, EnterWindowMask, &ev));
245 /* There's no way to check accesses to destroyed windows, thus those cases are
246 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
247 * default error handler, which may call exit.
250 xerror(Display * edpy, XErrorEvent * ee)
252 if(ee->error_code == BadWindow
253 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
254 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
255 || (ee->request_code == X_PolyFillRectangle
256 && ee->error_code == BadDrawable)
257 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
258 || (ee->request_code == X_ConfigureWindow
259 && ee->error_code == BadMatch) || (ee->request_code == X_GrabKey
260 && ee->error_code == BadAccess)
261 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
262 return 0;
263 fprintf(stderr, "awesome: fatal error: request code=%d, error code=%d\n",
264 ee->request_code, ee->error_code);
266 return xerrorxlib(edpy, ee); /* may call exit */
270 main(int argc, char *argv[])
272 char *p;
273 int r, xfd;
274 fd_set rd;
275 XEvent ev;
276 Display * dpy;
277 Window root;
278 awesome_config awesomeconf;
280 if(argc == 2 && !strcmp("-v", argv[1]))
281 eprint("awesome-" VERSION " © 2007 Julien Danjou\n");
282 else if(argc != 1)
283 eprint("usage: awesome [-v]\n");
284 setlocale(LC_CTYPE, "");
287 if(!(dpy = XOpenDisplay(NULL)))
288 eprint("awesome: cannot open display\n");
289 xfd = ConnectionNumber(dpy);
290 root = RootWindow(dpy, DefaultScreen(dpy));
291 XSetErrorHandler(xerrorstart);
293 /* this causes an error if some other window manager is running */
294 XSelectInput(dpy, root, SubstructureRedirectMask);
295 XSync(dpy, False);
297 XSync(dpy, False);
298 XSetErrorHandler(NULL);
299 xerrorxlib = XSetErrorHandler(xerror);
300 XSync(dpy, False);
301 parse_config(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
302 setup(dpy, &dc, &awesomeconf);
303 drawstatus(dpy, &dc, &awesomeconf);
304 scan(dpy, &dc, &awesomeconf);
305 XSync(dpy, False);
307 void (*handler[LASTEvent]) (XEvent *, awesome_config *) =
309 [ButtonPress] = handle_event_buttonpress,
310 [ConfigureRequest] = handle_event_configurerequest,
311 [ConfigureNotify] = handle_event_configurenotify,
312 [DestroyNotify] = handle_event_destroynotify,
313 [EnterNotify] = handle_event_enternotify,
314 [LeaveNotify] = handle_event_leavenotify,
315 [Expose] = handle_event_expose,
316 [KeyPress] = handle_event_keypress,
317 [MappingNotify] = handle_event_mappingnotify,
318 [MapRequest] = handle_event_maprequest,
319 [PropertyNotify] = handle_event_propertynotify,
320 [UnmapNotify] = handle_event_unmapnotify
324 /* main event loop, also reads status text from stdin */
325 while(running)
327 FD_ZERO(&rd);
328 if(readin)
329 FD_SET(STDIN_FILENO, &rd);
330 FD_SET(xfd, &rd);
331 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
333 if(errno == EINTR)
334 continue;
335 eprint("select failed\n");
337 if(FD_ISSET(STDIN_FILENO, &rd))
339 switch (r = read(STDIN_FILENO, awesomeconf.statustext, sizeof(awesomeconf.statustext) - 1))
341 case -1:
342 strncpy(awesomeconf.statustext, strerror(errno), sizeof(awesomeconf.statustext) - 1);
343 awesomeconf.statustext[sizeof(awesomeconf.statustext) - 1] = '\0';
344 readin = False;
345 break;
346 case 0:
347 strncpy(awesomeconf.statustext, "EOF", 4);
348 readin = False;
349 break;
350 default:
351 for(awesomeconf.statustext[r] = '\0', p = awesomeconf.statustext + a_strlen(awesomeconf.statustext) - 1;
352 p >= awesomeconf.statustext && *p == '\n'; *p-- = '\0');
353 for(; p >= awesomeconf.statustext && *p != '\n'; --p);
354 if(p > awesomeconf.statustext)
355 strncpy(awesomeconf.statustext, p + 1, sizeof(awesomeconf.statustext));
357 drawstatus(dpy, &dc, &awesomeconf);
360 while(XPending(dpy))
362 XNextEvent(dpy, &ev);
363 if(handler[ev.type])
364 (handler[ev.type]) (&ev, &awesomeconf); /* call handler */
367 cleanup(dpy, &dc, &awesomeconf);
368 XCloseDisplay(dpy);
370 return 0;