Re: rpws and sfdump/sfrestore (was: select patch)

Johannes Altmanninger <[email protected]> Wed, 02 Jul 2014 22:10:22 +0200
Newsgroups gmane.comp.window-managers.ratpoison.devel
Message-ID <20140702201022.28560.74913@jakiro>
I took the patch from [1] and adapted it to work with the git HEAD.
It works as described in the mail, a usage example is there too [2].
This should fix the issues addressed in the bug and it also is a much
cleaner implementation of workspaces (the user only has to add hooks
that restore and clean frames when switching groups)

Johannes

[1] http://lists.nongnu.org/archive/html/ratpoison-devel/2013-10/msg00000.html
[2] http://lists.nongnu.org/archive/html/ratpoison-devel/2013-10/txtWpZPBxO_TL.txt

Quoting Jeff Abrahamson (2014-07-02 11:22:25)
> I'm moving this to a separate thread for sanity.
> 
> I proposed doing this in 42224 <https://savannah.nongnu.org/bugs/?42224>.
>  I still mean to, but some professional things have gotten in the way the
> last couple months.  I am not a jealous person, should you want to have a
> go.  ;-)  Otherwise, I'm sure I will get to this later this Summer, as it
> annoys me.
> 
> I strongly believe that ditching rpws in favor of an internal
> implementation is the right thing to do.  WS switching should be instant,
> and it is currently far from instant.
> 
> -Jeff
> 
> 
> On 2 July 2014 09:32, Johannes Altmanninger <[email protected]> wrote:
> 
> > If sfdump is fixed now, you could change the rpws script to use
> > sfdump/sfrestore instead of fdump/frestore, although builtin workspaces
> > [1] would probably make more sense. (I do not use workspaces myself but
> > rpws seems a bit hacky)
> >
> > [1]
> > http://lists.nongnu.org/archive/html/ratpoison-devel/2013-10/msg00000.html
> >
> 
> Jeff Abrahamson
> +33 6 24 40 01 57   <-- brièvement indisponible le 4 juillet
> +44 7920 594 255    <-- will change 18 July
> 
> http://jeff.purple.com/
> http://blog.purple.com/jeff/

_______________________________________________
Ratpoison-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/ratpoison-devel
builtin_workspaces.patch (text/x-diff, 10.2 KB)
diff --git a/src/actions.c b/src/actions.c
index cf08e79..8bb69e5 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -256,6 +256,8 @@ init_user_commands(void)
                "Frames: ", arg_REST);
   add_command ("fselect",       cmd_fselect,    1, 1, 1,
                "", arg_FRAME);
+  add_command ("gclean",        cmd_gclean,     1, 0, 0,
+               "Group: ", arg_GROUP);
   add_command ("gdelete",       cmd_gdelete,    1, 0, 0,
                "Group:", arg_GROUP);
   add_command ("getenv",        cmd_getenv,     1, 1, 1,
@@ -273,6 +275,8 @@ init_user_commands(void)
                "Number: ", arg_NUMBER);
   add_command ("grename",       cmd_grename,    1, 1, 1,
                "Change group name to: ", arg_REST);
+  add_command ("grestore",      cmd_grestore,   1, 0, 0,
+               "Group: ", arg_GROUP);
   add_command ("gnext",         cmd_gnext,      0, 0, 0);
   add_command ("gprev",         cmd_gprev,      0, 0, 0);
   add_command ("gother",        cmd_gother,     0, 0, 0);
@@ -5055,6 +5059,7 @@ set_winliststyle (struct cmdarg **args)
 cmdret *
 cmd_gnext (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
+  store_current_group_frames (sfdump());
   set_current_group (group_next_group ());
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -5062,6 +5067,7 @@ cmd_gnext (int interactive UNUSED, struct cmdarg **args UNUSED)
 cmdret *
 cmd_gprev (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
+  store_current_group_frames (sfdump());
   set_current_group (group_prev_group ());
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -5069,6 +5075,7 @@ cmd_gprev (int interactive UNUSED, struct cmdarg **args UNUSED)
 cmdret *
 cmd_gother (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
+  store_current_group_frames(sfdump());
   set_current_group (group_last_group ());
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -5078,6 +5085,7 @@ cmd_gnew (int interactive UNUSED, struct cmdarg **args)
 {
   if (groups_find_group_by_name (ARG_STRING (0), 1))
     return cmdret_new (RET_FAILURE, "gnew: group already exists");
+  store_current_group_frames (sfdump());
   set_current_group (group_add_new_group (ARG_STRING(0)));
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -5158,13 +5166,100 @@ cmd_gselect (int interactive, struct cmdarg **args)
   g = find_group (ARG_STRING(0));
 
   if (g)
-    set_current_group (g);
+    {
+      store_current_group_frames (sfdump());
+      set_current_group (g);
+    }
   else
     return cmd_groups (interactive, NULL);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
 
+/* Restore group's sfdump, i.e. the screens' state when the group was last
+   used. */
+cmdret *
+cmd_grestore (int interactive, struct cmdarg **args)
+{
+  rp_group *g;
+  cmdret *ret = NULL;
+  struct sbuf *s;
+  char *tmp;
+  int i;
+
+  if (args[0])
+    g = find_group (ARG_STRING(0));
+  else
+    g = rp_current_group;
+
+  if (g)
+    {
+      if (g->sframes)
+        {
+          ret = sfrestore (g->sframes);
+        }
+      else
+        {
+          /* No saved sfdump: blanks screens by creating an sfdump with a single
+             empty frame per screen, then restoring it. */
+          s = sbuf_new (0);
+          for (i=0; i<num_screens; i++)
+            {
+              tmp = xsprintf ("(frame :number %d :x %d :y %d :width %d :height %d :screenw %d :screenh %d :window %ld :last-access %d :dedicated %d) %d%s",
+                              0, 0, 0,
+                              screen_width(&screens[i]), screen_height(&screens[i]),
+                              screens[i].width, screens[i].height,
+                              0, 0, 0,
+                              (rp_have_xinerama)?(screens[i].xine_screen_num):(screens[i].screen_num),
+                              /* don't add a comma to the last screen */
+                              (i < num_screens-1)?(","):(""));
+
+              sbuf_concat (s, tmp);
+              free (tmp);
+            }
+          tmp = sbuf_free_struct(s);
+          ret = sfrestore (tmp);
+          free (tmp);
+        }
+    }
+  else
+    return cmd_groups (interactive, NULL);
+
+  /* return success or failure according to what sfrestore returned */
+  return ret;
+}
+
+/* Clean screens by blanking frames containing windows not in the current
+   group. */
+cmdret *
+cmd_gclean (int interactive, struct cmdarg **args)
+{
+  rp_group *g;
+  rp_window *win;
+  rp_frame *cur;
+  int i;
+
+  if (args[0])
+    g = find_group (ARG_STRING(0));
+  else
+    g = rp_current_group;
+
+  if (g)
+    {
+      for (i=0; i<num_screens; i++)
+        {
+          list_for_each_entry (cur, &(screens[i].frames), node)
+            {
+              win = find_window_number (cur->win_number);
+              /* blank frame if window doesn't belong to group */
+              if (win && !group_find_window(&g->mapped_windows, win))
+                blank_frame(cur);
+            }
+        }
+    }
+    return cmd_groups (interactive, NULL);
+}
+
 /* Show all the groups, with the current one highlighted. */
 cmdret *
 cmd_groups (int interactive, struct cmdarg **args UNUSED)
@@ -5484,11 +5579,10 @@ cmd_set (int interactive UNUSED, struct cmdarg **args)
     }
 }
 
-cmdret *
-cmd_sfdump (int interactively UNUSED, struct cmdarg **args UNUSED)
+char *
+sfdump (void)
 {
   char screen_suffix[16];
-  cmdret *ret;
   struct sbuf *dump;
   rp_frame *cur;
   int i;
@@ -5513,13 +5607,20 @@ cmd_sfdump (int interactively UNUSED, struct cmdarg **args UNUSED)
         }
     }
   sbuf_chop (dump);
-  ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (dump));
-  sbuf_free (dump);
+  return sbuf_free_struct (dump);
+}
+
+cmdret *
+cmd_sfdump (int interactively UNUSED, struct cmdarg **args UNUSED)
+{
+  char *s = sfdump();
+  cmdret *ret = cmdret_new (RET_SUCCESS, "%s", s);
+  free (s);
   return ret;
 }
 
 cmdret *
-cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
+sfrestore (char *sframes)
 {
   struct sbuf *buffer[num_screens];
   char *copy, *ptr, *token;
@@ -5531,7 +5632,7 @@ cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
   for (i = 0; i < num_screens; i++)
     buffer[i] = sbuf_new (0);
 
-  copy = xstrdup (ARG_STRING (0));
+  copy = xstrdup (sframes);
 
   token = strtok (copy, ",");
   if (token == NULL)
@@ -5589,6 +5690,12 @@ cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
 }
 
 cmdret *
+cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
+{
+    return sfrestore (ARG_STRING(0));
+}
+
+cmdret *
 cmd_sdump (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
   cmdret *ret;
diff --git a/src/actions.h b/src/actions.h
index d813bc9..608fced 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -130,6 +130,7 @@ RP_CMD (exchangeright);
 RP_CMD (swap);
 RP_CMD (frestore);
 RP_CMD (fselect);
+RP_CMD (gclean);
 RP_CMD (gdelete);
 RP_CMD (getenv);
 RP_CMD (gmerge);
@@ -142,6 +143,7 @@ RP_CMD (gprev);
 RP_CMD (gother);
 RP_CMD (gravity);
 RP_CMD (grename);
+RP_CMD (grestore);
 RP_CMD (groups);
 RP_CMD (gselect);
 RP_CMD (h_split);
@@ -233,6 +235,8 @@ void free_keymaps (void);
 char *wingravity_to_string (int g);
 rp_action* find_keybinding (KeySym keysym, unsigned int state, rp_keymap *map);
 rp_action* find_keybinding_by_action (char *action, rp_keymap *map);
+char *sfdump (void);
+cmdret *sfrestore (char *sframes);
 
 
 #endif /* ! _RATPOISON_ACTIONS_H */
diff --git a/src/data.h b/src/data.h
index 01a8f1a..5e286cb 100644
--- a/src/data.h
+++ b/src/data.h
@@ -147,6 +147,9 @@ struct rp_group
 
   /* This structure can exist in a list. */
   struct list_head node;
+
+  /* screens' frame dump from the last time this group was used */
+  char *sframes;
 };
 
 struct rp_screen
diff --git a/src/globals.c b/src/globals.c
index 1481a5c..ae8d1a9 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -233,6 +233,7 @@ LIST_HEAD (rp_switch_screen_hook);
 LIST_HEAD (rp_quit_hook);
 LIST_HEAD (rp_restart_hook);
 LIST_HEAD (rp_delete_window_hook);
+LIST_HEAD (rp_move_to_group_hook);
 LIST_HEAD (rp_new_window_hook);
 LIST_HEAD (rp_title_changed_hook);
 
@@ -243,6 +244,7 @@ struct rp_hook_db_entry rp_hook_db[]=
    {"switchgroup",      &rp_switch_group_hook},
    {"switchscreen",      &rp_switch_screen_hook},
    {"deletewindow",     &rp_delete_window_hook},
+   {"movetogroup",      &rp_move_to_group_hook},
    {"quit",             &rp_quit_hook},
    {"restart",          &rp_restart_hook},
    {"newwindow",	&rp_new_window_hook},
diff --git a/src/globals.h b/src/globals.h
index 2100a79..80136c3 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -187,6 +187,7 @@ extern struct list_head rp_switch_frame_hook;
 extern struct list_head rp_switch_group_hook;
 extern struct list_head rp_switch_screen_hook;
 extern struct list_head rp_delete_window_hook;
+extern struct list_head rp_move_to_group_hook;
 extern struct list_head rp_quit_hook;
 extern struct list_head rp_restart_hook;
 extern struct list_head rp_new_window_hook;
diff --git a/src/group.c b/src/group.c
index 02d2073..9d23a73 100644
--- a/src/group.c
+++ b/src/group.c
@@ -137,6 +137,7 @@ group_new (int number, char *name)
   g->numset = numset_new();
   INIT_LIST_HEAD (&g->unmapped_windows);
   INIT_LIST_HEAD (&g->mapped_windows);
+  g->sframes = NULL;
 
   return g;
 }
@@ -147,6 +148,7 @@ group_free (rp_group *g)
   free (g->name);
   numset_free (g->numset);
   numset_release (group_numset, g->number);
+  free (g->sframes);
   free (g);
 }
 
@@ -600,6 +602,8 @@ group_move_window (rp_group *to, rp_window *win)
   /* and shove it into the other one. */
   we->number = numset_request (to->numset);
   group_insert_window (&to->mapped_windows, we);
+
+  hook_run (&rp_move_to_group_hook);
 }
 
 void
@@ -642,6 +646,16 @@ set_current_group (rp_group *g)
   hook_run (&rp_switch_group_hook);
 }
 
+void
+store_current_group_frames (char *sframes)
+{
+  if (rp_current_group)
+    {
+      free (rp_current_group->sframes);
+      rp_current_group->sframes = sframes;
+    }
+}
+
 int
 group_delete_group (rp_group *g)
 {
diff --git a/src/group.h b/src/group.h
index 1081043..310d31a 100644
--- a/src/group.h
+++ b/src/group.h
@@ -68,6 +68,7 @@ void group_move_window (rp_group *to, rp_window *win);
 void groups_merge (rp_group *from, rp_group *to);
 
 void set_current_group (rp_group *g);
+void store_current_group_frames (char *sframes);
 
 rp_window *group_last_window_by_class (rp_group *g, char *class);
 rp_window *group_last_window_by_class_complement (rp_group *g, char *class);