add screen arg to uicb*
[awesome.git] / awesome.c
blobddfe3a68464d45e666980159ee2fb3c86fd3ff60
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>
32 #include <X11/extensions/shape.h>
33 #include <X11/extensions/Xrandr.h>
35 #include "awesome.h"
36 #include "event.h"
37 #include "layout.h"
38 #include "tag.h"
39 #include "screen.h"
40 #include "util.h"
41 #include "statusbar.h"
43 Client *clients = NULL;
44 Client *sel = NULL;
45 Client *stack = NULL;
46 DC dc;
48 /* static */
50 static int (*xerrorxlib) (Display *, XErrorEvent *);
51 static Bool readin = True, running = True;
53 static void
54 cleanup(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
56 int screen;
58 close(STDIN_FILENO);
60 while(stack)
62 unban(stack);
63 unmanage(stack, drawcontext, NormalState, awesomeconf);
66 if(drawcontext->font.set)
67 XFreeFontSet(disp, drawcontext->font.set);
68 else
69 XFreeFont(disp, drawcontext->font.xfont);
71 for(screen = 0; screen < ScreenCount(disp); screen++);
72 XUngrabKey(disp, AnyKey, AnyModifier, RootWindow(disp, screen));
74 XFreePixmap(disp, awesomeconf->statusbar.drawable);
75 XFreeGC(disp, drawcontext->gc);
76 XDestroyWindow(disp, awesomeconf->statusbar.window);
77 XFreeCursor(disp, drawcontext->cursor[CurNormal]);
78 XFreeCursor(disp, drawcontext->cursor[CurResize]);
79 XFreeCursor(disp, drawcontext->cursor[CurMove]);
80 XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
81 XSync(disp, False);
84 static long
85 getstate(Display *disp, Window w)
87 int format, status;
88 long result = -1;
89 unsigned char *p = NULL;
90 unsigned long n, extra;
91 Atom real;
92 status = XGetWindowProperty(disp, w, XInternAtom(disp, "WM_STATE", False),
93 0L, 2L, False, XInternAtom(disp, "WM_STATE", False),
94 &real, &format, &n, &extra, (unsigned char **) &p);
95 if(status != Success)
96 return -1;
97 if(n != 0)
98 result = *p;
99 XFree(p);
100 return result;
103 static void
104 scan(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
106 unsigned int i, num;
107 int screen;
108 Window *wins, d1, d2;
109 XWindowAttributes wa;
111 wins = NULL;
112 for(screen = 0; screen < ScreenCount(disp); screen++)
114 if(XQueryTree(disp, RootWindow(disp, screen), &d1, &d2, &wins, &num))
116 for(i = 0; i < num; i++)
118 if(!XGetWindowAttributes(disp, wins[i], &wa)
119 || wa.override_redirect
120 || XGetTransientForHint(disp, wins[i], &d1))
121 continue;
122 if(wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState)
123 manage(disp, screen, drawcontext, wins[i], &wa, awesomeconf);
125 /* now the transients */
126 for(i = 0; i < num; i++)
128 if(!XGetWindowAttributes(disp, wins[i], &wa))
129 continue;
130 if(XGetTransientForHint(disp, wins[i], &d1)
131 && (wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState))
132 manage(disp, screen, drawcontext, wins[i], &wa, awesomeconf);
136 if(wins)
137 XFree(wins);
142 enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
143 Atom netatom[NetWMName];
144 /** Setup everything before running
145 * \param disp Display ref
146 * \param awesomeconf awesome config ref
147 * \todo clean things...
149 static void
150 setup(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
152 XSetWindowAttributes wa;
153 int screen;
155 netatom[NetSupported] = XInternAtom(disp, "_NET_SUPPORTED", False);
156 netatom[NetWMName] = XInternAtom(disp, "_NET_WM_NAME", False);
157 for(screen = 0; screen < ScreenCount(disp); screen++)
158 XChangeProperty(disp, RootWindow(disp, screen), netatom[NetSupported],
159 XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast);
160 /* init cursors */
161 drawcontext->cursor[CurNormal] = XCreateFontCursor(disp, XC_left_ptr);
162 drawcontext->cursor[CurResize] = XCreateFontCursor(disp, XC_sizing);
163 drawcontext->cursor[CurMove] = XCreateFontCursor(disp, XC_fleur);
164 /* select for events */
165 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
166 | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
167 wa.cursor = drawcontext->cursor[CurNormal];
168 for(screen = 0; screen < ScreenCount(disp); screen++)
170 XChangeWindowAttributes(disp, RootWindow(disp, screen), CWEventMask | CWCursor, &wa);
171 XSelectInput(disp, RootWindow(disp, screen), wa.event_mask);
172 grabkeys(disp, screen, awesomeconf);
174 compileregs(awesomeconf->rules, awesomeconf->nrules);
175 /* bar */
176 drawcontext->h = awesomeconf->statusbar.height = drawcontext->font.height + 2;
177 initstatusbar(disp, DefaultScreen(disp), drawcontext, &awesomeconf->statusbar);
178 drawcontext->gc = XCreateGC(disp, DefaultRootWindow(disp), 0, 0);
179 XSetLineAttributes(disp, drawcontext->gc, 1, LineSolid, CapButt, JoinMiter);
180 if(!drawcontext->font.set)
181 XSetFont(disp, drawcontext->gc, drawcontext->font.xfont->fid);
182 for(screen = 0; screen < ScreenCount(disp); screen++)
183 loadawesomeprops(disp, screen, awesomeconf);
187 * Startup Error handler to check if another window manager
188 * is already running.
190 static int __attribute__ ((noreturn))
191 xerrorstart(Display * dsply __attribute__ ((unused)), XErrorEvent * ee __attribute__ ((unused)))
193 eprint("awesome: another window manager is already running\n");
196 /* extern */
198 void
199 uicb_quit(Display *disp __attribute__ ((unused)),
200 int screen __attribute__ ((unused)),
201 DC *drawcontext __attribute__ ((unused)),
202 awesome_config *awesomeconf __attribute__((unused)),
203 const char *arg __attribute__ ((unused)))
205 readin = running = False;
209 get_windows_area_x(Statusbar statusbar __attribute__ ((unused)))
211 return 0;
215 get_windows_area_y(Statusbar statusbar)
217 if(statusbar.position == BarTop)
218 return statusbar.height;
220 return 0;
224 get_windows_area_height(Display *disp, Statusbar statusbar)
226 if(statusbar.position == BarTop || statusbar.position == BarBot)
227 return DisplayHeight(disp, DefaultScreen(disp)) - statusbar.height;
229 return DisplayHeight(disp, DefaultScreen(disp));
233 get_windows_area_width(Display *disp,
234 Statusbar statusbar __attribute__ ((unused)))
236 return DisplayWidth(disp, DefaultScreen(disp));
239 /* There's no way to check accesses to destroyed windows, thus those cases are
240 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
241 * default error handler, which may call exit.
244 xerror(Display * edpy, XErrorEvent * ee)
246 if(ee->error_code == BadWindow
247 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
248 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
249 || (ee->request_code == X_PolyFillRectangle
250 && ee->error_code == BadDrawable)
251 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
252 || (ee->request_code == X_ConfigureWindow
253 && ee->error_code == BadMatch) || (ee->request_code == X_GrabKey
254 && ee->error_code == BadAccess)
255 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
256 return 0;
257 fprintf(stderr, "awesome: fatal error: request code=%d, error code=%d\n",
258 ee->request_code, ee->error_code);
260 return xerrorxlib(edpy, ee); /* may call exit */
264 main(int argc, char *argv[])
266 char *p;
267 int r, xfd, e_dummy;
268 fd_set rd;
269 XEvent ev;
270 Display * dpy;
271 awesome_config awesomeconf;
272 int shape_event, randr_event_base;
273 int screen;
275 if(argc == 2 && !strcmp("-v", argv[1]))
276 eprint("awesome-" VERSION " © 2007 Julien Danjou\n");
277 else if(argc != 1)
278 eprint("usage: awesome [-v]\n");
279 setlocale(LC_CTYPE, "");
282 if(!(dpy = XOpenDisplay(NULL)))
283 eprint("awesome: cannot open display\n");
284 xfd = ConnectionNumber(dpy);
285 XSetErrorHandler(xerrorstart);
287 /* this causes an error if some other window manager is running */
288 for(screen = 0; screen < ScreenCount(dpy); screen++)
289 XSelectInput(dpy, RootWindow(dpy, screen), SubstructureRedirectMask);
291 XSync(dpy, False);
292 XSetErrorHandler(NULL);
293 xerrorxlib = XSetErrorHandler(xerror);
294 XSync(dpy, False);
295 parse_config(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
296 setup(dpy, &dc, &awesomeconf);
297 drawstatusbar(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
299 void (*handler[LASTEvent]) (XEvent *, awesome_config *) =
301 [ButtonPress] = handle_event_buttonpress,
302 [ConfigureRequest] = handle_event_configurerequest,
303 [ConfigureNotify] = handle_event_configurenotify,
304 [DestroyNotify] = handle_event_destroynotify,
305 [EnterNotify] = handle_event_enternotify,
306 [LeaveNotify] = handle_event_leavenotify,
307 [Expose] = handle_event_expose,
308 [KeyPress] = handle_event_keypress,
309 [MappingNotify] = handle_event_mappingnotify,
310 [MapRequest] = handle_event_maprequest,
311 [PropertyNotify] = handle_event_propertynotify,
312 [UnmapNotify] = handle_event_unmapnotify,
315 /* check for shape extension */
316 if((awesomeconf.have_shape = XShapeQueryExtension(dpy, &shape_event, &e_dummy)))
317 handler[shape_event] = handle_event_shape;
319 /* check for randr extension */
320 if((awesomeconf.have_randr = XRRQueryExtension(dpy, &randr_event_base, &e_dummy)))
321 handler[randr_event_base + RRScreenChangeNotify] = handle_event_randr_screen_change_notify;
323 scan(dpy, &dc, &awesomeconf);
324 XSync(dpy, False);
326 /* main event loop, also reads status text from stdin */
327 while(running)
329 FD_ZERO(&rd);
330 if(readin)
331 FD_SET(STDIN_FILENO, &rd);
332 FD_SET(xfd, &rd);
333 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
335 if(errno == EINTR)
336 continue;
337 eprint("select failed\n");
339 if(FD_ISSET(STDIN_FILENO, &rd))
341 switch (r = read(STDIN_FILENO, awesomeconf.statustext, sizeof(awesomeconf.statustext) - 1))
343 case -1:
344 strncpy(awesomeconf.statustext, strerror(errno), sizeof(awesomeconf.statustext) - 1);
345 awesomeconf.statustext[sizeof(awesomeconf.statustext) - 1] = '\0';
346 readin = False;
347 break;
348 case 0:
349 strncpy(awesomeconf.statustext, "EOF", 4);
350 readin = False;
351 break;
352 default:
353 for(awesomeconf.statustext[r] = '\0', p = awesomeconf.statustext + a_strlen(awesomeconf.statustext) - 1;
354 p >= awesomeconf.statustext && *p == '\n'; *p-- = '\0');
355 for(; p >= awesomeconf.statustext && *p != '\n'; --p);
356 if(p > awesomeconf.statustext)
357 strncpy(awesomeconf.statustext, p + 1, sizeof(awesomeconf.statustext));
359 drawstatusbar(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
362 while(XPending(dpy))
364 XNextEvent(dpy, &ev);
365 if(handler[ev.type])
366 (handler[ev.type]) (&ev, &awesomeconf); /* call handler */
369 cleanup(dpy, &dc, &awesomeconf);
370 XCloseDisplay(dpy);
372 return 0;