move uicb_togglebar to statusbar.c
[awesome.git] / awesome.c
blobdf55780ba226a1c329b2733eb4120fd627c3eb94
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 close(STDIN_FILENO);
57 while(stack)
59 unban(stack);
60 unmanage(stack, drawcontext, NormalState, awesomeconf);
62 if(drawcontext->font.set)
63 XFreeFontSet(disp, drawcontext->font.set);
64 else
65 XFreeFont(disp, drawcontext->font.xfont);
66 XUngrabKey(disp, AnyKey, AnyModifier, DefaultRootWindow(disp));
67 XFreePixmap(disp, awesomeconf->statusbar.drawable);
68 XFreeGC(disp, drawcontext->gc);
69 XDestroyWindow(disp, awesomeconf->statusbar.window);
70 XFreeCursor(disp, drawcontext->cursor[CurNormal]);
71 XFreeCursor(disp, drawcontext->cursor[CurResize]);
72 XFreeCursor(disp, drawcontext->cursor[CurMove]);
73 XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
74 XSync(disp, False);
77 static long
78 getstate(Display *disp, Window w)
80 int format, status;
81 long result = -1;
82 unsigned char *p = NULL;
83 unsigned long n, extra;
84 Atom real;
85 status = XGetWindowProperty(disp, w, XInternAtom(disp, "WM_STATE", False),
86 0L, 2L, False, XInternAtom(disp, "WM_STATE", False),
87 &real, &format, &n, &extra, (unsigned char **) &p);
88 if(status != Success)
89 return -1;
90 if(n != 0)
91 result = *p;
92 XFree(p);
93 return result;
96 static void
97 scan(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
99 unsigned int i, num;
100 Window *wins, d1, d2;
101 XWindowAttributes wa;
103 wins = NULL;
104 if(XQueryTree(disp, DefaultRootWindow(disp), &d1, &d2, &wins, &num))
105 for(i = 0; i < num; i++)
107 if(!XGetWindowAttributes(disp, wins[i], &wa)
108 || wa.override_redirect || XGetTransientForHint(disp, wins[i], &d1))
109 continue;
110 if(wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState)
111 manage(disp, drawcontext, wins[i], &wa, awesomeconf);
113 /* now the transients */
114 for(i = 0; i < num; i++)
116 if(!XGetWindowAttributes(disp, wins[i], &wa))
117 continue;
118 if(XGetTransientForHint(disp, wins[i], &d1)
119 && (wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState))
120 manage(disp, drawcontext, wins[i], &wa, awesomeconf);
122 if(wins)
123 XFree(wins);
128 enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
129 Atom netatom[NetWMName];
130 /** Setup everything before running
131 * \param disp Display ref
132 * \param awesomeconf awesome config ref
133 * \todo clean things...
135 static void
136 setup(Display *disp, DC *drawcontext, awesome_config *awesomeconf)
138 XSetWindowAttributes wa;
140 netatom[NetSupported] = XInternAtom(disp, "_NET_SUPPORTED", False);
141 netatom[NetWMName] = XInternAtom(disp, "_NET_WM_NAME", False);
142 XChangeProperty(disp, DefaultRootWindow(disp), netatom[NetSupported],
143 XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast);
144 /* init cursors */
145 drawcontext->cursor[CurNormal] = XCreateFontCursor(disp, XC_left_ptr);
146 drawcontext->cursor[CurResize] = XCreateFontCursor(disp, XC_sizing);
147 drawcontext->cursor[CurMove] = XCreateFontCursor(disp, XC_fleur);
148 /* select for events */
149 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
150 | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
151 wa.cursor = drawcontext->cursor[CurNormal];
152 XChangeWindowAttributes(disp, DefaultRootWindow(disp), CWEventMask | CWCursor, &wa);
153 XSelectInput(disp, DefaultRootWindow(disp), wa.event_mask);
154 grabkeys(disp, awesomeconf);
155 compileregs(awesomeconf->rules, awesomeconf->nrules);
156 /* bar */
157 drawcontext->h = awesomeconf->statusbar.height = drawcontext->font.height + 2;
158 wa.override_redirect = 1;
159 wa.background_pixmap = ParentRelative;
160 wa.event_mask = ButtonPressMask | ExposureMask;
161 awesomeconf->statusbar.window = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, 0,
162 DefaultDepth(disp, DefaultScreen(disp)), CopyFromParent,
163 DefaultVisual(disp, DefaultScreen(disp)),
164 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
165 XDefineCursor(disp, awesomeconf->statusbar.window, drawcontext->cursor[CurNormal]);
166 updatebarpos(disp, awesomeconf->statusbar);
167 XMapRaised(disp, awesomeconf->statusbar.window);
168 /* pixmap for everything */
169 awesomeconf->statusbar.drawable = XCreatePixmap(disp, DefaultRootWindow(disp), DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, DefaultDepth(disp, DefaultScreen(disp)));
170 drawcontext->gc = XCreateGC(disp, DefaultRootWindow(disp), 0, 0);
171 XSetLineAttributes(disp, drawcontext->gc, 1, LineSolid, CapButt, JoinMiter);
172 if(!drawcontext->font.set)
173 XSetFont(disp, drawcontext->gc, drawcontext->font.xfont->fid);
174 loadawesomeprops(disp, awesomeconf);
178 * Startup Error handler to check if another window manager
179 * is already running.
181 static int __attribute__ ((noreturn))
182 xerrorstart(Display * dsply __attribute__ ((unused)), XErrorEvent * ee __attribute__ ((unused)))
184 eprint("awesome: another window manager is already running\n");
187 /* extern */
189 void
190 uicb_quit(Display *disp __attribute__ ((unused)),
191 DC *drawcontext __attribute__ ((unused)),
192 awesome_config *awesomeconf __attribute__((unused)),
193 const char *arg __attribute__ ((unused)))
195 readin = running = False;
199 get_windows_area_x(Statusbar statusbar __attribute__ ((unused)))
201 return 0;
205 get_windows_area_y(Statusbar statusbar)
207 if(statusbar.position == BarTop)
208 return statusbar.height;
210 return 0;
214 get_windows_area_height(Display *disp, Statusbar statusbar)
216 if(statusbar.position == BarTop || statusbar.position == BarBot)
217 return DisplayHeight(disp, DefaultScreen(disp)) - statusbar.height;
219 return DisplayHeight(disp, DefaultScreen(disp));
223 get_windows_area_width(Display *disp,
224 Statusbar statusbar __attribute__ ((unused)))
226 return DisplayWidth(disp, DefaultScreen(disp));
229 /* There's no way to check accesses to destroyed windows, thus those cases are
230 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
231 * default error handler, which may call exit.
234 xerror(Display * edpy, XErrorEvent * ee)
236 if(ee->error_code == BadWindow
237 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
238 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
239 || (ee->request_code == X_PolyFillRectangle
240 && ee->error_code == BadDrawable)
241 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
242 || (ee->request_code == X_ConfigureWindow
243 && ee->error_code == BadMatch) || (ee->request_code == X_GrabKey
244 && ee->error_code == BadAccess)
245 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
246 return 0;
247 fprintf(stderr, "awesome: fatal error: request code=%d, error code=%d\n",
248 ee->request_code, ee->error_code);
250 return xerrorxlib(edpy, ee); /* may call exit */
254 main(int argc, char *argv[])
256 char *p;
257 int r, xfd, e_dummy;
258 fd_set rd;
259 XEvent ev;
260 Display * dpy;
261 Window root;
262 awesome_config awesomeconf;
263 int shape_event, randr_event_base;
265 if(argc == 2 && !strcmp("-v", argv[1]))
266 eprint("awesome-" VERSION " © 2007 Julien Danjou\n");
267 else if(argc != 1)
268 eprint("usage: awesome [-v]\n");
269 setlocale(LC_CTYPE, "");
272 if(!(dpy = XOpenDisplay(NULL)))
273 eprint("awesome: cannot open display\n");
274 xfd = ConnectionNumber(dpy);
275 root = RootWindow(dpy, DefaultScreen(dpy));
276 XSetErrorHandler(xerrorstart);
278 /* this causes an error if some other window manager is running */
279 XSelectInput(dpy, root, SubstructureRedirectMask);
280 XSync(dpy, False);
282 XSync(dpy, False);
283 XSetErrorHandler(NULL);
284 xerrorxlib = XSetErrorHandler(xerror);
285 XSync(dpy, False);
286 parse_config(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
287 setup(dpy, &dc, &awesomeconf);
288 drawstatusbar(dpy, &dc, &awesomeconf);
290 void (*handler[LASTEvent]) (XEvent *, awesome_config *) =
292 [ButtonPress] = handle_event_buttonpress,
293 [ConfigureRequest] = handle_event_configurerequest,
294 [ConfigureNotify] = handle_event_configurenotify,
295 [DestroyNotify] = handle_event_destroynotify,
296 [EnterNotify] = handle_event_enternotify,
297 [LeaveNotify] = handle_event_leavenotify,
298 [Expose] = handle_event_expose,
299 [KeyPress] = handle_event_keypress,
300 [MappingNotify] = handle_event_mappingnotify,
301 [MapRequest] = handle_event_maprequest,
302 [PropertyNotify] = handle_event_propertynotify,
303 [UnmapNotify] = handle_event_unmapnotify,
306 /* check for shape extension */
307 if((awesomeconf.have_shape = XShapeQueryExtension(dpy, &shape_event, &e_dummy)))
308 handler[shape_event] = handle_event_shape;
310 /* check for randr extension */
311 if((awesomeconf.have_randr = XRRQueryExtension(dpy, &randr_event_base, &e_dummy)))
312 handler[randr_event_base + RRScreenChangeNotify] = handle_event_randr_screen_change_notify;
314 scan(dpy, &dc, &awesomeconf);
315 XSync(dpy, False);
317 /* main event loop, also reads status text from stdin */
318 while(running)
320 FD_ZERO(&rd);
321 if(readin)
322 FD_SET(STDIN_FILENO, &rd);
323 FD_SET(xfd, &rd);
324 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
326 if(errno == EINTR)
327 continue;
328 eprint("select failed\n");
330 if(FD_ISSET(STDIN_FILENO, &rd))
332 switch (r = read(STDIN_FILENO, awesomeconf.statustext, sizeof(awesomeconf.statustext) - 1))
334 case -1:
335 strncpy(awesomeconf.statustext, strerror(errno), sizeof(awesomeconf.statustext) - 1);
336 awesomeconf.statustext[sizeof(awesomeconf.statustext) - 1] = '\0';
337 readin = False;
338 break;
339 case 0:
340 strncpy(awesomeconf.statustext, "EOF", 4);
341 readin = False;
342 break;
343 default:
344 for(awesomeconf.statustext[r] = '\0', p = awesomeconf.statustext + a_strlen(awesomeconf.statustext) - 1;
345 p >= awesomeconf.statustext && *p == '\n'; *p-- = '\0');
346 for(; p >= awesomeconf.statustext && *p != '\n'; --p);
347 if(p > awesomeconf.statustext)
348 strncpy(awesomeconf.statustext, p + 1, sizeof(awesomeconf.statustext));
350 drawstatusbar(dpy, &dc, &awesomeconf);
353 while(XPending(dpy))
355 XNextEvent(dpy, &ev);
356 if(handler[ev.type])
357 (handler[ev.type]) (&ev, &awesomeconf); /* call handler */
360 cleanup(dpy, &dc, &awesomeconf);
361 XCloseDisplay(dpy);
363 return 0;