Merge lp:~gordallott/unity/fix-hud-lose-last-application-focus into lp:unity

Proposed by Gord Allott
Status: Merged
Approved by: Gord Allott
Approved revision: no longer in the source branch.
Merged at revision: 2063
Proposed branch: lp:~gordallott/unity/fix-hud-lose-last-application-focus
Merge into: lp:unity
Diff against target: 174 lines (+80/-9)
3 files modified
plugins/unityshell/src/HudController.cpp (+6/-3)
tests/autopilot/autopilot/emulators/bamf.py (+54/-6)
tests/autopilot/autopilot/tests/test_hud.py (+20/-0)
To merge this branch: bzr merge lp:~gordallott/unity/fix-hud-lose-last-application-focus
Reviewer Review Type Date Requested Status
Gord Allott (community) Approve
Mirco Müller (community) Approve
Review via email: mp+94345@code.launchpad.net

Description of the change

fixes issue with hud not returning focus correctly, hack was bad.

UNBLOCK

To post a comment you must log in.
Revision history for this message
Gord Allott (gordallott) wrote :

no tests

review: Needs Fixing
Revision history for this message
Gord Allott (gordallott) wrote :

now has ap test

review: Approve
Revision history for this message
Mirco Müller (macslow) wrote :

I cannot replicate the test-case Seb described in the bug-entry.

Running...

  unity/tools/autopilot run autopilot.tests.HudTests.test_restore_focus

... aborts with:
------------------------------------------------------------------

  Tests running...
  No handlers could be found for logger "autopilot.emulators.X11"
  ======================================================================
  FAIL: autopilot.tests.test_hud.HudTests.test_restore_focus
  ----------------------------------------------------------------------
  test-log: {{{
  17:31:45.413 DEBUG autopilot/emulators/unity/__init__.py:49 - Querying unity for state piece: '//HudController'
  17:31:48.092 DEBUG autopilot/emulators/unity/__init__.py:142 - Refreshing state for <autopilot.emulators.unity.hud.HudController object at 0x8beb5ac>
  17:31:48.092 DEBUG autopilot/emulators/unity/__init__.py:61 - Getting state for object HudController with id 17
  17:31:48.092 DEBUG autopilot/emulators/unity/__init__.py:49 - Querying unity for state piece: '//HudController[id=17]'
  }}}

  Traceback (most recent call last):
    File "autopilot/tests/test_hud.py", line 152, in test_restore_focus
      self.assertEqual(b.application_is_focused('Calculator'), True)
  MismatchError: False != True

  Ran 1 test in 2.767s
  FAILED (failures=1)
------------------------------------------------------------------

Running the command...

  python -m testtools.run autopilot.tests.test_hud.HudTests.test_restore_focus

... aborts with:
------------------------------------------------------------------
Xlib.protocol.request.QueryExtension
Traceback (most recent call last):
  File "./tools/autopilot", line 145, in <module>
    main()
  File "./tools/autopilot", line 139, in main
    run_tests(args)
  File "./tools/autopilot", line 106, in run_tests
    test_suite = loader.loadTestsFromNames(args.test)
  File "/usr/lib/python2.7/unittest/loader.py", line 128, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'HudTests'
------------------------------------------------------------------

review: Needs Fixing
Revision history for this message
Mirco Müller (macslow) wrote :

Yay, also the test works (and passes) now... sweet! Approved.

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Gord Allott (gordallott) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/HudController.cpp'
2--- plugins/unityshell/src/HudController.cpp 2012-03-02 01:59:42 +0000
3+++ plugins/unityshell/src/HudController.cpp 2012-03-05 12:14:19 +0000
4@@ -351,10 +351,13 @@
5 //THIS IS BAD - VERY VERY BAD
6 LOG_DEBUG(logger) << "Last attempt, forcing window focus";
7 Controller* self = static_cast<Controller*>(data);
8- nux::GetWindowCompositor().SetKeyFocusArea(self->view_->default_focus());
9+ if (self->visible_)
10+ {
11+ nux::GetWindowCompositor().SetKeyFocusArea(self->view_->default_focus());
12
13- self->window_->PushToFront();
14- self->window_->SetInputFocus();
15+ self->window_->PushToFront();
16+ self->window_->SetInputFocus();
17+ }
18 return FALSE;
19 }, self);
20 }
21
22=== modified file 'tests/autopilot/autopilot/emulators/bamf.py'
23--- tests/autopilot/autopilot/emulators/bamf.py 2012-02-28 08:52:10 +0000
24+++ tests/autopilot/autopilot/emulators/bamf.py 2012-03-05 12:14:19 +0000
25@@ -11,6 +11,7 @@
26 import dbus.glib
27 import gio
28 import gobject
29+import os
30 from Xlib import display, X, protocol
31
32 from autopilot.emulators.dbus_handler import session_bus
33@@ -73,6 +74,15 @@
34 """
35 return [a for a in self.get_running_applications() if a.name == app_title]
36
37+ def get_running_applications_by_desktop_file(self, desktop_file):
38+ """Return a list of applications that have the desktop file 'desktop_file'`.
39+
40+ This method may return an empty list, if no applications
41+ are found with the specified desktop file.
42+
43+ """
44+ return [a for a in self.get_running_applications() if a.desktop_file == desktop_file]
45+
46 def get_open_windows(self, user_visible_only=True):
47 """Get a list of currently open windows.
48
49@@ -104,8 +114,33 @@
50 return app_name in [a.name for a in self.get_running_applications()]
51 except dbus.DBusException:
52 return False
53-
54- def wait_until_application_is_running(self, app_name, timeout):
55+
56+ def application_is_running_desktop_file(self, desktop_file):
57+ """Detect if an application with a given .desktop file is currently running.
58+
59+ 'desktop_file' is the .desktop file of the application you are looking for.
60+ """
61+ try:
62+ return desktop_file in [a.desktop_file for a in self.get_running_applications()]
63+ except dbus.DBusException:
64+ return False
65+
66+ def application_is_focused(self, desktop_file):
67+ """Detect if an application with given name is currently focused.
68+
69+ 'desktop_file' is the desktop_file of the application you are looking for.
70+ """
71+ try:
72+ found_focused = False
73+ for app in self.get_running_applications_by_desktop_file(desktop_file):
74+ if app.is_active:
75+ found_focused = True
76+
77+ return found_focused
78+ except dbus.DBusException:
79+ return False
80+
81+ def wait_until_application_is_running(self, app_name, timeout, is_desktop_file=False):
82 """Wait until a given application is running.
83
84 'app_name' is the name of the application.
85@@ -120,7 +155,13 @@
86 found_app = [True]
87
88 # maybe the app is running already?
89- if not self.application_is_running(app_name):
90+ is_running = False
91+ if (is_desktop_file):
92+ is_running = self.application_is_running_desktop_file(app_name)
93+ else:
94+ is_running = self.application_is_running(app_name)
95+
96+ if not is_running:
97 wait_forever = timeout < 0
98 gobject_loop = gobject.MainLoop()
99
100@@ -128,9 +169,10 @@
101 def on_view_added(bamf_path, name):
102 if bamf_path.split('/')[-1].startswith('application'):
103 app = BamfApplication(bamf_path)
104- if app.name == app_name:
105+ if ((is_desktop_file and app_name == app.desktop_file)
106+ or (not is_desktop_file and app.name == app_name)):
107 gobject_loop.quit()
108-
109+
110 # ...and one for when the user-defined timeout has been reached:
111 def on_timeout_reached():
112 gobject_loop.quit()
113@@ -158,7 +200,7 @@
114 proc = gio.unix.DesktopAppInfo(desktop_file)
115 proc.launch()
116 if wait:
117- self.wait_until_application_is_running(proc.get_name(), -1)
118+ self.wait_until_application_is_running(desktop_file, -1, True)
119 return proc
120
121
122@@ -174,11 +216,17 @@
123 try:
124 self._app_proxy = session_bus.get_object(_BAMF_BUS_NAME, bamf_app_path)
125 self._view_iface = dbus.Interface(self._app_proxy, 'org.ayatana.bamf.view')
126+ self._app_iface = dbus.Interface(self._app_proxy, 'org.ayatana.bamf.application')
127 except dbus.DBusException, e:
128 e.message += 'bamf_app_path=%r' % (bamf_app_path)
129 raise
130
131 @property
132+ def desktop_file(self):
133+ """Get the application desktop file"""
134+ return os.path.split(self._app_iface.DesktopFile())[1]
135+
136+ @property
137 def name(self):
138 """Get the application name."""
139 return self._view_iface.Name()
140
141=== modified file 'tests/autopilot/autopilot/tests/test_hud.py'
142--- tests/autopilot/autopilot/tests/test_hud.py 2012-03-04 23:36:23 +0000
143+++ tests/autopilot/autopilot/tests/test_hud.py 2012-03-05 12:14:19 +0000
144@@ -10,6 +10,7 @@
145
146 from testtools.matchers import Equals, LessThan
147
148+from autopilot.emulators.bamf import Bamf
149 from autopilot.emulators.unity.hud import HudController
150 from autopilot.tests import AutopilotTestCase
151
152@@ -135,3 +136,22 @@
153 num_active = self.get_num_active_launcher_icons()
154 self.assertLessEqual(num_active, 1, "More than one launcher icon active after test has run!")
155
156+ def test_restore_focus(self):
157+ """Ensures that once the hud is dismissed, the same application
158+ that was focused before hud invocation is refocused
159+ """
160+ b = Bamf();
161+ app_desktop_file = 'gcalctool.desktop'
162+ b.launch_application(app_desktop_file)
163+
164+ # first ensure that the application has started and is focused
165+ self.assertEqual(b.application_is_focused(app_desktop_file), True)
166+
167+ self.hud.toggle_reveal()
168+ sleep(1)
169+ self.hud.toggle_reveal()
170+ sleep(1)
171+
172+ # again ensure that the application we started is focused
173+ self.assertEqual(b.application_is_focused(app_desktop_file), True)
174+