Remove xsession file
[evilwm.git] / main.c
bloba2732b0ac1c75b1d660361677552c9d9d4eff0b5
1 /* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2009 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <signal.h>
9 #include <X11/cursorfont.h>
10 #include "evilwm.h"
11 #include "log.h"
12 #include "xconfig.h"
14 #ifdef DEBUG
15 int log_indent = 0;
16 #endif
18 /* Commonly used X information */
19 Display *dpy;
20 XFontStruct *font;
21 Cursor move_curs;
22 Cursor resize_curs;
23 int num_screens;
24 ScreenInfo *screens;
25 #ifdef SHAPE
26 int have_shape, shape_event;
27 #endif
28 #ifdef RANDR
29 int have_randr, randr_event_base;
30 #endif
32 /* Standard X protocol atoms */
33 Atom xa_wm_state;
34 Atom xa_wm_protos;
35 Atom xa_wm_delete;
36 Atom xa_wm_cmapwins;
38 /* Motif atoms */
39 Atom mwm_hints;
41 /* evilwm atoms */
42 Atom xa_evilwm_unmaximised_horz;
43 Atom xa_evilwm_unmaximised_vert;
45 /* Things that affect user interaction */
46 #define CONFIG_FILE ".evilwmrc"
47 static const char *opt_display = "";
48 static const char *opt_font = DEF_FONT;
49 static const char *opt_fg = DEF_FG;
50 static const char *opt_bg = DEF_BG;
51 #ifdef VWM
52 static const char *opt_fc = DEF_FC;
53 #endif
54 static char *opt_grabmask1 = NULL;
55 static char *opt_grabmask2 = NULL;
56 static char *opt_altmask = NULL;
57 unsigned int numlockmask = 0;
58 unsigned int grabmask1 = ControlMask|Mod1Mask;
59 unsigned int grabmask2 = Mod1Mask;
60 unsigned int altmask = ShiftMask;
61 const char *opt_term[3] = { DEF_TERM, DEF_TERM, NULL };
62 int opt_bw = DEF_BW;
63 int opt_snap = 0;
64 #ifdef SOLIDDRAG
65 int no_solid_drag = 0; /* use solid drag by default */
66 #endif
67 struct list *applications = NULL;
69 /* Client tracking information */
70 struct list *clients_tab_order = NULL;
71 struct list *clients_mapping_order = NULL;
72 struct list *clients_stacking_order = NULL;
73 Client *current = NULL;
74 volatile Window initialising = None;
76 /* Event loop will run until this flag is set */
77 int wm_exit;
79 static void set_app(const char *arg);
80 static void set_app_geometry(const char *arg);
81 static void set_app_dock(void);
82 #ifdef VWM
83 static void set_app_vdesk(const char *arg);
84 static void set_app_fixed(void);
85 #endif
87 static struct xconfig_option evilwm_options[] = {
88 { XCONFIG_STRING, "fn", &opt_font },
89 { XCONFIG_STRING, "display", &opt_display },
90 { XCONFIG_STRING, "fg", &opt_fg },
91 { XCONFIG_STRING, "bg", &opt_bg },
92 #ifdef VWM
93 { XCONFIG_STRING, "fc", &opt_fc },
94 #endif
95 { XCONFIG_INT, "bw", &opt_bw },
96 { XCONFIG_STRING, "term", &opt_term[0] },
97 { XCONFIG_INT, "snap", &opt_snap },
98 { XCONFIG_STRING, "mask1", &opt_grabmask1 },
99 { XCONFIG_STRING, "mask2", &opt_grabmask2 },
100 { XCONFIG_STRING, "altmask", &opt_altmask },
101 { XCONFIG_CALL_1, "app", &set_app },
102 { XCONFIG_CALL_1, "geometry", &set_app_geometry },
103 { XCONFIG_CALL_1, "g", &set_app_geometry },
104 { XCONFIG_CALL_0, "dock", &set_app_dock },
105 #ifdef VWM
106 { XCONFIG_CALL_1, "vdesk", &set_app_vdesk },
107 { XCONFIG_CALL_1, "v", &set_app_vdesk },
108 { XCONFIG_CALL_0, "fixed", &set_app_fixed },
109 { XCONFIG_CALL_0, "f", &set_app_fixed },
110 { XCONFIG_CALL_0, "s", &set_app_fixed },
111 #endif
112 #ifdef SOLIDDRAG
113 { XCONFIG_BOOL, "nosoliddrag", &no_solid_drag },
114 #endif
115 { XCONFIG_END, NULL, NULL }
118 static void setup_display(void);
119 static void *xmalloc(size_t size);
120 static unsigned int parse_modifiers(char *s);
122 #ifdef STDIO
123 static void helptext(void) {
124 puts(
125 "usage: evilwm [-display display] [-term termprog] [-fn fontname]\n"
126 " [-fg foreground]"
127 #ifdef VWM
128 " [-fc fixed]"
129 #endif
130 " [-bg background] [-bw borderwidth]\n"
131 " [-mask1 modifiers] [-mask2 modifiers] [-altmask modifiers]\n"
132 " [-snap num]"
133 " [-app name/class] [-g geometry] [-dock]\n"
134 #ifdef VWM
135 " [-v vdesk] [-s]"
136 #endif
137 #ifdef SOLIDDRAG
138 " [-nosoliddrag]"
139 #endif
140 " [-V]"
143 #else
144 #define helptext()
145 #endif
147 int main(int argc, char *argv[]) {
148 struct sigaction act;
149 int argn = 1, ret;
152 const char *home = getenv("HOME");
153 if (home) {
154 char *conffile = xmalloc(strlen(home) + sizeof(CONFIG_FILE) + 2);
155 strcpy(conffile, home);
156 strcat(conffile, "/" CONFIG_FILE);
157 xconfig_parse_file(evilwm_options, conffile);
158 free(conffile);
161 ret = xconfig_parse_cli(evilwm_options, argc, argv, &argn);
162 if (ret == XCONFIG_MISSING_ARG) {
163 fprintf(stderr, "%s: missing argument to `%s'\n", argv[0], argv[argn]);
164 exit(1);
165 } else if (ret == XCONFIG_BAD_OPTION) {
166 if (0 == strcmp(argv[argn], "-h")
167 || 0 == strcmp(argv[argn], "--help")) {
168 helptext();
169 exit(0);
170 #ifdef STDIO
171 } else if (0 == strcmp(argv[argn], "-V")
172 || 0 == strcmp(argv[argn], "--version")) {
173 LOG_INFO("evilwm version " VERSION "\n");
174 exit(0);
175 #endif
176 } else {
177 helptext();
178 exit(1);
182 opt_term[1] = opt_term[0];
183 if (opt_grabmask1) grabmask1 = parse_modifiers(opt_grabmask1);
184 if (opt_grabmask2) grabmask2 = parse_modifiers(opt_grabmask2);
185 if (opt_altmask) altmask = parse_modifiers(opt_altmask);
187 wm_exit = 0;
188 act.sa_handler = handle_signal;
189 sigemptyset(&act.sa_mask);
190 act.sa_flags = 0;
191 sigaction(SIGTERM, &act, NULL);
192 sigaction(SIGINT, &act, NULL);
193 sigaction(SIGHUP, &act, NULL);
195 setup_display();
197 event_main_loop();
199 /* Quit Nicely */
200 while (clients_stacking_order)
201 remove_client(clients_stacking_order->data);
202 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
203 if (font) XFreeFont(dpy, font);
205 int i;
206 for (i = 0; i < num_screens; i++) {
207 ewmh_deinit_screen(&screens[i]);
208 XFreeGC(dpy, screens[i].invert_gc);
209 XInstallColormap(dpy, DefaultColormap(dpy, i));
212 free(screens);
213 XCloseDisplay(dpy);
215 return 0;
218 static void *xmalloc(size_t size) {
219 void *ptr = malloc(size);
220 if (!ptr) {
221 /* C99 defines the 'z' printf modifier for variables of
222 * type size_t. Fall back to casting to unsigned long. */
223 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
224 LOG_ERROR("out of memory, looking for %zu bytes\n", size);
225 #else
226 LOG_ERROR("out of memory, looking for %lu bytes\n",
227 (unsigned long)size);
228 #endif
229 exit(1);
231 return ptr;
234 static void setup_display(void) {
235 XGCValues gv;
236 XSetWindowAttributes attr;
237 XColor dummy;
238 XModifierKeymap *modmap;
239 /* used in scanning windows (XQueryTree) */
240 unsigned int i, j, nwins;
241 Window dw1, dw2, *wins;
242 XWindowAttributes winattr;
244 LOG_ENTER("setup_display()");
246 dpy = XOpenDisplay(opt_display);
247 if (!dpy) {
248 LOG_ERROR("can't open display %s\n", opt_display);
249 exit(1);
251 XSetErrorHandler(handle_xerror);
252 /* XSynchronize(dpy, True); */
254 /* Standard X protocol atoms */
255 xa_wm_state = XInternAtom(dpy, "WM_STATE", False);
256 xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False);
257 xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
258 xa_wm_cmapwins = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
259 /* Motif atoms */
260 mwm_hints = XInternAtom(dpy, _XA_MWM_HINTS, False);
261 /* evilwm atoms */
262 xa_evilwm_unmaximised_horz = XInternAtom(dpy, "_EVILWM_UNMAXIMISED_HORZ", False);
263 xa_evilwm_unmaximised_vert = XInternAtom(dpy, "_EVILWM_UNMAXIMISED_VERT", False);
264 /* EWMH atoms */
265 ewmh_init();
267 font = XLoadQueryFont(dpy, opt_font);
268 if (!font) font = XLoadQueryFont(dpy, DEF_FONT);
269 if (!font) {
270 LOG_ERROR("couldn't find a font to use: try starting with -fn fontname\n");
271 exit(1);
274 move_curs = XCreateFontCursor(dpy, XC_fleur);
275 resize_curs = XCreateFontCursor(dpy, XC_plus);
277 /* find out which modifier is NumLock - we'll use this when grabbing
278 * every combination of modifiers we can think of */
279 modmap = XGetModifierMapping(dpy);
280 for (i = 0; i < 8; i++) {
281 for (j = 0; j < (unsigned int)modmap->max_keypermod; j++) {
282 if (modmap->modifiermap[i*modmap->max_keypermod+j] == XKeysymToKeycode(dpy, XK_Num_Lock)) {
283 numlockmask = (1<<i);
284 LOG_DEBUG("XK_Num_Lock is (1<<0x%02x)\n", i);
288 XFreeModifiermap(modmap);
290 /* set up GC parameters - same for each screen */
291 gv.function = GXinvert;
292 gv.subwindow_mode = IncludeInferiors;
293 gv.line_width = 1; /* opt_bw */
294 gv.font = font->fid;
296 /* set up root window attributes - same for each screen */
297 attr.event_mask = ChildMask | EnterWindowMask | ColormapChangeMask;
299 /* SHAPE extension? */
300 #ifdef SHAPE
302 int e_dummy;
303 have_shape = XShapeQueryExtension(dpy, &shape_event, &e_dummy);
305 #endif
306 /* Xrandr extension? */
307 #ifdef RANDR
309 int e_dummy;
310 have_randr = XRRQueryExtension(dpy, &randr_event_base, &e_dummy);
311 if (!have_randr) {
312 LOG_DEBUG("XRandR is not supported on this display.\n");
315 #endif
317 /* now set up each screen in turn */
318 num_screens = ScreenCount(dpy);
319 if (num_screens < 0) {
320 LOG_ERROR("Can't count screens\n");
321 exit(1);
323 screens = xmalloc(num_screens * sizeof(ScreenInfo));
324 for (i = 0; i < (unsigned int)num_screens; i++) {
325 char *ds, *colon, *dot;
326 ds = DisplayString(dpy);
327 /* set up DISPLAY environment variable to use */
328 colon = strrchr(ds, ':');
329 if (colon && num_screens > 1) {
330 screens[i].display = xmalloc(14 + strlen(ds));
331 strcpy(screens[i].display, "DISPLAY=");
332 strcat(screens[i].display, ds);
333 colon = strrchr(screens[i].display, ':');
334 dot = strchr(colon, '.');
335 if (!dot)
336 dot = colon + strlen(colon);
337 snprintf(dot, 5, ".%d", i);
338 } else
339 screens[i].display = NULL;
341 screens[i].screen = i;
342 screens[i].root = RootWindow(dpy, i);
343 #ifdef RANDR
344 if (have_randr) {
345 XRRSelectInput(dpy, screens[i].root, RRScreenChangeNotifyMask);
347 #endif
348 #ifdef VWM
349 screens[i].vdesk = KEY_TO_VDESK(XK_1);
350 #endif
352 XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_fg, &screens[i].fg, &dummy);
353 XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_bg, &screens[i].bg, &dummy);
354 #ifdef VWM
355 XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_fc, &screens[i].fc, &dummy);
356 #endif
358 screens[i].invert_gc = XCreateGC(dpy, screens[i].root, GCFunction | GCSubwindowMode | GCLineWidth | GCFont, &gv);
360 XChangeWindowAttributes(dpy, screens[i].root, CWEventMask, &attr);
361 grab_keys_for_screen(&screens[i]);
362 screens[i].docks_visible = 1;
364 /* scan all the windows on this screen */
365 LOG_XENTER("XQueryTree(screen=%d)", i);
366 XQueryTree(dpy, screens[i].root, &dw1, &dw2, &wins, &nwins);
367 LOG_XDEBUG("%d windows\n", nwins);
368 LOG_XLEAVE();
369 for (j = 0; j < nwins; j++) {
370 XGetWindowAttributes(dpy, wins[j], &winattr);
371 if (!winattr.override_redirect && winattr.map_state == IsViewable)
372 make_new_client(wins[j], &screens[i]);
374 XFree(wins);
375 ewmh_init_screen(&screens[i]);
377 ewmh_set_net_active_window(NULL);
378 LOG_LEAVE();
381 /**************************************************************************/
382 /* Option parsing callbacks */
384 static void set_app(const char *arg) {
385 Application *new = xmalloc(sizeof(Application));
386 char *tmp;
387 new->res_name = new->res_class = NULL;
388 new->geometry_mask = 0;
389 new->is_dock = 0;
390 #ifdef VWM
391 new->vdesk = VDESK_NONE;
392 #endif
393 if ((tmp = strchr(arg, '/'))) {
394 *(tmp++) = 0;
396 if (strlen(arg) > 0) {
397 new->res_name = xmalloc(strlen(arg)+1);
398 strcpy(new->res_name, arg);
400 if (tmp && strlen(tmp) > 0) {
401 new->res_class = xmalloc(strlen(tmp)+1);
402 strcpy(new->res_class, tmp);
404 applications = list_prepend(applications, new);
407 static void set_app_geometry(const char *arg) {
408 if (applications) {
409 Application *app = applications->data;
410 app->geometry_mask = XParseGeometry(arg,
411 &app->x, &app->y, &app->width, &app->height);
415 static void set_app_dock(void) {
416 if (applications) {
417 Application *app = applications->data;
418 app->is_dock = 1;
422 #ifdef VWM
423 static void set_app_vdesk(const char *arg) {
424 unsigned int v = atoi(arg);
425 if (applications && valid_vdesk(v)) {
426 Application *app = applications->data;
427 app->vdesk = v;
431 static void set_app_fixed(void) {
432 if (applications) {
433 Application *app = applications->data;
434 app->vdesk = VDESK_FIXED;
437 #endif
439 /* Used for overriding the default WM modifiers */
440 static unsigned int parse_modifiers(char *s) {
441 static struct {
442 const char *name;
443 unsigned int mask;
444 } modifiers[9] = {
445 { "shift", ShiftMask },
446 { "lock", LockMask },
447 { "control", ControlMask },
448 { "alt", Mod1Mask },
449 { "mod1", Mod1Mask },
450 { "mod2", Mod2Mask },
451 { "mod3", Mod3Mask },
452 { "mod4", Mod4Mask },
453 { "mod5", Mod5Mask }
455 char *tmp = strtok(s, ",+");
456 unsigned int ret = 0;
457 int i;
458 if (!tmp)
459 return 0;
460 do {
461 for (i = 0; i < 9; i++) {
462 if (!strcmp(modifiers[i].name, tmp))
463 ret |= modifiers[i].mask;
465 tmp = strtok(NULL, ",+");
466 } while (tmp);
467 return ret;