[PATCH] Built-in workspaces
Repolho <[email protected]>
| Newsgroups | gmane.comp.window-managers.ratpoison.devel |
|---|---|
| Message-ID | <20131028200705.GB31685@darch> |
Here's a proposed implementation of built-in workspaces that keeps the group system intact from the user's point of view. It performs noticeably better under heavy CPU or disk usage than external solutions. It works by storing an sfdump into the current group before a group change, and then allowing for the user to restore those dumps when he goes back to that group. This is accomplished by making available two new user commands: grestore and gclean. grestore will restore the sfdump stored in a group (defaulting to the current one). gclean will empty any frames whose windows don't belong to a group (also defaulting to the current one). By adding both these commands to the switchgroup hook, the user will get built-in workspaces, where switching to another group restores the screens' state to the last state they were in when that group was last used. By not using the commands at all, the user will get the usual group behavior. The only difference for the latter is the extra memory usage of storing an sfdump per group, and the extra CPU usage of an sfdump() call per group change, both of which are insignificant and unnoticeable. Additionally, the patch also adds a new hook, movetogroup, to be triggered when a window is moved to another group. This is so that the user can add gclean to said hook, so the window will disappear from the screen after being moved. Again, a user that chooses not to do anything will experience the same group behavior as always. A sample configuration file is also attached to ease testing. I look forward to hearing your opinions on the idea as well as the implementation. _______________________________________________ Ratpoison-devel mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/ratpoison-devel
ratpoison-builtin-workspaces.patch
(text/x-diff, 10.2 KB)
diff --git a/src/actions.c b/src/actions.c
index 2369067..2db049c 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -249,6 +249,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,
@@ -266,6 +268,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);
@@ -5043,6 +5047,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);
}
@@ -5050,6 +5055,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);
}
@@ -5057,6 +5063,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);
}
@@ -5066,6 +5073,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);
}
@@ -5146,7 +5154,97 @@ 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);
+ }
+ }
+ }
else
return cmd_groups (interactive, NULL);
@@ -5471,12 +5569,10 @@ cmd_set (int interactive UNUSED, struct cmdarg **args)
return result;
}
}
-
-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;
@@ -5501,13 +5597,21 @@ cmd_sfdump (int interactively UNUSED, struct cmdarg **args UNUSED)
free (frameset);
}
}
- 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;
@@ -5519,7 +5623,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)
@@ -5578,6 +5682,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 519c1a7..4e9dffa 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -131,6 +131,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);
@@ -143,6 +144,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);
@@ -234,6 +236,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 2be9a98..172883f 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 05ebe28..6ad16bb 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -235,6 +235,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);
@@ -245,6 +246,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 12ccffd..622fefd 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -183,6 +183,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 2bbfead..654f131 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;
}
@@ -148,6 +149,7 @@ group_free (rp_group *g)
free (g->name);
numset_free (g->numset);
numset_release (group_numset, g->number);
+ free (g->sframes);
free (g);
}
@@ -595,6 +597,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
@@ -637,6 +641,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);
ratpoisonrc_workspaces
(text/plain, 923 B)
# workspaces # add groups # (in a single exec to avoid race and making sure the group doesn't # already exist) exec ratpoison -c groups | grep -q '^1' || ratpoison -c "gnewbg 1"; ratpoison -c groups | grep -q '^2' || ratpoison -c "gnewbg 2"; ratpoison -c groups | grep -q '^3' || ratpoison -c "gnewbg 3" # hooks # restore last seen frames for newly selected group addhook switchgroup grestore # hide windows which no longer belong to this group addhook switchgroup gclean # also hide when moving a window, so it will be hidden from the current group addhook movetogroup gclean # display groups list addhook switchgroup groups # bindings # select group definekey root 1 gselect 0 definekey root 2 gselect 1 definekey root 3 gselect 2 definekey root 4 gselect 3 # move window to group definekey root exclam gmove 0 definekey root at gmove 1 definekey root numbersign gmove 2 definekey root dollar gmove 3