Merge pull request #3214 from stapelberg/sync
unflake t/525-i3bar-mouse-bindings.t
This commit is contained in:
commit
8a805cdd5c
|
@ -100,11 +100,12 @@ use constant TYPE_GET_VERSION => 7;
|
||||||
use constant TYPE_GET_BINDING_MODES => 8;
|
use constant TYPE_GET_BINDING_MODES => 8;
|
||||||
use constant TYPE_GET_CONFIG => 9;
|
use constant TYPE_GET_CONFIG => 9;
|
||||||
use constant TYPE_SEND_TICK => 10;
|
use constant TYPE_SEND_TICK => 10;
|
||||||
|
use constant TYPE_SYNC => 11;
|
||||||
|
|
||||||
our %EXPORT_TAGS = ( 'all' => [
|
our %EXPORT_TAGS = ( 'all' => [
|
||||||
qw(i3 TYPE_RUN_COMMAND TYPE_COMMAND TYPE_GET_WORKSPACES TYPE_SUBSCRIBE TYPE_GET_OUTPUTS
|
qw(i3 TYPE_RUN_COMMAND TYPE_COMMAND TYPE_GET_WORKSPACES TYPE_SUBSCRIBE TYPE_GET_OUTPUTS
|
||||||
TYPE_GET_TREE TYPE_GET_MARKS TYPE_GET_BAR_CONFIG TYPE_GET_VERSION
|
TYPE_GET_TREE TYPE_GET_MARKS TYPE_GET_BAR_CONFIG TYPE_GET_VERSION
|
||||||
TYPE_GET_BINDING_MODES TYPE_GET_CONFIG TYPE_SEND_TICK)
|
TYPE_GET_BINDING_MODES TYPE_GET_CONFIG TYPE_SEND_TICK TYPE_SYNC)
|
||||||
] );
|
] );
|
||||||
|
|
||||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
||||||
|
@ -534,6 +535,19 @@ sub send_tick {
|
||||||
$self->message(TYPE_SEND_TICK, $payload);
|
$self->message(TYPE_SEND_TICK, $payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head2 sync
|
||||||
|
|
||||||
|
Sends an i3 sync event. Requires i3 >= 4.16
|
||||||
|
|
||||||
|
=cut
|
||||||
|
sub sync {
|
||||||
|
my ($self, $payload) = @_;
|
||||||
|
|
||||||
|
$self->_ensure_connection;
|
||||||
|
|
||||||
|
$self->message(TYPE_SYNC, $payload);
|
||||||
|
}
|
||||||
|
|
||||||
=head2 command($content)
|
=head2 command($content)
|
||||||
|
|
||||||
Makes i3 execute the given command
|
Makes i3 execute the given command
|
||||||
|
|
|
@ -562,6 +562,7 @@ i3_SOURCES = \
|
||||||
src/sd-daemon.c \
|
src/sd-daemon.c \
|
||||||
src/sighandler.c \
|
src/sighandler.c \
|
||||||
src/startup.c \
|
src/startup.c \
|
||||||
|
src/sync.c \
|
||||||
src/tree.c \
|
src/tree.c \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
src/version.c \
|
src/version.c \
|
||||||
|
|
13
docs/ipc
13
docs/ipc
|
@ -65,6 +65,7 @@ to do that).
|
||||||
| 8 | +GET_BINDING_MODES+ | <<_binding_modes_reply,BINDING_MODES>> | Gets the names of all currently configured binding modes.
|
| 8 | +GET_BINDING_MODES+ | <<_binding_modes_reply,BINDING_MODES>> | Gets the names of all currently configured binding modes.
|
||||||
| 9 | +GET_CONFIG+ | <<_config_reply,CONFIG>> | Returns the last loaded i3 config.
|
| 9 | +GET_CONFIG+ | <<_config_reply,CONFIG>> | Returns the last loaded i3 config.
|
||||||
| 10 | +SEND_TICK+ | <<_tick_reply,TICK>> | Sends a tick event with the specified payload.
|
| 10 | +SEND_TICK+ | <<_tick_reply,TICK>> | Sends a tick event with the specified payload.
|
||||||
|
| 11 | +SYNC+ | <<_sync_reply,SYNC>> | Sends an i3 sync event with the specified random value to the specified window.
|
||||||
|======================================================
|
|======================================================
|
||||||
|
|
||||||
So, a typical message could look like this:
|
So, a typical message could look like this:
|
||||||
|
@ -654,6 +655,18 @@ events generated prior to the +SEND_TICK+ message (happened-before relation).
|
||||||
{ "success": true }
|
{ "success": true }
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
[[_sync_reply]]
|
||||||
|
=== SYNC reply
|
||||||
|
|
||||||
|
The reply is a map containing the "success" member. After the reply was
|
||||||
|
received, the https://i3wm.org/docs/testsuite.html#i3_sync[i3 sync message] was
|
||||||
|
responded to.
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
-------------------
|
||||||
|
{ "success": true }
|
||||||
|
-------------------
|
||||||
|
|
||||||
== Events
|
== Events
|
||||||
|
|
||||||
[[events]]
|
[[events]]
|
||||||
|
|
|
@ -114,13 +114,18 @@ void got_bar_config(char *reply) {
|
||||||
|
|
||||||
/* Data structure to easily call the reply handlers later */
|
/* Data structure to easily call the reply handlers later */
|
||||||
handler_t reply_handlers[] = {
|
handler_t reply_handlers[] = {
|
||||||
&got_command_reply,
|
&got_command_reply, /* I3_IPC_REPLY_TYPE_COMMAND */
|
||||||
&got_workspace_reply,
|
&got_workspace_reply, /* I3_IPC_REPLY_TYPE_WORKSPACES */
|
||||||
&got_subscribe_reply,
|
&got_subscribe_reply, /* I3_IPC_REPLY_TYPE_SUBSCRIBE */
|
||||||
&got_output_reply,
|
&got_output_reply, /* I3_IPC_REPLY_TYPE_OUTPUTS */
|
||||||
NULL,
|
NULL, /* I3_IPC_REPLY_TYPE_TREE */
|
||||||
NULL,
|
NULL, /* I3_IPC_REPLY_TYPE_MARKS */
|
||||||
&got_bar_config,
|
&got_bar_config, /* I3_IPC_REPLY_TYPE_BAR_CONFIG */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_VERSION */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_BINDING_MODES */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_CONFIG */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_TICK */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_SYNC */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -694,21 +694,12 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
if (event->type == atoms[I3_SYNC]) {
|
if (event->type == atoms[I3_SYNC]) {
|
||||||
xcb_window_t window = event->data.data32[0];
|
xcb_window_t window = event->data.data32[0];
|
||||||
uint32_t rnd = event->data.data32[1];
|
uint32_t rnd = event->data.data32[1];
|
||||||
DLOG("[i3 sync protocol] Forwarding random value %d, X11 window 0x%08x to i3\n", rnd, window);
|
/* Forward the request to i3 via the IPC interface so that all pending
|
||||||
|
* IPC messages are guaranteed to be handled. */
|
||||||
void *reply = scalloc(32, 1);
|
char *payload = NULL;
|
||||||
xcb_client_message_event_t *ev = reply;
|
sasprintf(&payload, "{\"rnd\":%d, \"window\":%d}", rnd, window);
|
||||||
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_SYNC, payload);
|
||||||
ev->response_type = XCB_CLIENT_MESSAGE;
|
free(payload);
|
||||||
ev->window = window;
|
|
||||||
ev->type = atoms[I3_SYNC];
|
|
||||||
ev->format = 32;
|
|
||||||
ev->data.data32[0] = window;
|
|
||||||
ev->data.data32[1] = rnd;
|
|
||||||
|
|
||||||
xcb_send_event(conn, false, xcb_root, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)ev);
|
|
||||||
xcb_flush(conn);
|
|
||||||
free(reply);
|
|
||||||
} else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
|
} else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
|
||||||
event->format == 32) {
|
event->format == 32) {
|
||||||
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
||||||
|
|
|
@ -82,4 +82,5 @@
|
||||||
#include "fake_outputs.h"
|
#include "fake_outputs.h"
|
||||||
#include "display_version.h"
|
#include "display_version.h"
|
||||||
#include "restore_layout.h"
|
#include "restore_layout.h"
|
||||||
|
#include "sync.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -63,6 +63,9 @@ typedef struct i3_ipc_header {
|
||||||
/** Send a tick event to all subscribers. */
|
/** Send a tick event to all subscribers. */
|
||||||
#define I3_IPC_MESSAGE_TYPE_SEND_TICK 10
|
#define I3_IPC_MESSAGE_TYPE_SEND_TICK 10
|
||||||
|
|
||||||
|
/** Trigger an i3 sync protocol message via IPC. */
|
||||||
|
#define I3_IPC_MESSAGE_TYPE_SYNC 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messages from i3 to clients
|
* Messages from i3 to clients
|
||||||
*
|
*
|
||||||
|
@ -78,6 +81,7 @@ typedef struct i3_ipc_header {
|
||||||
#define I3_IPC_REPLY_TYPE_BINDING_MODES 8
|
#define I3_IPC_REPLY_TYPE_BINDING_MODES 8
|
||||||
#define I3_IPC_REPLY_TYPE_CONFIG 9
|
#define I3_IPC_REPLY_TYPE_CONFIG 9
|
||||||
#define I3_IPC_REPLY_TYPE_TICK 10
|
#define I3_IPC_REPLY_TYPE_TICK 10
|
||||||
|
#define I3_IPC_REPLY_TYPE_SYNC 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Events from i3 to clients. Events have the first bit set high.
|
* Events from i3 to clients. Events have the first bit set high.
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* vim:ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* i3 - an improved dynamic tiling window manager
|
||||||
|
* © 2009 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
|
*
|
||||||
|
* sync.c: i3 sync protocol: https://i3wm.org/docs/testsuite.html#i3_sync
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
void sync_respond(xcb_window_t window, uint32_t rnd);
|
|
@ -800,21 +800,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
} else if (event->type == A_I3_SYNC) {
|
} else if (event->type == A_I3_SYNC) {
|
||||||
xcb_window_t window = event->data.data32[0];
|
xcb_window_t window = event->data.data32[0];
|
||||||
uint32_t rnd = event->data.data32[1];
|
uint32_t rnd = event->data.data32[1];
|
||||||
DLOG("[i3 sync protocol] Sending random value %d back to X11 window 0x%08x\n", rnd, window);
|
sync_respond(window, rnd);
|
||||||
|
|
||||||
void *reply = scalloc(32, 1);
|
|
||||||
xcb_client_message_event_t *ev = reply;
|
|
||||||
|
|
||||||
ev->response_type = XCB_CLIENT_MESSAGE;
|
|
||||||
ev->window = window;
|
|
||||||
ev->type = A_I3_SYNC;
|
|
||||||
ev->format = 32;
|
|
||||||
ev->data.data32[0] = window;
|
|
||||||
ev->data.data32[1] = rnd;
|
|
||||||
|
|
||||||
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)ev);
|
|
||||||
xcb_flush(conn);
|
|
||||||
free(reply);
|
|
||||||
} else if (event->type == A__NET_REQUEST_FRAME_EXTENTS) {
|
} else if (event->type == A__NET_REQUEST_FRAME_EXTENTS) {
|
||||||
/*
|
/*
|
||||||
* A client can request an estimate for the frame size which the window
|
* A client can request an estimate for the frame size which the window
|
||||||
|
|
62
src/ipc.c
62
src/ipc.c
|
@ -1173,9 +1173,68 @@ IPC_HANDLER(send_tick) {
|
||||||
DLOG("Sent tick event\n");
|
DLOG("Sent tick event\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sync_state {
|
||||||
|
char *last_key;
|
||||||
|
uint32_t rnd;
|
||||||
|
xcb_window_t window;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _sync_json_key(void *extra, const unsigned char *val, size_t len) {
|
||||||
|
struct sync_state *state = extra;
|
||||||
|
FREE(state->last_key);
|
||||||
|
state->last_key = scalloc(len + 1, 1);
|
||||||
|
memcpy(state->last_key, val, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sync_json_int(void *extra, long long val) {
|
||||||
|
struct sync_state *state = extra;
|
||||||
|
if (strcasecmp(state->last_key, "rnd") == 0) {
|
||||||
|
state->rnd = val;
|
||||||
|
} else if (strcasecmp(state->last_key, "window") == 0) {
|
||||||
|
state->window = (xcb_window_t)val;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC_HANDLER(sync) {
|
||||||
|
yajl_handle p;
|
||||||
|
yajl_status stat;
|
||||||
|
|
||||||
|
/* Setup the JSON parser */
|
||||||
|
static yajl_callbacks callbacks = {
|
||||||
|
.yajl_map_key = _sync_json_key,
|
||||||
|
.yajl_integer = _sync_json_int,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sync_state state;
|
||||||
|
memset(&state, '\0', sizeof(struct sync_state));
|
||||||
|
p = yalloc(&callbacks, (void *)&state);
|
||||||
|
stat = yajl_parse(p, (const unsigned char *)message, message_size);
|
||||||
|
FREE(state.last_key);
|
||||||
|
if (stat != yajl_status_ok) {
|
||||||
|
unsigned char *err;
|
||||||
|
err = yajl_get_error(p, true, (const unsigned char *)message,
|
||||||
|
message_size);
|
||||||
|
ELOG("YAJL parse error: %s\n", err);
|
||||||
|
yajl_free_error(p, err);
|
||||||
|
|
||||||
|
const char *reply = "{\"success\":false}";
|
||||||
|
ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
|
||||||
|
yajl_free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
yajl_free(p);
|
||||||
|
|
||||||
|
DLOG("received IPC sync request (rnd = %d, window = 0x%08x)\n", state.rnd, state.window);
|
||||||
|
sync_respond(state.window, state.rnd);
|
||||||
|
const char *reply = "{\"success\":true}";
|
||||||
|
ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
|
||||||
|
}
|
||||||
|
|
||||||
/* The index of each callback function corresponds to the numeric
|
/* The index of each callback function corresponds to the numeric
|
||||||
* value of the message type (see include/i3/ipc.h) */
|
* value of the message type (see include/i3/ipc.h) */
|
||||||
handler_t handlers[11] = {
|
handler_t handlers[12] = {
|
||||||
handle_run_command,
|
handle_run_command,
|
||||||
handle_get_workspaces,
|
handle_get_workspaces,
|
||||||
handle_subscribe,
|
handle_subscribe,
|
||||||
|
@ -1187,6 +1246,7 @@ handler_t handlers[11] = {
|
||||||
handle_get_binding_modes,
|
handle_get_binding_modes,
|
||||||
handle_get_config,
|
handle_get_config,
|
||||||
handle_send_tick,
|
handle_send_tick,
|
||||||
|
handle_sync,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* vim:ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* i3 - an improved dynamic tiling window manager
|
||||||
|
* © 2009 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
|
*
|
||||||
|
* sync.c: i3 sync protocol: https://i3wm.org/docs/testsuite.html#i3_sync
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
void sync_respond(xcb_window_t window, uint32_t rnd) {
|
||||||
|
DLOG("[i3 sync protocol] Sending random value %d back to X11 window 0x%08x\n", rnd, window);
|
||||||
|
|
||||||
|
void *reply = scalloc(32, 1);
|
||||||
|
xcb_client_message_event_t *ev = reply;
|
||||||
|
|
||||||
|
ev->response_type = XCB_CLIENT_MESSAGE;
|
||||||
|
ev->window = window;
|
||||||
|
ev->type = A_I3_SYNC;
|
||||||
|
ev->format = 32;
|
||||||
|
ev->data.data32[0] = window;
|
||||||
|
ev->data.data32[1] = rnd;
|
||||||
|
|
||||||
|
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)ev);
|
||||||
|
xcb_flush(conn);
|
||||||
|
free(reply);
|
||||||
|
}
|
|
@ -100,11 +100,19 @@ sub focus_subtest {
|
||||||
is_deeply(\@focus, $want, $msg);
|
is_deeply(\@focus, $want, $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub sync {
|
||||||
|
# Ensure XTEST events were sent to i3, which grabs and hence needs to
|
||||||
|
# forward any events to i3bar:
|
||||||
|
xtest_sync_with_i3;
|
||||||
|
# Ensure any pending i3bar IPC messages were handled by i3:
|
||||||
|
xtest_sync_with($i3bar_window);
|
||||||
|
}
|
||||||
|
|
||||||
subtest 'button 1 moves focus left', \&focus_subtest,
|
subtest 'button 1 moves focus left', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(1, 3, 3);
|
xtest_button_press(1, 3, 3);
|
||||||
xtest_button_release(1, 3, 3);
|
xtest_button_release(1, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $left->{id} ],
|
[ $left->{id} ],
|
||||||
'button 1 moves focus left';
|
'button 1 moves focus left';
|
||||||
|
@ -113,7 +121,7 @@ subtest 'button 2 moves focus right', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(2, 3, 3);
|
xtest_button_press(2, 3, 3);
|
||||||
xtest_button_release(2, 3, 3);
|
xtest_button_release(2, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $right->{id} ],
|
[ $right->{id} ],
|
||||||
'button 2 moves focus right';
|
'button 2 moves focus right';
|
||||||
|
@ -122,7 +130,7 @@ subtest 'button 3 moves focus left', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(3, 3, 3);
|
xtest_button_press(3, 3, 3);
|
||||||
xtest_button_release(3, 3, 3);
|
xtest_button_release(3, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $left->{id} ],
|
[ $left->{id} ],
|
||||||
'button 3 moves focus left';
|
'button 3 moves focus left';
|
||||||
|
@ -131,7 +139,7 @@ subtest 'button 4 moves focus right', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(4, 3, 3);
|
xtest_button_press(4, 3, 3);
|
||||||
xtest_button_release(4, 3, 3);
|
xtest_button_release(4, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $right->{id} ],
|
[ $right->{id} ],
|
||||||
'button 4 moves focus right';
|
'button 4 moves focus right';
|
||||||
|
@ -140,7 +148,7 @@ subtest 'button 5 moves focus left', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(5, 3, 3);
|
xtest_button_press(5, 3, 3);
|
||||||
xtest_button_release(5, 3, 3);
|
xtest_button_release(5, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $left->{id} ],
|
[ $left->{id} ],
|
||||||
'button 5 moves focus left';
|
'button 5 moves focus left';
|
||||||
|
@ -152,7 +160,7 @@ my $old_focus = get_focused($ws);
|
||||||
subtest 'button 6 does not move focus while pressed', \&focus_subtest,
|
subtest 'button 6 does not move focus while pressed', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(6, 3, 3);
|
xtest_button_press(6, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
'button 6 does not move focus while pressed';
|
'button 6 does not move focus while pressed';
|
||||||
|
@ -161,7 +169,7 @@ is(get_focused($ws), $old_focus, 'focus unchanged');
|
||||||
subtest 'button 6 release moves focus right', \&focus_subtest,
|
subtest 'button 6 release moves focus right', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_release(6, 3, 3);
|
xtest_button_release(6, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $right->{id} ],
|
[ $right->{id} ],
|
||||||
'button 6 release moves focus right';
|
'button 6 release moves focus right';
|
||||||
|
@ -171,7 +179,7 @@ subtest 'button 6 release moves focus right', \&focus_subtest,
|
||||||
subtest 'button 7 press moves focus left', \&focus_subtest,
|
subtest 'button 7 press moves focus left', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_press(7, 3, 3);
|
xtest_button_press(7, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $left->{id} ],
|
[ $left->{id} ],
|
||||||
'button 7 press moves focus left';
|
'button 7 press moves focus left';
|
||||||
|
@ -179,7 +187,7 @@ subtest 'button 7 press moves focus left', \&focus_subtest,
|
||||||
subtest 'button 7 release moves focus right', \&focus_subtest,
|
subtest 'button 7 release moves focus right', \&focus_subtest,
|
||||||
sub {
|
sub {
|
||||||
xtest_button_release(7, 3, 3);
|
xtest_button_release(7, 3, 3);
|
||||||
xtest_sync_with($i3bar_window);
|
sync;
|
||||||
},
|
},
|
||||||
[ $right->{id} ],
|
[ $right->{id} ],
|
||||||
'button 7 release moves focus right';
|
'button 7 release moves focus right';
|
||||||
|
|
Loading…
Reference in New Issue