JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Merge branch 'master' of opensource.conformal.com:/git/scrotwm
[spectrwm.git] / scrotwm.c
index e5d1c7e..55bf753 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -55,7 +55,7 @@
 static const char      *cvstag =
     "$scrotwm$";
 
-#define        SWM_VERSION     "0.9.32"
+#define        SWM_VERSION     "0.9.34"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -87,6 +87,7 @@ static const char     *cvstag =
 #include <X11/Xproto.h>
 #include <X11/Xutil.h>
 #include <X11/extensions/Xrandr.h>
+#include <X11/extensions/XTest.h>
 
 #ifdef __OSX__
 #include <osx.h>
@@ -220,6 +221,7 @@ int                 bar_verbose = 1;
 int                    bar_height = 0;
 int                    stack_enabled = 1;
 int                    clock_enabled = 1;
+int                    urgent_enabled = 0;
 char                   *clock_format = NULL;
 int                    title_name_enabled = 0;
 int                    title_class_enabled = 0;
@@ -329,10 +331,10 @@ struct layout {
        void            (*l_string)(struct workspace *);
 } layouts[] =  {
        /* stack,               configure */
-       { vertical_stack,       vertical_config,        0,      fancy_stacker },
-       { horizontal_stack,     horizontal_config,      0,      fancy_stacker },
+       { vertical_stack,       vertical_config,        0,      plain_stacker },
+       { horizontal_stack,     horizontal_config,      0,      plain_stacker },
        { max_stack,            NULL,
-         SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV,                   fancy_stacker },
+         SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV,                   plain_stacker },
        { NULL,                 NULL,                   0,      NULL  },
 };
 
@@ -418,6 +420,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;
 };
 
@@ -612,12 +622,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);
@@ -806,7 +815,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;
@@ -1165,8 +1174,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 "
@@ -1261,6 +1270,44 @@ bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus)
        }
 }
 
+int            urgent[SWM_WS_MAX];
+void
+bar_urgent(char *s, ssize_t sz)
+{
+       XWMHints                *wmh = NULL;
+       struct ws_win           *win;
+       int                     i, j;
+       char                    b[8];
+
+       if (urgent_enabled == 0)
+               return;
+
+       for (i = 0; i < SWM_WS_MAX; i++)
+               urgent[i] = 0;
+
+       for (i = 0; i < ScreenCount(display); i++)
+               for (j = 0; j < SWM_WS_MAX; j++)
+                       TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) {
+                               wmh = XGetWMHints(display, win->id);
+                               if (wmh == NULL)
+                                       continue;
+
+                               if (wmh->flags & XUrgencyHint)
+                                       urgent[j] = 1;
+                               XFree(wmh);
+                       }
+
+       strlcat(s, "* ", sz);
+       for (i = 0; i < SWM_WS_MAX; i++) {
+               if (urgent[i])
+                       snprintf(b, sizeof b, "%d ", i + 1);
+               else
+                       snprintf(b, sizeof b, "- ");
+               strlcat(s, b, sz);
+       }
+       strlcat(s, "*    ", sz);
+}
+
 void
 bar_update(void)
 {
@@ -1305,6 +1352,7 @@ bar_update(void)
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
                        strlcpy(cn, "", sizeof cn);
                        if (r && r->ws) {
+                               bar_urgent(cn, sizeof cn);
                                bar_class_name(cn, sizeof cn, r->ws->focus);
                                bar_window_name(cn, sizeof cn, r->ws->focus);
                        }
@@ -3017,7 +3065,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,
@@ -3028,6 +3077,13 @@ send_to_ws(struct swm_region *r, union arg *args)
 }
 
 void
+pressbutton(struct swm_region *r, union arg *args)
+{
+       XTestFakeButtonEvent(display, args->id, True, CurrentTime);
+       XTestFakeButtonEvent(display, args->id, False, CurrentTime);
+}
+
+void
 raise_toggle(struct swm_region *r, union arg *args)
 {
        if (r && r->ws == NULL)
@@ -3091,7 +3147,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;
 
@@ -3142,7 +3198,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");
@@ -3289,14 +3346,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);
@@ -3313,6 +3376,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();
 
@@ -3380,6 +3470,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;
@@ -3399,12 +3503,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);
@@ -3423,6 +3534,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;
@@ -3468,6 +3607,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,
@@ -3526,6 +3682,15 @@ enum keyfuncid {
        kf_iconify,
        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
 };
@@ -3603,6 +3768,15 @@ struct keyfunc {
        { "iconify",            iconify,        {0} },
        { "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} },
 };
@@ -4152,7 +4326,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);
@@ -4186,15 +4360,24 @@ 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
@@ -4433,7 +4616,7 @@ enum      { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH,
          SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT,
          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_WINDOW_NAME_ENABLED,
+         SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, SWM_S_URGENT_ENABLED,
          SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH,
          SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM,
          SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM,
@@ -4491,6 +4674,9 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_TITLE_NAME_ENABLED:
                title_name_enabled = atoi(value);
                break;
+       case SWM_S_URGENT_ENABLED:
+               urgent_enabled = atoi(value);
+               break;
        case SWM_S_FOCUS_MODE:
                if (!strcmp(value, "default"))
                        focus_mode = SWM_FOCUS_DEFAULT;
@@ -4531,7 +4717,7 @@ setconfvalue(char *selector, char *value, int flags)
                break;
        case SWM_S_VERBOSE_LAYOUT:
                verbose_layout = atoi(value);
-               for (i=0; layouts[i].l_stack != NULL; i++) {
+               for (i = 0; layouts[i].l_stack != NULL; i++) {
                        if (verbose_layout)
                                layouts[i].l_string = fancy_stacker;
                        else
@@ -4642,7 +4828,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;
 
@@ -4738,6 +4925,7 @@ struct config_option configopt[] = {
        { "screenshot_enabled",         setconfvalue,   SWM_S_SS_ENABLED },
        { "screenshot_app",             setconfvalue,   SWM_S_SS_APP },
        { "window_name_enabled",        setconfvalue,   SWM_S_WINDOW_NAME_ENABLED },
+       { "urgent_enabled",             setconfvalue,   SWM_S_URGENT_ENABLED },
        { "term_width",                 setconfvalue,   SWM_S_TERM_WIDTH },
        { "title_class_enabled",        setconfvalue,   SWM_S_TITLE_CLASS_ENABLED },
        { "title_name_enabled",         setconfvalue,   SWM_S_TITLE_NAME_ENABLED },
@@ -4933,7 +5121,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);
 
@@ -5027,7 +5215,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);
@@ -5068,7 +5256,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,
@@ -5280,7 +5469,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;
 
@@ -6155,7 +6343,6 @@ main(int argc, char *argv[])
        setup_ewmh();
        /* set some values to work around bad programs */
        workaround();
-
        /* grab existing windows (before we build the bars) */
        grab_windows();