JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
new keyboard_mapping option to load pre-defined key bindings for
[spectrwm.git] / scrotwm.c
index 503bcf0..47e7319 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -1,4 +1,3 @@
-/* $scrotwm$ */
 /*
  * Copyright (c) 2009-2010-2011 Marco Peereboom <marco@peereboom.us>
  * Copyright (c) 2009-2010-2011 Ryan McBride <mcbride@countersiege.com>
@@ -163,6 +162,9 @@ u_int32_t           swm_debug = 0
 #define SWM_FOCUS_SYNERGY      (1)
 #define SWM_FOCUS_FOLLOW       (2)
 
+#define SWM_CONF_DEFAULT       (0)
+#define SWM_CONF_KEYMAPPING    (1)
+
 #ifndef SWM_LIB
 #define SWM_LIB                        "/usr/local/lib/libswmhack.so"
 #endif
@@ -237,6 +239,7 @@ int                 bar_fidx = 0;
 XFontStruct            *bar_fs;
 char                   *bar_fonts[] = { NULL, NULL, NULL, NULL };/* XXX Make fully dynamic */
 char                   *spawn_term[] = { NULL, NULL };         /* XXX Make fully dynamic */
+struct passwd          *pwd;
 
 #define SWM_MENU_FN    (2)
 #define SWM_MENU_NB    (4)
@@ -322,6 +325,8 @@ void        new_region(struct swm_screen *, int, int, int, int);
 void   unmanage_window(struct ws_win *);
 long   getstate(Window);
 
+int    conf_load(char *, int);
+
 struct layout {
        void            (*l_stack)(struct workspace *, struct swm_geometry *);
        void            (*l_config)(struct workspace *, int);
@@ -420,6 +425,14 @@ union arg {
 #define SWM_ARG_ID_CENTER      (71)
 #define SWM_ARG_ID_KILLWINDOW  (80)
 #define SWM_ARG_ID_DELETEWINDOW        (81)
+#define SWM_ARG_ID_WIDTHGROW   (90)
+#define SWM_ARG_ID_WIDTHSHRINK (91)
+#define SWM_ARG_ID_HEIGHTGROW  (92)
+#define SWM_ARG_ID_HEIGHTSHRINK        (93)
+#define SWM_ARG_ID_MOVEUP      (100)
+#define SWM_ARG_ID_MOVEDOWN    (101)
+#define SWM_ARG_ID_MOVELEFT    (102)
+#define SWM_ARG_ID_MOVERIGHT   (103)
        char                    **argv;
 };
 
@@ -614,12 +627,11 @@ void
 ewmh_autoquirk(struct ws_win *win)
 {
        int                     success, i;
-       unsigned long           *data = NULL;
-       unsigned long           n;
+       unsigned long           *data = NULL, n;
        Atom                    type;
 
        success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L),
-           XA_ATOM, &n, (unsigned char **)&data);
+           XA_ATOM, &n, (void *)&data);
 
        if (!success) {
                XFree(data);
@@ -808,7 +820,7 @@ ewmh_get_win_state(struct ws_win *win)
                win->ewmh_flags |= SWM_F_MANUAL;
 
        success = get_property(win->id, ewmh[_NET_WM_STATE].atom,
-           (~0L), XA_ATOM, &n, (unsigned char **)&states);
+           (~0L), XA_ATOM, &n, (void *)&states);
 
        if (!success)
                return;
@@ -1167,8 +1179,8 @@ custom_region(char *val)
        if (w < 1 || h < 1)
                errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y);
 
-       if (x  < 0 || x > DisplayWidth(display, sidx) ||
-           y < 0 || y > DisplayHeight(display, sidx) ||
+       if (x > DisplayWidth(display, sidx) ||
+           y > DisplayHeight(display, sidx) ||
            w + x > DisplayWidth(display, sidx) ||
            h + y > DisplayHeight(display, sidx)) {
                fprintf(stderr, "ignoring region %ux%u+%u+%u "
@@ -3058,7 +3070,8 @@ send_to_ws(struct swm_region *r, union arg *args)
        /* Try to update the window's workspace property */
        ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
        if (ws_idx_atom &&
-           snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
+           snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", nws->idx) <
+               SWM_PROPLEN) {
                DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",
                    ws_idx_str);
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
@@ -3139,7 +3152,7 @@ uniconify(struct swm_region *r, union arg *args)
 {
        struct ws_win           *win;
        FILE                    *lfile;
-       char                    *name;
+       unsigned char           *name;
        int                     count = 0;
        unsigned long           len;
 
@@ -3190,7 +3203,8 @@ search_do_resp(void)
 {
        ssize_t                 rbytes;
        struct ws_win           *win;
-       char                    *name, *resp, *s;
+       unsigned char           *name;
+       char                    *resp, *s;
        unsigned long           len;
 
        DNPRINTF(SWM_D_MISC, "search_do_resp:\n");
@@ -3337,14 +3351,20 @@ resize_window(struct ws_win *win, int center)
        XConfigureWindow(display, win->id, mask, &wc);
 }
 
+#define SWM_RESIZE_STEPS       (50)
+
 void
 resize(struct ws_win *win, union arg *args)
 {
        XEvent                  ev;
        Time                    time = 0;
-       struct swm_region       *r = win->ws->r;
+       struct swm_region       *r = NULL;
        int                     relx, rely;
+       int                     resize_step = 0;
 
+       if (win == NULL)
+               return;
+       r = win->ws->r;
 
        DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %lu\n",
            win->id, win->floating, win->transient);
@@ -3361,6 +3381,33 @@ resize(struct ws_win *win, union arg *args)
            _NET_WM_STATE_ADD);
 
        stack();
+
+       switch (args->id) {
+       case SWM_ARG_ID_WIDTHSHRINK:
+               win->g.w -= SWM_RESIZE_STEPS;
+               resize_step = 1;
+               break;
+       case SWM_ARG_ID_WIDTHGROW:
+               win->g.w += SWM_RESIZE_STEPS;
+               resize_step = 1;
+               break;
+       case SWM_ARG_ID_HEIGHTSHRINK:
+               win->g.h -= SWM_RESIZE_STEPS;
+               resize_step = 1;
+               break;
+       case SWM_ARG_ID_HEIGHTGROW:
+               win->g.h += SWM_RESIZE_STEPS;
+               resize_step = 1;
+               break;
+       default:
+               break;
+       }
+       if (resize_step) {
+               resize_window(win, 0);
+               store_float_geom(win,r);
+               return;
+       }
+
        if (focus_mode == SWM_FOCUS_DEFAULT)
                drain_enter_notify();
 
@@ -3428,6 +3475,20 @@ resize(struct ws_win *win, union arg *args)
 }
 
 void
+resize_step(struct swm_region *r, union arg *args)
+{
+       struct ws_win           *win = NULL;
+
+       if (r && r->ws && r->ws->focus)
+               win = r->ws->focus;
+       else
+               return;
+
+       resize(win, args);
+}
+
+
+void
 move_window(struct ws_win *win)
 {
        unsigned int            mask;
@@ -3447,12 +3508,19 @@ move_window(struct ws_win *win)
        XConfigureWindow(display, win->id, mask, &wc);
 }
 
+#define SWM_MOVE_STEPS (50)
+
 void
 move(struct ws_win *win, union arg *args)
 {
        XEvent                  ev;
        Time                    time = 0;
-       struct swm_region       *r = win->ws->r;
+       int                     move_step = 0;
+       struct swm_region       *r = NULL;
+
+       if (win == NULL)
+               return;
+       r = win->ws->r;
 
        DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %lu\n",
            win->id, win->floating, win->transient);
@@ -3471,6 +3539,34 @@ move(struct ws_win *win, union arg *args)
 
        stack();
 
+       move_step = 0;
+       switch (args->id) {
+       case SWM_ARG_ID_MOVELEFT:
+               win->g.x -= (SWM_MOVE_STEPS - border_width);
+               move_step = 1;
+               break;
+       case SWM_ARG_ID_MOVERIGHT:
+               win->g.x += (SWM_MOVE_STEPS - border_width);
+               move_step = 1;
+               break;
+       case SWM_ARG_ID_MOVEUP:
+               win->g.y -= (SWM_MOVE_STEPS - border_width);
+               move_step = 1;
+               break;
+       case SWM_ARG_ID_MOVEDOWN:
+               win->g.y += (SWM_MOVE_STEPS - border_width);
+               move_step = 1;
+               break;
+       default:
+               break;
+       }
+       if (move_step) {
+               move_window(win);
+               store_float_geom(win,r);
+               return;
+       }
+
+
        if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
            GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
                return;
@@ -3516,6 +3612,23 @@ move(struct ws_win *win, union arg *args)
        drain_enter_notify();
 }
 
+void
+move_step(struct swm_region *r, union arg *args)
+{
+       struct ws_win           *win = NULL;
+
+       if (r && r->ws && r->ws->focus)
+               win = r->ws->focus;
+       else
+               return;
+
+       if (!(win->transient != 0 || win->floating != 0))
+               return;
+
+       move(win, args);
+}
+
+
 /* user/key callable function IDs */
 enum keyfuncid {
        kf_cycle_layout,
@@ -3575,6 +3688,14 @@ enum keyfuncid {
        kf_uniconify,
        kf_raise_toggle,
        kf_button2,
+       kf_width_shrink,
+       kf_width_grow,
+       kf_height_shrink,
+       kf_height_grow,
+       kf_move_left,
+       kf_move_right,
+       kf_move_up,
+       kf_move_down,
        kf_dumpwins, /* MUST BE LAST */
        kf_invalid
 };
@@ -3653,6 +3774,14 @@ struct keyfunc {
        { "uniconify",          uniconify,      {0} },
        { "raise_toggle",       raise_toggle,   {0} },
        { "button2",            pressbutton,    {2} },
+       { "width_shrink",       resize_step,    {.id = SWM_ARG_ID_WIDTHSHRINK} },
+       { "width_grow",         resize_step,    {.id = SWM_ARG_ID_WIDTHGROW} },
+       { "height_shrink",      resize_step,    {.id = SWM_ARG_ID_HEIGHTSHRINK} },
+       { "height_grow",        resize_step,    {.id = SWM_ARG_ID_HEIGHTGROW} },
+       { "move_left",          move_step,      {.id = SWM_ARG_ID_MOVELEFT} },
+       { "move_right",         move_step,      {.id = SWM_ARG_ID_MOVERIGHT} },
+       { "move_up",            move_step,      {.id = SWM_ARG_ID_MOVEUP} },
+       { "move_down",          move_step,      {.id = SWM_ARG_ID_MOVEDOWN} },
        { "dumpwins",           dumpwins,       {0} }, /* MUST BE LAST */
        { "invalid key func",   NULL,           {0} },
 };
@@ -4202,7 +4331,7 @@ setup_keys(void)
        setkeybinding(MODKEY|ShiftMask, XK_j,           kf_swap_next,   NULL);
        setkeybinding(MODKEY|ShiftMask, XK_k,           kf_swap_prev,   NULL);
        setkeybinding(MODKEY|ShiftMask, XK_Return,      kf_spawn_term,  NULL);
-       setkeybinding(MODKEY,           XK_p,           kf_spawn_custom,        "menu");
+       setkeybinding(MODKEY,           XK_p,           kf_spawn_custom,"menu");
        setkeybinding(MODKEY|ShiftMask, XK_q,           kf_quit,        NULL);
        setkeybinding(MODKEY,           XK_q,           kf_restart,     NULL);
        setkeybinding(MODKEY,           XK_m,           kf_focus_main,  NULL);
@@ -4236,22 +4365,61 @@ setup_keys(void)
        setkeybinding(MODKEY|ShiftMask, XK_Tab,         kf_focus_prev,  NULL);
        setkeybinding(MODKEY|ShiftMask, XK_x,           kf_wind_kill,   NULL);
        setkeybinding(MODKEY,           XK_x,           kf_wind_del,    NULL);
-       setkeybinding(MODKEY,           XK_s,           kf_spawn_custom,        "screenshot_all");
-       setkeybinding(MODKEY|ShiftMask, XK_s,           kf_spawn_custom,        "screenshot_wind");
+       setkeybinding(MODKEY,           XK_s,           kf_spawn_custom,"screenshot_all");
+       setkeybinding(MODKEY|ShiftMask, XK_s,           kf_spawn_custom,"screenshot_wind");
        setkeybinding(MODKEY,           XK_t,           kf_float_toggle,NULL);
        setkeybinding(MODKEY|ShiftMask, XK_v,           kf_version,     NULL);
-       setkeybinding(MODKEY|ShiftMask, XK_Delete,      kf_spawn_custom,        "lock");
-       setkeybinding(MODKEY|ShiftMask, XK_i,           kf_spawn_custom,        "initscr");
+       setkeybinding(MODKEY|ShiftMask, XK_Delete,      kf_spawn_custom,"lock");
+       setkeybinding(MODKEY|ShiftMask, XK_i,           kf_spawn_custom,"initscr");
        setkeybinding(MODKEY,           XK_w,           kf_iconify,     NULL);
        setkeybinding(MODKEY|ShiftMask, XK_w,           kf_uniconify,   NULL);
        setkeybinding(MODKEY|ShiftMask, XK_r,           kf_raise_toggle,NULL);
        setkeybinding(MODKEY,           XK_v,           kf_button2,     NULL);
+       setkeybinding(MODKEY,           XK_equal,       kf_width_grow,  NULL);
+       setkeybinding(MODKEY,           XK_minus,       kf_width_shrink,NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_equal,       kf_height_grow, NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_minus,       kf_height_shrink,NULL);
+       setkeybinding(MODKEY,           XK_bracketleft, kf_move_left,   NULL);
+       setkeybinding(MODKEY,           XK_bracketright,kf_move_right,  NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up,     NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down,   NULL);
 #ifdef SWM_DEBUG
        setkeybinding(MODKEY|ShiftMask, XK_d,           kf_dumpwins,    NULL);
 #endif
 }
 
 void
+clear_keys(void)
+{
+       int                     i;
+
+       /* clear all key bindings, if any */
+       for (i = 0; i < keys_length; i++)
+               free(keys[i].spawn_name);
+       keys_length = 0;
+}
+
+int
+setkeymapping(char *selector, char *value, int flags)
+{
+       char                    keymapping_file[PATH_MAX];
+       DNPRINTF(SWM_D_KEY, "setkeymapping: enter\n");
+       if (value[0] == '~')
+               snprintf(keymapping_file, sizeof keymapping_file, "%s/%s",
+                   pwd->pw_dir, &value[1]);
+       else
+               strlcpy(keymapping_file, value, sizeof keymapping_file);
+       clear_keys();
+       /* load new key bindings; if it fails, revert to default bindings */
+       if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) {
+               clear_keys();
+               setup_keys();
+       }
+       DNPRINTF(SWM_D_KEY, "setkeymapping: leave\n");
+       return (0);
+}
+
+void
 updatenumlockmask(void)
 {
        unsigned int            i, j;
@@ -4696,7 +4864,8 @@ setautorun(char *selector, char *value, int flags)
 int
 setlayout(char *selector, char *value, int flags)
 {
-       int                     ws_id, st, i, x, mg, ma, si, raise;
+       int                     ws_id, i, x, mg, ma, si, raise;
+       int                     st = SWM_V_STACK;
        char                    s[1024];
        struct workspace        *ws;
 
@@ -4774,6 +4943,7 @@ struct config_option configopt[] = {
        { "bar_font",                   setconfvalue,   SWM_S_BAR_FONT },
        { "bar_action",                 setconfvalue,   SWM_S_BAR_ACTION },
        { "bar_delay",                  setconfvalue,   SWM_S_BAR_DELAY },
+       { "keyboard_mapping",           setkeymapping,  0 },
        { "bind",                       setconfbinding, 0 },
        { "stack_enabled",              setconfvalue,   SWM_S_STACK_ENABLED },
        { "clock_enabled",              setconfvalue,   SWM_S_CLOCK_ENABLED },
@@ -4805,7 +4975,7 @@ struct config_option configopt[] = {
 
 
 int
-conf_load(char *filename)
+conf_load(char *filename, int keymapping)
 {
        FILE                    *config;
        char                    *line, *cp, *optsub, *optval;
@@ -4820,7 +4990,7 @@ conf_load(char *filename)
                return (1);
        }
        if ((config = fopen(filename, "r")) == NULL) {
-               warn("conf_load: fopen");
+               warn("conf_load: fopen: %s", filename);
                return (1);
        }
 
@@ -4860,6 +5030,11 @@ conf_load(char *filename)
                            filename, lineno, wordlen, cp);
                        return (1);
                }
+               if (keymapping && strcmp(opt->optname, "bind")) {
+                       warnx("%s: line %zd: invalid option %.*s",
+                           filename, lineno, wordlen, cp);
+                       return (1);
+               }
                cp += wordlen;
                cp += strspn(cp, " \t\n"); /* eat whitespace */
                /* get [selector] if any */
@@ -4988,7 +5163,7 @@ tryharder:
        if (prop == NULL)
                return (0);
 
-       ret = strtonum(prop, 0, UINT_MAX, &errstr);
+       ret = strtonum((const char *)prop, 0, UINT_MAX, &errstr);
        /* ignore error because strtonum returns 0 anyway */
        XFree(prop);
 
@@ -5082,7 +5257,7 @@ manage_window(Window id)
                p = NULL;
        } else if (prop && win->transient == 0) {
                DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop);
-               ws_idx = strtonum(prop, 0, 9, &errstr);
+               ws_idx = strtonum((const char *)prop, 0, 9, &errstr);
                if (errstr) {
                        DNPRINTF(SWM_D_EVENT, "window idx is %s: %s",
                            errstr, prop);
@@ -5123,7 +5298,8 @@ manage_window(Window id)
 
        /* Set window properties so we can remember this after reincarnation */
        if (ws_idx_atom && prop == NULL &&
-           snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) {
+           snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", ws->idx) <
+               SWM_PROPLEN) {
                DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",
                    ws_idx_str);
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
@@ -5335,7 +5511,6 @@ buttonpress(XEvent *e)
 
        DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
 
-       action = root_click;
        if ((win = find_window(ev->window)) == NULL)
                return;
 
@@ -6134,7 +6309,6 @@ workaround(void)
 int
 main(int argc, char *argv[])
 {
-       struct passwd           *pwd;
        struct swm_region       *r, *rr;
        struct ws_win           *winfocus = NULL;
        struct timeval          tv;
@@ -6205,7 +6379,7 @@ main(int argc, char *argv[])
                                cfile = conf;
        }
        if (cfile)
-               conf_load(cfile);
+               conf_load(cfile, SWM_CONF_DEFAULT);
 
        setup_ewmh();
        /* set some values to work around bad programs */