1#!perl 2# vim:ts=4:sw=4:expandtab 3# 4# Please read the following documents before working on tests: 5# • https://build.i3wm.org/docs/testsuite.html 6# (or docs/testsuite) 7# 8# • https://build.i3wm.org/docs/lib-i3test.html 9# (alternatively: perldoc ./testcases/lib/i3test.pm) 10# 11# • https://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# Checks if the 'move [window/container] to workspace' command works correctly 18# 19use i3test; 20 21my $i3 = i3(get_socket_path()); 22 23# We move the pointer out of our way to avoid a bug where the focus will 24# be set to the window under the cursor 25sync_with_i3; 26$x->root->warp_pointer(0, 0); 27sync_with_i3; 28 29sub move_workspace_test { 30 my ($movecmd) = @_; 31 32 my $tmp = get_unused_workspace(); 33 my $tmp2 = get_unused_workspace(); 34 cmd "workspace $tmp"; 35 36 is_num_children($tmp, 0, 'no containers yet'); 37 38 my $first = open_empty_con($i3); 39 my $second = open_empty_con($i3); 40 is_num_children($tmp, 2, 'two containers on first ws'); 41 42 cmd "workspace $tmp2"; 43 is_num_children($tmp2, 0, 'no containers on second ws yet'); 44 45 cmd "workspace $tmp"; 46 47 cmd "$movecmd $tmp2"; 48 is_num_children($tmp, 1, 'one container on first ws anymore'); 49 is_num_children($tmp2, 1, 'one container on second ws'); 50 my ($nodes, $focus) = get_ws_content($tmp2); 51 52 is($focus->[0], $second, 'same container on different ws'); 53 54 ($nodes, $focus) = get_ws_content($tmp); 55 ok($nodes->[0]->{focused}, 'first container focused on first ws'); 56} 57 58move_workspace_test('move workspace'); # supported for legacy reasons 59move_workspace_test('move to workspace'); 60# Those are just synonyms and more verbose ways of saying the same thing: 61move_workspace_test('move window to workspace'); 62move_workspace_test('move container to workspace'); 63 64################################################################################ 65# Check that 'move to workspace number <number>' works to move a window to 66# named workspaces which start with <number>. 67################################################################################ 68 69cmd 'workspace 13: meh'; 70cmd 'open'; 71is_num_children('13: meh', 1, 'one container on 13: meh'); 72 73ok(!workspace_exists('13'), 'workspace 13 does not exist yet'); 74 75cmd 'workspace 12'; 76cmd 'open'; 77 78cmd 'move to workspace number 13'; 79is_num_children('13: meh', 2, 'one container on 13: meh'); 80is_num_children('12', 0, 'no container on 12 anymore'); 81 82ok(!workspace_exists('13'), 'workspace 13 does still not exist'); 83 84################################################################################ 85# Check that 'move to workspace number <number><name>' works to move a window to 86# named workspaces which start with <number>. 87################################################################################ 88 89cmd 'workspace 15: meh'; 90cmd 'open'; 91is_num_children('15: meh', 1, 'one container on 15: meh'); 92 93ok(!workspace_exists('15'), 'workspace 15 does not exist yet'); 94ok(!workspace_exists('15: duh'), 'workspace 15: duh does not exist yet'); 95 96cmd 'workspace 14'; 97cmd 'open'; 98 99cmd 'move to workspace number 15: duh'; 100is_num_children('15: meh', 2, 'two containers on 15: meh'); 101is_num_children('14', 0, 'no container on 14 anymore'); 102 103ok(!workspace_exists('15'), 'workspace 15 does still not exist'); 104ok(!workspace_exists('15: duh'), 'workspace 15 does still not exist'); 105 106################################################################### 107# check if 'move workspace next' and 'move workspace prev' work 108################################################################### 109 110# Open two containers on the first workspace, one container on the second 111# workspace. Because the workspaces are named, they will be sorted by order of 112# creation. 113my $tmp = get_unused_workspace(); 114my $tmp2 = get_unused_workspace(); 115cmd "workspace $tmp"; 116is_num_children($tmp, 0, 'no containers yet'); 117my $first = open_empty_con($i3); 118my $second = open_empty_con($i3); 119is_num_children($tmp, 2, 'two containers'); 120 121cmd "workspace $tmp2"; 122is_num_children($tmp2, 0, 'no containers yet'); 123my $third = open_empty_con($i3); 124is_num_children($tmp2, 1, 'one container on second ws'); 125 126# go back to the first workspace, move one of the containers to the next one 127cmd "workspace $tmp"; 128cmd 'move workspace next'; 129is_num_children($tmp, 1, 'one container on first ws'); 130is_num_children($tmp2, 2, 'two containers on second ws'); 131 132# go to the second workspace and move two containers to the first one 133cmd "workspace $tmp2"; 134cmd 'move workspace prev'; 135cmd 'move workspace prev'; 136is_num_children($tmp, 3, 'three containers on first ws'); 137is_num_children($tmp2, 0, 'no containers on second ws'); 138 139################################################################### 140# check if 'move workspace current' works 141################################################################### 142 143$tmp = get_unused_workspace(); 144$tmp2 = get_unused_workspace(); 145 146cmd "workspace $tmp"; 147$first = open_window(name => 'win-name'); 148is_num_children($tmp, 1, 'one container on first ws'); 149 150cmd "workspace $tmp2"; 151is_num_children($tmp2, 0, 'no containers yet'); 152 153cmd qq|[title="win-name"] move workspace $tmp2|; 154is_num_children($tmp2, 1, 'one container on second ws'); 155 156cmd qq|[title="win-name"] move workspace $tmp|; 157is_num_children($tmp2, 0, 'no containers on second ws'); 158 159################################################################### 160# check if floating cons are moved to new workspaces properly 161# (that is, if they are floating on the target ws, too) 162################################################################### 163 164$tmp = get_unused_workspace(); 165$tmp2 = get_unused_workspace(); 166cmd "workspace $tmp"; 167 168cmd "open"; 169cmd "floating toggle"; 170 171my $ws = get_ws($tmp); 172is(@{$ws->{nodes}}, 0, 'no nodes on workspace'); 173is(@{$ws->{floating_nodes}}, 1, 'one floating node on workspace'); 174 175cmd "move workspace $tmp2"; 176 177$ws = get_ws($tmp2); 178is(@{$ws->{nodes}}, 0, 'no nodes on workspace'); 179is(@{$ws->{floating_nodes}}, 1, 'one floating node on workspace'); 180 181################################################################################ 182# Check that 'move workspace number' works correctly. 183################################################################################ 184 185$tmp = get_unused_workspace(); 186cmd 'open'; 187 188cmd 'workspace 16'; 189cmd 'open'; 190is_num_children('16', 1, 'one node on ws 16'); 191 192cmd "workspace $tmp"; 193cmd 'open'; 194cmd 'move workspace number 16'; 195is_num_children('16', 2, 'two nodes on ws 16'); 196 197ok(!workspace_exists('17'), 'workspace 17 does not exist yet'); 198cmd 'open'; 199cmd 'move workspace number 17'; 200ok(workspace_exists('17'), 'workspace 17 created by moving'); 201is(@{get_ws('17')->{nodes}}, 1, 'one node on ws 16'); 202 203################################################################################ 204# The following four tests verify the various 'move workspace' commands when 205# the selection is itself a workspace. 206################################################################################ 207 208# borrowed from 122-split.t 209# recursively sums up all nodes and their children 210sub sum_nodes { 211 my ($nodes) = @_; 212 213 return 0 if !@{$nodes}; 214 215 my @children = (map { @{$_->{nodes}} } @{$nodes}, 216 map { @{$_->{'floating_nodes'}} } @{$nodes}); 217 218 return @{$nodes} + sum_nodes(\@children); 219} 220 221############################################################ 222# move workspace 'next|prev' 223############################################################ 224$tmp = get_unused_workspace(); 225$tmp2 = get_unused_workspace(); 226 227cmd "workspace $tmp"; 228cmd 'open'; 229is_num_children($tmp, 1, 'one container on first ws'); 230 231cmd "workspace $tmp2"; 232cmd 'open'; 233is_num_children($tmp2, 1, 'one container on second ws'); 234cmd 'open'; 235is_num_children($tmp2, 2, 'two containers on second ws'); 236 237cmd 'focus parent'; 238cmd 'move workspace prev'; 239 240is_num_children($tmp, 2, 'two child containers on first ws'); 241is(sum_nodes(get_ws_content($tmp)), 4, 'four total containers on first ws'); 242is_num_children($tmp2, 0, 'no containers on second ws'); 243 244############################################################ 245# move workspace current 246# This is a special case that should be a no-op. 247############################################################ 248$tmp = fresh_workspace(); 249 250cmd 'open'; 251is_num_children($tmp, 1, 'one container on first ws'); 252my $tmpcount = sum_nodes(get_ws_content($tmp)); 253 254cmd 'focus parent'; 255cmd "move workspace $tmp"; 256 257is(sum_nodes(get_ws_content($tmp)), $tmpcount, 'number of containers in first ws unchanged'); 258 259############################################################ 260# move workspace '<name>' 261############################################################ 262$tmp2 = get_unused_workspace(); 263$tmp = fresh_workspace(); 264 265cmd 'open'; 266is_num_children($tmp, 1, 'one container on first ws'); 267 268cmd "workspace $tmp2"; 269cmd 'open'; 270is_num_children($tmp2, 1, 'one container on second ws'); 271cmd 'open'; 272is_num_children($tmp2, 2, 'two containers on second ws'); 273 274cmd 'focus parent'; 275cmd "move workspace $tmp"; 276 277is_num_children($tmp, 2, 'two child containers on first ws'); 278is(sum_nodes(get_ws_content($tmp)), 4, 'four total containers on first ws'); 279is_num_children($tmp2, 0, 'no containers on second ws'); 280 281############################################################ 282# move workspace number '<number>' 283############################################################ 284cmd 'workspace 18'; 285cmd 'open'; 286is_num_children('18', 1, 'one container on ws 18'); 287 288cmd 'workspace 19'; 289cmd 'open'; 290is_num_children('19', 1, 'one container on ws 19'); 291cmd 'open'; 292is_num_children('19', 2, 'two containers on ws 19'); 293 294cmd 'focus parent'; 295cmd 'move workspace number 18'; 296 297is_num_children('18', 2, 'two child containers on ws 18'); 298is(sum_nodes(get_ws_content('18')), 4, 'four total containers on ws 18'); 299is_num_children('19', 0, 'no containers on ws 19'); 300 301################################################################### 302# move workspace '<name>' with a floating child 303################################################################### 304$tmp2 = get_unused_workspace(); 305$tmp = fresh_workspace(); 306cmd 'open'; 307cmd 'floating toggle'; 308cmd 'open'; 309cmd 'floating toggle'; 310cmd 'open'; 311 312$ws = get_ws($tmp); 313is_num_children($tmp, 1, 'one container on first workspace'); 314is(@{$ws->{floating_nodes}}, 2, 'two floating nodes on first workspace'); 315 316cmd 'focus parent'; 317cmd "move workspace $tmp2"; 318 319$ws = get_ws($tmp2); 320is_num_children($tmp2, 1, 'one container on second workspace'); 321is(@{$ws->{floating_nodes}}, 2, 'two floating nodes on second workspace'); 322 323################################################################### 324# same as the above, but with only floating children 325################################################################### 326$tmp2 = get_unused_workspace(); 327$tmp = fresh_workspace(); 328cmd 'open'; 329cmd 'floating toggle'; 330 331$ws = get_ws($tmp); 332is_num_children($tmp, 0, 'no regular nodes on first workspace'); 333is(@{$ws->{floating_nodes}}, 1, 'one floating node on first workspace'); 334 335cmd 'focus parent'; 336cmd "move workspace $tmp2"; 337 338$ws = get_ws($tmp2); 339is_num_children($tmp2, 0, 'no regular nodes on second workspace'); 340is(@{$ws->{floating_nodes}}, 1, 'one floating node on second workspace'); 341 342################################################################### 343# Test that when moving a fullscreen floating window to a workspace 344# that already has an other fullscreen container, the second 345# container gets un-fullscreened. 346# See #4124 347################################################################### 348$tmp2 = fresh_workspace; 349$second = open_window; 350cmd 'fullscreen enable'; 351$ws = get_ws($tmp2); 352is($ws->{nodes}->[0]->{fullscreen_mode}, 1, 'sanity check: fullscreen enabled'); 353 354$tmp = fresh_workspace; 355$first = open_window; 356cmd 'floating enable, fullscreen enable'; 357cmd "move workspace $tmp2"; 358 359$ws = get_ws($tmp2); 360is_num_children($tmp2, 1, 'one regular node on second workspace'); 361is_num_fullscreen($tmp2, 1, 'one fullscreen node on second workspace'); 362is(@{$ws->{floating_nodes}}, 1, 'one floating node on second workspace'); 363is($ws->{nodes}->[0]->{fullscreen_mode}, 0, 'previous fullscreen disabled'); 364 365################################################################### 366# Same as above, but trigger the bug with the parent of a 367# fullscreen container, instead of a CT_FLOATING_CON. 368################################################################### 369$tmp2 = fresh_workspace; 370$second = open_window; 371cmd 'fullscreen enable'; 372$ws = get_ws($tmp2); 373is($ws->{nodes}->[0]->{fullscreen_mode}, 1, 'sanity check: fullscreen enabled'); 374 375$tmp = fresh_workspace; 376open_window; 377$first = open_window; 378cmd 'layout tabbed'; 379cmd 'focus parent, mark a, focus child'; 380cmd 'fullscreen enable'; 381cmd "[con_mark=a] move workspace $tmp2"; 382 383$ws = get_ws($tmp2); 384is(sum_nodes(get_ws_content($tmp2)), 4, '3 leafs & 1 split node in second workspace'); 385# is_num_fullscreen does not catch this nested fullscreen container 386is($ws->{nodes}->[0]->{fullscreen_mode}, 0, 'previous fullscreen disabled'); 387is($ws->{nodes}->[1]->{nodes}->[1]->{fullscreen_mode}, 1, 'nested fullscreen from moved container preserved'); 388 389################################################################### 390# Check that moving an empty workspace using criteria doesn't 391# create unfocused empty workspace. 392################################################################### 393$tmp2 = get_unused_workspace(); 394$tmp = fresh_workspace(); 395cmd 'mark a'; 396cmd "[con_mark=a] move to workspace $tmp2"; 397 398is (get_ws($tmp2), undef, 'No empty workspace created'); 399 400done_testing; 401