1 /* See LICENSE file for copyright and license details. */
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>
21 int wax
, way
, waw
, wah
;
22 Atom netatom
[NetLast
];
23 Client
*clients
= NULL
;
26 Cursor cursor
[CurLast
];
31 static int (*xerrorxlib
) (Display
*, XErrorEvent
*);
32 static Bool otherwm
= False
, readin
= True
;
33 static Bool running
= True
;
37 gettextprop(Display
*disp
, Window w
, Atom atom
, char *text
, unsigned int size
)
44 if(!text
|| size
== 0)
48 XGetTextProperty(disp
, w
, &name
, atom
);
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';
68 cleanup(Display
*disp
, awesome_config
*awesomeconf
)
74 unmanage(stack
, &dc
, NormalState
, awesomeconf
);
77 XFreeFontSet(disp
, dc
.font
.set
);
79 XFreeFont(disp
, dc
.font
.xfont
);
80 XUngrabKey(disp
, AnyKey
, AnyModifier
, DefaultRootWindow(disp
));
81 XFreePixmap(disp
, dc
.drawable
);
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
);
92 getstate(Display
*disp
, Window w
)
96 unsigned char *p
= NULL
;
97 unsigned long n
, extra
;
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
)
111 scan(Display
*disp
, awesome_config
*awesomeconf
)
114 Window
*wins
, d1
, d2
;
115 XWindowAttributes wa
;
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
))
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
))
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
);
140 /** Setup everything before running
141 * \param disp Display ref
142 * \param awesomeconf awesome config ref
143 * \todo clean things...
146 setup(Display
*disp
, awesome_config
*awesomeconf
)
148 XSetWindowAttributes wa
;
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
);
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
);
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
);
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.
193 xerrorstart(Display
* dsply
__attribute__ ((unused
)), XErrorEvent
* ee
__attribute__ ((unused
)))
202 uicb_quit(Display
*disp
__attribute__ ((unused
)),
203 awesome_config
*awesomeconf
__attribute__((unused
)),
204 const char *arg
__attribute__ ((unused
)))
206 readin
= running
= False
;
210 updatebarpos(Display
*disp
, Statusbar statusbar
)
216 wah
= DisplayHeight(disp
, DefaultScreen(disp
));
217 waw
= DisplayWidth(disp
, DefaultScreen(disp
));
218 switch (statusbar
.position
)
221 wah
-= statusbar
.height
;
222 way
+= statusbar
.height
;
223 XMoveWindow(disp
, statusbar
.window
, 0, 0);
226 wah
-= statusbar
.height
;
227 XMoveWindow(disp
, statusbar
.window
, 0, wah
);
230 XMoveWindow(disp
, statusbar
.window
, 0, 0 - statusbar
.height
);
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
))
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
[])
270 awesome_config awesomeconf
;
272 if(argc
== 2 && !strcmp("-v", argv
[1]))
273 eprint("awesome-" VERSION
" © 2007 Julien Danjou\n");
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
);
290 eprint("awesome: another window manager is already running\n");
293 XSetErrorHandler(NULL
);
294 xerrorxlib
= XSetErrorHandler(xerror
);
296 parse_config(dpy
, DefaultScreen(dpy
), &dc
, &awesomeconf
);
297 setup(dpy
, &awesomeconf
);
298 drawstatus(dpy
, &awesomeconf
);
299 scan(dpy
, &awesomeconf
);
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 */
324 FD_SET(STDIN_FILENO
, &rd
);
326 if(select(xfd
+ 1, &rd
, NULL
, NULL
, NULL
) == -1)
330 eprint("select failed\n");
332 if(FD_ISSET(STDIN_FILENO
, &rd
))
334 switch (r
= read(STDIN_FILENO
, awesomeconf
.statustext
, sizeof(awesomeconf
.statustext
) - 1))
337 strncpy(awesomeconf
.statustext
, strerror(errno
), sizeof(awesomeconf
.statustext
) - 1);
338 awesomeconf
.statustext
[sizeof(awesomeconf
.statustext
) - 1] = '\0';
342 strncpy(awesomeconf
.statustext
, "EOF", 4);
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
);
357 XNextEvent(dpy
, &ev
);
359 (handler
[ev
.type
]) (&ev
, &awesomeconf
); /* call handler */
362 cleanup(dpy
, &awesomeconf
);