1# Copyright (c) 2011 Florian Mounier 2# Copyright (c) 2012, 2014-2015 Tycho Andersen 3# Copyright (c) 2013 Mattias Svala 4# Copyright (c) 2013 Craig Barnes 5# Copyright (c) 2014 ramnes 6# Copyright (c) 2014 Sean Vig 7# Copyright (c) 2014 Adi Sieker 8# Copyright (c) 2014 Chris Wesseling 9# 10# Permission is hereby granted, free of charge, to any person obtaining a copy 11# of this software and associated documentation files (the "Software"), to deal 12# in the Software without restriction, including without limitation the rights 13# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14# copies of the Software, and to permit persons to whom the Software is 15# furnished to do so, subject to the following conditions: 16# 17# The above copyright notice and this permission notice shall be included in 18# all copies or substantial portions of the Software. 19# 20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26# SOFTWARE. 27 28import pytest 29 30import libqtile.config 31from libqtile import layout 32from libqtile.confreader import Config 33from test.layouts.layout_utils import assert_focus_path, assert_focused 34 35 36class StackConfig(Config): 37 auto_fullscreen = True 38 groups = [ 39 libqtile.config.Group("a"), 40 libqtile.config.Group("b"), 41 libqtile.config.Group("c"), 42 libqtile.config.Group("d") 43 ] 44 layouts = [ 45 layout.Stack(num_stacks=2), 46 layout.Stack(num_stacks=1), 47 ] 48 floating_layout = libqtile.resources.default_config.floating_layout 49 keys = [] 50 mouse = [] 51 screens = [] 52 follow_mouse_focus = False 53 54 55stack_config = pytest.mark.parametrize("manager", [StackConfig], indirect=True) 56 57 58def _stacks(manager): 59 stacks = [] 60 for i in manager.c.layout.info()["stacks"]: 61 windows = i["clients"] 62 current = i["current"] 63 stacks.append(windows[current:] + windows[:current]) 64 return stacks 65 66 67@stack_config 68def test_stack_commands(manager): 69 assert manager.c.layout.info()["current_stack"] == 0 70 manager.test_window("one") 71 assert _stacks(manager) == [["one"], []] 72 assert manager.c.layout.info()["current_stack"] == 0 73 manager.test_window("two") 74 assert _stacks(manager) == [["one"], ["two"]] 75 assert manager.c.layout.info()["current_stack"] == 1 76 manager.test_window("three") 77 assert _stacks(manager) == [["one"], ["three", "two"]] 78 assert manager.c.layout.info()["current_stack"] == 1 79 80 manager.c.layout.delete() 81 assert _stacks(manager) == [["one", "three", "two"]] 82 info = manager.c.groups()["a"] 83 assert info["focus"] == "one" 84 manager.c.layout.delete() 85 assert len(_stacks(manager)) == 1 86 87 manager.c.layout.add() 88 assert _stacks(manager) == [["one", "three", "two"], []] 89 90 manager.c.layout.rotate() 91 assert _stacks(manager) == [[], ["one", "three", "two"]] 92 93 94@stack_config 95def test_stack_cmd_down(manager): 96 manager.c.layout.down() 97 98 99@stack_config 100def test_stack_addremove(manager): 101 one = manager.test_window("one") 102 manager.c.layout.next() 103 two = manager.test_window("two") 104 three = manager.test_window("three") 105 assert _stacks(manager) == [['one'], ['three', 'two']] 106 assert manager.c.layout.info()["current_stack"] == 1 107 manager.kill_window(three) 108 assert manager.c.layout.info()["current_stack"] == 1 109 manager.kill_window(two) 110 assert manager.c.layout.info()["current_stack"] == 0 111 manager.c.layout.next() 112 two = manager.test_window("two") 113 manager.c.layout.next() 114 assert manager.c.layout.info()["current_stack"] == 0 115 manager.kill_window(one) 116 assert manager.c.layout.info()["current_stack"] == 1 117 118 119@stack_config 120def test_stack_rotation(manager): 121 manager.c.layout.delete() 122 manager.test_window("one") 123 manager.test_window("two") 124 manager.test_window("three") 125 assert _stacks(manager) == [["three", "two", "one"]] 126 manager.c.layout.down() 127 assert _stacks(manager) == [["two", "one", "three"]] 128 manager.c.layout.up() 129 assert _stacks(manager) == [["three", "two", "one"]] 130 manager.c.layout.down() 131 manager.c.layout.down() 132 assert _stacks(manager) == [["one", "three", "two"]] 133 134 135@stack_config 136def test_stack_nextprev(manager): 137 manager.c.layout.add() 138 one = manager.test_window("one") 139 two = manager.test_window("two") 140 three = manager.test_window("three") 141 142 assert manager.c.groups()["a"]["focus"] == "three" 143 manager.c.layout.next() 144 assert manager.c.groups()["a"]["focus"] == "one" 145 146 manager.c.layout.previous() 147 assert manager.c.groups()["a"]["focus"] == "three" 148 manager.c.layout.previous() 149 assert manager.c.groups()["a"]["focus"] == "two" 150 151 manager.c.layout.next() 152 manager.c.layout.next() 153 manager.c.layout.next() 154 assert manager.c.groups()["a"]["focus"] == "two" 155 156 manager.kill_window(three) 157 manager.c.layout.next() 158 assert manager.c.groups()["a"]["focus"] == "one" 159 manager.c.layout.previous() 160 assert manager.c.groups()["a"]["focus"] == "two" 161 manager.c.layout.next() 162 manager.kill_window(two) 163 manager.c.layout.next() 164 assert manager.c.groups()["a"]["focus"] == "one" 165 166 manager.kill_window(one) 167 manager.c.layout.next() 168 assert manager.c.groups()["a"]["focus"] is None 169 manager.c.layout.previous() 170 assert manager.c.groups()["a"]["focus"] is None 171 172 173@stack_config 174def test_stack_window_removal(manager): 175 manager.c.layout.next() 176 manager.test_window("one") 177 two = manager.test_window("two") 178 manager.c.layout.down() 179 manager.kill_window(two) 180 181 182@stack_config 183def test_stack_split(manager): 184 manager.test_window("one") 185 manager.test_window("two") 186 manager.test_window("three") 187 stacks = manager.c.layout.info()["stacks"] 188 assert not stacks[1]["split"] 189 manager.c.layout.toggle_split() 190 stacks = manager.c.layout.info()["stacks"] 191 assert stacks[1]["split"] 192 193 194@stack_config 195def test_stack_shuffle(manager): 196 manager.c.next_layout() 197 manager.test_window("one") 198 manager.test_window("two") 199 manager.test_window("three") 200 201 stack = manager.c.layout.info()["stacks"][0] 202 assert stack["clients"][stack["current"]] == "three" 203 for i in range(5): 204 manager.c.layout.shuffle_up() 205 stack = manager.c.layout.info()["stacks"][0] 206 assert stack["clients"][stack["current"]] == "three" 207 for i in range(5): 208 manager.c.layout.shuffle_down() 209 stack = manager.c.layout.info()["stacks"][0] 210 assert stack["clients"][stack["current"]] == "three" 211 212 213@stack_config 214def test_stack_client_to(manager): 215 manager.test_window("one") 216 manager.test_window("two") 217 assert manager.c.layout.info()["stacks"][0]["clients"] == ["one"] 218 manager.c.layout.client_to_previous() 219 assert manager.c.layout.info()["stacks"][0]["clients"] == ["two", "one"] 220 manager.c.layout.client_to_previous() 221 assert manager.c.layout.info()["stacks"][0]["clients"] == ["one"] 222 assert manager.c.layout.info()["stacks"][1]["clients"] == ["two"] 223 manager.c.layout.client_to_next() 224 assert manager.c.layout.info()["stacks"][0]["clients"] == ["two", "one"] 225 226 227@stack_config 228def test_stack_info(manager): 229 manager.test_window("one") 230 assert manager.c.layout.info()["stacks"] 231 232 233@stack_config 234def test_stack_window_focus_cycle(manager): 235 # setup 3 tiled and two floating clients 236 manager.test_window("one") 237 manager.test_window("two") 238 manager.test_window("float1") 239 manager.c.window.toggle_floating() 240 manager.test_window("float2") 241 manager.c.window.toggle_floating() 242 manager.test_window("three") 243 244 # test preconditions, stack adds clients at pos of current 245 assert manager.c.layout.info()['clients'] == ['three', 'one', 'two'] 246 # last added window has focus 247 assert_focused(manager, "three") 248 249 # assert window focus cycle, according to order in layout 250 assert_focus_path(manager, 'one', 'two', 'float1', 'float2', 'three') 251