tests: implement xtest_sync_with_i3

The regular sync_with_i3 is not sufficient because i3test::XTEST uses a separate
X11 connection.
This commit is contained in:
Michael Stapelberg 2017-09-30 11:27:53 +02:00
parent c08ef36199
commit 14c8cf8622
5 changed files with 124 additions and 4 deletions

View File

@ -14,6 +14,7 @@ use ExtUtils::PkgConfig;
use Exporter (); use Exporter ();
our @EXPORT = qw( our @EXPORT = qw(
inlinec_connect inlinec_connect
xtest_sync_with_i3
set_xkb_group set_xkb_group
xtest_key_press xtest_key_press
xtest_key_release xtest_key_release
@ -38,7 +39,7 @@ i3test::XTEST - Inline::C wrappers for xcb-xtest and xcb-xkb
# ineffective. # ineffective.
my %sn_config; my %sn_config;
BEGIN { BEGIN {
%sn_config = ExtUtils::PkgConfig->find('xcb-xkb xcb-xtest'); %sn_config = ExtUtils::PkgConfig->find('xcb-xkb xcb-xtest xcb-util');
} }
use Inline C => Config => LIBS => $sn_config{libs}, CCFLAGS => $sn_config{cflags}; use Inline C => Config => LIBS => $sn_config{libs}, CCFLAGS => $sn_config{cflags};
@ -53,8 +54,12 @@ use Inline C => <<'END_OF_C_CODE';
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xkb.h> #include <xcb/xkb.h>
#include <xcb/xtest.h> #include <xcb/xtest.h>
#include <xcb/xcb_aux.h>
static xcb_connection_t *conn = NULL; static xcb_connection_t *conn = NULL;
static xcb_window_t sync_window;
static xcb_window_t root_window;
static xcb_atom_t i3_sync_atom;
bool inlinec_connect() { bool inlinec_connect() {
int screen; int screen;
@ -89,9 +94,90 @@ bool inlinec_connect() {
} }
free(usereply); free(usereply);
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, xcb_intern_atom(conn, 0, strlen("I3_SYNC"), "I3_SYNC"), NULL);
i3_sync_atom = reply->atom;
free(reply);
xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screen);
root_window = root_screen->root;
sync_window = xcb_generate_id(conn);
xcb_create_window(conn,
XCB_COPY_FROM_PARENT, // depth
sync_window, // window
root_window, // parent
-15, // x
-15, // y
1, // width
1, // height
0, // border_width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
XCB_COPY_FROM_PARENT, // visual
XCB_CW_OVERRIDE_REDIRECT, // value_mask
(uint32_t[]){
1, // override_redirect
}); // value_list
return true; return true;
} }
void xtest_sync_with_i3() {
xcb_client_message_event_t ev;
memset(&ev, '\0', sizeof(xcb_client_message_event_t));
const int nonce = rand() % 255;
ev.response_type = XCB_CLIENT_MESSAGE;
ev.window = sync_window;
ev.type = i3_sync_atom;
ev.format = 32;
ev.data.data32[0] = sync_window;
ev.data.data32[1] = nonce;
xcb_send_event(conn, false, root_window, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)&ev);
xcb_flush(conn);
xcb_generic_event_t *event = NULL;
while (1) {
free(event);
if ((event = xcb_wait_for_event(conn)) == NULL) {
break;
}
if (event->response_type == 0) {
fprintf(stderr, "X11 Error received! sequence %x\n", event->sequence);
continue;
}
/* Strip off the highest bit (set if the event is generated) */
const int type = (event->response_type & 0x7F);
switch (type) {
case XCB_CLIENT_MESSAGE: {
xcb_client_message_event_t *ev = (xcb_client_message_event_t *)event;
{
const uint32_t got = ev->data.data32[0];
const uint32_t want = sync_window;
if (got != want) {
fprintf(stderr, "Ignoring ClientMessage: unknown window: got %d, want %d\n", got, want);
continue;
}
}
{
const uint32_t got = ev->data.data32[1];
const uint32_t want = nonce;
if (got != want) {
fprintf(stderr, "Ignoring ClientMessage: unknown nonce: got %d, want %d\n", got, want);
continue;
}
}
return;
}
default:
fprintf(stderr, "Unexpected X11 event of type %d received (XCB_CLIENT_MESSAGE = %d)\n", type, XCB_CLIENT_MESSAGE);
break;
}
}
free(event);
}
// NOTE: while |group| should be a uint8_t, Inline::C will not define the // NOTE: while |group| should be a uint8_t, Inline::C will not define the
// function unless we use an int. // function unless we use an int.
bool set_xkb_group(int group) { bool set_xkb_group(int group) {
@ -283,6 +369,10 @@ Sends a ButtonRelease event via XTEST, with the specified C<$button>.
Returns false when there was an X11 error, true otherwise. Returns false when there was an X11 error, true otherwise.
=head2 xtest_sync_with_i3()
Ensures i3 has processed all X11 events which were triggered by this module.
=head1 AUTHOR =head1 AUTHOR
Michael Stapelberg <michael@i3wm.org> Michael Stapelberg <michael@i3wm.org>

View File

@ -44,6 +44,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(107); xtest_key_press(107);
xtest_key_release(107); xtest_key_release(107);
xtest_sync_with_i3;
}, },
), ),
'Print', 'Print',
@ -55,6 +56,7 @@ is(listen_for_binding(
xtest_key_press(36); # Return xtest_key_press(36); # Return
xtest_key_release(36); # Return xtest_key_release(36); # Return
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_sync_with_i3;
}, },
), ),
'Mod4+Return', 'Mod4+Return',
@ -67,6 +69,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(107); xtest_key_press(107);
xtest_key_release(107); xtest_key_release(107);
xtest_sync_with_i3;
}, },
), ),
'Print', 'Print',
@ -78,6 +81,7 @@ is(listen_for_binding(
xtest_key_press(36); # Return xtest_key_press(36); # Return
xtest_key_release(36); # Return xtest_key_release(36); # Return
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_sync_with_i3;
}, },
), ),
'Mod4+Return', 'Mod4+Return',

View File

@ -43,6 +43,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(107); # Print xtest_key_press(107); # Print
xtest_key_release(107); # Print xtest_key_release(107); # Print
xtest_sync_with_i3;
}, },
), ),
'Print', 'Print',
@ -54,6 +55,7 @@ is(listen_for_binding(
xtest_key_press(107); # Print xtest_key_press(107); # Print
xtest_key_release(107); # Print xtest_key_release(107); # Print
xtest_key_release(37); # Control_L xtest_key_release(37); # Control_L
xtest_sync_with_i3;
}, },
), ),
'Control+Print', 'Control+Print',
@ -65,6 +67,7 @@ is(listen_for_binding(
xtest_key_press(56); # b xtest_key_press(56); # b
xtest_key_release(56); # b xtest_key_release(56); # b
xtest_key_release(64); # Alt_L xtest_key_release(64); # Alt_L
xtest_sync_with_i3;
}, },
), ),
'Mod1+b', 'Mod1+b',
@ -78,6 +81,7 @@ is(listen_for_binding(
xtest_key_release(56); # b xtest_key_release(56); # b
xtest_key_release(50); # Shift_L xtest_key_release(50); # Shift_L
xtest_key_release(64); # Alt_L xtest_key_release(64); # Alt_L
xtest_sync_with_i3;
}, },
), ),
'Mod1+Shift+b release', 'Mod1+Shift+b release',

View File

@ -30,7 +30,7 @@ fresh_workspace;
xtest_button_press(4, 50, 50); xtest_button_press(4, 50, 50);
xtest_button_release(4, 50, 50); xtest_button_release(4, 50, 50);
sync_with_i3; xtest_sync_with_i3;
is(focused_ws(), 'special', 'the binding was triggered'); is(focused_ws(), 'special', 'the binding was triggered');

View File

@ -57,6 +57,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(87); # KP_End xtest_key_press(87); # KP_End
xtest_key_release(87); # KP_End xtest_key_release(87); # KP_End
xtest_sync_with_i3;
}, },
), ),
'KP_End', 'KP_End',
@ -70,6 +71,7 @@ is(listen_for_binding(
xtest_key_release(87); # KP_1 xtest_key_release(87); # KP_1
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'KP_1', 'KP_1',
@ -81,6 +83,7 @@ is(listen_for_binding(
xtest_key_press(38); # a xtest_key_press(38); # a
xtest_key_release(38); # a xtest_key_release(38); # a
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_sync_with_i3;
}, },
), ),
'a', 'a',
@ -96,6 +99,7 @@ is(listen_for_binding(
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'a', 'a',
@ -105,6 +109,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(9); # Escape xtest_key_press(9); # Escape
xtest_key_release(9); # Escape xtest_key_release(9); # Escape
xtest_sync_with_i3;
}, },
), ),
'Escape', 'Escape',
@ -118,6 +123,7 @@ is(listen_for_binding(
xtest_key_release(9); # Escape xtest_key_release(9); # Escape
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'Escape', 'Escape',
@ -129,6 +135,7 @@ is(listen_for_binding(
xtest_key_press(9); # Escape xtest_key_press(9); # Escape
xtest_key_release(9); # Escape xtest_key_release(9); # Escape
xtest_key_release(50); # Shift_L xtest_key_release(50); # Shift_L
xtest_sync_with_i3;
}, },
), ),
'Shift+Escape', 'Shift+Escape',
@ -144,6 +151,7 @@ is(listen_for_binding(
xtest_key_release(50); # Shift_L xtest_key_release(50); # Shift_L
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'Shift+Escape', 'Shift+Escape',
@ -157,6 +165,7 @@ is(listen_for_binding(
xtest_key_release(24); # q xtest_key_release(24); # q
xtest_key_release(64); # Alt_L xtest_key_release(64); # Alt_L
xtest_key_release(50); # Shift_L xtest_key_release(50); # Shift_L
xtest_sync_with_i3;
}, },
), ),
'Mod1+Shift+q', 'Mod1+Shift+q',
@ -174,6 +183,7 @@ is(listen_for_binding(
xtest_key_release(50); # Shift_L xtest_key_release(50); # Shift_L
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'Mod1+Shift+q', 'Mod1+Shift+q',
@ -183,6 +193,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(39); # s xtest_key_press(39); # s
xtest_key_release(39); # s xtest_key_release(39); # s
xtest_sync_with_i3;
}, },
), ),
's', 's',
@ -196,6 +207,7 @@ is(listen_for_binding(
xtest_key_release(39); # s xtest_key_release(39); # s
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
's', 's',
@ -228,6 +240,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(133); # Super_L xtest_key_press(133); # Super_L
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_sync_with_i3;
}, },
), ),
'Super_L', 'Super_L',
@ -241,6 +254,7 @@ is(listen_for_binding(
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'Super_L', 'Super_L',
@ -252,6 +266,7 @@ is(listen_for_binding(
xtest_key_press(36); # Return xtest_key_press(36); # Return
xtest_key_release(36); # Return xtest_key_release(36); # Return
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_sync_with_i3;
}, },
), ),
'Return', 'Return',
@ -267,6 +282,7 @@ is(listen_for_binding(
xtest_key_release(133); # Super_L xtest_key_release(133); # Super_L
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'Return', 'Return',
@ -297,6 +313,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(87); # KP_End xtest_key_press(87); # KP_End
xtest_key_release(87); # KP_End xtest_key_release(87); # KP_End
xtest_sync_with_i3;
}, },
), ),
'KP_End', 'KP_End',
@ -306,6 +323,7 @@ is(listen_for_binding(
sub { sub {
xtest_key_press(88); # KP_Down xtest_key_press(88); # KP_Down
xtest_key_release(88); # KP_Down xtest_key_release(88); # KP_Down
xtest_sync_with_i3;
}, },
), ),
'KP_Down', 'KP_Down',
@ -319,6 +337,7 @@ is(listen_for_binding(
xtest_key_release(87); # KP_1 xtest_key_release(87); # KP_1
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'timeout', 'timeout',
@ -332,6 +351,7 @@ is(listen_for_binding(
xtest_key_release(88); # KP_2 xtest_key_release(88); # KP_2
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'timeout', 'timeout',
@ -369,6 +389,7 @@ is(listen_for_binding(
xtest_button_release(4, 50, 50); xtest_button_release(4, 50, 50);
xtest_key_press(77); # disable Num_Lock xtest_key_press(77); # disable Num_Lock
xtest_key_release(77); # disable Num_Lock xtest_key_release(77); # disable Num_Lock
xtest_sync_with_i3;
}, },
), ),
'button4', 'button4',
@ -378,6 +399,7 @@ is(listen_for_binding(
sub { sub {
xtest_button_press(4, 50, 50); xtest_button_press(4, 50, 50);
xtest_button_release(4, 50, 50); xtest_button_release(4, 50, 50);
xtest_sync_with_i3;
}, },
), ),
'button4', 'button4',