remove wmatom
[awesome.git] / awesome.c
blob07fc5e8ad2255899e3ab658dc27e273f6e3f8b3b
1 /* See LICENSE file for copyright and license details. */
3 #include <errno.h>
4 #include <locale.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/select.h>
9 #include <X11/cursorfont.h>
10 #include <X11/keysym.h>
11 #include <X11/Xatom.h>
12 #include <X11/Xproto.h>
13 #include <X11/Xutil.h>
15 #include "awesome.h"
16 #include "util.h"
17 #include "event.h"
18 #include "layout.h"
19 #include "tag.h"
21 int wax, way, waw, wah;
22 Atom netatom[NetLast];
23 Client *clients = NULL;
24 Client *sel = NULL;
25 Client *stack = NULL;
26 Cursor cursor[CurLast];
27 DC dc;
29 /* static */
31 static int (*xerrorxlib) (Display *, XErrorEvent *);
32 static Bool otherwm = False, readin = True;
33 static Bool running = True;
36 Bool
37 gettextprop(Display *disp, Window w, Atom atom, char *text, unsigned int size)
39 char **list = NULL;
40 int n;
42 XTextProperty name;
44 if(!text || size == 0)
45 return False;
47 text[0] = '\0';
48 XGetTextProperty(disp, w, &name, atom);
50 if(!name.nitems)
51 return False;
53 if(name.encoding == XA_STRING)
54 strncpy(text, (char *) name.value, size - 1);
55 else if(XmbTextPropertyToTextList(disp, &name, &list, &n) >= Success && n > 0 && *list)
57 strncpy(text, *list, size - 1);
58 XFreeStringList(list);
61 text[size - 1] = '\0';
62 XFree(name.value);
64 return True;
67 static void
68 cleanup(Display *disp, awesome_config *awesomeconf)
70 close(STDIN_FILENO);
71 while(stack)
73 unban(stack);
74 unmanage(stack, &dc, NormalState, awesomeconf);
76 if(dc.font.set)
77 XFreeFontSet(disp, dc.font.set);
78 else
79 XFreeFont(disp, dc.font.xfont);
80 XUngrabKey(disp, AnyKey, AnyModifier, DefaultRootWindow(disp));
81 XFreePixmap(disp, dc.drawable);
82 XFreeGC(disp, dc.gc);
83 XDestroyWindow(disp, awesomeconf->statusbar.window);
84 XFreeCursor(disp, cursor[CurNormal]);
85 XFreeCursor(disp, cursor[CurResize]);
86 XFreeCursor(disp, cursor[CurMove]);
87 XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
88 XSync(disp, False);
91 static long
92 getstate(Display *disp, Window w)
94 int format, status;
95 long result = -1;
96 unsigned char *p = NULL;
97 unsigned long n, extra;
98 Atom real;
99 status = XGetWindowProperty(disp, w, XInternAtom(disp, "WM_STATE", False),
100 0L, 2L, False, XInternAtom(disp, "WM_STATE", False),
101 &real, &format, &n, &extra, (unsigned char **) &p);
102 if(status != Success)
103 return -1;
104 if(n != 0)
105 result = *p;
106 XFree(p);
107 return result;
110 static void
111 scan(Display *disp, awesome_config *awesomeconf)
113 unsigned int i, num;
114 Window *wins, d1, d2;
115 XWindowAttributes wa;
117 wins = NULL;
118 if(XQueryTree(disp, DefaultRootWindow(disp), &d1, &d2, &wins, &num))
119 for(i = 0; i < num; i++)
121 if(!XGetWindowAttributes(disp, wins[i], &wa)
122 || wa.override_redirect || XGetTransientForHint(disp, wins[i], &d1))
123 continue;
124 if(wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState)
125 manage(disp, &dc, wins[i], &wa, awesomeconf);
127 /* now the transients */
128 for(i = 0; i < num; i++)
130 if(!XGetWindowAttributes(disp, wins[i], &wa))
131 continue;
132 if(XGetTransientForHint(disp, wins[i], &d1)
133 && (wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState))
134 manage(disp, &dc, wins[i], &wa, awesomeconf);
136 if(wins)
137 XFree(wins);
140 /** Setup everything before running
141 * \param disp Display ref
142 * \param awesomeconf awesome config ref
143 * \todo clean things...
145 static void
146 setup(Display *disp, awesome_config *awesomeconf)
148 XSetWindowAttributes wa;
150 /* init atoms */
151 netatom[NetSupported] = XInternAtom(disp, "_NET_SUPPORTED", False);
152 netatom[NetWMName] = XInternAtom(disp, "_NET_WM_NAME", False);
153 XChangeProperty(disp, DefaultRootWindow(disp), netatom[NetSupported], XA_ATOM, 32,
154 PropModeReplace, (unsigned char *) netatom, NetLast);
155 /* init cursors */
156 cursor[CurNormal] = XCreateFontCursor(disp, XC_left_ptr);
157 cursor[CurResize] = XCreateFontCursor(disp, XC_sizing);
158 cursor[CurMove] = XCreateFontCursor(disp, XC_fleur);
159 /* select for events */
160 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
161 | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
162 wa.cursor = cursor[CurNormal];
163 XChangeWindowAttributes(disp, DefaultRootWindow(disp), CWEventMask | CWCursor, &wa);
164 XSelectInput(disp, DefaultRootWindow(disp), wa.event_mask);
165 grabkeys(disp, awesomeconf);
166 compileregs(awesomeconf);
167 /* bar */
168 dc.h = awesomeconf->statusbar.height = dc.font.height + 2;
169 wa.override_redirect = 1;
170 wa.background_pixmap = ParentRelative;
171 wa.event_mask = ButtonPressMask | ExposureMask;
172 awesomeconf->statusbar.window = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, 0,
173 DefaultDepth(disp, DefaultScreen(disp)), CopyFromParent,
174 DefaultVisual(disp, DefaultScreen(disp)),
175 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
176 XDefineCursor(disp, awesomeconf->statusbar.window, cursor[CurNormal]);
177 updatebarpos(disp, awesomeconf->statusbar);
178 XMapRaised(disp, awesomeconf->statusbar.window);
179 /* pixmap for everything */
180 dc.drawable = XCreatePixmap(disp, DefaultRootWindow(disp), DisplayWidth(disp, DefaultScreen(disp)), awesomeconf->statusbar.height, DefaultDepth(disp, DefaultScreen(disp)));
181 dc.gc = XCreateGC(disp, DefaultRootWindow(disp), 0, 0);
182 XSetLineAttributes(disp, dc.gc, 1, LineSolid, CapButt, JoinMiter);
183 if(!dc.font.set)
184 XSetFont(disp, dc.gc, dc.font.xfont->fid);
185 loadawesomeprops(disp, awesomeconf);
189 * Startup Error handler to check if another window manager
190 * is already running.
192 static int
193 xerrorstart(Display * dsply __attribute__ ((unused)), XErrorEvent * ee __attribute__ ((unused)))
195 otherwm = True;
196 return -1;
199 /* extern */
201 void
202 uicb_quit(Display *disp __attribute__ ((unused)),
203 awesome_config *awesomeconf __attribute__((unused)),
204 const char *arg __attribute__ ((unused)))
206 readin = running = False;
209 void
210 updatebarpos(Display *disp, Statusbar statusbar)
212 XEvent ev;
214 wax = 0;
215 way = 0;
216 wah = DisplayHeight(disp, DefaultScreen(disp));
217 waw = DisplayWidth(disp, DefaultScreen(disp));
218 switch (statusbar.position)
220 default:
221 wah -= statusbar.height;
222 way += statusbar.height;
223 XMoveWindow(disp, statusbar.window, 0, 0);
224 break;
225 case BarBot:
226 wah -= statusbar.height;
227 XMoveWindow(disp, statusbar.window, 0, wah);
228 break;
229 case BarOff:
230 XMoveWindow(disp, statusbar.window, 0, 0 - statusbar.height);
231 break;
233 XSync(disp, False);
234 while(XCheckMaskEvent(disp, EnterWindowMask, &ev));
237 /* There's no way to check accesses to destroyed windows, thus those cases are
238 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
239 * default error handler, which may call exit.
242 xerror(Display * edpy, XErrorEvent * ee)
244 if(ee->error_code == BadWindow
245 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
246 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
247 || (ee->request_code == X_PolyFillRectangle
248 && ee->error_code == BadDrawable)
249 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
250 || (ee->request_code == X_ConfigureWindow
251 && ee->error_code == BadMatch) || (ee->request_code == X_GrabKey
252 && ee->error_code == BadAccess)
253 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
254 return 0;
255 fprintf(stderr, "awesome: fatal error: request code=%d, error code=%d\n",
256 ee->request_code, ee->error_code);
258 return xerrorxlib(edpy, ee); /* may call exit */
262 main(int argc, char *argv[])
264 char *p;
265 int r, xfd;
266 fd_set rd;
267 XEvent ev;
268 Display * dpy;
269 Window root;
270 awesome_config awesomeconf;
272 if(argc == 2 && !strcmp("-v", argv[1]))
273 eprint("awesome-" VERSION " © 2007 Julien Danjou\n");
274 else if(argc != 1)
275 eprint("usage: awesome [-v]\n");
276 setlocale(LC_CTYPE, "");
279 if(!(dpy = XOpenDisplay(NULL)))
280 eprint("awesome: cannot open display\n");
281 xfd = ConnectionNumber(dpy);
282 root = RootWindow(dpy, DefaultScreen(dpy));
283 XSetErrorHandler(xerrorstart);
285 /* this causes an error if some other window manager is running */
286 XSelectInput(dpy, root, SubstructureRedirectMask);
287 XSync(dpy, False);
289 if(otherwm)
290 eprint("awesome: another window manager is already running\n");
292 XSync(dpy, False);
293 XSetErrorHandler(NULL);
294 xerrorxlib = XSetErrorHandler(xerror);
295 XSync(dpy, False);
296 parse_config(dpy, DefaultScreen(dpy), &dc, &awesomeconf);
297 setup(dpy, &awesomeconf);
298 drawstatus(dpy, &awesomeconf);
299 scan(dpy, &awesomeconf);
300 XSync(dpy, False);
302 void (*handler[LASTEvent]) (XEvent *, awesome_config *) =
304 [ButtonPress] = handle_event_buttonpress,
305 [ConfigureRequest] = handle_event_configurerequest,
306 [ConfigureNotify] = handle_event_configurenotify,
307 [DestroyNotify] = handle_event_destroynotify,
308 [EnterNotify] = handle_event_enternotify,
309 [LeaveNotify] = handle_event_leavenotify,
310 [Expose] = handle_event_expose,
311 [KeyPress] = handle_event_keypress,
312 [MappingNotify] = handle_event_mappingnotify,
313 [MapRequest] = handle_event_maprequest,
314 [PropertyNotify] = handle_event_propertynotify,
315 [UnmapNotify] = handle_event_unmapnotify
319 /* main event loop, also reads status text from stdin */
320 while(running)
322 FD_ZERO(&rd);
323 if(readin)
324 FD_SET(STDIN_FILENO, &rd);
325 FD_SET(xfd, &rd);
326 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
328 if(errno == EINTR)
329 continue;
330 eprint("select failed\n");
332 if(FD_ISSET(STDIN_FILENO, &rd))
334 switch (r = read(STDIN_FILENO, awesomeconf.statustext, sizeof(awesomeconf.statustext) - 1))
336 case -1:
337 strncpy(awesomeconf.statustext, strerror(errno), sizeof(awesomeconf.statustext) - 1);
338 awesomeconf.statustext[sizeof(awesomeconf.statustext) - 1] = '\0';
339 readin = False;
340 break;
341 case 0:
342 strncpy(awesomeconf.statustext, "EOF", 4);
343 readin = False;
344 break;
345 default:
346 for(awesomeconf.statustext[r] = '\0', p = awesomeconf.statustext + strlen(awesomeconf.statustext) - 1;
347 p >= awesomeconf.statustext && *p == '\n'; *p-- = '\0');
348 for(; p >= awesomeconf.statustext && *p != '\n'; --p);
349 if(p > awesomeconf.statustext)
350 strncpy(awesomeconf.statustext, p + 1, sizeof(awesomeconf.statustext));
352 drawstatus(dpy, &awesomeconf);
355 while(XPending(dpy))
357 XNextEvent(dpy, &ev);
358 if(handler[ev.type])
359 (handler[ev.type]) (&ev, &awesomeconf); /* call handler */
362 cleanup(dpy, &awesomeconf);
363 XCloseDisplay(dpy);
365 return 0;