Author: Trent Buck Patched-Against: cvs2004-07-02 Description: Adds :undo, which allows (repeated) undoing of frame operations. Todo: * Make undo limit a variable (set with :set) * Put prototypes and shit in the right files. * Typedef the struct. * Make it work with class and sfdump patches. * Avoid extending linkedlist.h. diff -ur ratpoison.orig/src/actions.c ratpoison/src/actions.c --- ratpoison.orig/src/actions.c 2004-05-20 22:40:02.000000000 +1000 +++ ratpoison/src/actions.c 2004-07-02 17:00:44.000000000 +1000 @@ -31,6 +31,9 @@ /* rp_keymaps is ratpoison's list of keymaps. */ LIST_HEAD(rp_keymaps); +LIST_HEAD(rp_frame_histories); +int num_frame_histories; +#define MAX_FRAME_HISTORIES 20 static user_command user_commands[] = { /address@hidden (tag required for genrpbindings) */ @@ -105,6 +108,7 @@ {"title", cmd_rename, arg_STRING}, {"tmpwm", cmd_tmpwm, arg_STRING}, {"unalias", cmd_unalias, arg_STRING}, + {"undo", cmd_undo, arg_STRING}, {"unmanage", cmd_unmanage, arg_STRING}, {"unsetenv", cmd_unsetenv, arg_STRING}, {"verbexec", cmd_verbexec, arg_STRING}, @@ -1367,6 +1371,7 @@ char * cmd_newwm(int interactive, char *data) { + push_frame_history (current_screen()); char *prog; if (data == NULL) @@ -1658,6 +1663,7 @@ char * cmd_v_split (int interactive, char *data) { + push_frame_history (current_screen()); rp_frame *frame; int pixels; @@ -1680,6 +1686,7 @@ char * cmd_h_split (int interactive, char *data) { + push_frame_history (current_screen()); rp_frame *frame; int pixels; @@ -1702,6 +1709,7 @@ char * cmd_only (int interactive, char *data) { + push_frame_history (current_screen()); remove_all_splits(); maximize (current_window()); @@ -1711,6 +1719,7 @@ char * cmd_remove (int interactive, char *data) { + push_frame_history (current_screen()); rp_screen *s = current_screen(); rp_frame *frame; @@ -1735,6 +1744,7 @@ char * cmd_shrink (int interactive, char *data) { + push_frame_history (current_screen()); resize_shrink_to_window (current_frame()); return NULL; } @@ -1742,6 +1752,7 @@ char * cmd_resize (int interactive, char *data) { + push_frame_history (current_screen()); rp_screen *s = current_screen (); /* If the user calls resize with arguments, treat it like the @@ -3446,8 +3457,8 @@ return NULL; } -char * -cmd_fdump (int interactively, char *data) +static char * +fdump (rp_screen *screen) { struct sbuf *s; char *tmp; @@ -3456,7 +3467,7 @@ s = sbuf_new (0); /* FIXME: Oooh, gross! there's a trailing comma, yuk! */ - list_for_each_entry (cur, ¤t_screen()->frames, node) + list_for_each_entry (cur, &(screen->frames), node) { char *tmp; @@ -3472,9 +3483,21 @@ } char * +cmd_fdump (int interactively, char *data) +{ + return fdump (current_screen()); +} + +char * cmd_frestore (int interactively, char *data) { - rp_screen *s = current_screen(); + push_frame_history (current_screen()); + return frestore (interactively, data, current_screen()); +} + +char * +frestore (int interactively, char *data, rp_screen *s) +{ char *token; char *dup; rp_frame *new, *cur; @@ -4298,3 +4321,56 @@ free (rest); return NULL; } + +void +push_frame_history(struct rp_screen *screen) +{ + struct rp_frame_history *cur; + if (num_frame_histories > MAX_FRAME_HISTORIES) + { + /* Delete the oldest node */ + list_last (cur, &rp_frame_histories, node); + remove_frame_history (cur); + num_frame_histories--; + } + cur = xmalloc (sizeof(struct rp_frame_history)); + cur->frames = fdump(screen); + cur->screen = screen; + list_add (&cur->node, &rp_frame_histories); + num_frame_histories++; +} + +char * +cmd_undo (int interactive, char *data) +{ + /* assert(!data); */ + struct rp_frame_history *cur; + + list_first (cur, &rp_frame_histories, node); + if (NULL == cur) + { + message (" No more undo information available "); + return NULL; + } + else + { + char *ret; + + ret = frestore (interactive, cur->frames, cur->screen); + /* Delete the newest node */ + remove_frame_history (cur); + num_frame_histories--; + return ret; + } +} + +void +remove_frame_history (struct rp_frame_history *f) +{ + if (NULL == f) + return; + if (f->frames) + free (f->frames); + list_del (&(f->node)); +} + diff -ur ratpoison.orig/src/actions.h ratpoison/src/actions.h --- ratpoison.orig/src/actions.h 2004-04-19 11:30:39.000000000 +1000 +++ ratpoison/src/actions.h 2004-07-02 16:51:22.000000000 +1000 @@ -133,5 +133,9 @@ rp_action* find_keybinding (KeySym keysym, int state, rp_keymap *map); rp_action* find_keybinding_by_action (char *action, rp_keymap *map); +void push_frame_history(rp_screen *); +char *cmd_undo (int, char *); +void remove_frame_history (struct rp_frame_history *f); +char *frestore (int interactively, char *data, rp_screen *s); #endif /* ! _RATPOISON_ACTIONS_H */ diff -ur ratpoison.orig/src/data.h ratpoison/src/data.h --- ratpoison.orig/src/data.h 2004-05-20 22:40:02.000000000 +1000 +++ ratpoison/src/data.h 2004-07-02 16:47:54.000000000 +1000 @@ -325,4 +325,11 @@ struct list_head *hook; }; +struct rp_frame_history +{ + char *frames; + rp_screen *screen; + struct list_head node; +}; + #endif /* _RATPOISON_DATA_H */ diff -ur ratpoison.orig/src/linkedlist.h ratpoison/src/linkedlist.h --- ratpoison.orig/src/linkedlist.h 2003-05-27 17:51:07.000000000 +1000 +++ ratpoison/src/linkedlist.h 2004-07-02 15:20:01.000000000 +1000 @@ -180,3 +180,11 @@ if (&first->member == (head)) \ first = NULL; \ } + +/* Return the last element in the list. */ +#define list_last(last, head, member) \ +{ \ + last = list_entry((head)->prev, typeof(*last), member); \ + if (&last->member == (head)) \ + last = NULL; \ +}