Bugfix: `move <direction>` sends workspace focus
Patch status: merged
Patch by Tony Crisci
Long description:
Make sure the command `move <direction>` properly sends the workspace focus ipc event required for i3bar to be properly updated and redrawn. Make `ipc_send_workspace_focus_event publicly available from ipc.h for more flexible event sending.
To apply this patch, use:
curl http://cr.i3wm.org/patch/377/raw.patch | git am
b/include/ipc.h
| 23 |
@@ -80,3 +80,10 @@ void ipc_send_event(const char *event, uint32_t message_type, const char *payloa |
| 24 |
void ipc_shutdown(void); |
| 25 |
|
| 26 |
void dump_node(yajl_gen gen, Con *con, bool inplace_restart); |
| 27 |
+ |
| 28 |
+/** |
| 29 |
+ * For the workspace "focus" event we send, along the usual "change" field, |
| 30 |
+ * also the current and previous workspace, in "current" and "old" |
| 31 |
+ * respectively. |
| 32 |
+ */ |
| 33 |
+void ipc_send_workspace_focus_event(Con *current, Con *old); |
b/src/ipc.c
| 38 |
@@ -1022,3 +1022,37 @@ int ipc_create_socket(const char *filename) {
|
| 39 |
current_socketpath = resolved; |
| 40 |
return sockfd; |
| 41 |
} |
| 42 |
+ |
| 43 |
+/* |
| 44 |
+ * For the workspace "focus" event we send, along the usual "change" field, |
| 45 |
+ * also the current and previous workspace, in "current" and "old" |
| 46 |
+ * respectively. |
| 47 |
+ */ |
| 48 |
+void ipc_send_workspace_focus_event(Con *current, Con *old) {
|
| 49 |
+ setlocale(LC_NUMERIC, "C"); |
| 50 |
+ yajl_gen gen = ygenalloc(); |
| 51 |
+ |
| 52 |
+ y(map_open); |
| 53 |
+ |
| 54 |
+ ystr("change");
|
| 55 |
+ ystr("focus");
|
| 56 |
+ |
| 57 |
+ ystr("current");
|
| 58 |
+ dump_node(gen, current, false); |
| 59 |
+ |
| 60 |
+ ystr("old");
|
| 61 |
+ if (old == NULL) |
| 62 |
+ y(null); |
| 63 |
+ else |
| 64 |
+ dump_node(gen, old, false); |
| 65 |
+ |
| 66 |
+ y(map_close); |
| 67 |
+ |
| 68 |
+ const unsigned char *payload; |
| 69 |
+ ylength length; |
| 70 |
+ y(get_buf, &payload, &length); |
| 71 |
+ |
| 72 |
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
|
| 73 |
+ y(free); |
| 74 |
+ setlocale(LC_NUMERIC, ""); |
| 75 |
+} |
b/src/move.c
| 80 |
@@ -99,6 +99,7 @@ static void attach_to_workspace(Con *con, Con *ws, direction_t direction) {
|
| 81 |
* |
| 82 |
*/ |
| 83 |
static void move_to_output_directed(Con *con, direction_t direction) {
|
| 84 |
+ Con *old_ws = con_get_workspace(con); |
| 85 |
Con *current_output_con = con_get_output(con); |
| 86 |
Output *current_output = get_output_by_name(current_output_con->name); |
| 87 |
Output *output = get_output_next(direction, current_output, CLOSEST_OUTPUT); |
| 88 |
@@ -117,6 +118,16 @@ static void move_to_output_directed(Con *con, direction_t direction) {
|
| 89 |
} |
| 90 |
|
| 91 |
attach_to_workspace(con, ws, direction); |
| 92 |
+ |
| 93 |
+ /* fix the focus stack */ |
| 94 |
+ con_focus(con); |
| 95 |
+ |
| 96 |
+ /* force re-painting the indicators */ |
| 97 |
+ FREE(con->deco_render_params); |
| 98 |
+ |
| 99 |
+ tree_flatten(croot); |
| 100 |
+ |
| 101 |
+ ipc_send_workspace_focus_event(ws, old_ws); |
| 102 |
} |
| 103 |
|
| 104 |
/* |
| 105 |
@@ -141,7 +152,7 @@ void tree_move(int direction) {
|
| 106 |
if (con->parent->type == CT_WORKSPACE && con_num_children(con->parent) == 1) {
|
| 107 |
/* This is the only con on this workspace */ |
| 108 |
move_to_output_directed(con, direction); |
| 109 |
- goto end; |
| 110 |
+ return; |
| 111 |
} |
| 112 |
|
| 113 |
orientation_t o = (direction == D_LEFT || direction == D_RIGHT ? HORIZ : VERT); |
| 114 |
@@ -201,7 +212,7 @@ void tree_move(int direction) {
|
| 115 |
/* If we couldn't find a place to move it on this workspace, |
| 116 |
* try to move it to a workspace on a different output */ |
| 117 |
move_to_output_directed(con, direction); |
| 118 |
- goto end; |
| 119 |
+ return; |
| 120 |
} |
| 121 |
|
| 122 |
/* If there was no con with which we could swap the current one, |
b/src/workspace.c
| 127 |
@@ -11,9 +11,6 @@ |
| 128 |
* |
| 129 |
*/ |
| 130 |
#include "all.h" |
| 131 |
-#include "yajl_utils.h" |
| 132 |
- |
| 133 |
-#include <yajl/yajl_gen.h> |
| 134 |
|
| 135 |
/* Stores a copy of the name of the last used workspace for the workspace |
| 136 |
* back-and-forth switching. */ |
| 137 |
@@ -335,39 +332,6 @@ static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents |
| 138 |
FREE(con->urgency_timer); |
| 139 |
} |
| 140 |
|
| 141 |
-/* |
| 142 |
- * For the "focus" event we send, along the usual "change" field, also the |
| 143 |
- * current and previous workspace, in "current" and "old" respectively. |
| 144 |
- */ |
| 145 |
-static void ipc_send_workspace_focus_event(Con *current, Con *old) {
|
| 146 |
- setlocale(LC_NUMERIC, "C"); |
| 147 |
- yajl_gen gen = ygenalloc(); |
| 148 |
- |
| 149 |
- y(map_open); |
| 150 |
- |
| 151 |
- ystr("change");
|
| 152 |
- ystr("focus");
|
| 153 |
- |
| 154 |
- ystr("current");
|
| 155 |
- dump_node(gen, current, false); |
| 156 |
- |
| 157 |
- ystr("old");
|
| 158 |
- if (old == NULL) |
| 159 |
- y(null); |
| 160 |
- else |
| 161 |
- dump_node(gen, old, false); |
| 162 |
- |
| 163 |
- y(map_close); |
| 164 |
- |
| 165 |
- const unsigned char *payload; |
| 166 |
- ylength length; |
| 167 |
- y(get_buf, &payload, &length); |
| 168 |
- |
| 169 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
|
| 170 |
- y(free); |
| 171 |
- setlocale(LC_NUMERIC, ""); |
| 172 |
-} |
| 173 |
- |
| 174 |
static void _workspace_show(Con *workspace) {
|
| 175 |
Con *current, *old = NULL; |
| 176 |
|
b/testcases/t/517-regress-move-direction-ipc.t
| 182 |
@@ -0,0 +1,79 @@ |
| 183 |
+#!perl |
| 184 |
+# vim:ts=4:sw=4:expandtab |
| 185 |
+# |
| 186 |
+# Please read the following documents before working on tests: |
| 187 |
+# • http://build.i3wm.org/docs/testsuite.html |
| 188 |
+# (or docs/testsuite) |
| 189 |
+# |
| 190 |
+# • http://build.i3wm.org/docs/lib-i3test.html |
| 191 |
+# (alternatively: perldoc ./testcases/lib/i3test.pm) |
| 192 |
+# |
| 193 |
+# • http://build.i3wm.org/docs/ipc.html |
| 194 |
+# (or docs/ipc) |
| 195 |
+# |
| 196 |
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf |
| 197 |
+# (unless you are already familiar with Perl) |
| 198 |
+# |
| 199 |
+# Make sure the command `move <direction>` properly sends the workspace focus |
| 200 |
+# ipc event required for i3bar to be properly updated and redrawn. |
| 201 |
+# |
| 202 |
+# Bug still in: 4.6-195-g34232b8 |
| 203 |
+use i3test i3_autostart => 0; |
| 204 |
+ |
| 205 |
+my $config = <<EOT; |
| 206 |
+# i3 config file (v4) |
| 207 |
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 |
| 208 |
+ |
| 209 |
+fake-outputs 1024x768+0+0,1024x768+1024+0 |
| 210 |
+workspace ws-left output fake-0 |
| 211 |
+workspace ws-right output fake-1 |
| 212 |
+EOT |
| 213 |
+ |
| 214 |
+my $pid = launch_with_config($config); |
| 215 |
+ |
| 216 |
+my $i3 = i3(get_socket_path()); |
| 217 |
+$i3->connect()->recv; |
| 218 |
+ |
| 219 |
+# subscribe to the 'focus' ipc event |
| 220 |
+my $focus = AnyEvent->condvar; |
| 221 |
+$i3->subscribe({
|
| 222 |
+ workspace => sub {
|
| 223 |
+ my ($event) = @_; |
| 224 |
+ if ($event->{change} eq 'focus') {
|
| 225 |
+ $focus->send($event); |
| 226 |
+ } |
| 227 |
+ } |
| 228 |
+})->recv; |
| 229 |
+ |
| 230 |
+# give up after 0.5 seconds |
| 231 |
+my $timer = AnyEvent->timer( |
| 232 |
+ after => 0.5, |
| 233 |
+ cb => sub {
|
| 234 |
+ $focus->send(0); |
| 235 |
+ } |
| 236 |
+); |
| 237 |
+ |
| 238 |
+# open two windows on the left output |
| 239 |
+cmd 'workspace ws-left'; |
| 240 |
+open_window; |
| 241 |
+open_window; |
| 242 |
+ |
| 243 |
+# move a window over to the right output |
| 244 |
+cmd 'move right'; |
| 245 |
+my $event = $focus->recv; |
| 246 |
+ |
| 247 |
+ok($event, 'moving from workspace with two windows triggered focus ipc event'); |
| 248 |
+is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace');
|
| 249 |
+is(@{$event->{current}->{nodes}}, 1, 'focus event gave the right number of windows on the workspace');
|
| 250 |
+ |
| 251 |
+# reset and try again |
| 252 |
+$focus = AnyEvent->condvar; |
| 253 |
+cmd 'workspace ws-left; move right'; |
| 254 |
+$event = $focus->recv; |
| 255 |
+ok($event, 'moving from workspace with one window triggered focus ipc event'); |
| 256 |
+is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace');
|
| 257 |
+is(@{$event->{current}->{nodes}}, 2, 'focus event gave the right number of windows on the workspace');
|
| 258 |
+ |
| 259 |
+exit_gracefully($pid); |
| 260 |
+ |
| 261 |
+done_testing; |