X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=ae5fd0df916c0b404aa9050a980d3450b4c51dea;hb=26fa228650f79b639e4b92c577e7c981db65ab5d;hp=29290d5d60a4922f8c1acf8f889d7fcc8147abc7;hpb=a1d2fb7ac3944d438cec8635ce113177c25b085b;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 29290d5..ae5fd0d 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2009 Marco Peereboom * Copyright (c) 2009 Ryan McBride + * Copyright (c) 2009 Darrin Chandler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,7 +51,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.8" +#define SWM_VERSION "0.9.5" #include #include @@ -105,6 +106,8 @@ static const char *cvstag = "$scrotwm$"; #define SWM_D_MOUSE 0x0040 #define SWM_D_PROP 0x0080 #define SWM_D_CLASS 0x0100 +#define SWM_D_KEY 0x0200 +#define SWM_D_QUIRK 0x0400 u_int32_t swm_debug = 0 | SWM_D_MISC @@ -116,6 +119,8 @@ u_int32_t swm_debug = 0 | SWM_D_MOUSE | SWM_D_PROP | SWM_D_CLASS + | SWM_D_KEY + | SWM_D_QUIRK ; #else #define DPRINTF(x...) @@ -128,6 +133,9 @@ u_int32_t swm_debug = 0 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define SWM_PROPLEN (16) +#define SWM_FUNCNAME_LEN (32) +#define SWM_KEYS_LEN (255) +#define SWM_QUIRK_LEN (32) #define X(r) (r)->g.x #define Y(r) (r)->g.y #define WIDTH(r) (r)->g.w @@ -140,6 +148,8 @@ u_int32_t swm_debug = 0 char **start_argv; Atom astate; +Atom aprot; +Atom adelete; int (*xerrorxlib)(Display *, XErrorEvent *); int other_wm; int running = 1; @@ -158,7 +168,7 @@ int font_adjusted = 0; /* dialog windows */ double dialog_ratio = .6; /* status bar */ -#define SWM_BAR_MAX (128) +#define SWM_BAR_MAX (256) char *bar_argv[] = { NULL, NULL }; int bar_pipe[2]; char bar_ext[SWM_BAR_MAX]; @@ -171,13 +181,14 @@ int bar_extra = 1; int bar_extra_running = 0; int bar_verbose = 1; int bar_height = 0; +int clock_enabled = 1; pid_t bar_pid; GC bar_gc; XGCValues bar_gcv; int bar_fidx = 0; XFontStruct *bar_fs; char *bar_fonts[] = { - "-*-terminus-*-*-*-*-*-*-*-*-*-*-*-*", + "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*", "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*", NULL }; @@ -228,6 +239,7 @@ struct ws_win { int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; int last_inc; + int can_delete; unsigned long quirks; struct workspace *ws; /* always valid */ struct swm_screen *s; /* always valid, never changes */ @@ -237,6 +249,62 @@ struct ws_win { }; TAILQ_HEAD(ws_win_list, ws_win); +/* user/key callable function IDs */ +enum keyfuncid { + kf_cycle_layout, + kf_stack_reset, + kf_master_shrink, + kf_master_grow, + kf_master_add, + kf_master_del, + kf_stack_inc, + kf_stack_dec, + kf_swap_main, + kf_focus_next, + kf_focus_prev, + kf_swap_next, + kf_swap_prev, + kf_spawn_term, + kf_spawn_menu, + kf_quit, + kf_restart, + kf_focus_main, + kf_ws_1, + kf_ws_2, + kf_ws_3, + kf_ws_4, + kf_ws_5, + kf_ws_6, + kf_ws_7, + kf_ws_8, + kf_ws_9, + kf_ws_10, + kf_ws_next, + kf_ws_prev, + kf_screen_next, + kf_screen_prev, + kf_mvws_1, + kf_mvws_2, + kf_mvws_3, + kf_mvws_4, + kf_mvws_5, + kf_mvws_6, + kf_mvws_7, + kf_mvws_8, + kf_mvws_9, + kf_mvws_10, + kf_bar_toggle, + kf_wind_kill, + kf_wind_del, + kf_screenshot_all, + kf_screenshot_wind, + kf_float_toggle, + kf_version, + kf_spawn_lock, + kf_spawn_initscr, + kf_invalid +}; + /* layout handlers */ void stack(void); void vertical_config(struct workspace *, int); @@ -246,6 +314,16 @@ void horizontal_stack(struct workspace *, struct swm_geometry *); void max_stack(struct workspace *, struct swm_geometry *); void grabbuttons(struct ws_win *, int); +void new_region(struct swm_screen *, int, int, int, int); +void update_modkey(unsigned int); +/* user functions / key binding */ +int bindmatch(const char *var, const char *name, unsigned int currmod, char *keystr, + enum keyfuncid *kfid, unsigned int *mod, KeySym *ks); +void setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid); +/* quirks */ +int quirkmatch(const char *var, const char *name, char *qstr, + char *qclass, char *qname, unsigned long *qquirk); +void setquirk(const char *class, const char *name, const int quirk); struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); @@ -330,27 +408,24 @@ union arg { #define SWM_ARG_ID_SS_WINDOW (1) #define SWM_ARG_ID_DONTCENTER (0) #define SWM_ARG_ID_CENTER (1) +#define SWM_ARG_ID_KILLWINDOW (0) +#define SWM_ARG_ID_DELETEWINDOW (1) char **argv; }; /* quirks */ struct quirk { - char *class; - char *name; + char class[SWM_QUIRK_LEN]; + char name[SWM_QUIRK_LEN]; unsigned long quirk; #define SWM_Q_FLOAT (1<<0) /* float this window */ #define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ #define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ #define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */ -} quirks[] = { - { "MPlayer", "xv", SWM_Q_FLOAT }, - { "OpenOffice.org 2.4", "VCLSalFrame", SWM_Q_FLOAT }, - { "OpenOffice.org 3.0", "VCLSalFrame", SWM_Q_FLOAT }, - { "Firefox-bin", "firefox-bin", SWM_Q_TRANSSZ}, - { "Gimp", "gimp", SWM_Q_FLOAT | SWM_Q_ANYWHERE}, - { "XTerm", "xterm", SWM_Q_XTERM_FONTADJ}, - { NULL, NULL, 0}, +#define SWM_Q_FULLSCREEN (1<<4) /* remove border */ }; +int quirks_size = 0, quirks_length = 0; +struct quirk *quirks = NULL; /* events */ void expose(XEvent *); @@ -361,6 +436,7 @@ void configurenotify(XEvent *); void destroynotify(XEvent *); void enternotify(XEvent *); void focusin(XEvent *); +void focusout(XEvent *); void mappingnotify(XEvent *); void maprequest(XEvent *); void propertynotify(XEvent *); @@ -376,6 +452,7 @@ void (*handler[LASTEvent])(XEvent *) = { [DestroyNotify] = destroynotify, [EnterNotify] = enternotify, [FocusIn] = focusin, + [FocusOut] = focusout, [MappingNotify] = mappingnotify, [MapRequest] = maprequest, [PropertyNotify] = propertynotify, @@ -425,8 +502,6 @@ setscreencolor(char *val, int i, int c) i, ScreenCount(display)); } -void new_region(struct swm_screen *, int, int, int, int); - void custom_region(char *val) { @@ -490,6 +565,12 @@ conf_load(char *filename) char *line, *cp, *var, *val; size_t len, lineno = 0; int i, sc; + unsigned int modkey = MODKEY, modmask; + KeySym ks; + enum keyfuncid kfid; + char class[SWM_QUIRK_LEN]; + char name[SWM_QUIRK_LEN]; + unsigned long quirk; DNPRINTF(SWM_D_MISC, "conf_load: filename %s\n", filename); @@ -533,12 +614,17 @@ conf_load(char *filename) asprintf(&bar_argv[0], "%s", val); else if (!strncmp(var, "bar_delay", strlen("bar_delay"))) bar_delay = atoi(val); + else if (!bindmatch(var, "bind", modkey, val, + &kfid, &modmask, &ks)) + setkeybinding(modmask, ks, kfid); else goto bad; break; case 'c': - if (!varmatch(var, "color_focus", &i)) + if (!strncmp(var, "clock_enabled", strlen("clock_enabled"))) + clock_enabled = atoi(val); + else if (!varmatch(var, "color_focus", &i)) setscreencolor(val, i, SWM_S_COLOR_FOCUS); else if (!varmatch(var, "color_unfocus", &i)) setscreencolor(val, i, SWM_S_COLOR_UNFOCUS); @@ -560,6 +646,29 @@ conf_load(char *filename) goto bad; break; + case 'm': + if (!strncmp(var, "modkey", strlen("modkey"))) { + modkey = MODKEY; + if (!strncmp(val, "Mod2", strlen("Mod2"))) + modkey = Mod2Mask; + else if (!strncmp(val, "Mod3", strlen("Mod3"))) + modkey = Mod3Mask; + else if (!strncmp(val, "Mod4", strlen("Mod4"))) + modkey = Mod4Mask; + else + modkey = Mod1Mask; + update_modkey(modkey); + } else + goto bad; + break; + + case 'q': + if (!quirkmatch(var, "quirk", val, class, name, &quirk)) + setquirk(class, name, quirk); + else + goto bad; + break; + case 'r': if (!strncmp(var, "region", strlen("region"))) custom_region(val); @@ -665,14 +774,18 @@ bar_update(void) } else strlcpy(bar_ext, "", sizeof bar_ext); - time(&tmt); - localtime_r(&tmt, &tm); - strftime(s, sizeof s, "%a %b %d %R %Z %Y", &tm); + if (clock_enabled == 0) + strlcpy(s, "", sizeof s); + else { + time(&tmt); + localtime_r(&tmt, &tm); + strftime(s, sizeof s, "%a %b %d %R %Z %Y ", &tm); + } for (i = 0; i < ScreenCount(display); i++) { x = 1; TAILQ_FOREACH(r, &screens[i].rl, entry) { - snprintf(loc, sizeof loc, "%s %d:%d %s %s", - s, x++, r->ws->idx + 1, bar_ext, bar_vertext); + snprintf(loc, sizeof loc, "%d:%d %s%s %s", + x++, r->ws->idx + 1, s, bar_ext, bar_vertext); bar_print(r, loc); } } @@ -694,15 +807,15 @@ bar_toggle(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_MISC, "bar_toggle\n"); - if (bar_enabled) { + if (bar_enabled) for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) XUnmapWindow(display, tmpr->bar_window); - } else { + else for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) XMapRaised(display, tmpr->bar_window); - } + bar_enabled = !bar_enabled; for (i = 0; i < sc; i++) for (j = 0; j < SWM_WS_MAX; j++) @@ -799,13 +912,29 @@ version(struct swm_region *r, union arg *args) { bar_version = !bar_version; if (bar_version) - strlcpy(bar_vertext, cvstag, sizeof bar_vertext); + snprintf(bar_vertext, sizeof bar_vertext, "Version: %s CVS: %s", + SWM_VERSION, cvstag); else strlcpy(bar_vertext, "", sizeof bar_vertext); bar_update(); } void +client_msg(struct ws_win *win, Atom a) +{ + XClientMessageEvent cm; + + bzero(&cm, sizeof cm); + cm.type = ClientMessage; + cm.window = win->id; + cm.message_type = aprot; + cm.format = 32; + cm.data.l[0] = a; + cm.data.l[1] = CurrentTime; + XSendEvent(display, win->id, False, 0L, (XEvent *)&cm); +} + +void config_win(struct ws_win *win) { XConfigureEvent ce; @@ -1017,6 +1146,28 @@ spawnmenu(struct swm_region *r, union arg *args) } void +unfocus_win(struct ws_win *win) +{ + if (win == NULL) + return; + + if (win->ws->focus != win && win->ws->focus != NULL) + win->ws->focus_prev = win->ws->focus; + + if (win->ws->r == NULL) + return; + + grabbuttons(win, 0); + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); + win->got_focus = 0; + if (win->ws->focus == win) + win->ws->focus = NULL; + if (cur_focus == win) + cur_focus = NULL; +} + +void unfocus_all(void) { struct ws_win *win; @@ -1026,16 +1177,8 @@ unfocus_all(void) for (i = 0; i < ScreenCount(display); i++) for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { - if (win->ws->r == NULL) - continue; - grabbuttons(win, 0); - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); - win->got_focus = 0; - win->ws->focus = NULL; - cur_focus = NULL; - } + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + unfocus_win(win); } void @@ -1046,10 +1189,14 @@ focus_win(struct ws_win *win) if (win == NULL) return; - if (win->ws->focus != win && win->ws->focus != NULL) - win->ws->focus_prev = win->ws->focus; - - unfocus_all(); + if (cur_focus) + unfocus_win(cur_focus); + if (win->ws->focus) { + /* probably shouldn't happen due to the previous unfocus_win */ + DNPRINTF(SWM_D_FOCUS, "unfocusing win->ws->focus: %lu\n", + win->ws->focus->id); + unfocus_win(win->ws->focus); + } win->ws->focus = win; if (win->ws->r != NULL) { cur_focus = win; @@ -1104,6 +1251,8 @@ switchws(struct swm_region *r, union arg *args) ignore_enter = 1; /* set focus */ + if (new_ws->focus == NULL) + new_ws->focus = TAILQ_FIRST(&new_ws->winlist); if (new_ws->focus) focus_win(new_ws->focus); stack(); @@ -1262,6 +1411,10 @@ focus(struct swm_region *r, union arg *args) case SWM_ARG_ID_FOCUSMAIN: winfocus = TAILQ_FIRST(wl); + if (winfocus == cur_focus) + winfocus = cur_focus->ws->focus_prev; + if (winfocus == NULL) + return; break; default: @@ -1345,7 +1498,11 @@ stack_floater(struct ws_win *win, struct swm_region *r) bzero(&wc, sizeof wc); mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight; - wc.border_width = 1; + if ((win->quirks & SWM_Q_FULLSCREEN) && (win->g.w == WIDTH(r)) && + (win->g.h == HEIGHT(r))) + wc.border_width = 0; + else + wc.border_width = 1; if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { win->g.w = (double)WIDTH(r) * dialog_ratio; win->g.h = (double)HEIGHT(r) * dialog_ratio; @@ -1410,7 +1567,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; int split, colno, winno, mwin, msize, mscale; - int remain, missing, v_slice;; + int remain, missing, v_slice; unsigned int mask; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d\n rot=%s flip=%s", @@ -1761,9 +1918,16 @@ send_to_ws(struct swm_region *r, union arg *args) void wkill(struct swm_region *r, union arg *args) { - DNPRINTF(SWM_D_MISC, "wkill\n"); - if(r->ws->focus != NULL) + DNPRINTF(SWM_D_MISC, "wkill %d\n", args->id); + + if(r->ws->focus == NULL) + return; + + if (args->id == SWM_ARG_ID_KILLWINDOW) XKillClient(display, r->ws->focus->id); + else + if (r->ws->focus->can_delete) + client_msg(r->ws->focus, adelete); } void @@ -1804,68 +1968,6 @@ floating_toggle(struct swm_region *r, union arg *args) focus_win(win); } -/* key definitions */ -struct key { - unsigned int mod; - KeySym keysym; - void (*func)(struct swm_region *r, union arg *); - union arg args; -} keys[] = { - /* modifier key function argument */ - { MODKEY, XK_space, cycle_layout, {0} }, - { MODKEY | ShiftMask, XK_space, stack_config, {.id = SWM_ARG_ID_STACKRESET} }, - { MODKEY, XK_h, stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, - { MODKEY, XK_l, stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, - { MODKEY, XK_comma, stack_config, {.id = SWM_ARG_ID_MASTERADD} }, - { MODKEY, XK_period, stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, - { MODKEY | ShiftMask, XK_comma, stack_config, {.id = SWM_ARG_ID_STACKINC} }, - { MODKEY | ShiftMask, XK_period, stack_config, {.id = SWM_ARG_ID_STACKDEC} }, - { MODKEY, XK_Return, swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, - { MODKEY, XK_j, focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, - { MODKEY, XK_k, focus, {.id = SWM_ARG_ID_FOCUSPREV} }, - { MODKEY | ShiftMask, XK_j, swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, - { MODKEY | ShiftMask, XK_k, swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, - { MODKEY | ShiftMask, XK_Return, spawnterm, {.argv = spawn_term} }, - { MODKEY, XK_p, spawnmenu, {.argv = spawn_menu} }, - { MODKEY | ShiftMask, XK_q, quit, {0} }, - { MODKEY, XK_q, restart, {0} }, - { MODKEY, XK_m, focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, - { MODKEY, XK_1, switchws, {.id = 0} }, - { MODKEY, XK_2, switchws, {.id = 1} }, - { MODKEY, XK_3, switchws, {.id = 2} }, - { MODKEY, XK_4, switchws, {.id = 3} }, - { MODKEY, XK_5, switchws, {.id = 4} }, - { MODKEY, XK_6, switchws, {.id = 5} }, - { MODKEY, XK_7, switchws, {.id = 6} }, - { MODKEY, XK_8, switchws, {.id = 7} }, - { MODKEY, XK_9, switchws, {.id = 8} }, - { MODKEY, XK_0, switchws, {.id = 9} }, - { MODKEY, XK_Right, cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, - { MODKEY, XK_Left, cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, - { MODKEY | ShiftMask, XK_Right, cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, - { MODKEY | ShiftMask, XK_Left, cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, - { MODKEY | ShiftMask, XK_1, send_to_ws, {.id = 0} }, - { MODKEY | ShiftMask, XK_2, send_to_ws, {.id = 1} }, - { MODKEY | ShiftMask, XK_3, send_to_ws, {.id = 2} }, - { MODKEY | ShiftMask, XK_4, send_to_ws, {.id = 3} }, - { MODKEY | ShiftMask, XK_5, send_to_ws, {.id = 4} }, - { MODKEY | ShiftMask, XK_6, send_to_ws, {.id = 5} }, - { MODKEY | ShiftMask, XK_7, send_to_ws, {.id = 6} }, - { MODKEY | ShiftMask, XK_8, send_to_ws, {.id = 7} }, - { MODKEY | ShiftMask, XK_9, send_to_ws, {.id = 8} }, - { MODKEY | ShiftMask, XK_0, send_to_ws, {.id = 9} }, - { MODKEY, XK_b, bar_toggle, {0} }, - { MODKEY, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, - { MODKEY | ShiftMask, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSPREV} }, - { MODKEY | ShiftMask, XK_x, wkill, {0} }, - { MODKEY, XK_s, screenshot, {.id = SWM_ARG_ID_SS_ALL} }, - { MODKEY | ShiftMask, XK_s, screenshot, {.id = SWM_ARG_ID_SS_WINDOW} }, - { MODKEY, XK_t, floating_toggle,{0} }, - { MODKEY | ShiftMask, XK_v, version, {0} }, - { MODKEY | ShiftMask, XK_Delete, spawn, {.argv = spawn_lock} }, - { MODKEY | ShiftMask, XK_i, spawn, {.argv = spawn_initscr} }, -}; - void resize_window(struct ws_win *win, int center) { @@ -2021,6 +2123,73 @@ move(struct ws_win *win, union arg *args) while (XCheckMaskEvent(display, EnterWindowMask, &ev)); } +/* key definitions */ +struct keyfunc { + char name[SWM_FUNCNAME_LEN]; + void (*func)(struct swm_region *r, union arg *); + union arg args; +} keyfuncs[kf_invalid] = { + /* name function argument */ + { "cycle_layout", cycle_layout, {0} }, + { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, + { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, + { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, + { "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} }, + { "master_del", stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, + { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, + { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, + { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, + { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, + { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, + { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, + { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, + { "spawn_term", spawnterm, {.argv = spawn_term} }, + { "spawn_menu", spawnmenu, {.argv = spawn_menu} }, + { "quit", quit, {0} }, + { "restart", restart, {0} }, + { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, + { "ws_1", switchws, {.id = 0} }, + { "ws_2", switchws, {.id = 1} }, + { "ws_3", switchws, {.id = 2} }, + { "ws_4", switchws, {.id = 3} }, + { "ws_5", switchws, {.id = 4} }, + { "ws_6", switchws, {.id = 5} }, + { "ws_7", switchws, {.id = 6} }, + { "ws_8", switchws, {.id = 7} }, + { "ws_9", switchws, {.id = 8} }, + { "ws_10", switchws, {.id = 9} }, + { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, + { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, + { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, + { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, + { "mvws_1", send_to_ws, {.id = 0} }, + { "mvws_2", send_to_ws, {.id = 1} }, + { "mvws_3", send_to_ws, {.id = 2} }, + { "mvws_4", send_to_ws, {.id = 3} }, + { "mvws_5", send_to_ws, {.id = 4} }, + { "mvws_6", send_to_ws, {.id = 5} }, + { "mvws_7", send_to_ws, {.id = 6} }, + { "mvws_8", send_to_ws, {.id = 7} }, + { "mvws_9", send_to_ws, {.id = 8} }, + { "mvws_10", send_to_ws, {.id = 9} }, + { "bar_toggle", bar_toggle, {0} }, + { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, + { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, + { "screenshot_all", screenshot, {.id = SWM_ARG_ID_SS_ALL} }, + { "screenshot_wind", screenshot, {.id = SWM_ARG_ID_SS_WINDOW} }, + { "float_toggle", floating_toggle,{0} }, + { "version", version, {0} }, + { "spawn_lock", spawn, {.argv = spawn_lock} }, + { "spawn_initscr", spawn, {.argv = spawn_initscr} }, +}; +struct key { + unsigned int mod; + KeySym keysym; + enum keyfuncid funcid; +}; +int keys_size = 0, keys_length = 0; +struct key *keys = NULL; + /* mouse */ enum { client_click, root_click }; struct button { @@ -2037,6 +2206,223 @@ struct button { }; void +update_modkey(unsigned int mod) +{ + int i; + + for (i = 0; i < keys_length; i++) + if (keys[i].mod & ShiftMask) + keys[i].mod = mod | ShiftMask; + else + keys[i].mod = mod; + + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].mask & ShiftMask) + buttons[i].mask = mod | ShiftMask; + else + buttons[i].mask = mod; +} + +#define SWM_MODNAME_SIZE 32 +#define SWM_KEY_WS "\n+ \t" +int +parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks) +{ + char *cp, *name; + KeySym uks; + if (mod == NULL || ks == NULL) + return (0); + cp = keystr; + *mod = 0; + while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) { + if (cp) + cp += (long)strspn(cp, SWM_KEY_WS); + if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0) + *mod |= currmod; + else if (!strncasecmp(name, "Mod1", SWM_MODNAME_SIZE)) + *mod |= Mod1Mask; + else if (!strncasecmp(name, "Mod2", SWM_MODNAME_SIZE)) + *mod += Mod2Mask; + else if (!strncmp(name, "Mod3", SWM_MODNAME_SIZE)) + *mod |= Mod3Mask; + else if (!strncmp(name, "Mod4", SWM_MODNAME_SIZE)) + *mod |= Mod4Mask; + else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) + *mod |= ShiftMask; + else { + *ks = XStringToKeysym(name); + XConvertCase(*ks, ks, &uks); + if (ks == NoSymbol) { + DNPRINTF(SWM_D_KEY, + "parsekeys: invalid key %s\n", + name); + return (0); + } + } + } + return (1); +} +int +bindmatch(const char *var, const char *name, unsigned int currmod, char *keystr, + enum keyfuncid *kfid, unsigned int *mod, KeySym *ks) +{ + char *p; + int i; + char funcname[SWM_FUNCNAME_LEN]; + i = strncmp(var, name, 255); + if (kfid == NULL || mod == NULL || ks == NULL) + return (i); + *kfid = kf_invalid; + *mod = 0; + *ks = NoSymbol; + bzero(funcname, LENGTH(funcname)); + if (i <= 0) + return (i); + p = (char *)var + strlen(name); + if (*p++ != '[') + return (i); + i = 0; + while (isgraph(*p) && *p != ']' && i < LENGTH(funcname)) + funcname[i++] = *p++; + if (i >= LENGTH(funcname) || *p != ']') + return (1); + if (i == 0) + return (!parsekeys(keystr, currmod, mod, ks)); + for (*kfid = 0; *kfid < kf_invalid; (*kfid)++) { + if (strncasecmp(funcname, keyfuncs[*kfid].name, + SWM_FUNCNAME_LEN) == 0) { + return (!parsekeys(keystr, currmod, mod, ks)); + } + + } + return (1); +} +void +setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid) +{ + int i, j; + /* find existing */ + for (i = 0; i < keys_length; i++) { + if (keys[i].mod == mod && keys[i].keysym == ks) { + if (kfid == kf_invalid) { + /* found: delete */ + DNPRINTF(SWM_D_KEY, + "setkeybinding: delete #%d %s\n", + i, keyfuncs[keys[i].funcid].name); + j = keys_length - 1; + if (i < j) + keys[i] = keys[j]; + keys_length--; + return; + } else { + /* found: replace */ + DNPRINTF(SWM_D_KEY, + "setkeybinding: replace #%d %s\n", + i, keyfuncs[keys[i].funcid].name); + keys[i].mod = mod; + keys[i].keysym = ks; + keys[i].funcid = kfid; + return; + } + } + } + if (kfid == kf_invalid) { + fprintf(stderr, + "error: setkeybinding: cannot find mod/key combination"); + return; + } + /* not found: add */ + if (keys_size == 0 || keys == NULL) { + keys_size = 4; + DNPRINTF(SWM_D_KEY, "setkeybinding: init list %d\n", keys_size); + keys = malloc((size_t)keys_size * sizeof(struct key)); + if (!keys) { + fprintf(stderr, "malloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } else if (keys_length == keys_size) { + keys_size *= 2; + DNPRINTF(SWM_D_KEY, "setkeybinding: grow list %d\n", keys_size); + keys = realloc(keys, (size_t)keys_size * sizeof(struct key)); + if (!keys) { + fprintf(stderr, "realloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } + if (keys_length < keys_size) { + DNPRINTF(SWM_D_KEY, "setkeybinding: add %d\n", keys_length); + j = keys_length++; + keys[j].mod = mod; + keys[j].keysym = ks; + keys[j].funcid = kfid; + } else { + fprintf(stderr, "keys array problem?\n"); + if (!keys) { + fprintf(stderr, "keys array problem\n"); + quit(NULL, NULL); + } + } +} +void +setup_keys(void) +{ + setkeybinding(MODKEY, XK_space, kf_cycle_layout); + setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset); + setkeybinding(MODKEY, XK_h, kf_master_shrink); + setkeybinding(MODKEY, XK_l, kf_master_grow); + setkeybinding(MODKEY, XK_comma, kf_master_add); + setkeybinding(MODKEY, XK_period, kf_master_del); + setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc); + setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec); + setkeybinding(MODKEY, XK_Return, kf_swap_main); + setkeybinding(MODKEY, XK_j, kf_focus_next); + setkeybinding(MODKEY, XK_k, kf_focus_prev); + setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next); + setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev); + setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term); + setkeybinding(MODKEY, XK_p, kf_spawn_menu); + setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit); + setkeybinding(MODKEY, XK_q, kf_restart); + setkeybinding(MODKEY, XK_m, kf_focus_main); + setkeybinding(MODKEY, XK_1, kf_ws_1); + setkeybinding(MODKEY, XK_2, kf_ws_2); + setkeybinding(MODKEY, XK_3, kf_ws_3); + setkeybinding(MODKEY, XK_4, kf_ws_4); + setkeybinding(MODKEY, XK_5, kf_ws_5); + setkeybinding(MODKEY, XK_6, kf_ws_6); + setkeybinding(MODKEY, XK_7, kf_ws_7); + setkeybinding(MODKEY, XK_8, kf_ws_8); + setkeybinding(MODKEY, XK_9, kf_ws_9); + setkeybinding(MODKEY, XK_0, kf_ws_10); + setkeybinding(MODKEY, XK_Right, kf_ws_next); + setkeybinding(MODKEY, XK_Left, kf_ws_prev); + setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next); + setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev); + setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1); + setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2); + setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3); + setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4); + setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5); + setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6); + setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7); + setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8); + setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9); + setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10); + setkeybinding(MODKEY, XK_b, kf_bar_toggle); + setkeybinding(MODKEY, XK_Tab, kf_focus_next); + setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev); + setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill); + setkeybinding(MODKEY, XK_x, kf_wind_del); + setkeybinding(MODKEY, XK_s, kf_screenshot_all); + setkeybinding(MODKEY|ShiftMask, XK_s, kf_screenshot_wind); + setkeybinding(MODKEY, XK_t, kf_float_toggle); + setkeybinding(MODKEY|ShiftMask, XK_v, kf_version); + setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_lock); + setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_initscr); +} +void updatenumlockmask(void) { unsigned int i, j; @@ -2069,7 +2455,7 @@ grabkeys(void) if (TAILQ_EMPTY(&screens[k].rl)) continue; XUngrabKey(display, AnyKey, AnyModifier, screens[k].root); - for (i = 0; i < LENGTH(keys); i++) { + for (i = 0; i < keys_length; i++) { if ((code = XKeysymToKeycode(display, keys[i].keysym))) for (j = 0; j < LENGTH(modifiers); j++) XGrabKey(display, code, @@ -2119,12 +2505,14 @@ keypress(XEvent *e) DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window); keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); - for (i = 0; i < LENGTH(keys); i++) + for (i = 0; i < keys_length; i++) if (keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) - && keys[i].func) - keys[i].func(root_to_region(ev->root), - &(keys[i].args)); + && keyfuncs[keys[i].funcid].func) + keyfuncs[keys[i].funcid].func( + root_to_region(ev->root), + &(keyfuncs[keys[i].funcid].args) + ); } void @@ -2163,15 +2551,186 @@ set_win_state(struct ws_win *win, long state) (unsigned char *)data, 2); } +const char *quirkname[] = { + "NONE", /* config string for "no value" */ + "FLOAT", + "TRANSSZ", + "ANYWHERE", + "XTERM_FONTADJ", + "FULLSCREEN", +}; + +#define SWM_Q_WS "\n| \t" +int +parsequirks(char *qstr, unsigned long *quirk) +{ + char *cp, *name; + int i; + if (quirk == NULL) + return (0); + cp = qstr; + *quirk = 0; + while ((name = strsep(&cp, SWM_Q_WS)) != NULL) { + if (cp) + cp += (long)strspn(cp, SWM_Q_WS); + for (i = 0; i < LENGTH(quirkname); i++) { + if (!strncasecmp(name, quirkname[i], SWM_QUIRK_LEN)) { + DNPRINTF(SWM_D_QUIRK, "parsequirks: %s\n", name); + if (i == 0) { + *quirk = 0; + return (1); + } + *quirk |= 1 << (i-1); + break; + } + } + if (i >= LENGTH(quirkname)) { + DNPRINTF(SWM_D_QUIRK, + "parsequirks: invalid quirk [%s]\n", name); + return (0); + } + } + return (1); +} +int +quirkmatch(const char *var, const char *name, char *qstr, char *qclass, + char *qname, unsigned long *qquirk) +{ + char *p; + int i; + char classname[SWM_QUIRK_LEN*2+1]; + DNPRINTF(SWM_D_QUIRK, "quirkmatch: in [%s]\n", var); + i = strncmp(var, name, 255); + if (qclass == NULL || qname == NULL || qquirk == NULL) + return (i); + *qquirk = 0; + *qclass = '\0'; + *qname = '\0'; + bzero(classname, LENGTH(classname)); + if (i <= 0) + return (i); + p = (char *)var + strlen(name); + if (*p++ != '[') + return (i); + i = 0; + while (isgraph(*p) && *p != ']' && i < LENGTH(classname)) + classname[i++] = *p++; + if (i >= LENGTH(classname) || *p != ']') + return (1); + if ((p = strchr(classname, ':')) == NULL || p-classname >= SWM_QUIRK_LEN) + return (1); + strlcpy(qclass, classname, p-classname+1); + strlcpy(qname, ++p, SWM_QUIRK_LEN); + for (p = qclass; *p && p-qclass < SWM_QUIRK_LEN; p++) + if (*p == '_') + *p = ' '; + for (p = qname; *p && p-qname < SWM_QUIRK_LEN; p++) + if (*p == '_') + *p = ' '; + i = (!parsequirks(qstr, qquirk)); + DNPRINTF(SWM_D_QUIRK, "quirkmatch: [%s][%s] %d\n", qclass, qname, i); + return (i); +} +void +setquirk(const char *class, const char *name, const int quirk) +{ + int i, j; + /* find existing */ + for (i = 0; i < quirks_length; i++) { + if (!strcmp(quirks[i].class, class) && + !strcmp(quirks[i].name, name)) { + if (!quirk) { + /* found: delete */ + DNPRINTF(SWM_D_QUIRK, + "setquirk: delete #%d %s:%s\n", + i, quirks[i].class, quirks[i].name); + j = quirks_length - 1; + if (i < j) + quirks[i] = quirks[j]; + quirks_length--; + return; + } else { + /* found: replace */ + DNPRINTF(SWM_D_QUIRK, + "setquirk: replace #%d %s:%s\n", + i, quirks[i].class, quirks[i].name); + strlcpy(quirks[i].class, class, + sizeof quirks->class); + strlcpy(quirks[i].name, name, + sizeof quirks->name); + quirks[i].quirk = quirk; + return; + } + } + } + if (!quirk) { + fprintf(stderr, + "error: setquirk: cannot find class/name combination"); + return; + } + /* not found: add */ + if (quirks_size == 0 || quirks == NULL) { + quirks_size = 4; + DNPRINTF(SWM_D_QUIRK, "setquirk: init list %d\n", quirks_size); + quirks = malloc((size_t)quirks_size * sizeof(struct quirk)); + if (!quirks) { + fprintf(stderr, "setquirk: malloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } else if (quirks_length == quirks_size) { + quirks_size *= 2; + DNPRINTF(SWM_D_QUIRK, "setquirk: grow list %d\n", quirks_size); + quirks = realloc(quirks, (size_t)quirks_size * sizeof(struct quirk)); + if (!quirks) { + fprintf(stderr, "setquirk: realloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } + if (quirks_length < quirks_size) { + DNPRINTF(SWM_D_QUIRK, "setquirk: add %d\n", quirks_length); + j = quirks_length++; + strlcpy(quirks[j].class, class, sizeof quirks->class); + strlcpy(quirks[j].name, name, sizeof quirks->name); + quirks[j].quirk = quirk; + } else { + fprintf(stderr, "quirks array problem?\n"); + if (!quirks) { + fprintf(stderr, "quirks array problem!\n"); + quit(NULL, NULL); + } + } +} + +void +setup_quirks(void) +{ + setquirk("MPlayer", "xv", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); + setquirk("OpenOffice.org 2.4", "VCLSalFrame", SWM_Q_FLOAT); + setquirk("OpenOffice.org 3.0", "VCLSalFrame", SWM_Q_FLOAT); + setquirk("Firefox-bin", "firefox-bin", SWM_Q_TRANSSZ); + setquirk("Firefox", "Dialog", SWM_Q_FLOAT); + setquirk("Gimp", "gimp", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("XTerm", "xterm", SWM_Q_XTERM_FONTADJ); + setquirk("xine", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xitk Combo", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Panel", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Video Fullscreen Window", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); + setquirk("pcb", "pcb", SWM_Q_FLOAT); +} + struct ws_win * manage_window(Window id) { Window trans; struct workspace *ws; struct ws_win *win; - int format, i, ws_idx; + int format, i, ws_idx, n; unsigned long nitems, bytes; Atom ws_idx_atom = 0, type; + Atom *prot = NULL, *pp; unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; struct swm_region *r; long mask; @@ -2197,6 +2756,14 @@ manage_window(Window id) DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n", (unsigned)win->id, win->transient); } + /* get supported protocols */ + if (XGetWMProtocols(display, id, &prot, &n)) { + for (i = 0, pp = prot; i < n; i++, pp++) + if (*pp == adelete) + win->can_delete = 1; + if (prot) + XFree(prot); + } /* * Figure out where to put the window. If it was previously assigned to @@ -2239,8 +2806,7 @@ manage_window(Window id) if (XGetClassHint(display, win->id, &win->ch)) { DNPRINTF(SWM_D_CLASS, "class: %s name: %s\n", win->ch.res_class, win->ch.res_name); - for (i = 0; quirks[i].class != NULL && quirks[i].name != NULL && - quirks[i].quirk != 0; i++){ + for (i = 0; i < quirks_length; i++){ if (!strcmp(win->ch.res_class, quirks[i].class) && !strcmp(win->ch.res_name, quirks[i].name)) { DNPRINTF(SWM_D_CLASS, "found: %s name: %s\n", @@ -2270,6 +2836,14 @@ manage_window(Window id) XConfigureWindow(display, win->id, mask, &wc); } + /* Reset font sizes (the bruteforce way; no default keybinding). */ + if (win->quirks & SWM_Q_XTERM_FONTADJ) { + for (i = 0; i < SWM_MAX_FONT_STEPS; i++) + fake_keypress(win, XK_KP_Subtract, ShiftMask); + for (i = 0; i < SWM_MAX_FONT_STEPS; i++) + fake_keypress(win, XK_KP_Add, ShiftMask); + } + XSelectInput(display, id, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); @@ -2307,7 +2881,7 @@ unmanage_window(struct ws_win *win) ws->focus = TAILQ_FIRST(&ws->winlist); if (ws->focus == NULL || ws->focus == win) { ws->focus = NULL; - unfocus_all(); + unfocus_win(win); } else focus_win(ws->focus); if (ws->focus_prev == win) @@ -2360,13 +2934,13 @@ configurerequest(XEvent *e) if (win->ws->r != NULL) { /* this seems to be full screen */ if (win->g.w >= WIDTH(win->ws->r)) { - win->g.x = -1; + win->g.x = 0; win->g.w = WIDTH(win->ws->r); ev->value_mask |= CWX | CWWidth; } if (win->g.h >= HEIGHT(win->ws->r)) { /* kill border */ - win->g.y = -1; + win->g.y = 0; win->g.h = HEIGHT(win->ws->r); ev->value_mask |= CWY | CWHeight; } @@ -2390,13 +2964,15 @@ configurenotify(XEvent *e) DNPRINTF(SWM_D_EVENT, "configurenotify: window: %lu\n", e->xconfigure.window); + XMapWindow(display, e->xconfigure.window); win = find_window(e->xconfigure.window); - XMapWindow(display, win->id); - XGetWMNormalHints(display, win->id, &win->sh, &mask); - adjust_font(win); - XMapWindow(display, win->id); - if (font_adjusted) - stack(); + if (win) { + XGetWMNormalHints(display, win->id, &win->sh, &mask); + adjust_font(win); + XMapWindow(display, win->id); + if (font_adjusted) + stack(); + } } void @@ -2438,6 +3014,29 @@ focusin(XEvent *e) } void +focusout(XEvent *e) +{ + DNPRINTF(SWM_D_EVENT, "focusout: window: %lu\n", e->xfocus.window); + + if (cur_focus && cur_focus->ws->r && + cur_focus->id == e->xfocus.window) { + struct swm_screen *s = cur_focus->ws->r->s; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + + /* Try to detect synergy hiding the cursor. */ + if (XQueryPointer(display, cur_focus->id, + &rr, &cr, &x, &y, &wx, &wy, &mask) != False && + cr == 0 && !mask && + x == DisplayWidth(display, s->idx)/2 && + y == DisplayHeight(display, s->idx)/2) { + unfocus_win(cur_focus); + } + } +} + +void mappingnotify(XEvent *e) { XMappingEvent *ev = &e->xmapping; @@ -2571,13 +3170,12 @@ getstate(Window w) unsigned long n, extra; Atom real; - astate = XInternAtom(display, "WM_STATE", False); status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate, &real, &format, &n, &extra, (unsigned char **)&p); if (status != Success) return (-1); if (n != 0) - result = *p; + result = *((long *)p); XFree(p); return (result); } @@ -2735,6 +3333,11 @@ screenchange(XEvent *e) { TAILQ_FOREACH(r, &screens[i].rl, entry) TAILQ_FOREACH(win, &r->ws->winlist, entry) XUnmapWindow(display, win->id); + + /* add bars to all regions */ + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + bar_setup(r); stack(); } @@ -2834,6 +3437,26 @@ setup_screens(void) } } +void +workaround(void) +{ + int i; + Atom netwmcheck, netwmname, utf8_string; + Window root; + + /* work around sun jdk bugs, code from wmname */ + netwmcheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + netwmname = XInternAtom(display, "_NET_WM_NAME", False); + utf8_string = XInternAtom(display, "UTF8_STRING", False); + for (i = 0; i < ScreenCount(display); i++) { + root = screens[i].root; + XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&root, 1); + XChangeProperty(display, root, netwmname, utf8_string, 8, + PropModeReplace, "LG3D", strlen("LG3D")); + } +} + int main(int argc, char *argv[]) { @@ -2858,6 +3481,8 @@ main(int argc, char *argv[]) errx(1, "other wm running"); astate = XInternAtom(display, "WM_STATE", False); + aprot = XInternAtom(display, "WM_PROTOCOLS", False); + adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); /* look for local and global conf file */ pwd = getpwuid(getuid()); @@ -2865,6 +3490,8 @@ main(int argc, char *argv[]) errx(1, "invalid user %d", getuid()); setup_screens(); + setup_keys(); + setup_quirks(); snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); if (stat(conf, &sb) != -1) { @@ -2885,7 +3512,8 @@ main(int argc, char *argv[]) TAILQ_FOREACH(r, &screens[i].rl, entry) bar_setup(r); - /* ws[0].focus = TAILQ_FIRST(&ws[0].winlist); */ + /* set some values to work around bad programs */ + workaround(); grabkeys(); stack();