Merge lp:~3v1n0/unity/switcher-no-inputwin-5.0 into lp:unity/5.0

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Marco Trevisan (Treviño)
Approved revision: no longer in the source branch.
Merged at revision: 2419
Proposed branch: lp:~3v1n0/unity/switcher-no-inputwin-5.0
Merge into: lp:unity/5.0
Diff against target: 574 lines (+185/-78)
11 files modified
plugins/unityshell/src/DashView.cpp (+14/-9)
plugins/unityshell/src/HudView.cpp (+13/-0)
plugins/unityshell/src/IconRenderer.cpp (+36/-10)
plugins/unityshell/src/SwitcherController.cpp (+7/-5)
plugins/unityshell/src/SwitcherController.h (+0/-1)
plugins/unityshell/src/SwitcherModel.h (+2/-2)
plugins/unityshell/src/WindowManager.h (+4/-0)
plugins/unityshell/src/unityshell.cpp (+86/-46)
plugins/unityshell/src/unityshell.h (+5/-5)
tests/autopilot/autopilot/tests/test_dash.py (+9/-0)
tests/autopilot/autopilot/tests/test_hud.py (+9/-0)
To merge this branch: bzr merge lp:~3v1n0/unity/switcher-no-inputwin-5.0
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
Review via email: mp+160253@code.launchpad.net

Commit message

SwitcherController: use again the SwitcherView as non-input window

Otherwise it could only lead to focusing troubles.
Added utilities to manage the WindowManager default close-window keybinding and using
it in our views.

To post a comment you must log in.
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Sweet, looks good to me!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'plugins/unityshell/resources/launcher_pip_large_ltr.png'
2Binary files plugins/unityshell/resources/launcher_pip_large_ltr.png 1970-01-01 00:00:00 +0000 and plugins/unityshell/resources/launcher_pip_large_ltr.png 2013-04-23 02:51:28 +0000 differ
3=== added file 'plugins/unityshell/resources/launcher_pip_large_rtl.png'
4Binary files plugins/unityshell/resources/launcher_pip_large_rtl.png 1970-01-01 00:00:00 +0000 and plugins/unityshell/resources/launcher_pip_large_rtl.png 2013-04-23 02:51:28 +0000 differ
5=== modified file 'plugins/unityshell/src/DashView.cpp'
6--- plugins/unityshell/src/DashView.cpp 2012-06-28 08:49:20 +0000
7+++ plugins/unityshell/src/DashView.cpp 2013-04-23 02:51:28 +0000
8@@ -33,6 +33,7 @@
9 #include "DashSettings.h"
10 #include "UBusMessages.h"
11 #include "KeyboardUtil.h"
12+#include "WindowManager.h"
13
14 namespace unity
15 {
16@@ -494,7 +495,7 @@
17 });
18
19 // global search done is handled by the home lens, no need to connect to it
20- // BUT, we will special case global search finished coming from
21+ // BUT, we will special case global search finished coming from
22 // the applications lens, because we want to be able to launch applications
23 // immediately without waiting for the search finished signal which will
24 // be delayed by all the lenses we're searching
25@@ -808,6 +809,10 @@
26 unsigned long x11_key_code,
27 unsigned long special_keys_state)
28 {
29+ // Only care about states of Alt, Ctrl, Super, Shift, not the lock keys
30+ special_keys_state &= (nux::NUX_STATE_ALT | nux::NUX_STATE_CTRL |
31+ nux::NUX_STATE_SUPER | nux::NUX_STATE_SHIFT);
32+
33 // Do what nux::View does, but if the event isn't a key navigation,
34 // designate the text entry to process it.
35
36@@ -841,15 +846,15 @@
37 // Not sure if Enter should be a navigation key
38 direction = KEY_NAV_ENTER;
39 break;
40- case NUX_VK_F4:
41- // Maybe we should not do it here, but it needs to be checked where
42- // we are able to know if alt is pressed.
43- if (special_keys_state & NUX_STATE_ALT)
44- {
45- ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
46- }
47- break;
48 default:
49+ auto const& close_key = WindowManager::Default()->close_window_key();
50+
51+ if (close_key.first == special_keys_state && close_key.second == x11_key_code)
52+ {
53+ ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
54+ return nullptr;
55+ }
56+
57 direction = KEY_NAV_NONE;
58 }
59
60
61=== modified file 'plugins/unityshell/src/HudView.cpp'
62--- plugins/unityshell/src/HudView.cpp 2012-08-20 14:52:48 +0000
63+++ plugins/unityshell/src/HudView.cpp 2013-04-23 02:51:28 +0000
64@@ -29,6 +29,7 @@
65
66 #include "UBusMessages.h"
67 #include "DashStyle.h"
68+#include "WindowManager.h"
69
70 namespace unity
71 {
72@@ -563,6 +564,10 @@
73 unsigned long x11_key_code,
74 unsigned long special_keys_state)
75 {
76+ // Only care about states of Alt, Ctrl, Super, Shift, not the lock keys
77+ special_keys_state &= (nux::NUX_STATE_ALT | nux::NUX_STATE_CTRL |
78+ nux::NUX_STATE_SUPER | nux::NUX_STATE_SHIFT);
79+
80 nux::KeyNavDirection direction = nux::KEY_NAV_NONE;
81 switch (x11_key_code)
82 {
83@@ -590,6 +595,14 @@
84 direction = nux::KEY_NAV_ENTER;
85 break;
86 default:
87+ auto const& close_key = WindowManager::Default()->close_window_key();
88+
89+ if (close_key.first == special_keys_state && close_key.second == x11_key_code)
90+ {
91+ ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
92+ return nullptr;
93+ }
94+
95 direction = nux::KEY_NAV_NONE;
96 break;
97 }
98
99=== modified file 'plugins/unityshell/src/IconRenderer.cpp'
100--- plugins/unityshell/src/IconRenderer.cpp 2012-10-17 17:46:12 +0000
101+++ plugins/unityshell/src/IconRenderer.cpp 2013-04-23 02:51:28 +0000
102@@ -188,6 +188,8 @@
103 nux::BaseTexture* progress_bar_fill = 0;
104 nux::BaseTexture* pip_ltr = 0;
105 nux::BaseTexture* pip_rtl = 0;
106+nux::BaseTexture* large_pip_ltr = 0;
107+nux::BaseTexture* large_pip_rtl = 0;
108 nux::BaseTexture* arrow_ltr = 0;
109 nux::BaseTexture* arrow_rtl = 0;
110 nux::BaseTexture* arrow_empty_ltr = 0;
111@@ -871,8 +873,8 @@
112 if (running > 0)
113 {
114 int scale = 1;
115-
116 int markerX;
117+
118 if (pip_style == OUTSIDE_TILE)
119 {
120 markerX = geo.x;
121@@ -880,8 +882,7 @@
122 else
123 {
124 auto bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
125- markerX = bounds[0].x + 2;
126- scale = 2;
127+ markerX = bounds[0].x + 1;
128 }
129
130 nux::TexCoordXForm texxform;
131@@ -902,26 +903,47 @@
132
133 if (!arg.running_on_viewport)
134 {
135+ scale = (pip_style == OUTSIDE_TILE) ? 1 : 2;
136 markers[0] = markerCenter;
137 texture = local::arrow_empty_ltr;
138 }
139 else if (running == 1)
140 {
141+ scale = (pip_style == OUTSIDE_TILE) ? 1 : 2;
142 markers[0] = markerCenter;
143 texture = local::arrow_ltr;
144 }
145 else if (running == 2)
146 {
147- markers[0] = markerCenter - 2 * scale;
148- markers[1] = markerCenter + 2 * scale;
149- texture = local::pip_ltr;
150+ if (pip_style == OUTSIDE_TILE)
151+ {
152+ texture = local::pip_ltr;
153+ markers[0] = markerCenter - 2;
154+ markers[1] = markerCenter + 2;
155+ }
156+ else
157+ {
158+ texture = local::large_pip_ltr;
159+ markers[0] = markerCenter - 4;
160+ markers[1] = markerCenter + 4;
161+ }
162 }
163 else
164 {
165- markers[0] = markerCenter - 4 * scale;
166- markers[1] = markerCenter;
167- markers[2] = markerCenter + 4 * scale;
168- texture = local::pip_ltr;
169+ if (pip_style == OUTSIDE_TILE)
170+ {
171+ texture = local::pip_ltr;
172+ markers[0] = markerCenter - 4;
173+ markers[1] = markerCenter;
174+ markers[2] = markerCenter + 4;
175+ }
176+ else
177+ {
178+ texture = local::large_pip_ltr;
179+ markers[0] = markerCenter - 8;
180+ markers[1] = markerCenter;
181+ markers[2] = markerCenter + 8;
182+ }
183 }
184
185
186@@ -1218,10 +1240,12 @@
187 squircle_shine = load_texture(PKGDATADIR"/squircle_shine_54.png");
188
189 pip_ltr = load_texture(PKGDATADIR"/launcher_pip_ltr.png");
190+ large_pip_ltr = load_texture(PKGDATADIR"/launcher_pip_large_ltr.png");
191 arrow_ltr = load_texture(PKGDATADIR"/launcher_arrow_ltr.png");
192 arrow_empty_ltr = load_texture(PKGDATADIR"/launcher_arrow_outline_ltr.png");
193
194 pip_rtl = load_texture(PKGDATADIR"/launcher_pip_rtl.png");
195+ large_pip_rtl = load_texture(PKGDATADIR"/launcher_pip_large_rt.png");
196 arrow_rtl = load_texture(PKGDATADIR"/launcher_arrow_rtl.png");
197 arrow_empty_rtl = load_texture(PKGDATADIR"/launcher_arrow_outline_rtl.png");
198
199@@ -1248,6 +1272,8 @@
200 progress_bar_fill->UnReference();
201 pip_ltr->UnReference();
202 pip_rtl->UnReference();
203+ large_pip_ltr->UnReference();
204+ large_pip_rtl->UnReference();
205 arrow_ltr->UnReference();
206 arrow_rtl->UnReference();
207 arrow_empty_ltr->UnReference();
208
209=== modified file 'plugins/unityshell/src/SwitcherController.cpp'
210--- plugins/unityshell/src/SwitcherController.cpp 2012-06-25 23:18:15 +0000
211+++ plugins/unityshell/src/SwitcherController.cpp 2013-04-23 02:51:28 +0000
212@@ -40,7 +40,7 @@
213 }
214
215 Controller::Controller(unsigned int load_timeout)
216- : timeout_length(75)
217+ : timeout_length(50)
218 , detail_on_timeout(true)
219 , detail_timeout_length(500)
220 , initial_detail_timeout_length(1500)
221@@ -91,12 +91,15 @@
222 void Controller::Show(ShowMode show, SortMode sort, bool reverse,
223 std::vector<AbstractLauncherIcon::Ptr> results)
224 {
225+ if (results.empty() || visible_)
226+ return;
227+
228 if (sort == SortMode::FOCUS_ORDER)
229 {
230 std::sort(results.begin(), results.end(), CompareSwitcherItemsPriority);
231 }
232
233- model_.reset(new SwitcherModel(results));
234+ model_ = std::make_shared<SwitcherModel>(results);
235 AddChild(model_.get());
236 model_->selection_changed.connect(sigc::mem_fun(this, &Controller::OnModelSelectionChanged));
237 model_->only_detail_on_viewport = (show == ShowMode::CURRENT_VIEWPORT);
238@@ -192,7 +195,8 @@
239
240 ubus_manager_.SendMessage(UBUS_SWITCHER_START);
241
242- if (view_window_) {
243+ if (view_window_)
244+ {
245 view_window_->ShowWindow(true);
246 view_window_->PushToFront();
247 view_window_->SetOpacity(1.0f);
248@@ -218,7 +222,6 @@
249 view_window_->SetLayout(main_layout_);
250 view_window_->SetBackgroundColor(nux::Color(0x00000000));
251 view_window_->SetGeometry(workarea_);
252- view_window_->EnableInputWindow(true, "Switcher", false, false);
253 }
254 }
255
256@@ -303,7 +306,6 @@
257 view_window_->SetOpacity(0.0f);
258 view_window_->ShowWindow(false);
259 view_window_->PushToBack();
260- view_window_->EnableInputWindow(false);
261 }
262
263 if (show_timer_)
264
265=== modified file 'plugins/unityshell/src/SwitcherController.h'
266--- plugins/unityshell/src/SwitcherController.h 2012-06-25 23:18:15 +0000
267+++ plugins/unityshell/src/SwitcherController.h 2013-04-23 02:51:28 +0000
268@@ -29,7 +29,6 @@
269 #include "SwitcherView.h"
270 #include "UBusWrapper.h"
271
272-#include <boost/shared_ptr.hpp>
273 #include <sigc++/sigc++.h>
274
275 #include <Nux/Nux.h>
276
277=== modified file 'plugins/unityshell/src/SwitcherModel.h'
278--- plugins/unityshell/src/SwitcherModel.h 2012-08-15 18:26:01 +0000
279+++ plugins/unityshell/src/SwitcherModel.h 2013-04-23 02:51:28 +0000
280@@ -27,7 +27,7 @@
281
282 #include "Introspectable.h"
283
284-#include <boost/shared_ptr.hpp>
285+#include <memory>
286 #include <sigc++/sigc++.h>
287
288 namespace unity
289@@ -39,7 +39,7 @@
290 {
291
292 public:
293- typedef boost::shared_ptr<SwitcherModel> Ptr;
294+ typedef std::shared_ptr<SwitcherModel> Ptr;
295
296 typedef std::vector<launcher::AbstractLauncherIcon::Ptr> Base;
297 typedef Base::iterator iterator;
298
299=== modified file 'plugins/unityshell/src/WindowManager.h'
300--- plugins/unityshell/src/WindowManager.h 2013-03-18 21:20:01 +0000
301+++ plugins/unityshell/src/WindowManager.h 2013-04-23 02:51:28 +0000
302@@ -20,6 +20,7 @@
303 #define WINDOW_MANAGER_H
304
305 #include <Nux/Nux.h>
306+#include <NuxCore/Property.h>
307 #include <gdk/gdkx.h>
308 #include <core/core.h>
309
310@@ -110,6 +111,9 @@
311 virtual bool saveInputFocus() = 0;
312 virtual bool restoreInputFocus() = 0;
313
314+ // Nux Modifiers, Nux Keycode (= X11 KeySym)
315+ nux::Property<std::pair<unsigned, unsigned>> close_window_key;
316+
317 // Signals
318 sigc::signal<void, guint32> window_mapped;
319 sigc::signal<void, guint32> window_unmapped;
320
321=== modified file 'plugins/unityshell/src/unityshell.cpp'
322--- plugins/unityshell/src/unityshell.cpp 2013-04-04 18:37:52 +0000
323+++ plugins/unityshell/src/unityshell.cpp 2013-04-23 02:51:28 +0000
324@@ -351,12 +351,6 @@
325 ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWTICHER,
326 sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav));
327
328- ubus_manager_.RegisterInterest(UBUS_SWITCHER_START,
329- sigc::mem_fun(this, &UnityScreen::OnSwitcherStart));
330-
331- ubus_manager_.RegisterInterest(UBUS_SWITCHER_END,
332- sigc::mem_fun(this, &UnityScreen::OnSwitcherEnd));
333-
334 g_idle_add_full (G_PRIORITY_DEFAULT, &UnityScreen::initPluginActions, this, NULL);
335 super_keypressed_ = false;
336
337@@ -944,7 +938,7 @@
338 {
339 /* Create a new keybinding for the Escape key and the current modifiers,
340 * compiz will take of the ref-counting of the repeated actions */
341- KeyCode escape = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Escape"));
342+ KeyCode escape = XKeysymToKeycode(screen->dpy(), XK_Escape);
343 CompAction::KeyBinding binding(escape, modifiers);
344
345 CompActionPtr &escape_action = _escape_actions[target];
346@@ -1604,6 +1598,16 @@
347 break;
348 }
349 }
350+ else if (switcher_controller_->Visible())
351+ {
352+ auto const& close_key = PluginAdapter::Default()->close_window_key();
353+
354+ if (key_sym == close_key.second && XModifiersToNux(event->xkey.state) == close_key.first)
355+ {
356+ switcher_controller_->Hide(false);
357+ skip_other_plugins = true;
358+ }
359+ }
360
361 if (result > 0)
362 {
363@@ -1673,10 +1677,9 @@
364 }
365
366 if (!skip_other_plugins &&
367- screen->otherGrabExist("deco", "move", "switcher", "resize", NULL) &&
368- !switcher_controller_->Visible())
369+ screen->otherGrabExist("deco", "move", "switcher", "resize", "unity-switcher", nullptr))
370 {
371- wt->ProcessForeignEvent(event, NULL);
372+ wt->ProcessForeignEvent(event, nullptr);
373 }
374 }
375
376@@ -2105,41 +2108,10 @@
377
378 void UnityScreen::OnLauncherEndKeyNav(GVariant* data)
379 {
380- RestoreWindow(data);
381-}
382-
383-void UnityScreen::OnSwitcherStart(GVariant* data)
384-{
385- if (switcher_controller_->Visible())
386- {
387- newFocusedWindow = screen->findWindow(switcher_controller_->GetSwitcherInputWindowId());
388-
389- if (switcher_controller_->GetSwitcherInputWindowId() != screen->activeWindow())
390- PluginAdapter::Default()->saveInputFocus();
391-
392- if (newFocusedWindow)
393- newFocusedWindow->moveInputFocusTo();
394- }
395-}
396-
397-void UnityScreen::OnSwitcherEnd(GVariant* data)
398-{
399- RestoreWindow(data);
400-}
401-
402-void UnityScreen::RestoreWindow(GVariant* data)
403-{
404- bool preserve_focus = false;
405-
406- if (data)
407- {
408- preserve_focus = g_variant_get_boolean(data);
409- }
410-
411 // Return input-focus to previously focused window (before key-nav-mode was
412 // entered)
413- if (preserve_focus)
414- PluginAdapter::Default ()->restoreInputFocus ();
415+ if (data && g_variant_get_boolean(data))
416+ PluginAdapter::Default()->restoreInputFocus();
417 }
418
419 bool UnityScreen::ShowHud()
420@@ -2226,9 +2198,70 @@
421 return ShowHud();
422 }
423
424+unsigned UnityScreen::CompizModifiersToNux(unsigned input) const
425+{
426+ unsigned modifiers = 0;
427+
428+ if (input & CompAltMask)
429+ {
430+ input &= ~CompAltMask;
431+ input |= Mod1Mask;
432+ }
433+
434+ if (modifiers & CompSuperMask)
435+ {
436+ input &= ~CompSuperMask;
437+ input |= Mod4Mask;
438+ }
439+
440+ return XModifiersToNux(input);
441+}
442+
443+unsigned UnityScreen::XModifiersToNux(unsigned input) const
444+{
445+ unsigned modifiers = 0;
446+
447+ if (input & Mod1Mask)
448+ modifiers |= nux::KEY_MODIFIER_ALT;
449+
450+ if (input & ShiftMask)
451+ modifiers |= nux::KEY_MODIFIER_SHIFT;
452+
453+ if (input & ControlMask)
454+ modifiers |= nux::KEY_MODIFIER_CTRL;
455+
456+ if (input & Mod4Mask)
457+ modifiers |= nux::KEY_MODIFIER_SUPER;
458+
459+ return modifiers;
460+}
461+
462+void UnityScreen::UpdateCloseWindowKey(CompAction::KeyBinding const& keybind)
463+{
464+ KeySym keysym = XkbKeycodeToKeysym(screen->dpy(), keybind.keycode(), 0, 0);
465+ unsigned modifiers = CompizModifiersToNux(keybind.modifiers());
466+
467+ WindowManager::Default()->close_window_key = std::make_pair(modifiers, keysym);
468+}
469+
470 gboolean UnityScreen::initPluginActions(gpointer data)
471 {
472- CompPlugin* p = CompPlugin::find("expo");
473+ CompPlugin* p = CompPlugin::find("core");
474+ auto self = static_cast<UnityScreen*>(data);
475+
476+ if (p)
477+ {
478+ for (CompOption& option : p->vTable->getOptions())
479+ {
480+ if (option.name() == "close_window_key")
481+ {
482+ self->UpdateCloseWindowKey(option.value().action().key());
483+ break;
484+ }
485+ }
486+ }
487+
488+ p = CompPlugin::find("expo");
489
490 if (p)
491 {
492@@ -2995,9 +3028,16 @@
493 bool status = screen->setOptionForPlugin(plugin, name, v);
494 if (status)
495 {
496- if (strcmp(plugin, "core") == 0 && strcmp(name, "hsize") == 0)
497+ if (strcmp(plugin, "core") == 0)
498 {
499- launcher_controller_->UpdateNumWorkspaces(screen->vpSize().width() * screen->vpSize().height());
500+ if (strcmp(name, "hsize") == 0 || strcmp(name, "vsize") == 0)
501+ {
502+ launcher_controller_->UpdateNumWorkspaces(screen->vpSize().width() * screen->vpSize().height());
503+ }
504+ else if (strcmp(name, "close_window_key") == 0)
505+ {
506+ UpdateCloseWindowKey(v.action().key());
507+ }
508 }
509 }
510 return status;
511
512=== modified file 'plugins/unityshell/src/unityshell.h'
513--- plugins/unityshell/src/unityshell.h 2013-04-04 18:18:50 +0000
514+++ plugins/unityshell/src/unityshell.h 2013-04-23 02:51:28 +0000
515@@ -232,15 +232,15 @@
516 void OnLauncherStartKeyNav(GVariant* data);
517 void OnLauncherEndKeyNav(GVariant* data);
518
519- void OnSwitcherStart(GVariant* data);
520- void OnSwitcherEnd(GVariant* data);
521-
522- void RestoreWindow(GVariant* data);
523-
524 void InitHints();
525
526 void OnPanelStyleChanged();
527
528+ unsigned CompizModifiersToNux(unsigned input) const;
529+ unsigned XModifiersToNux(unsigned input) const;
530+
531+ void UpdateCloseWindowKey(CompAction::KeyBinding const&);
532+
533 dash::Settings dash_settings_;
534 dash::Style dash_style_;
535 panel::Style panel_style_;
536
537=== modified file 'tests/autopilot/autopilot/tests/test_dash.py'
538--- tests/autopilot/autopilot/tests/test_dash.py 2012-06-27 01:19:32 +0000
539+++ tests/autopilot/autopilot/tests/test_dash.py 2013-04-23 02:51:28 +0000
540@@ -60,6 +60,15 @@
541 self.keyboard.press_and_release("Alt+F4")
542 self.assertThat(self.dash.visible, Eventually(Equals(False)))
543
544+ def test_alt_f4_close_dash_with_capslock_on(self):
545+ """Dash must close on Alt+F4 even when the capslock is turned on."""
546+ self.keyboard.press_and_release("Caps_Lock")
547+ self.addCleanup(self.keyboard.press_and_release, "Caps_Lock")
548+
549+ self.dash.ensure_visible()
550+ self.keyboard.press_and_release("Alt+F4")
551+ self.assertThat(self.dash.visible, Eventually(Equals(False)))
552+
553 def test_dash_closes_on_spread(self):
554 """This test shows that when the spread is initiated, the dash closes."""
555 self.dash.ensure_visible()
556
557=== modified file 'tests/autopilot/autopilot/tests/test_hud.py'
558--- tests/autopilot/autopilot/tests/test_hud.py 2012-06-25 22:02:54 +0000
559+++ tests/autopilot/autopilot/tests/test_hud.py 2013-04-23 02:51:28 +0000
560@@ -266,6 +266,15 @@
561
562 self.assertThat(self.hud.visible, Eventually(Equals(False)))
563
564+ def test_alt_f4_close_hud_with_capslock_on(self):
565+ """Hud must close on Alt+F4 even when the capslock is turned on."""
566+ self.keyboard.press_and_release("Caps_Lock")
567+ self.addCleanup(self.keyboard.press_and_release, "Caps_Lock")
568+
569+ self.hud.ensure_visible()
570+ self.keyboard.press_and_release("Alt+F4")
571+ self.assertThat(self.hud.visible, Eventually(Equals(False)))
572+
573
574 class HudLauncherInteractionsTests(HudTestsBase):
575

Subscribers

People subscribed via source and target branches