+ XConfigureWindow(display, win->id, mask, &wc);
+ config_win(win);
+}
+
+void
+resize(struct ws_win *win, union arg *args)
+{
+ XEvent ev;
+ Time time = 0;
+
+ DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %d\n",
+ win->id, win->floating, win->transient);
+
+ if (!(win->transient != 0 || win->floating != 0))
+ return;
+
+ if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
+ GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
+ return;
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w, win->g.h);
+ do {
+ XMaskEvent(display, MOUSEMASK | ExposureMask |
+ SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ if (ev.xmotion.x <= 1)
+ ev.xmotion.x = 1;
+ if (ev.xmotion.y <= 1)
+ ev.xmotion.y = 1;
+ win->g.w = ev.xmotion.x;
+ win->g.h = ev.xmotion.y;
+
+ /* not free, don't sync more than 60 times / second */
+ if ((ev.xmotion.time - time) > (1000 / 60) ) {
+ time = ev.xmotion.time;
+ XSync(display, False);
+ resize_window(win, args->id);
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ if (time) {
+ XSync(display, False);
+ resize_window(win, args->id);
+ }
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w - 1,
+ win->g.h - 1);
+ XUngrabPointer(display, CurrentTime);
+
+ /* drain events */
+ while (XCheckMaskEvent(display, EnterWindowMask, &ev));
+}
+
+void
+move_window(struct ws_win *win)
+{
+ unsigned int mask;
+ XWindowChanges wc;
+ struct swm_region *r;
+
+ r = root_to_region(win->wa.root);
+ bzero(&wc, sizeof wc);
+ mask = CWX | CWY;
+ wc.x = win->g.x;
+ wc.y = win->g.y;
+
+ DNPRINTF(SWM_D_STACK, "move_window: win %lu x %d y %d w %d h %d\n",
+ win->id, wc.x, wc.y, wc.width, wc.height);
+
+ XConfigureWindow(display, win->id, mask, &wc);
+ config_win(win);
+}
+
+void
+move(struct ws_win *win, union arg *args)
+{
+ XEvent ev;
+ Time time = 0;
+ int restack = 0;
+
+ DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %d\n",
+ win->id, win->floating, win->transient);
+
+ if (win->floating == 0) {
+ win->floating = 1;
+ win->manual = 1;
+ restack = 1;
+ }
+
+ if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
+ GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
+ return;
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
+ do {
+ XMaskEvent(display, MOUSEMASK | ExposureMask |
+ SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ win->g.x = ev.xmotion.x_root;
+ win->g.y = ev.xmotion.y_root;
+
+ /* not free, don't sync more than 60 times / second */
+ if ((ev.xmotion.time - time) > (1000 / 60) ) {
+ time = ev.xmotion.time;
+ XSync(display, False);
+ move_window(win);
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ if (time) {
+ XSync(display, False);
+ move_window(win);
+ }
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
+ XUngrabPointer(display, CurrentTime);
+ if (restack)
+ stack();
+
+ /* drain events */
+ 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 {
+ unsigned int action;
+ unsigned int mask;
+ unsigned int button;
+ void (*func)(struct ws_win *, union arg *);
+ union arg args;
+} buttons[] = {
+ /* action key mouse button func args */
+ { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
+ { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} },
+ { client_click, MODKEY, Button1, move, {0} },
+};
+
+void
+update_modkey(unsigned int mod)
+{
+ int i;
+
+ mod_key = mod;
+ 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 if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0)
+ *mod |= ControlMask;
+ 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);
+}
+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);
+ }
+ }
+}
+int
+setconfbinding(char *selector, char *value, int flags)
+{
+ enum keyfuncid kfid;
+ unsigned int mod;
+ KeySym ks;
+ for (kfid = 0; kfid < kf_invalid; (kfid)++) {
+ if (strncasecmp(selector, keyfuncs[kfid].name,
+ SWM_FUNCNAME_LEN) == 0) {
+ if (parsekeys(value, mod_key, &mod, &ks))
+ setkeybinding(mod, ks, kfid);
+ else
+ return (0);
+ }
+
+ }
+ return (1);
+}
+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;
+ XModifierKeymap *modmap;
+
+ DNPRINTF(SWM_D_MISC, "updatenumlockmask\n");
+ numlockmask = 0;
+ modmap = XGetModifierMapping(display);
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < modmap->max_keypermod; j++)
+ if (modmap->modifiermap[i * modmap->max_keypermod + j]
+ == XKeysymToKeycode(display, XK_Num_Lock))
+ numlockmask = (1 << i);
+
+ XFreeModifiermap(modmap);
+}
+
+void
+grabkeys(void)
+{
+ unsigned int i, j, k;
+ KeyCode code;
+ unsigned int modifiers[] =
+ { 0, LockMask, numlockmask, numlockmask | LockMask };
+
+ DNPRINTF(SWM_D_MISC, "grabkeys\n");
+ updatenumlockmask();
+
+ for (k = 0; k < ScreenCount(display); k++) {
+ if (TAILQ_EMPTY(&screens[k].rl))
+ continue;
+ XUngrabKey(display, AnyKey, AnyModifier, screens[k].root);
+ for (i = 0; i < keys_length; i++) {
+ if ((code = XKeysymToKeycode(display, keys[i].keysym)))
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabKey(display, code,
+ keys[i].mod | modifiers[j],
+ screens[k].root, True,
+ GrabModeAsync, GrabModeAsync);
+ }
+ }
+}
+
+void
+grabbuttons(struct ws_win *win, int focused)
+{
+ unsigned int i, j;
+ unsigned int modifiers[] =
+ { 0, LockMask, numlockmask, numlockmask|LockMask };
+
+ updatenumlockmask();
+ XUngrabButton(display, AnyButton, AnyModifier, win->id);
+ if(focused) {
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (buttons[i].action == client_click)
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabButton(display, buttons[i].button,
+ buttons[i].mask | modifiers[j],
+ win->id, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None,
+ None);
+ } else
+ XGrabButton(display, AnyButton, AnyModifier, win->id, False,
+ BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+}
+
+void
+expose(XEvent *e)
+{
+ DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window);
+}
+
+void
+keypress(XEvent *e)
+{
+ unsigned int i;
+ KeySym keysym;
+ XKeyEvent *ev = &e->xkey;
+
+ DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window);
+
+ keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
+ for (i = 0; i < keys_length; i++)
+ if (keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+ && keyfuncs[keys[i].funcid].func)
+ keyfuncs[keys[i].funcid].func(
+ root_to_region(ev->root),
+ &(keyfuncs[keys[i].funcid].args)
+ );
+}
+
+void
+buttonpress(XEvent *e)
+{
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ struct ws_win *win;
+ int i, action;
+
+ DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
+
+ action = root_click;
+ if ((win = find_window(ev->window)) == NULL)
+ return;
+ else {
+ focus_win(win);
+ action = client_click;
+ }
+
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (action == buttons[i].action && buttons[i].func &&
+ buttons[i].button == ev->button &&
+ CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
+ buttons[i].func(win, &buttons[i].args);
+}
+
+void
+set_win_state(struct ws_win *win, long state)
+{
+ long data[] = {state, None};
+
+ DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id);
+
+ XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace,
+ (unsigned char *)data, 2);
+}
+
+const char *quirkname[] = {
+ "NONE", /* config string for "no value" */
+ "FLOAT",
+ "TRANSSZ",
+ "ANYWHERE",
+ "XTERM_FONTADJ",
+ "FULLSCREEN",
+};
+
+/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
+#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);
+}
+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);
+ free(quirks[i].class);
+ free(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);
+ free(quirks[i].class);
+ free(quirks[i].name);
+ quirks[i].class = strdup(class);
+ quirks[i].name = strdup(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++;
+ quirks[j].class = strdup(class);
+ quirks[j].name = strdup(name);
+ quirks[j].quirk = quirk;
+ } else {
+ fprintf(stderr, "quirks array problem?\n");
+ if (!quirks) {
+ fprintf(stderr, "quirks array problem!\n");
+ quit(NULL, NULL);
+ }
+ }
+}
+int
+setconfquirk(char *selector, char *value, int flags)
+{
+ char *cp, *class, *name;
+ int retval;
+ unsigned long quirks;
+ if (selector == NULL)
+ return (0);
+ if ((cp = strchr(selector, ':')) == NULL)
+ return (0);
+ *cp = '\0';
+ class = selector;
+ name = cp + 1;
+ if ((retval = parsequirks(value, &quirks)))
+ setquirk(class, name, quirks);
+ return (retval);
+}
+
+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);
+}
+
+/* conf file stuff */
+#define SWM_CONF_FILE "scrotwm.conf"
+
+enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_CLOCK_ENABLED,
+ SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED,
+ SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED,
+ SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP,
+ SWM_S_DIALOG_RATIO };
+
+int
+setconfvalue(char *selector, char *value, int flags)
+{
+ switch (flags) {
+ case SWM_S_BAR_DELAY:
+ bar_delay = atoi(value);
+ break;
+ case SWM_S_BAR_ENABLED:
+ bar_enabled = atoi(value);
+ break;
+ case SWM_S_CLOCK_ENABLED:
+ clock_enabled = atoi(value);
+ break;
+ case SWM_S_CYCLE_EMPTY:
+ cycle_empty = atoi(value);
+ break;
+ case SWM_S_CYCLE_VISIBLE:
+ cycle_visible = atoi(value);
+ break;
+ case SWM_S_SS_ENABLED:
+ ss_enabled = atoi(value);
+ break;
+ case SWM_S_TERM_WIDTH:
+ term_width = atoi(value);
+ break;
+ case SWM_S_TITLE_CLASS_ENABLED:
+ title_class_enabled = atoi(value);
+ break;
+ case SWM_S_TITLE_NAME_ENABLED:
+ title_name_enabled = atoi(value);
+ break;
+ case SWM_S_BAR_FONT:
+ bar_fonts[0] = strdup(value);
+ break;
+ case SWM_S_BAR_ACTION:
+ bar_argv[0] = strdup(value);
+ break;
+ case SWM_S_SPAWN_TERM:
+ spawn_term[0] = strdup(value);
+ break;
+ case SWM_S_SS_APP:
+ spawn_screenshot[0] = strdup(value);
+ break;
+ case SWM_S_DIALOG_RATIO:
+ dialog_ratio = atof(value);
+ if (dialog_ratio > 1.0 || dialog_ratio <= .3)
+ dialog_ratio = .6;
+ break;
+ default:
+ return (0);
+ }
+ return (1);
+}
+
+int
+setconfmodkey(char *selector, char *value, int flags)
+{
+ if (!strncasecmp(value, "Mod1", strlen("Mod1")))
+ update_modkey(Mod1Mask);
+ else if (!strncasecmp(value, "Mod2", strlen("Mod2")))
+ update_modkey(Mod2Mask);
+ else if (!strncasecmp(value, "Mod3", strlen("Mod3")))
+ update_modkey(Mod3Mask);
+ else if (!strncasecmp(value, "Mod4", strlen("Mod4")))
+ update_modkey(Mod4Mask);
+ else
+ return (0);
+ return (1);
+}