summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog71
-rw-r--r--src/actions.c481
-rw-r--r--src/actions.h14
-rw-r--r--src/data.h18
-rw-r--r--src/frame.c1
-rw-r--r--src/globals.c5
-rw-r--r--src/globals.h2
-rw-r--r--src/group.c55
-rw-r--r--src/group.h2
-rw-r--r--src/linkedlist.h9
-rw-r--r--src/main.c10
-rw-r--r--src/screen.c21
-rw-r--r--src/screen.h2
-rw-r--r--src/window.c66
-rw-r--r--src/window.h2
15 files changed, 737 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index efd0d8e..c4dc093 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,76 @@
2004-11-18 Shawn Betts <katia_dilkina@verizon.net>
+ * src/actions.c (set_vars): add maxundos
+ (push_frame_undo): new function
+ (pop_frame_undo): likewise
+ (initialize_default_keybindings): add binding for "undo"
+ (initialize_default_keybindings): add def alias for maxundos
+ (cmd_other): call set_active_window_force instead of
+ set_active_window
+ (cmd_v_split): push the frame set
+ (cmd_h_split): likewise
+ (cmd_only): likewise
+ (cmd_remove): likewise
+ (cmd_shrink): likewise
+ (cmd_tmpwm): likewise
+ (cmd_license): update copyright. Add build date and time.
+ (cmd_fselect): simplify code that returns the frame selected.
+ (fdump): new function
+ (cmd_fdump): call fdump to dump the screen's frame set.
+ (frestore): new function
+ (cmd_frestore): call frestore to restore the screen's frame set.
+ (cmd_sfdump): new function
+ (cmd_sdump): likewise
+ (set_maxundos): likewise
+ (cmd_cnext): likewise
+ (cmd_cprev): likewise
+ (cmd_inext): likewise
+ (cmd_iprev): likewise
+ (cmd_cother): likewise
+ (cmd_iother): likewise
+ (cmd_undo): likewise
+ (cmd_prompt): likewise
+ (cmd_describekey): likewise
+ (cmd_dedicate): likewise
+
+ * src/main.c (init_defaults): init maxundos to 20
+ (clean_up): free the undo history lists
+
+ * src/window.h (set_active_window_body): new function
+ (set_active_window_force): likewise
+
+ * src/window.c (set_active_window): new function
+ (set_active_window_force): likewise
+ (set_active_window_body): renamed from set_active_window
+ (set_active_window_body): Add code to handle dedicated frames.
+
+
+ * src/screen.h (screen_dump): new prototype
+
+ * src/screen.c (screen_dump): new function
+
+ * src/linkedlist.h (list_last): new macro
+
+ * src/group.h (group_last_window_by_class_complement): new prototype
+ (group_last_window_by_class): likewise
+
+ * src/group.c (group_last_window_by_class): new function
+ (group_last_window_by_class_complement): likewise
+
+ * src/globals.h (rp_frame_undos): new extern.
+ (rp_num_frame_undos): likewise
+
+ * src/globals.c (rp_frame_undos): new list.
+ (rp_num_frame_undos): new global
+
+ * src/frame.c (frame_new): init f->dedicated to 0.
+
+ * src/data.h (struct rp_frame): add dedicated member.
+ (struct rp_defaults): add maxundos member.
+ (struct rp_frame_undo): new struct.
+
+ * src/actions.c: new commands, cnext, cother, cprev,
+
* src/window.c (print_window_information): add argument,
group. print the window's number in the group. All callers
updated.
diff --git a/src/actions.c b/src/actions.c
index e334de1..fee6e77 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -120,6 +120,19 @@ static user_command user_commands[] =
{"vsplit", cmd_v_split, arg_STRING},
{"warp", cmd_warp, arg_STRING},
{"windows", cmd_windows, arg_VOID},
+ {"cnext", cmd_cnext, arg_VOID},
+ {"cother", cmd_cother, arg_VOID},
+ {"cprev", cmd_cprev, arg_VOID},
+ {"dedicate", cmd_dedicate, arg_VOID},
+ {"describekey", cmd_describekey, arg_STRING},
+ {"focusprev", cmd_prev_frame, arg_VOID},
+ {"inext", cmd_inext, arg_VOID},
+ {"iother", cmd_iother, arg_VOID},
+ {"iprev", cmd_iprev, arg_VOID},
+ {"prompt", cmd_prompt, arg_STRING},
+ {"sdump", cmd_sdump, arg_VOID},
+ {"sfdump", cmd_sfdump, arg_VOID},
+ {"undo", cmd_undo, arg_STRING},
/*@end (tag required for genrpbindings) */
/* Commands to help debug ratpoison. */
@@ -161,8 +174,10 @@ static char * set_bgcolor (char *data);
static char * set_barpadding (char *data);
static char * set_winliststyle (char *data);
static char * set_framesels (char *data);
+static char * set_maxundos (char *data);
static struct set_var set_vars[] =
{ {"resizeunit", set_resizeunit},
+ {"maxundos", set_maxundos},
{"wingravity", set_wingravity},
{"transgravity", set_transgravity},
{"maxsizegravity", set_maxsizegravity},
@@ -192,6 +207,35 @@ static alias_t *alias_list;
static int alias_list_size;
static int alias_list_last;
+static char *frestore (char *data, rp_screen *s);
+static char *fdump (rp_screen *screen);
+
+static void
+push_frame_undo(rp_screen *screen)
+{
+ rp_frame_undo *cur;
+ if (rp_num_frame_undos > defaults.maxundos)
+ {
+ /* Delete the oldest node */
+ list_last (cur, &rp_frame_undos, node);
+ pop_frame_undo (cur);
+ }
+ cur = xmalloc (sizeof(rp_frame_undo));
+ cur->frames = fdump (screen);
+ cur->screen = screen;
+ list_add (&cur->node, &rp_frame_undos);
+ rp_num_frame_undos++; /* increment counter */
+}
+
+void
+pop_frame_undo (rp_frame_undo *u)
+{
+ if (!u) return;
+ if (u->frames) free (u->frames);
+ list_del (&(u->node));
+ rp_num_frame_undos--; /* decrement counter */
+}
+
rp_action*
find_keybinding_by_action (char *action, rp_keymap *map)
{
@@ -483,6 +527,7 @@ initialize_default_keybindings (void)
add_keybinding (XK_r, 0, "resize", map);
add_keybinding (XK_r, RP_CONTROL_MASK, "resize", map);
add_keybinding (XK_question, 0, "help " ROOT_KEYMAP, map);
+ add_keybinding (XK_underscore, RP_CONTROL_MASK, "undo", map);
add_alias ("unbind", "definekey " ROOT_KEYMAP);
add_alias ("bind", "definekey " ROOT_KEYMAP);
@@ -504,6 +549,7 @@ initialize_default_keybindings (void)
add_alias ("defbarpadding", "set barpadding");
add_alias ("defwinliststyle", "set winliststyle");
add_alias ("defframesels", "set framesels");
+ add_alias ("defmaxundos", "set maxundos");
}
void
@@ -922,7 +968,7 @@ cmd_other (int interactive, char *data)
if (!w)
message (MESSAGE_NO_OTHER_WINDOW);
else
- set_active_window (w);
+ set_active_window_force (w);
return NULL;
}
@@ -1674,6 +1720,7 @@ cmd_v_split (int interactive, char *data)
rp_frame *frame;
int pixels;
+ push_frame_undo (current_screen()); /* fdump to stack */
frame = current_frame();
/* Default to dividing the frame in half. */
@@ -1696,6 +1743,7 @@ cmd_h_split (int interactive, char *data)
rp_frame *frame;
int pixels;
+ push_frame_undo (current_screen()); /* fdump to stack */
frame = current_frame();
/* Default to dividing the frame in half. */
@@ -1715,6 +1763,7 @@ cmd_h_split (int interactive, char *data)
char *
cmd_only (int interactive, char *data)
{
+ push_frame_undo (current_screen()); /* fdump to stack */
remove_all_splits();
maximize (current_window());
@@ -1727,6 +1776,8 @@ cmd_remove (int interactive, char *data)
rp_screen *s = current_screen();
rp_frame *frame;
+ push_frame_undo (current_screen()); /* fdump to stack */
+
if (num_frames(s) <= 1)
{
message (" remove: cannot remove only frame ");
@@ -1748,6 +1799,7 @@ cmd_remove (int interactive, char *data)
char *
cmd_shrink (int interactive, char *data)
{
+ push_frame_undo (current_screen()); /* fdump to stack */
resize_shrink_to_window (current_frame());
return NULL;
}
@@ -2036,9 +2088,9 @@ cmd_license (int interactive, char *data)
int y = 10;
int i;
int max_width = 0;
- char *license_text[] = { PACKAGE " " VERSION,
+ char *license_text[] = { PACKAGE " " VERSION, "(built " __DATE__ " " __TIME__ ")",
"",
- "Copyright (C) 2000, 2001 Shawn Betts",
+ "Copyright (C) 2000-2004 Shawn Betts",
"",
"ratpoison is free software; you can redistribute it and/or modify ",
"it under the terms of the GNU General Public License as published by ",
@@ -3418,6 +3470,7 @@ cmd_tmpwm (int interactive, char *data)
int pid;
int i;
+ push_frame_undo (current_screen()); /* fdump to stack */
if (data == NULL)
{
message (" tmpwm: one argument required ");
@@ -3642,17 +3695,8 @@ cmd_fselect (int interactive, char *data)
frame = find_frame_number (fnum);
if (frame)
{
- char *s;
- struct sbuf *sb;
-
- /* Return the frame number that was selected. */
- sb = sbuf_new(0);
- sbuf_printf (sb, "%d", fnum);
- s = sbuf_get(sb);
- free (sb);
-
set_active_frame (frame);
- return s;
+ return xsprintf("%d", frame->number);
}
else
{
@@ -3661,8 +3705,8 @@ cmd_fselect (int interactive, char *data)
}
}
-char *
-cmd_fdump (int interactively, char *data)
+static char *
+fdump (rp_screen *screen)
{
struct sbuf *s;
char *tmp;
@@ -3671,7 +3715,7 @@ cmd_fdump (int interactively, char *data)
s = sbuf_new (0);
/* FIXME: Oooh, gross! there's a trailing comma, yuk! */
- list_for_each_entry (cur, &current_screen()->frames, node)
+ list_for_each_entry (cur, &(screen->frames), node)
{
char *tmp;
@@ -3687,9 +3731,33 @@ cmd_fdump (int interactively, char *data)
}
char *
-cmd_frestore (int interactively, char *data)
+cmd_fdump (int interactively, char *data)
+{
+ if (!data)
+ {
+ return fdump (current_screen());
+ }
+ else
+ {
+ /* assert (NULL != data); */
+ int snum;
+ if (1 != sscanf (data, "%d", &snum)
+ || snum < 0
+ || num_screens <= snum)
+ {
+ message (" fdump: invalid argument ");
+ return NULL;
+ }
+ else
+ {
+ return fdump (&screens[snum]);
+ }
+ }
+}
+
+static char *
+frestore (char *data, rp_screen *s)
{
- rp_screen *s = current_screen();
char *token;
char *dup;
rp_frame *new, *cur;
@@ -3791,6 +3859,13 @@ cmd_frestore (int interactively, char *data)
}
char *
+cmd_frestore (int interactively, char *data)
+{
+ push_frame_undo (current_screen()); /* fdump to stack */
+ return frestore (data, current_screen());
+}
+
+char *
cmd_verbexec (int interactive, char *data)
{
char msg[100]="Running ";
@@ -4517,3 +4592,373 @@ cmd_set (int interactive, char *data)
free (rest);
return NULL;
}
+
+char *
+cmd_sfdump (int interactively, char *data)
+{
+ struct sbuf *s;
+ char *tmp, *tmp2;
+ rp_frame *cur;
+
+ s = sbuf_new (0);
+
+ register int i;
+ for (i=0; i<num_screens; i++)
+ {
+ tmp2 = xsprintf (" %d,", (rp_have_xinerama)?(screens[i].xine_screen_num):(screens[i].screen_num));
+
+ /* FIXME: Oooh, gross! there's a trailing comma, yuk! */
+ list_for_each_entry (cur, &(screens[i].frames), node)
+ {
+ char *tmp;
+
+ tmp = frame_dump (cur);
+ sbuf_concat (s, tmp);
+ sbuf_concat (s, tmp2);
+ free (tmp);
+ }
+
+ free (tmp2);
+ }
+ tmp = sbuf_get (s);
+ free (s);
+ return tmp;
+}
+
+char *
+cmd_sdump (int interactive, char *data)
+{
+ /* assert(!data); */
+ struct sbuf *s;
+ char *tmp;
+ register int i;
+
+ s = sbuf_new (0);
+ for (i=0; i<num_screens; ++i)
+ {
+ tmp = screen_dump (&screens[i]);
+ sbuf_concat (s, tmp);
+ if (i + 1 != num_screens) /* No trailing comma. */
+ sbuf_concat (s, ",");
+ free (tmp);
+ }
+
+ tmp = sbuf_get (s);
+ free (s);
+ return tmp;
+}
+
+static char *
+set_maxundos (char *data)
+{
+ int tmp;
+ rp_frame_undo *cur;
+
+ if (!data)
+ return xsprintf ("%d", defaults.maxundos);
+
+ if (1 != sscanf (data, "%d", &tmp) || tmp < 0)
+ {
+ message (" defmaxundos: invalid argument ");
+ return NULL;
+ }
+
+ defaults.maxundos = tmp;
+
+ /* Delete any superfluous undos */
+ while (rp_num_frame_undos > defaults.maxundos)
+ {
+ /* Delete the oldest node */
+ list_last (cur, &rp_frame_undos, node);
+ pop_frame_undo (cur);
+ }
+
+ return NULL;
+}
+
+char *
+cmd_cnext (int interactive, char *data)
+{
+ rp_window *cur, *last, *win;
+
+ cur = current_window();
+ if (!cur || !cur->res_class) /* Can't be done. */
+ return cmd_next (interactive, data);
+
+ /* CUR !in cycle list, so LAST marks last node. */
+ last = group_prev_window (rp_current_group, cur);
+
+ if (last)
+ for (win = group_next_window (rp_current_group, cur);
+ win;
+ win = group_next_window (rp_current_group, win))
+ {
+ if (win->res_class
+ && strcmp (cur->res_class, win->res_class))
+ {
+ set_active_window_force (win);
+ return NULL;
+ }
+
+ if (win == last) break;
+ }
+
+ message (MESSAGE_NO_OTHER_WINDOW);
+ return NULL;
+}
+
+char *
+cmd_cprev (int interactive, char *data)
+{
+ rp_window *cur, *last, *win;
+
+ cur = current_window();
+ if (!cur || !cur->res_class) /* Can't be done. */
+ return cmd_next (interactive, data);
+
+ /* CUR !in cycle list, so LAST marks last node. */
+ last = group_next_window (rp_current_group, cur);
+
+ if (last)
+ for (win = group_prev_window (rp_current_group, cur);
+ win;
+ win = group_prev_window (rp_current_group, win))
+ {
+ if (win->res_class
+ && strcmp (cur->res_class, win->res_class))
+ {
+ set_active_window_force (win);
+ return NULL;
+ }
+
+ if (win == last) break;
+ }
+
+ message (MESSAGE_NO_OTHER_WINDOW);
+ return NULL;
+}
+
+char *
+cmd_inext (int interactive, char *data)
+{
+ rp_window *cur, *last, *win;
+
+ cur = current_window();
+ if (!cur || !cur->res_class) /* Can't be done. */
+ return cmd_next (interactive, data);
+
+ /* CUR !in cycle list, so LAST marks last node. */
+ last = group_prev_window (rp_current_group, cur);
+
+ if (last)
+ for (win = group_next_window (rp_current_group, cur);
+ win;
+ win = group_next_window (rp_current_group, win))
+ {
+ if (win->res_class
+ && !strcmp (cur->res_class, win->res_class))
+ {
+ set_active_window_force (win);
+ return NULL;
+ }
+
+ if (win == last) break;
+ }
+
+ message (MESSAGE_NO_OTHER_WINDOW);
+ return NULL;
+}
+
+char *
+cmd_iprev (int interactive, char *data)
+{
+ rp_window *cur, *last, *win;
+
+ cur = current_window();
+ if (!cur || !cur->res_class) /* Can't be done. */
+ return cmd_next (interactive, data);
+
+ /* CUR !in cycle list, so LAST marks last node. */
+ last = group_next_window (rp_current_group, cur);
+
+ if (last)
+ for (win = group_prev_window (rp_current_group, cur);
+ win;
+ win = group_prev_window (rp_current_group, win))
+ {
+ if (win->res_class
+ && !strcmp (cur->res_class, win->res_class))
+ {
+ set_active_window_force (win);
+ return NULL;
+ }
+
+ if (win == last) break;
+ }
+
+ message (MESSAGE_NO_OTHER_WINDOW);
+ return NULL;
+}
+
+char *
+cmd_cother (int interactive, char *data)
+{
+ rp_window *cur, *w;
+
+ cur = current_window();
+ w = group_last_window_by_class (rp_current_group, cur->res_class);
+
+ if (!w)
+ message (MESSAGE_NO_OTHER_WINDOW);
+ else
+ set_active_window_force (w);
+
+ return NULL;
+}
+
+char *
+cmd_iother (int interactive, char *data)
+{
+ rp_window *cur, *w;
+
+ cur = current_window();
+ w = group_last_window_by_class_complement (rp_current_group, cur->res_class);
+
+ if (!w)
+ message (MESSAGE_NO_OTHER_WINDOW);
+ else
+ set_active_window_force (w);
+
+ return NULL;
+}
+
+char *
+cmd_undo (int interactive, char *data)
+{
+ rp_frame_undo *cur;
+
+ list_first (cur, &rp_frame_undos, node);
+ if (!cur)
+ {
+ message (" No more undo information available ");
+ return NULL;
+ }
+ else
+ {
+ char *ret;
+
+ ret = frestore (cur->frames, cur->screen);
+ /* Delete the newest node */
+ pop_frame_undo (cur);
+ return ret;
+ }
+}
+
+char *
+cmd_prompt (int interactive, char *data)
+{
+ char *query, *ret, *prefix;
+
+ if (interactive) return NULL;
+
+ if (NULL == data)
+ ret = get_input(MESSAGE_PROMPT_COMMAND, trivial_completions);
+ else
+ {
+ prefix = strchr (data, ':');
+ if (prefix)
+ {
+ prefix++; /* Don't return the colon. */
+ query = xmalloc (prefix - data + 1);
+ strncpy (query, data, prefix - data);
+ query[prefix - data] = 0; /* null terminate */
+ ret = get_more_input (query, prefix, trivial_completions);
+ free (query);
+ }
+ else
+ {
+ ret = get_input (data, trivial_completions);
+ }
+ }
+ return ret;
+}
+
+char *
+cmd_describekey (int interactive, char *data)
+{
+ char *keysym_name;
+ rp_action *key_action;
+ KeySym keysym; /* Key pressed */
+ unsigned int mod; /* Modifiers */
+ int rat_grabbed = 0;
+ rp_keymap *map;
+
+ if (data == NULL)
+ {
+ message (" readkey: keymap expected ");
+ return NULL;
+ }
+
+ map = find_keymap (data);
+ if (map == NULL)
+ {
+ marked_message_printf (0, 0, " readkey: Unknown keymap '%s' ", data);
+ return NULL;
+ }
+
+ XGrabKeyboard (dpy, current_screen()->key_window, False, GrabModeSync, GrabModeAsync, CurrentTime);
+
+ /* Change the mouse icon to indicate to the user we are waiting for
+ more keystrokes */
+ if (defaults.wait_for_key_cursor)
+ {
+ grab_rat();
+ rat_grabbed = 1;
+ }
+
+ read_key (&keysym, &mod, NULL, 0);
+ XUngrabKeyboard (dpy, CurrentTime);
+
+ if (rat_grabbed)
+ ungrab_rat();
+
+ if ((key_action = find_keybinding (keysym, x11_mask_to_rp_mask (mod), map)))
+ {
+ char *result;
+ result = cmd_echo (1, key_action->data);
+
+ /* Gobble the result. */
+ if (result)
+ free (result);
+ }
+ else
+ {
+ /* No key match, notify user. */
+ keysym_name = keysym_to_string (keysym, x11_mask_to_rp_mask (mod));
+ marked_message_printf (0, 0, " %s unbound key ", keysym_name);
+ free (keysym_name);
+ }
+
+ return NULL;
+}
+
+char *
+cmd_dedicate (int interactive, char *data)
+{
+ rp_frame *f;
+
+ f = current_frame();
+ if (!f) return NULL;
+
+ if (data)
+ /* Whatever you set it to. */
+ f->dedicated = atoi(data);
+ else
+ /* Just toggle it, rather than on or off. */
+ f->dedicated = !(f->dedicated);
+
+ marked_message_printf (0, 0, " Consider this frame %s. ", (f->dedicated)?"chaste":"promiscuous");
+
+ return NULL;
+}
+
diff --git a/src/actions.h b/src/actions.h
index 8f2df78..84237a7 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -129,6 +129,20 @@ char *cmd_ratwarp (int interactive, char *data);
char *cmd_ratclick (int interactive, char *data);
char *cmd_ratrelwarp (int interactive, char *data);
char *cmd_rathold (int interactive, char *data);
+char *cmd_cnext (int interactive, char *data);
+char *cmd_cother (int interactive, char *data);
+char *cmd_cprev (int interactive, char *data);
+char *cmd_dedicate (int interactive, char *data);
+char *cmd_describekey (int interactive, char *data);
+char *cmd_inext (int interactive, char *data);
+char *cmd_iother (int interactive, char *data);
+char *cmd_iprev (int interactive, char *data);
+char *cmd_prompt (int interactive, char *data);
+char *cmd_sdump (int interactive, char *data);
+char *cmd_sfdump (int interactively, char *data);
+char *cmd_undo (int interactive, char *data);
+void pop_frame_undo (rp_frame_undo *u);
+
rp_keymap *find_keymap (char *name);
void initialize_default_keybindings (void);
diff --git a/src/data.h b/src/data.h
index 8cc4038..f8086e5 100644
--- a/src/data.h
+++ b/src/data.h
@@ -50,7 +50,11 @@ struct rp_frame
/* For determining the last frame. */
int last_access;
-
+
+ /* Boolean that is set when a frame is
+ `dedicated' (a.k.a. glued) to one window. */
+ unsigned int dedicated;
+
struct list_head node;
};
@@ -237,6 +241,9 @@ struct rp_defaults
int history_size;
char *frame_selectors;
+
+ /* How many frame sets to remember when undoing. */
+ int maxundos;
};
/* Information about a child process. */
@@ -325,4 +332,13 @@ struct rp_hook_db_entry
struct list_head *hook;
};
+typedef struct rp_frame_undo rp_frame_undo;
+struct rp_frame_undo
+{
+ char *frames;
+ rp_screen *screen;
+ struct list_head node;
+};
+
+
#endif /* _RATPOISON_DATA_H */
diff --git a/src/frame.c b/src/frame.c
index 18352c1..6a06f8f 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -115,6 +115,7 @@ frame_new (rp_screen *s)
f = xmalloc (sizeof (rp_frame));
f->number = numset_request (s->frames_numset);
f->last_access = 0;
+ f->dedicated = 0;
return f;
}
diff --git a/src/globals.c b/src/globals.c
index f23eb9c..d57721e 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -87,7 +87,7 @@ struct rp_hook_db_entry rp_hook_db[]=
{"quit", &rp_quit_hook},
{"restart", &rp_restart_hook},
{NULL, NULL}};
-
+
void
set_rp_window_focus (rp_window *win)
{
@@ -103,3 +103,6 @@ set_window_focus (Window window)
XSetInputFocus (dpy, window,
RevertToPointerRoot, CurrentTime);
}
+
+LIST_HEAD (rp_frame_undos);
+int rp_num_frame_undos = 0;
diff --git a/src/globals.h b/src/globals.h
index 063abc3..6dd0136 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -146,4 +146,6 @@ extern int xine_screen_count;
extern struct numset *rp_frame_numset;
+extern struct list_head rp_frame_undos;
+extern int rp_num_frame_undos;
#endif
diff --git a/src/group.c b/src/group.c
index 883e7d8..43fab12 100644
--- a/src/group.c
+++ b/src/group.c
@@ -508,3 +508,58 @@ group_delete_group (rp_group *g)
}
}
+/* Used by :cother / :iother */
+rp_window *
+group_last_window_by_class (rp_group *g, char *class)
+{
+ int last_access = 0;
+ rp_window_elem *most_recent = NULL;
+ rp_window_elem *cur;
+ rp_screen *s = current_screen();
+
+ list_for_each_entry (cur, &g->mapped_windows, node)
+ {
+ if (cur->win->last_access >= last_access
+ && cur->win != current_window()
+ && !find_windows_frame (cur->win)
+ && (cur->win->scr == s || rp_have_xinerama)
+ && strcmp(class, cur->win->res_class))
+ {
+ most_recent = cur;
+ last_access = cur->win->last_access;
+ }
+ }
+
+ if (most_recent)
+ return most_recent->win;
+
+ return NULL;
+}
+
+/* Used by :cother / :iother */
+rp_window *
+group_last_window_by_class_complement (rp_group *g, char *class)
+{
+ int last_access = 0;
+ rp_window_elem *most_recent = NULL;
+ rp_window_elem *cur;
+ rp_screen *s = current_screen();
+
+ list_for_each_entry (cur, &g->mapped_windows, node)
+ {
+ if (cur->win->last_access >= last_access
+ && cur->win != current_window()
+ && !find_windows_frame (cur->win)
+ && (cur->win->scr == s || rp_have_xinerama)
+ && !strcmp(class, cur->win->res_class))
+ {
+ most_recent = cur;
+ last_access = cur->win->last_access;
+ }
+ }
+
+ if (most_recent)
+ return most_recent->win;
+
+ return NULL;
+}
diff --git a/src/group.h b/src/group.h
index 7678bbb..c314f20 100644
--- a/src/group.h
+++ b/src/group.h
@@ -39,4 +39,6 @@ void groups_merge (rp_group *from, rp_group *to);
void set_current_group (rp_group *g);
+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);
#endif
diff --git a/src/linkedlist.h b/src/linkedlist.h
index fc1b8db..a056093 100644
--- a/src/linkedlist.h
+++ b/src/linkedlist.h
@@ -57,6 +57,14 @@ void __list_add(struct list_head *new,
struct list_head *next);
void prefetch(const void *x);
+/* 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; \
+}
+
/**
* container_of - cast a member of a structure out to the containing structure
@@ -180,3 +188,4 @@ void prefetch(const void *x);
if (&first->member == (head)) \
first = NULL; \
}
+
diff --git a/src/main.c b/src/main.c
index cfee3a6..90f2ab9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -499,6 +499,7 @@ init_defaults ()
defaults.history_size = 20;
defaults.frame_selectors = xstrdup ("");
+ defaults.maxundos = 20;
}
int
@@ -705,6 +706,15 @@ clean_up ()
}
free (screens);
+ /* Delete the undo histories */
+ while (rp_num_frame_undos > 0)
+ {
+ /* Delete the oldest node */
+ rp_frame_undo *cur;
+ list_last (cur, &rp_frame_undos, node);
+ pop_frame_undo (cur);
+ }
+
/* Free the global frame numset shared by all screens. */
free (rp_frame_numset);
diff --git a/src/screen.c b/src/screen.c
index 56aa96e..cf88895 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -354,3 +354,24 @@ is_rp_window_for_screen(Window w, rp_screen *s)
}
}
+char *
+screen_dump (rp_screen *screen)
+{
+ char *tmp;
+ struct sbuf *s;
+
+ s = sbuf_new (0);
+ sbuf_printf (s, "%d %d %d %d %d %d",
+ (rp_have_xinerama)?screen->xine_screen_num:screen->screen_num,
+ screen->left,
+ screen->top,
+ screen->width,
+ screen->height,
+ (current_screen() == screen)?1:0 /* is current? */
+ );
+
+ /* Extract the string and return it, and don't forget to free s. */
+ tmp = sbuf_get (s);
+ free (s);
+ return tmp;
+}
diff --git a/src/screen.h b/src/screen.h
index fdc37af..b7c4fc1 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -39,4 +39,6 @@ void init_screens (int screen_arg, int screen_num);
int is_rp_window_for_screen (Window w, rp_screen *s);
int is_a_root_window (int w);
+char *screen_dump (rp_screen *screen);
+
#endif
diff --git a/src/window.c b/src/window.c
index 68e5963..5ba5454 100644
--- a/src/window.c
+++ b/src/window.c
@@ -455,11 +455,21 @@ is_transient_ancestor (rp_window *win, rp_window *transient_for)
#endif
/* In the current frame, set the active window to win. win will have focus. */
+void set_active_window (rp_window *win)
+{
+ set_active_window_body(win, 0);
+}
+
+void set_active_window_force (rp_window *win)
+{
+ set_active_window_body(win, 1);
+}
+
void
-set_active_window (rp_window *win)
+set_active_window_body (rp_window *win, int force)
{
rp_window *last_win;
- rp_frame *frame;
+ rp_frame *frame, *last_frame = NULL;
if (win == NULL) return;
@@ -474,6 +484,54 @@ set_active_window (rp_window *win)
{
frame = screen_get_frame (win->scr, win->scr->current_frame);
}
+
+ if (frame->dedicated && !force)
+ {
+ /* Try to find a non-dedicated frame. */
+ rp_frame *cur;
+ rp_screen *scr;
+ int done;
+
+ scr = (rp_have_xinerama)?&screens[rp_current_screen]:win->scr;
+ done = 0;
+
+ /* Try the only / current screen... */
+ for (cur = list_next_entry (frame, &scr->frames, node);
+ cur != frame && !done;
+ cur = list_next_entry (cur, &scr->frames, node))
+ {
+ if (!cur->dedicated)
+ {
+ set_active_frame (cur);
+ last_frame = frame;
+ frame = cur;
+ done = 1;
+ }
+ }
+
+ /* If we have Xinerama, we can check *all* screens... */
+ if (rp_have_xinerama && !done)
+ {
+ int i;
+
+ for (i=0; i<num_screens && !done; i++)
+ {
+ if (scr == &screens[i]) continue;
+ list_for_each_entry (cur,&screens[i].frames,node)
+ {
+ if (!cur->dedicated)
+ {
+ set_active_frame (cur);
+ last_frame = frame;
+ frame = cur;
+ done = 1; /* Break outer loop. */
+ break; /* Break inner loop. */
+ }
+ }
+ }
+ }
+ }
+
last_win = set_frames_window (frame, win);
if (last_win) PRINT_DEBUG (("last window: %s\n", window_name (last_win)));
@@ -502,6 +560,10 @@ set_active_window (rp_window *win)
XSync (dpy, False);
+ /* If we switched frame, go back to the old one. */
+ if (last_frame)
+ set_active_frame (last_frame);
+
/* Call the switch window hook */
hook_run (&rp_switch_win_hook);
}
diff --git a/src/window.h b/src/window.h
index 874de05..f0ec828 100644
--- a/src/window.h
+++ b/src/window.h
@@ -65,4 +65,6 @@ void free_window_stuff ();
rp_frame *win_get_frame (rp_window *win);
+void set_active_window_force (rp_window *win);
+void set_active_window_body (rp_window *win, int force);
#endif /* ! _RATPOISON_LIST_H */