JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
scrotwm_se.conf: Swedish keyboard_mapping file.
[spectrwm.git] / scrotwm.c
index dfbdefc..b0c116d 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -205,6 +205,26 @@ int                        select_list_pipe[2];
 int                    select_resp_pipe[2];
 pid_t                  searchpid;
 volatile sig_atomic_t  search_resp;
+int                    search_resp_action;
+
+struct search_window {
+       TAILQ_ENTRY(search_window)      entry;
+       int                                     idx;
+       struct ws_win           *win;
+       Window                          indicator;
+};
+TAILQ_HEAD(search_winlist, search_window);
+
+struct search_winlist search_wl;
+
+/* search actions */
+enum {
+       SWM_SEARCH_NONE,
+       SWM_SEARCH_UNICONIFY,
+       SWM_SEARCH_NAME_WORKSPACE,
+       SWM_SEARCH_SEARCH_WORKSPACE,
+       SWM_SEARCH_SEARCH_WINDOW
+};
 
 /* dialog windows */
 double                 dialog_ratio = .6;
@@ -362,6 +382,7 @@ struct layout {
 /* define work spaces */
 struct workspace {
        int                     idx;            /* workspace index */
+       char                    *name;          /* workspace name */
        int                     always_raise;   /* raise windows on focus */
        struct layout           *cur_layout;    /* current layout handlers */
        struct ws_win           *focus;         /* may be NULL */
@@ -1352,6 +1373,7 @@ bar_update(void)
        struct swm_region       *r;
        int                     i, x;
        size_t                  len;
+       char                    ws[SWM_BAR_MAX];
        char                    s[SWM_BAR_MAX];
        char                    cn[SWM_BAR_MAX];
        char                    loc[SWM_BAR_MAX];
@@ -1387,16 +1409,20 @@ bar_update(void)
                x = 1;
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
                        strlcpy(cn, "", sizeof cn);
+                       strlcpy(ws, "", sizeof ws);
                        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);
+                               if (r->ws->name)
+                                       snprintf(ws, sizeof ws, "<%s>", r->ws->name);
                        }
                        if (stack_enabled)
                                stack = r->ws->stacker;
 
-                       snprintf(loc, sizeof loc, "%d:%d %s   %s%s    %s    %s",
-                           x++, r->ws->idx + 1, stack, s, cn, bar_ext, bar_vertext);
+                       snprintf(loc, sizeof loc, "%d:%d %s %s   %s%s    %s    %s",
+                           x++, r->ws->idx + 1, stack, ws, s, cn, bar_ext,
+                           bar_vertext);
                        bar_print(r, loc);
                }
        }
@@ -1919,12 +1945,12 @@ validate_win(struct ws_win *testwin)
        struct ws_win           *win;
        struct workspace        *ws;
        struct swm_region       *r;
-       int                     i, x, foundit = 0;
+       int                     i, x;
 
        if (testwin == NULL)
                return (0);
 
-       for (i = 0, foundit = 0; i < ScreenCount(display); i++)
+       for (i = 0; i < ScreenCount(display); i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        for (x = 0; x < SWM_WS_MAX; x++) {
                                ws = &r->s->ws[x];
@@ -1940,10 +1966,10 @@ validate_ws(struct workspace *testws)
 {
        struct swm_region       *r;
        struct workspace        *ws;
-       int                     foundit, i, x;
+       int                     i, x;
 
        /* validate all ws */
-       for (i = 0, foundit = 0; i < ScreenCount(display); i++)
+       for (i = 0; i < ScreenCount(display); i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        for (x = 0; x < SWM_WS_MAX; x++) {
                                ws = &r->s->ws[x];
@@ -2497,13 +2523,10 @@ void
 cycle_layout(struct swm_region *r, union arg *args)
 {
        struct workspace        *ws = r->ws;
-       struct ws_win           *winfocus;
        union arg               a;
 
        DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx);
 
-       winfocus = ws->focus;
-
        ws->cur_layout++;
        if (ws->cur_layout->l_stack == NULL)
                ws->cur_layout = &layouts[0];
@@ -3213,8 +3236,9 @@ uniconify(struct swm_region *r, union arg *args)
                return;
 
        search_r = r;
+       search_resp_action = SWM_SEARCH_UNICONIFY;
 
-       spawn_select(r, args, "uniconify", &searchpid);
+       spawn_select(r, args, "search", &searchpid);
 
        if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
                return;
@@ -3236,36 +3260,148 @@ uniconify(struct swm_region *r, union arg *args)
        fclose(lfile);
 }
 
-#define MAX_RESP_LEN   1024
+void
+name_workspace(struct swm_region *r, union arg *args)
+{
+       FILE                    *lfile;
+
+       DNPRINTF(SWM_D_MISC, "name_workspace\n");
+
+       if (r == NULL)
+               return;
+
+       search_r = r;
+       search_resp_action = SWM_SEARCH_NAME_WORKSPACE;
+
+       spawn_select(r, args, "name_workspace", &searchpid);
+
+       if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+               return;
+
+       fprintf(lfile, "%s", "");
+       fclose(lfile);
+}
 
 void
-search_do_resp(void)
+search_workspace(struct swm_region *r, union arg *args)
 {
-       ssize_t                 rbytes;
-       struct ws_win           *win;
-       unsigned char           *name;
-       char                    *resp, *s;
-       unsigned long           len;
+       int                     i;
+       struct workspace        *ws;
+       FILE                    *lfile;
 
-       DNPRINTF(SWM_D_MISC, "search_do_resp:\n");
+       DNPRINTF(SWM_D_MISC, "search_workspace\n");
 
-       search_resp = 0;
-       searchpid = 0;
+       if (r == NULL)
+               return;
 
-       if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) {
-               fprintf(stderr, "search: calloc\n");
-               goto done;
+       search_r = r;
+       search_resp_action = SWM_SEARCH_SEARCH_WORKSPACE;
+
+       spawn_select(r, args, "search", &searchpid);
+
+       if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+               return;
+
+       for (i = 0; i < SWM_WS_MAX; i++) {
+               ws = &r->s->ws[i];
+               if (ws == NULL)
+                       continue;
+               fprintf(lfile, "%d%s%s\n", ws->idx + 1,
+                   (ws->name ? ":" : ""), (ws->name ? ws->name : ""));
        }
 
-       rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN);
-       if (rbytes <= 0) {
-               fprintf(stderr, "search: read error: %s\n", strerror(errno));
-               goto done;
+       fclose(lfile);
+}
+
+void
+search_win_cleanup(void)
+{
+       struct search_window    *sw = NULL;
+
+       while ((sw = TAILQ_FIRST(&search_wl)) != NULL) {
+               XDestroyWindow(display, sw->indicator);
+               TAILQ_REMOVE(&search_wl, sw, entry);
+               free(sw);
+       }
+}
+
+void
+search_win(struct swm_region *r, union arg *args)
+{
+       struct ws_win           *win = NULL;
+       struct search_window    *sw = NULL;
+       Window                  w;
+       GC                      gc;
+       XGCValues               gcv;
+       int                     i;
+       char                    s[8];
+       FILE                    *lfile;
+       size_t                  len;
+       int                     textwidth;
+
+       DNPRINTF(SWM_D_MISC, "search_win\n");
+
+       search_r = r;
+       search_resp_action = SWM_SEARCH_SEARCH_WINDOW;
+
+       spawn_select(r, args, "search", &searchpid);
+
+       if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+               return;
+
+       TAILQ_INIT(&search_wl);
+
+       i = 1;
+       TAILQ_FOREACH(win, &r->ws->winlist, entry) {
+               if (win->iconic == 1)
+                       continue;
+
+               sw = calloc(1, sizeof(struct search_window));
+               if (sw == NULL) {
+                       fprintf(stderr, "search_win: calloc: %s", strerror(errno));
+                       fclose(lfile);
+                       search_win_cleanup();
+                       return;
+               }
+               sw->idx = i;
+               sw->win = win;
+
+               snprintf(s, sizeof s, "%d", i);
+               len = strlen(s);
+               textwidth = XTextWidth(bar_fs, s, len);
+
+               w = XCreateSimpleWindow(display,
+                   win->id, 0, 0, textwidth + 12,
+                   bar_fs->ascent + bar_fs->descent + 4, 1,
+                   r->s->c[SWM_S_COLOR_UNFOCUS].color,
+                   r->s->c[SWM_S_COLOR_FOCUS].color);
+
+               sw->indicator = w;
+               TAILQ_INSERT_TAIL(&search_wl, sw, entry);
+
+               gc = XCreateGC(display, w, 0, &gcv);
+               XSetFont(display, gc, bar_fs->fid);
+               XMapRaised(display, w);
+               XSetForeground(display, gc, r->s->c[SWM_S_COLOR_BAR].color);
+
+               XDrawString(display, w, gc, 6, bar_fs->ascent + 2, s, len);
+
+               fprintf(lfile, "%d\n", i);
+               i++;
        }
-       resp[rbytes] = '\0';
-       len = strlen(resp);
 
-       DNPRINTF(SWM_D_MISC, "search_do_resp: resp %s\n", resp);
+       fclose(lfile);
+}
+
+void
+search_resp_uniconify(char *resp, unsigned long len)
+{
+       unsigned char           *name;
+       struct ws_win           *win;
+       char                    *s;
+
+       DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp %s\n", resp);
+
        TAILQ_FOREACH(win, &search_r->ws->winlist, entry) {
                if (win->iconic == 0)
                        continue;
@@ -3285,7 +3421,151 @@ search_do_resp(void)
                }
                free(s);
        }
+}
+
+void
+search_resp_name_workspace(char *resp, unsigned long len)
+{
+       struct workspace        *ws;
+
+       DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: resp %s\n", resp);
+
+       if (search_r->ws == NULL)
+               return;
+       ws = search_r->ws;
+
+       if (ws->name) {
+               free(search_r->ws->name);
+               search_r->ws->name = NULL;
+       }
+
+       if (len > 1) {
+               ws->name = strdup(resp);
+               if (ws->name == NULL) {
+                       DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: strdup: %s",
+                           strerror(errno));
+                       return;
+               }
+       }
+}
+
+void
+search_resp_search_workspace(char *resp, unsigned long len)
+{
+       char                    *p, *q;
+       int                     ws_idx;
+       const char              *errstr;
+       union arg               a;
+
+       DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: resp %s\n", resp);
+
+       q = strdup(resp);
+       if (!q) {
+               DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: strdup: %s",
+                   strerror(errno));
+               return;
+       }
+       p = strchr(q, ':');
+       if (p != NULL)
+               *p = '\0';
+       ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr);
+       if (errstr) {
+               DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s",
+                   errstr, q);
+               free(q);
+               return;
+       }
+       free(q);
+       a.id = ws_idx - 1;
+       switchws(search_r, &a);
+}
+
+void
+search_resp_search_window(char *resp, unsigned long len)
+{
+       char                    *s;
+       int                     idx;
+       const char              *errstr;
+       struct search_window    *sw;
+
+       DNPRINTF(SWM_D_MISC, "search_resp_search_window: resp %s\n", resp);
+
+       s = strdup(resp);
+       if (!s) {
+               DNPRINTF(SWM_D_MISC, "search_resp_search_window: strdup: %s",
+                   strerror(errno));
+               return;
+       }
+
+       idx = strtonum(s, 1, INT_MAX, &errstr);
+       if (errstr) {
+               DNPRINTF(SWM_D_MISC, "window idx is %s: %s",
+                   errstr, s);
+               free(s);
+               return;
+       }
+       free(s);
+
+       TAILQ_FOREACH(sw, &search_wl, entry)
+               if (idx == sw->idx) {
+                       focus_win(sw->win);
+                       break;
+               }
+}
+
+#define MAX_RESP_LEN   1024
+
+void
+search_do_resp(void)
+{
+       ssize_t                 rbytes;
+       char                    *resp;
+       unsigned long           len;
+
+       DNPRINTF(SWM_D_MISC, "search_do_resp:\n");
+
+       search_resp = 0;
+       searchpid = 0;
+
+       if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) {
+               fprintf(stderr, "search: calloc\n");
+               goto done;
+       }
+
+       rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN);
+       if (rbytes <= 0) {
+               fprintf(stderr, "search: read error: %s\n", strerror(errno));
+               goto done;
+       }
+       resp[rbytes] = '\0';
+
+       /* XXX:
+        * Older versions of dmenu (Atleast pre 4.4.1) do not send a
+        * newline, so work around that by sanitizing the resp now.
+        */
+       resp[strcspn(resp, "\n")] = '\0';
+       len = strlen(resp);
+
+       switch (search_resp_action) {
+       case SWM_SEARCH_UNICONIFY:
+               search_resp_uniconify(resp, len);
+               break;
+       case SWM_SEARCH_NAME_WORKSPACE:
+               search_resp_name_workspace(resp, len);
+               break;
+       case SWM_SEARCH_SEARCH_WORKSPACE:
+               search_resp_search_workspace(resp, len);
+               break;
+       case SWM_SEARCH_SEARCH_WINDOW:
+               search_resp_search_window(resp, len);
+               break;
+       }
+
 done:
+       if (search_resp_action == SWM_SEARCH_SEARCH_WINDOW)
+               search_win_cleanup();
+
+       search_resp_action = SWM_SEARCH_NONE;
        close(select_resp_pipe[0]);
        free(resp);
 }
@@ -3534,9 +3814,7 @@ 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;
@@ -3739,6 +4017,9 @@ enum keyfuncid {
        kf_move_right,
        kf_move_up,
        kf_move_down,
+       kf_name_workspace,
+       kf_search_workspace,
+       kf_search_win,
        kf_dumpwins, /* MUST BE LAST */
        kf_invalid
 };
@@ -3827,6 +4108,9 @@ struct keyfunc {
        { "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} },
+       { "name_workspace",     name_workspace, {0} },
+       { "search_workspace",   search_workspace,       {0} },
+       { "search_win",         search_win,     {0} },
        { "dumpwins",           dumpwins,       {0} }, /* MUST BE LAST */
        { "invalid key func",   NULL,           {0} },
 };
@@ -4159,13 +4443,20 @@ setup_spawn(void)
                                        " -nf $bar_font_color"
                                        " -sb $bar_border"
                                        " -sf $bar_color",      0);
-       setconfspawn("uniconify",       "dmenu"
+       setconfspawn("search",          "dmenu"
                                        " -i"
                                        " -fn $bar_font"
                                        " -nb $bar_color"
                                        " -nf $bar_font_color"
                                        " -sb $bar_border"
                                        " -sf $bar_color",      0);
+       setconfspawn("name_workspace",  "dmenu"
+                                       " -p Workspace"
+                                       " -fn $bar_font"
+                                       " -nb $bar_color"
+                                       " -nf $bar_font_color"
+                                       " -sb $bar_border"
+                                       " -sf $bar_color",      0);
 }
 
 /* key bindings */
@@ -4430,6 +4721,9 @@ setup_keys(void)
        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);
+       setkeybinding(MODKEY|ShiftMask, XK_slash,       kf_name_workspace,NULL);
+       setkeybinding(MODKEY,           XK_slash,       kf_search_workspace,NULL);
+       setkeybinding(MODKEY,           XK_f,           kf_search_win,  NULL);
 #ifdef SWM_DEBUG
        setkeybinding(MODKEY|ShiftMask, XK_d,           kf_dumpwins,    NULL);
 #endif
@@ -6299,6 +6593,7 @@ setup_screens(void)
                for (j = 0; j < SWM_WS_MAX; j++) {
                        ws = &screens[i].ws[j];
                        ws->idx = j;
+                       ws->name = NULL;
                        ws->focus = NULL;
                        ws->r = NULL;
                        ws->old_r = NULL;