native virtuals

joshua stein <[email protected]>
Newsgroups gmane.comp.window-managers.ratpoison.devel
Message-ID <[email protected]>
i used to use ratpoison on a slow netbook with an even slower ssd
drive and found that under a high system load, spawning out to the
rpws shell script to switch between workspaces often was unbearably
slow.

to remedy that, i integrated virtual workspaces into the source so
that switching workspaces was much quicker.  i've been running this
for quite a long time and figured i'd send it out in case anyone
wants to formally integrate it or at least run it locally.

it adds a "virtuals" config option which specifies how many
workspaces there are (defaults to 5), a "vinit" command to
initialize those workspaces, a "vselect" command to switch to a
given workspace, and "vdump" command to print out the
workspace/frame config for each one.  it basically runs the same
commands that rpws did and uses groups, just does so internally.



diff --git a/src/actions.c b/src/actions.c
index bda8002..91f86a2 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -76,6 +76,7 @@ static cmdret * set_topkmap (struct cmdarg **args);
 static cmdret * set_historysize (struct cmdarg **args);
 static cmdret * set_historycompaction (struct cmdarg **args);
 static cmdret * set_historyexpansion (struct cmdarg **args);
+static cmdret * set_virtuals (struct cmdarg **args);
 
 LIST_HEAD(set_vars);
 
@@ -145,6 +146,7 @@ init_set_vars(void)
   add_set_var ("historysize", set_historysize, 1, "", arg_NUMBER);
   add_set_var ("historycompaction", set_historycompaction, 1, "", arg_NUMBER);
   add_set_var ("historyexpansion", set_historyexpansion, 1, "", arg_NUMBER);
+  add_set_var ("virtuals", set_virtuals, 1, "", arg_NUMBER);
 }
 
 /* rp_keymaps is ratpoison's list of keymaps. */
@@ -361,6 +363,10 @@ init_user_commands(void)
   add_command ("verbexec",      cmd_verbexec,   1, 1, 1,
                "/bin/sh -c ", arg_SHELLCMD);
   add_command ("version",       cmd_version,    0, 0, 0);
+  add_command ("vdump",         cmd_vdump,      0, 0, 0);
+  add_command ("vinit",         cmd_vinit,      0, 0, 0);
+  add_command ("vselect",       cmd_vselect,    1, 1, 1,
+               "Virtual Workspace: ", arg_NUMBER);
   add_command ("vsplit",        cmd_v_split,    1, 0, 0,
                "Split: ", arg_STRING);
   add_command ("warp",          cmd_warp,       1, 1, 1,
@@ -4111,6 +4117,22 @@ set_bwcolor (struct cmdarg **args)
   return cmdret_new (RET_SUCCESS, NULL);
 }
 
+static cmdret *
+set_virtuals (struct cmdarg **args)
+{
+  int i;
+
+  if (args[0] == NULL)
+    return cmdret_new (RET_SUCCESS, "%d", defaults.virtuals);
+
+  if (ARG(0,number) < 0)
+    return cmdret_new (RET_FAILURE, "virtuals: invalid argument");
+
+  defaults.virtuals = ARG(0,number);
+
+  return cmdret_new (RET_SUCCESS, NULL);
+}
+
 cmdret *
 cmd_setenv (int interactive UNUSED, struct cmdarg **args)
 {
@@ -5856,6 +5878,133 @@ cmd_getsel (int interactive UNUSED, struct cmdarg **args UNUSED)
   return ret;
 }
 
+cmdret *
+cmd_vdump (int interactive, struct cmdarg **args)
+{
+  char *input;
+  struct cmdarg *arg;
+  int which = ARG(0, number);
+
+  rp_virtual *cur;
+  rp_screen *screen = current_screen();
+
+  arg = xmalloc (sizeof(struct cmdarg));
+
+  PRINT_DEBUG (("virtual workspace config:\n"));
+
+  list_for_each_entry (cur, &rp_virtuals, node) {
+    PRINT_DEBUG ((" %d: %s\n", cur->number, cur->fconfig));
+  }
+
+  return cmdret_new (RET_SUCCESS, NULL);
+}
+
+cmdret *
+cmd_vinit (int interactive, struct cmdarg **args)
+{
+  int x;
+  char *input;
+  struct cmdarg *arg;
+  rp_screen *screen = current_screen();
+  rp_virtual *first;
+
+  INIT_LIST_HEAD (&rp_virtuals);
+
+  /* select - */
+  PRINT_DEBUG (("vinit: selecting -\n"));
+  arg = xmalloc (sizeof(struct cmdarg));
+  (arg)->type = arg_STRING;
+  input = xstrdup("-");
+  (arg)->string = input;
+  cmd_select (0, &arg);
+
+  PRINT_DEBUG (("vinit: only\n"));
+  cmd_only (0, NULL);
+
+  /* create a new group for each virtual space and init frame config */
+  for (x = 1; x <= defaults.virtuals; x++) {
+    rp_virtual *v;
+
+    if (x == 1)
+      input = xstrdup ("default");
+    else
+      input = xsprintf ("virtual%d", x);
+
+    PRINT_DEBUG (("vinit: creating space %d (%s)\n", x, input));
+
+    (arg)->string = input;
+    cmd_gnew (0, &arg);
+
+    v = xmalloc (sizeof (rp_virtual));
+    v->number = x;
+    v->fconfig = fdump (screen);
+
+    rp_current_virtual = v;
+
+    list_add_tail (&v->node, &rp_virtuals);
+  }
+
+  /* start in workspace 1 */
+  PRINT_DEBUG (("vinit: selecting default\n"));
+  input = xstrdup ("default");
+  (arg)->string = input;
+  cmd_gselect (0, &arg);
+  list_first (first, &rp_virtuals, node);
+  if (first) {
+    rp_current_virtual = first;
+
+    /* restore the frames */
+    PRINT_DEBUG (("vinit: restoring frame config\n"));
+    frestore (first->fconfig, screen);
+  } else
+    PRINT_DEBUG (("vinit: no first virtual?!\n"));
+  
+  return cmdret_new (RET_SUCCESS, NULL);
+}
+
+cmdret *
+cmd_vselect (int interactive, struct cmdarg **args)
+{
+  char *input;
+  struct cmdarg *arg;
+  int which = ARG(0, number);
+
+  rp_virtual *cur;
+  rp_screen *screen = current_screen();
+
+  arg = xmalloc (sizeof(struct cmdarg));
+
+  if (rp_current_virtual->number == which)
+    /* don't bother */
+    return cmdret_new (RET_SUCCESS, NULL);
+
+  /* store the current frame config */
+  rp_current_virtual->fconfig = fdump (screen);
+
+  list_for_each_entry (cur, &rp_virtuals, node) {
+    if (cur->number == which) {
+      if (which == 1)
+        input = xstrdup ("default");
+      else
+        input = xsprintf ("virtual%d", cur->number);
+
+      PRINT_DEBUG (("selecting %s\n", input));
+
+      (arg)->string = input;
+      cmd_gselect (0, &arg);
+
+      /* restore this space's frame config */
+      frestore (cur->fconfig, screen);
+
+      rp_current_virtual = cur;
+
+      return cmdret_new (RET_SUCCESS, NULL);
+    }
+  }
+
+  return cmdret_new (RET_FAILURE, "vselect: no such virtual workspace");
+}
+
 /* This is a command that restores old commands that have been
    recently depricated. */
 cmdret *
diff --git a/src/actions.h b/src/actions.h
index 5db4a56..b3cae5b 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -187,6 +187,9 @@ RP_CMD (unsetenv);
 RP_CMD (v_split);
 RP_CMD (verbexec);
 RP_CMD (version);
+RP_CMD (vdump);
+RP_CMD (vinit);
+RP_CMD (vselect);
 RP_CMD (warp);
 RP_CMD (windows);
 RP_CMD (readkey);
diff --git a/src/data.h b/src/data.h
index 541ca9e..634523b 100644
--- a/src/data.h
+++ b/src/data.h
@@ -40,6 +40,7 @@ typedef struct rp_keymap rp_keymap;
 typedef struct rp_frame rp_frame;
 typedef struct rp_child_info rp_child_info;
 typedef struct rp_group rp_group;
+typedef struct rp_virtual rp_virtual;
 typedef struct rp_window_elem rp_window_elem;
 typedef struct rp_completions rp_completions;
 typedef struct rp_input_line rp_input_line;
@@ -149,6 +150,14 @@ struct rp_group
   struct list_head node;
 };
 
+struct rp_virtual
+{
+  char *fconfig;
+  int number;
+
+  struct list_head node;
+};
+
 struct rp_screen
 {
   GC normal_gc, inverse_gc;
@@ -274,6 +283,9 @@ struct rp_defaults
 
   /* Frame indicator format */
   char *frame_fmt;
+
+  /* Number of virtual workspaces */
+  int virtuals;
 };
 
 /* Information about a child process. */
diff --git a/src/globals.c b/src/globals.c
index 9ebc8e3..88dd71c 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -60,6 +60,9 @@ rp_screen *screens;
 int num_screens;
 Display *dpy;
 
+rp_virtual *rp_current_virtual;
+LIST_HEAD (rp_virtuals);
+
 rp_group *rp_current_group;
 LIST_HEAD (rp_groups);
 LIST_HEAD (rp_children);
diff --git a/src/globals.h b/src/globals.h
index 00af94d..06577e0 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -90,6 +90,9 @@ extern struct list_head rp_children;
 
 extern struct rp_defaults defaults;
 
+extern rp_virtual *rp_current_virtual;
+extern struct list_head rp_virtuals;
+
 /* Cached font info. */
 extern int rp_font_ascent, rp_font_descent, rp_font_width;
 
diff --git a/src/main.c b/src/main.c
index 417fc1a..7c022a4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -567,6 +567,8 @@ init_defaults (void)
   defaults.history_expansion = False;
   defaults.frame_selectors = xstrdup ("");
   defaults.maxundos = 20;
+
+  defaults.virtuals = 5;
 }
 
 int
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.