Re: patch: push window to frame

Jeff Abrahamson <[email protected]> Tue, 16 Sep 2014 21:41:53 +0200
Newsgroups gmane.comp.window-managers.ratpoison.devel
Message-ID <CAM4Y7zxY79a-EN=WV5-mjz5BDjF=71uHkepgL=ARxQDGNiUUfg@mail.gmail.com>
Attached are patches to implement pushwindow and pullwindow.
This also fixes the bugs Johannes founds concerning bad border redraws and
empty frames.
The documentation is updated as well.

Feedback and bug reports welcome. I think it is just possible that it works
correctly this time. ;-)

I'm sending this as six patches because I think history is easier to
understand when commits correspond to what fits in human brains. If
requested, of course, I can rebase or squash this into a single commit.


Jeff Abrahamson
+33 6 24 40 01 57
+44 7920 594 255    <-- only if I'm in the UK

http://jeff.purple.com/
http://blog.purple.com/jeff/

On 7 September 2014 22:43, Jeff Abrahamson <[email protected]> wrote:

> Indeed, I think the idea is that I should call give_window_focus(). This
> handles other things that we are unlikely to test in such modern times but
> that we should strive not to break, like what happens in 8-bit color. ;-)
>
>
> Jeff Abrahamson
> +33 6 24 40 01 57
> +44 7920 594 255    <-- only if I'm in the UK
>
> http://jeff.purple.com/
> http://blog.purple.com/jeff/
>
>
> On 7 September 2014 22:40, Jeff Abrahamson <[email protected]> wrote:
>
>> Ah, I think I need to call XSetWindowBorder() myself...
>> Thanks!
>>
>>
>> Jeff Abrahamson
>> +33 6 24 40 01 57
>> +44 7920 594 255    <-- only if I'm in the UK
>>
>> http://jeff.purple.com/
>> http://blog.purple.com/jeff/
>>
>>
>> On 7 September 2014 21:59, Johannes Altmanninger <[email protected]
>> > wrote:
>>
>>>
>>> Hi, Jeff
>>>
>>> I just found another issue with the pushwindow command:
>>> When using window border colors, after a successful pushwindow, both
>>> frames have the color of an active frame. Nothing too serious but I
>>> couldn't figure out how to fix this yet.
>>>
>>> Johannes
>>>
>>
>>
>

_______________________________________________
Ratpoison-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/ratpoison-devel
0001-Add-command-pushwindow.patch (text/x-patch, 2.8 KB)
From 708eeae7807a3a7ce84df967c890ec4636b0d77f Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Sat, 6 Sep 2014 21:49:11 +0200
Subject: [PATCH 1/6] Add command pushwindow.

Add command to push the current window to another frame.
The current window moves to the selected frame.
The current frame gets assigned a new window.
The focus stays on the current frame (and so changes to the new window
now displayed in the current frame).
---
 src/actions.c | 30 ++++++++++++++++++++++++++++++
 src/actions.h |  1 +
 2 files changed, 31 insertions(+)

diff --git a/src/actions.c b/src/actions.c
index 7579101..7ce76c1 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -295,6 +295,8 @@ init_user_commands(void)
                "Hook: ", arg_HOOK);
   add_command ("meta",          cmd_meta,       1, 0, 0,
                "key: ", arg_KEY);
+  add_command("pushwindow",    cmd_pushwindow, 1, 1, 1,
+              "Push current window to frame: ", arg_FRAME);
   add_command ("msgwait",       cmd_msgwait,    1, 0, 0,
                "", arg_NUMBER);
   add_command ("newkmap",       cmd_newkmap,    1, 1, 1,
@@ -754,6 +756,7 @@ initialize_default_keybindings (void)
   add_keybinding (XK_colon, 0, "colon", map);
   add_keybinding (XK_exclam, 0, "exec", map);
   add_keybinding (XK_exclam, RP_CONTROL_MASK, "colon exec " TERM_PROG " -e ", map);
+  add_keybinding (XK_h, 0, "pushwindow", map);
   add_keybinding (XK_i, 0, "info", map);
   add_keybinding (XK_i, RP_CONTROL_MASK, "info", map);
   add_keybinding (XK_k, 0, "delete", map);
@@ -3684,6 +3687,33 @@ set_maxsizegravity (struct cmdarg **args)
 }
 
 cmdret *
+cmd_pushwindow (int interactive UNUSED, struct cmdarg **args)
+{
+  rp_frame *src_frame = current_frame();
+  rp_frame *dest_frame = ARG(0, frame);
+
+  rp_window *window_to_move = find_window_number(src_frame->win_number);
+  rp_window *window_to_reveal = find_window_for_frame (src_frame);
+  rp_window *window_to_cover = set_frames_window(dest_frame, window_to_move);
+  maximize (window_to_move);
+  unhide_window (window_to_move);
+  XRaiseWindow (dpy, window_to_move->w);
+
+  hide_window(window_to_cover);
+
+  set_frames_window(src_frame, window_to_reveal);
+  maximize (window_to_reveal);
+  unhide_window (window_to_reveal);
+  XRaiseWindow (dpy, window_to_reveal->w);
+
+  set_active_frame(src_frame, 0);
+
+  // Note that I haven't pushed anything to the undo stack yet.
+
+  return cmdret_new (RET_SUCCESS, NULL);
+}
+
+cmdret *
 cmd_msgwait (int interactive UNUSED, struct cmdarg **args)
 {
   if (args[0] == NULL)
diff --git a/src/actions.h b/src/actions.h
index 519c1a7..47564ec 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -165,6 +165,7 @@ RP_CMD (other);
 RP_CMD (prev);
 RP_CMD (prev_frame);
 RP_CMD (prevscreen);
+RP_CMD (pushwindow);
 RP_CMD (quit);
 RP_CMD (redisplay);
 RP_CMD (remhook);
-- 
1.9.1
0002-Add-pushwindow-to-the-man-page.patch (text/x-patch, 872 B)
From 345e3a64a25b4f4becbd4c90ed636e49b18150e3 Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Sat, 6 Sep 2014 22:11:16 +0200
Subject: [PATCH 2/6] Add pushwindow to the man page.

---
 doc/ratpoison.mdoc.1 | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/ratpoison.mdoc.1 b/doc/ratpoison.mdoc.1
index 2e3c356..c48f6ac 100644
--- a/doc/ratpoison.mdoc.1
+++ b/doc/ratpoison.mdoc.1
@@ -569,6 +569,10 @@ maximize this one to the size of the whole screen.
 .It Ic other Pq Ic C\-t C\-t
 Switch to the window of the current group that was last
 accessed but is not currently visible.
+.It Ic pushwindow Ar dest-frame Pq Ic C\-t h
+Move the current window to
+.Ar dest\-frame
+(or ask interactively if there is no argument)
 .It Ic prev Pq Ic C\-t p
 Switch to the previous window in the current group.
 .It Ic prevscreen Pq Ic C\-t P
-- 
1.9.1
0003-Add-documentation-for-command-pushwindow.patch (text/x-patch, 896 B)
From 083a9a7c6c9cd59212acd3857dc0ef28e3545905 Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Sun, 7 Sep 2014 19:53:57 +0200
Subject: [PATCH 3/6] Add documentation for command pushwindow.

---
 doc/ratpoison.texi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/ratpoison.texi b/doc/ratpoison.texi
index d12501f..9af7509 100644
--- a/doc/ratpoison.texi
+++ b/doc/ratpoison.texi
@@ -270,6 +270,12 @@ This toggles between the current window and the last window. By
 default, this is bound to @kbd{C-t C-t}.
 @end deffn
 
+@deffn Command pushwindow
+Move the current window to a different frame, leaving the focus
+on the current frame. Prompts for the destination frame.
+By default, this is bound to @kbd{C-t h}.
+@end deffn
+
 @deffn Command prev
 This jumps you to the previous window in the window list. By default,
 this is bound to @kbd{C-t p}.
-- 
1.9.1
0004-Add-command-pullwindow.patch (text/x-patch, 5.1 KB)
From 07d5d72b9d16fa2e1c23b9b71f3bae961505bdc3 Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Mon, 15 Sep 2014 20:20:00 +0200
Subject: [PATCH 4/6] Add command pullwindow.

Refactor pullwindow and pushwindow to share code.
Document some concerns to address before merging into trunk.
---
 src/actions.c | 35 ++++++++++++++++-------------------
 src/actions.h |  1 +
 src/window.c  | 29 +++++++++++++++++++++++++++++
 src/window.h  |  1 +
 4 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/src/actions.c b/src/actions.c
index 7ce76c1..668d7c6 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -295,6 +295,8 @@ init_user_commands(void)
                "Hook: ", arg_HOOK);
   add_command ("meta",          cmd_meta,       1, 0, 0,
                "key: ", arg_KEY);
+  add_command("pullwindow",    cmd_pullwindow, 1, 1, 1,
+              "Pull window to current frame: ", arg_FRAME);
   add_command("pushwindow",    cmd_pushwindow, 1, 1, 1,
               "Push current window to frame: ", arg_FRAME);
   add_command ("msgwait",       cmd_msgwait,    1, 0, 0,
@@ -761,7 +763,7 @@ initialize_default_keybindings (void)
   add_keybinding (XK_i, RP_CONTROL_MASK, "info", map);
   add_keybinding (XK_k, 0, "delete", map);
   add_keybinding (XK_k, RP_CONTROL_MASK, "delete", map);
-  add_keybinding (XK_l, 0, "redisplay", map);
+  add_keybinding (XK_l, 0, "pushwindow", map);
   add_keybinding (XK_l, RP_CONTROL_MASK, "redisplay", map);
   add_keybinding (XK_m, 0, "lastmsg", map);
   add_keybinding (XK_m, RP_CONTROL_MASK, "lastmsg", map);
@@ -3687,29 +3689,24 @@ set_maxsizegravity (struct cmdarg **args)
 }
 
 cmdret *
+cmd_pullwindow (int interactive UNUSED, struct cmdarg **args)
+{
+  rp_frame *src_frame = ARG(0, frame);
+  rp_frame *dest_frame = current_frame();
+  if (move_window_between_frames(src_frame, dest_frame))
+    return cmdret_new (RET_FAILURE, "no window to pull");
+  set_active_frame(dest_frame, 0);
+  return cmdret_new (RET_SUCCESS, NULL);
+}
+
+cmdret *
 cmd_pushwindow (int interactive UNUSED, struct cmdarg **args)
 {
   rp_frame *src_frame = current_frame();
   rp_frame *dest_frame = ARG(0, frame);
-
-  rp_window *window_to_move = find_window_number(src_frame->win_number);
-  rp_window *window_to_reveal = find_window_for_frame (src_frame);
-  rp_window *window_to_cover = set_frames_window(dest_frame, window_to_move);
-  maximize (window_to_move);
-  unhide_window (window_to_move);
-  XRaiseWindow (dpy, window_to_move->w);
-
-  hide_window(window_to_cover);
-
-  set_frames_window(src_frame, window_to_reveal);
-  maximize (window_to_reveal);
-  unhide_window (window_to_reveal);
-  XRaiseWindow (dpy, window_to_reveal->w);
-
+  if (move_window_between_frames(src_frame, dest_frame))
+    return cmdret_new (RET_FAILURE, "no window to push");
   set_active_frame(src_frame, 0);
-
-  // Note that I haven't pushed anything to the undo stack yet.
-
   return cmdret_new (RET_SUCCESS, NULL);
 }
 
diff --git a/src/actions.h b/src/actions.h
index 47564ec..43e792e 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -165,6 +165,7 @@ RP_CMD (other);
 RP_CMD (prev);
 RP_CMD (prev_frame);
 RP_CMD (prevscreen);
+RP_CMD (pullwindow);
 RP_CMD (pushwindow);
 RP_CMD (quit);
 RP_CMD (redisplay);
diff --git a/src/window.c b/src/window.c
index de9032a..74be244 100644
--- a/src/window.c
+++ b/src/window.c
@@ -105,6 +105,35 @@ window_name (rp_window *win)
   return NULL;
 }
 
+int move_window_between_frames(rp_frame *src_frame, rp_frame *dest_frame)
+{
+  rp_window *window_to_move = find_window_number(src_frame->win_number);
+  if (!window_to_move)
+    return -1;
+  rp_window *window_to_reveal = find_window_for_frame (src_frame);
+  rp_window *window_to_cover = set_frames_window(dest_frame, window_to_move);
+  maximize (window_to_move);
+  unhide_window (window_to_move);
+  XRaiseWindow (dpy, window_to_move->w);
+
+  hide_window(window_to_cover);
+
+  if (!window_to_reveal)
+    window_to_reveal = window_to_cover;
+  if (window_to_reveal) {
+    // It could happen that we are moving a window with no window to
+    // replace it. In that case, just leave the frame empty.
+    set_frames_window(src_frame, window_to_reveal);
+    maximize (window_to_reveal);
+    unhide_window (window_to_reveal);
+    XRaiseWindow (dpy, window_to_reveal->w);
+  }
+  // TODO(jma): What if a window is transient?
+  // TODO(jma): What if we are covering a transient window?
+  // TODO(jma): What manages active and inactive frame coloring?  Probably give_window_focus().
+  return 0;
+}
+
 /* FIXME: we need to verify that the window is running on the same
    host as something. otherwise there could be overlapping PIDs. */
 struct rp_child_info *
diff --git a/src/window.h b/src/window.h
index fdd246c..f32a2e8 100644
--- a/src/window.h
+++ b/src/window.h
@@ -36,6 +36,7 @@ void goto_window (rp_window *win);
 void set_current_window (rp_window *win);
 void update_window_gravity (rp_window *win);
 char *window_name (rp_window *win);
+int move_window_between_frames(rp_frame *src_frame, rp_frame *dest_frame);
 
 /* int goto_window_name (char *name); */
 rp_window *find_window_other (rp_screen *screen);
-- 
1.9.1
0005-Documentation-for-pullwindow.patch (text/x-patch, 1.5 KB)
From 5364d1df4229d7441b0caa6a18e31f79f3b98dee Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Mon, 15 Sep 2014 20:26:36 +0200
Subject: [PATCH 5/6] Documentation for pullwindow.

---
 doc/ratpoison.mdoc.1 | 4 ++++
 doc/ratpoison.texi   | 6 ++++++
 2 files changed, 10 insertions(+)

diff --git a/doc/ratpoison.mdoc.1 b/doc/ratpoison.mdoc.1
index c48f6ac..cb46901 100644
--- a/doc/ratpoison.mdoc.1
+++ b/doc/ratpoison.mdoc.1
@@ -569,6 +569,10 @@ maximize this one to the size of the whole screen.
 .It Ic other Pq Ic C\-t C\-t
 Switch to the window of the current group that was last
 accessed but is not currently visible.
+.It Ic pullwindow Ar src-frame Pq Ic C\-t l
+Move the window in 
+.Ar src\-frame
+to the current frame (or ask interactively if there is no argument)
 .It Ic pushwindow Ar dest-frame Pq Ic C\-t h
 Move the current window to
 .Ar dest\-frame
diff --git a/doc/ratpoison.texi b/doc/ratpoison.texi
index 9af7509..e6d1123 100644
--- a/doc/ratpoison.texi
+++ b/doc/ratpoison.texi
@@ -270,6 +270,12 @@ This toggles between the current window and the last window. By
 default, this is bound to @kbd{C-t C-t}.
 @end deffn
 
+@deffn Command pullwindow
+Move the a window from another frame to the current frame, leaving
+the focus on the current frame. Prompts for the source frame.
+By default, this is bound to @kbd{C-t l}.
+@end deffn
+
 @deffn Command pushwindow
 Move the current window to a different frame, leaving the focus
 on the current frame. Prompts for the destination frame.
-- 
1.9.1
0006-Fix-behavior-when-push-pull-window-leaves-an-empty-f.patch (text/x-patch, 2.8 KB)
From da989d31f9c3a370769eee4599b71b8c4dbb9fa6 Mon Sep 17 00:00:00 2001
From: Jeff Abrahamson <[email protected]>
Date: Tue, 16 Sep 2014 20:52:22 +0200
Subject: [PATCH 6/6] Fix behavior when push/pull window leaves an empty frame.

Fix frame color bug.
Fix pullwindow keybinding error.
Remove TODO about transient windows, we already did this right.
---
 src/actions.c |  2 +-
 src/window.c  | 21 +++++++++++----------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/actions.c b/src/actions.c
index 668d7c6..4f4dfd6 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -763,7 +763,7 @@ initialize_default_keybindings (void)
   add_keybinding (XK_i, RP_CONTROL_MASK, "info", map);
   add_keybinding (XK_k, 0, "delete", map);
   add_keybinding (XK_k, RP_CONTROL_MASK, "delete", map);
-  add_keybinding (XK_l, 0, "pushwindow", map);
+  add_keybinding (XK_l, 0, "pullwindow", map);
   add_keybinding (XK_l, RP_CONTROL_MASK, "redisplay", map);
   add_keybinding (XK_m, 0, "lastmsg", map);
   add_keybinding (XK_m, RP_CONTROL_MASK, "lastmsg", map);
diff --git a/src/window.c b/src/window.c
index 74be244..d6789b0 100644
--- a/src/window.c
+++ b/src/window.c
@@ -107,30 +107,31 @@ window_name (rp_window *win)
 
 int move_window_between_frames(rp_frame *src_frame, rp_frame *dest_frame)
 {
+  rp_frame *active_frame = current_frame();
+  rp_window *orig_window = find_window_number(active_frame->win_number);
+
   rp_window *window_to_move = find_window_number(src_frame->win_number);
   if (!window_to_move)
     return -1;
-  rp_window *window_to_reveal = find_window_for_frame (src_frame);
+  rp_window *window_to_reveal = find_window_for_frame(src_frame);
   rp_window *window_to_cover = set_frames_window(dest_frame, window_to_move);
   maximize (window_to_move);
   unhide_window (window_to_move);
-  XRaiseWindow (dpy, window_to_move->w);
 
-  hide_window(window_to_cover);
+  if(window_to_cover)
+    hide_window(window_to_cover);
 
   if (!window_to_reveal)
     window_to_reveal = window_to_cover;
+  // It could happen that we are moving a window with no window to
+  // replace it. In that case, just leave the frame empty.
+  set_frames_window(src_frame, window_to_reveal);
   if (window_to_reveal) {
-    // It could happen that we are moving a window with no window to
-    // replace it. In that case, just leave the frame empty.
-    set_frames_window(src_frame, window_to_reveal);
     maximize (window_to_reveal);
     unhide_window (window_to_reveal);
-    XRaiseWindow (dpy, window_to_reveal->w);
   }
-  // TODO(jma): What if a window is transient?
-  // TODO(jma): What if we are covering a transient window?
-  // TODO(jma): What manages active and inactive frame coloring?  Probably give_window_focus().
+  rp_window *new_window = find_window_number(active_frame->win_number);
+  give_window_focus(new_window, orig_window);
   return 0;
 }
 
-- 
1.9.1