]> git.sur5r.net Git - i3/i3/blob - testcases/t/175-startup-notification.t
Merge pull request #1805 from lasers/next
[i3/i3] / testcases / t / 175-startup-notification.t
1 #!perl
2 # vim:ts=4:sw=4:expandtab
3 #
4 # Please read the following documents before working on tests:
5 # • http://build.i3wm.org/docs/testsuite.html
6 #   (or docs/testsuite)
7 #
8 # • http://build.i3wm.org/docs/lib-i3test.html
9 #   (alternatively: perldoc ./testcases/lib/i3test.pm)
10 #
11 # • http://build.i3wm.org/docs/ipc.html
12 #   (or docs/ipc)
13 #
14 # • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
15 #   (unless you are already familiar with Perl)
16 #
17 # Test for the startup notification protocol.
18 #
19
20 use i3test;
21 use POSIX qw(mkfifo);
22 use File::Temp qw(:POSIX);
23
24 SKIP: {
25
26     skip "X11::XCB too old (need >= 0.07)", 24 if $X11::XCB::VERSION < 0.07;
27
28 use ExtUtils::PkgConfig;
29
30 # setup dependency on libstartup-notification using pkg-config
31 my %sn_config;
32 BEGIN {
33     %sn_config = ExtUtils::PkgConfig->find('libstartup-notification-1.0');
34 }
35
36 use Inline C => Config => LIBS => $sn_config{libs}, CCFLAGS => $sn_config{cflags};
37 use Inline C => <<'END_OF_C_CODE';
38
39 #include <xcb/xcb.h>
40
41 #define SN_API_NOT_YET_FROZEN 1
42 #include <libsn/sn-common.h>
43 #include <libsn/sn-launchee.h>
44
45 static SnDisplay *sndisplay;
46 static SnLauncheeContext *ctx;
47 static xcb_connection_t *conn;
48
49 void init_ctx(void *connptr) {
50     conn = (xcb_connection_t*)connptr;
51     sndisplay = sn_xcb_display_new(conn, NULL, NULL);
52     ctx = sn_launchee_context_new_from_environment(sndisplay, 0);
53 }
54
55 const char *get_startup_id() {
56     return sn_launchee_context_get_startup_id(ctx);
57 }
58
59 void mark_window(int window) {
60     sn_launchee_context_setup_window(ctx, (Window)window);
61     xcb_flush(conn);
62 }
63
64 void complete_startup() {
65     /* mark the startup process complete */
66     sn_launchee_context_complete(ctx);
67 }
68 END_OF_C_CODE
69
70 my $first_ws = fresh_workspace;
71
72 is_num_children($first_ws, 0, 'no containers on this workspace yet');
73
74 ######################################################################
75 # 1) initiate startup, switch workspace, create window
76 # (should be placed on the original workspace)
77 ######################################################################
78
79 # Start a new process via i3 (to initialize a new startup notification
80 # context), then steal its DESKTOP_STARTUP_ID variable. We handle the startup
81 # notification in the testcase from there on.
82 #
83 # This works by setting up a FIFO in which the process (started by i3) will
84 # echo its $DESKTOP_STARTUP_ID. We (blockingly) read the variable into
85 # $startup_id in the testcase.
86 my $tmp = tmpnam();
87 mkfifo($tmp, 0600) or BAIL_OUT "Could not create FIFO in $tmp: $!";
88
89 cmd qq|exec echo \$DESKTOP_STARTUP_ID >$tmp|;
90
91 open(my $fh, '<', $tmp);
92 chomp(my $startup_id = <$fh>);
93 close($fh);
94
95 unlink($tmp);
96
97 isnt($startup_id, '', 'startup_id not empty');
98
99 $ENV{DESKTOP_STARTUP_ID} = $startup_id;
100
101 # Create a new libstartup-notification launchee context
102 init_ctx($x->get_xcb_conn());
103
104 # Make sure the context was set up successfully
105 is(get_startup_id(), $startup_id, 'libstartup-notification returns the same id');
106
107 my $second_ws = fresh_workspace;
108
109 is_num_children($second_ws, 0, 'no containers on the second workspace yet');
110
111 my $win = open_window({ dont_map => 1 });
112 mark_window($win->id);
113 $win->map;
114 # We don’t use wait_for_map because the window will not get mapped -- it is on
115 # a different workspace.
116 # We sync with i3 here to make sure $x->input_focus is updated.
117 sync_with_i3;
118
119 is_num_children($second_ws, 0, 'still no containers on the second workspace');
120 is_num_children($first_ws, 1, 'one container on the first workspace');
121
122 ######################################################################
123 # same thing, but with _NET_STARTUP_ID set on the leader
124 ######################################################################
125
126 my $leader = open_window({ dont_map => 1 });
127 mark_window($leader->id);
128
129 $win = open_window({ dont_map => 1, client_leader => $leader });
130 $win->map;
131 sync_with_i3;
132
133 is_num_children($second_ws, 0, 'still no containers on the second workspace');
134 is_num_children($first_ws, 2, 'two containers on the first workspace');
135
136 ######################################################################
137 # verifies that finishing startup doesn't immediately stop windows
138 # from being placed on the sequence's workspace, but that moving
139 # the leader actually deletes the startup sequence mapping
140 ######################################################################
141
142 complete_startup();
143 sync_with_i3;
144
145 # even when renaming the workspace, windows should end up on the correct one
146 cmd "rename workspace $first_ws to temp";
147
148 # Startup has completed but the 30-second deletion time hasn't elapsed,
149 # so this window should still go on the leader's initial workspace.
150 $win = open_window({ dont_map => 1, client_leader => $leader });
151 $win->map;
152 sync_with_i3;
153
154 cmd "rename workspace temp to $first_ws";
155
156 is_num_children($first_ws, 3, 'three containers on the first workspace');
157
158 # empty 'from' workspaces should not crash the renaming of startup sequences
159 cmd "workspace $first_ws";
160 cmd "rename workspace to temp";
161 cmd "rename workspace to $first_ws";
162
163 # Switch to the first workspace and move the focused window to the
164 # second workspace.
165 cmd "workspace $first_ws";
166 cmd "move workspace $second_ws";
167
168 is_num_children($second_ws, 1, 'one container on the second workspace');
169
170 # Create and switch to a new workspace, just to be safe.
171 my $third_ws = fresh_workspace;
172
173 # Moving the window between workspaces should have immediately
174 # removed the startup workspace mapping. New windows with that
175 # leader should be created on the current workspace.
176 $win = open_window({ dont_map => 1, client_leader => $leader });
177 $win->map;
178 sync_with_i3;
179
180 is_num_children($third_ws, 1, 'one container on the third workspace');
181
182 ######################################################################
183 # 2) open another window after the startup process is completed
184 # (should be placed on the current workspace)
185 ######################################################################
186
187 my $otherwin = open_window;
188 is_num_children($third_ws, 2, 'two containers on the third workspace');
189
190 ######################################################################
191 # 3) test that the --no-startup-id flag for exec leads to no DESKTOP_STARTUP_ID
192 # environment variable.
193 ######################################################################
194
195 mkfifo($tmp, 0600) or BAIL_OUT "Could not create FIFO in $tmp";
196
197 cmd qq|exec --no-startup-id echo \$DESKTOP_STARTUP_ID >$tmp|;
198
199 open($fh, '<', $tmp);
200 chomp($startup_id = <$fh>);
201 close($fh);
202
203 unlink($tmp);
204
205 is($startup_id, '', 'startup_id empty');
206
207 ######################################################################
208 # 4) same thing, but with double quotes in exec
209 ######################################################################
210
211 mkfifo($tmp, 0600) or BAIL_OUT "Could not create FIFO in $tmp";
212
213 cmd qq|exec --no-startup-id "echo \$DESKTOP_STARTUP_ID >$tmp"|;
214
215 open($fh, '<', $tmp);
216 chomp($startup_id = <$fh>);
217 close($fh);
218
219 unlink($tmp);
220
221 is($startup_id, '', 'startup_id empty');
222 }
223
224 done_testing;