Hi guys,

I have had this patch sitting around in my $HOME for a while. It allows the user
to exit scrotwm to another window manager (one of the ones they define in
~/.scrotwm.conf) via a dmenu. The idea was taken from cwm.

What do you think?

OK to put into scrotwm?

-- 
Best Regards
Edd Barrett

http://www.theunixzoo.co.uk
opencvs server: Diffing inside .
Index: scrotwm.1
===================================================================
RCS file: /scrotwm/scrotwm/scrotwm.1,v
retrieving revision 1.28
diff -N -u -p -u scrotwm.1
--- scrotwm.1   7 Oct 2009 03:19:11 -0000       1.28
+++ scrotwm.1   21 Feb 2010 20:19:12 -0000
@@ -79,6 +79,8 @@ Enabling or disabling an option is done by using 1 or 
 The file supports the following keywords:
 .Pp
 .Bl -tag -width "title_class_enabledXXX" -offset indent -compact
+.It Cm alt_wms
+A comma separated list of alternative window managers for use with exec_alt_wm.
 .It Cm color_focus
 Border color of the currently focussed window.
 .It Cm color_unfocus
@@ -259,6 +261,8 @@ The default key bindings are described below:
 term
 .It Cm M-p
 menu
+.It Cm M-r
+exec_alt_wm
 .It Cm M-S-q
 quit
 .It Cm M-q
@@ -343,6 +347,8 @@ Menu
 (see
 .Sx PROGRAMS
 above)
+.It Cm exec_alt_wm
+Execute an alternative window manager
 .It Cm quit
 Quit
 .Nm
Index: scrotwm.c
===================================================================
RCS file: /scrotwm/scrotwm/scrotwm.c,v
retrieving revision 1.281
diff -N -u -p -u scrotwm.c
--- scrotwm.c   13 Jan 2010 23:22:31 -0000      1.281
+++ scrotwm.c   21 Feb 2010 20:19:13 -0000
@@ -179,6 +179,7 @@ int                 cycle_visible = 0;
 int                    term_width = 0;
 int                    font_adjusted = 0;
 unsigned int           mod_key = MODKEY;
+int                    ret_status = -1; /* store return status of fork/exec */
 
 /* dialog windows */
 double                 dialog_ratio = .6;
@@ -385,6 +386,15 @@ struct quirk {
 int                            quirks_size = 0, quirks_length = 0;
 struct quirk                   *quirks = NULL;
 
+/* alternative window managers */
+struct alt_wm {
+       SLIST_ENTRY(alt_wm)     entries;
+       char                    *wm;
+};
+SLIST_HEAD(head, alt_wm)       alt_wms;
+void                           exec_alt_wm();
+void                           free_alt_wm_list();
+
 /* events */
 #ifdef SWM_DEBUG
 void
@@ -587,7 +597,7 @@ sighdlr(int sig)
 
        switch (sig) {
        case SIGCHLD:
-               while ((pid = waitpid(WAIT_ANY, NULL, WNOHANG)) != -1) {
+               while ((pid = waitpid(WAIT_ANY, &ret_status, WNOHANG)) != -1) {
                        DNPRINTF(SWM_D_MISC, "reaping: %d\n", pid);
                        if (pid <= 0)
                                break;
@@ -1135,6 +1145,148 @@ restart(struct swm_region *r, union arg *args)
        quit(NULL, NULL);
 }
 
+/* execute a new window manager */
+void
+exec_alt_wm(struct swm_region *r, union arg *args)
+{
+       int                     fd[2], fd1[2], pipe_written = 0;
+       int                     pipe_read = 0, found_choice = 0;
+       int                     max_wm_len = -1, cur_wm_len;
+       int                     pipe_in_sz = 0, i, pid;
+       char                    *new_wm = NULL, *buf = NULL, *pipe_in;
+       struct                  alt_wm *wm_node;
+
+       if (SLIST_EMPTY(&alt_wms))
+               return;
+
+       if ((pipe(fd) == -1) || (pipe(fd1) == -1))
+               err(1, "exec_alt_wm: pipe fail");
+
+       if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+               err(1, "exec_alt_wm: could not disable SIGPIPE");
+
+       /* work out how many wms and the longest name */
+       SLIST_FOREACH(wm_node, &alt_wms, entries) {
+               cur_wm_len = strlen(wm_node->wm);
+               pipe_in_sz = pipe_in_sz + cur_wm_len + 1; /* +1 \n */
+               if (max_wm_len < cur_wm_len)
+                       max_wm_len = cur_wm_len;
+       }
+       pipe_in_sz ++; /* \0 */
+
+       pid = fork();
+       switch (pid) {
+       case -1:
+               err(1, "exec_alt_wm: can't fork");
+               break;
+       case 0: /* we are the child */
+               close(fd1[0]);
+
+               /* build \n delimited records for dmenu */
+               pipe_in = malloc(pipe_in_sz);
+               if (pipe_in == NULL)
+                       err(1, "exec_alt_wm: malloc failed\n");
+
+               memset(pipe_in, 0, pipe_in_sz);
+
+               SLIST_FOREACH(wm_node, &alt_wms, entries)
+                       snprintf(pipe_in, pipe_in_sz, "%s%s\n",
+                           pipe_in, wm_node->wm);
+
+               while (pipe_written != pipe_in_sz) {
+                       i = write(fd[1], pipe_in + pipe_written,
+                           pipe_in_sz - pipe_written);
+
+                       if (i == -1) {
+                               err(1, "alt_wm: can't write");
+                               i = 0; /* try again */
+                       }
+                       pipe_written += i;
+               }
+               close(fd[1]);
+               free(pipe_in);
+
+               /* replace stdin/stdout */
+               if (dup2(fd[0], STDIN_FILENO) == -1)
+                       err(1, "exec_alt_wm: can't dup2"); 
+
+               if (dup2(fd1[1], STDOUT_FILENO) == -1)
+                       err(1, "exec_alt_wm: can't dup2(2)");
+
+               if (execlp("dmenu", "dmenu", (char *)0) == -1)
+                       err(1, "exec_alt_wm: can't execlp");
+
+               _exit(0);
+               break;
+       default: /* parent */
+               close(fd[1]);
+               close(fd1[1]);
+
+               /* This will always be interrupted by signal handler */ 
+               if ((wait(NULL) == -1) && (errno != EINTR))
+                       err(1, "exec_alt_wm: wait failed");
+               else if (ret_status != 0) {
+                       fprintf(stderr,
+                           "scrotwm: dmenu returned non-zero (%d)\n",
+                           ret_status);
+                       return;
+               }
+
+               buf = malloc(max_wm_len + 1);
+               new_wm = malloc(max_wm_len + 1);
+               if ((buf == NULL) || (new_wm == NULL))
+                       err(1, "exec_alt_wm: cannot malloc()");
+
+               memset(buf, 0, max_wm_len + 1);
+               memset(new_wm, 0, max_wm_len + 1);
+
+               do {
+                       i = read(fd1[0], buf, max_wm_len - pipe_read + 1);
+                       if (i == -1)
+                               err(1, "exec_alt_wm: can't read");
+
+                       if (i != 0)
+                               snprintf(new_wm, i + 1,
+                                   "%s%s", new_wm, buf);
+                       pipe_read += i;
+               } while (i != 0); /* until EOF */
+
+               if (pipe_read == 0) /* user probably pressed escape */
+                       return;
+
+               /* check what was typed was one of the choices */
+               SLIST_FOREACH(wm_node, &alt_wms, entries)
+                       if (strcmp(wm_node->wm, new_wm) == 0)
+                               found_choice = 1;
+
+               if (!found_choice)
+                       return;
+
+               free(buf);
+               free(new_wm);
+               alarm(0); /* cancel any alarms */
+
+               if (execlp(new_wm, new_wm, (char *) 0) == -1)
+                       warn("exec_alt_wm: can't execlp new wm: %s", new_wm);
+
+               alarm(bar_delay); /* put back alarm if we failed */
+       }
+}
+
+void
+free_alt_wm_list()
+{
+       struct alt_wm *n;
+
+       while (!SLIST_EMPTY(&alt_wms)) {
+               n = SLIST_FIRST(&alt_wms);
+               printf("free: %s\n", n->wm);
+               SLIST_REMOVE_HEAD(&alt_wms, entries);
+               free(n->wm);
+               free(n);
+       }
+}
+
 struct swm_region *
 root_to_region(Window root)
 {
@@ -2468,6 +2620,7 @@ move(struct ws_win *win, union arg *args)
 
 /* user/key callable function IDs */
 enum keyfuncid {
+       kf_alt_wm,
        kf_cycle_layout,
        kf_stack_reset,
        kf_master_shrink,
@@ -2541,6 +2694,7 @@ struct keyfunc {
        union arg               args;
 } keyfuncs[kf_invalid + 1] = {
        /* name                 function        argument */
+       { "exec_alt_wm",        exec_alt_wm,    {0} },
        { "cycle_layout",       cycle_layout,   {0} },
        { "stack_reset",        stack_config,   {.id = SWM_ARG_ID_STACKRESET} },
        { "master_shrink",      stack_config,   {.id = SWM_ARG_ID_MASTERSHRINK} 
},
@@ -3080,6 +3234,7 @@ setup_keys(void)
        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_r,           kf_alt_wm,      NULL);
        setkeybinding(MODKEY,           XK_m,           kf_focus_main,  NULL);
        setkeybinding(MODKEY,           XK_1,           kf_ws_1,        NULL);
        setkeybinding(MODKEY,           XK_2,           kf_ws_2,        NULL);
@@ -3351,12 +3506,16 @@ enum    { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, 
SWM_S_STACK
          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_BAR_FONT,
-         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO
+         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO,
+         SWM_S_ALT_WMS
        };
 
 int
 setconfvalue(char *selector, char *value, int flags)
 {
+       char                    *wm;
+       struct                  alt_wm *wm_node;
+
        switch (flags) {
        case SWM_S_BAR_DELAY:
                bar_delay = atoi(value);
@@ -3417,6 +3576,23 @@ setconfvalue(char *selector, char *value, int flags)
                if (dialog_ratio > 1.0 || dialog_ratio <= .3)
                        dialog_ratio = .6;
                break;
+       case SWM_S_ALT_WMS:
+               for (wm = strtok(value, ","); wm != NULL;
+                   wm = strtok(NULL, ",")) {
+                       wm_node = malloc(sizeof(struct alt_wm));
+                       if (wm_node == NULL) {
+                               fprintf(stderr, "setconfvalue: malloc 
failed\n");
+                               perror(" failed");
+                               quit(NULL, NULL);
+                       }
+
+                       wm_node->wm = strdup(wm);
+                       if (wm_node->wm == NULL)
+                               err(1, "setconfvalue: can't strdup wm name");
+
+                       SLIST_INSERT_HEAD(&alt_wms, wm_node, entries);
+               }
+        break;
        default:
                return (1);
        }
@@ -3460,6 +3636,7 @@ struct config_option {
        int funcflags;
 };
 struct config_option configopt[] = {
+       { "alt_wms",                    setconfvalue,   SWM_S_ALT_WMS },
        { "bar_enabled",                setconfvalue,   SWM_S_BAR_ENABLED },
        { "bar_border",                 setconfcolor,   SWM_S_COLOR_BAR_BORDER 
},
        { "bar_color",                  setconfcolor,   SWM_S_COLOR_BAR },
@@ -4635,6 +4812,9 @@ main(int argc, char *argv[])
        adelete = XInternAtom(display, "WM_DELETE_WINDOW", False);
        takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False);
 
+       /* init list of alternative wms */
+       SLIST_INIT(&alt_wms);
+
        /* look for local and global conf file */
        pwd = getpwuid(getuid());
        if (pwd == NULL)
@@ -4740,7 +4920,7 @@ main(int argc, char *argv[])
        }
 done:
        bar_extra_stop();
-
+       free_alt_wm_list();
        XCloseDisplay(display);
 
        return (0);
Index: scrotwm.conf
===================================================================
RCS file: /scrotwm/scrotwm/scrotwm.conf,v
retrieving revision 1.23
diff -N -u -p -u scrotwm.conf
--- scrotwm.conf        13 Jan 2010 21:48:35 -0000      1.23
+++ scrotwm.conf        21 Feb 2010 20:19:13 -0000
@@ -55,6 +55,7 @@ dialog_ratio          = 0.6
 #bind[swap_prev]               = MOD+Shift+k
 #bind[spawn_term]      = MOD+Shift+Return
 #bind[menu]            = MOD+p
+#bind[exec_alt_wm]     = MOD+r
 #bind[quit]            = MOD+Shift+q
 #bind[restart]         = MOD+q
 #bind[focus_main]      = MOD+m
@@ -114,3 +115,6 @@ dialog_ratio                = 0.6
 # EXAMPLE: define firefox program and bind to key
 # program[firefox]     = firefox http://scrotwm.org/
 # bind[firefox]                = MOD+f
+
+# alternative window managers
+alt_wms = cwm,fvwm
opencvs server: Diffing inside html
opencvs server: Diffing inside lib
opencvs server: Diffing inside linux
opencvs server: Diffing inside osx
opencvs server: Diffing inside port
opencvs server: Diffing inside port/patches
opencvs server: Diffing inside port/pkg

Reply via email to