Merge lp:~unity-team/unity/3v1n0-quick-alt+tab-fixes into lp:unity

Proposed by Brandon Schaefer on 2012-04-05
Status: Superseded
Proposed branch: lp:~unity-team/unity/3v1n0-quick-alt+tab-fixes
Merge into: lp:unity
Diff against target: 697 lines (+275/-89)
12 files modified
manual-tests/Switcher.txt (+1/-1)
plugins/unityshell/src/BamfLauncherIcon.cpp (+45/-30)
plugins/unityshell/src/Launcher.cpp (+3/-1)
plugins/unityshell/src/PluginAdapter.cpp (+80/-44)
plugins/unityshell/src/PluginAdapter.h (+4/-1)
plugins/unityshell/src/UScreen.cpp (+9/-3)
plugins/unityshell/src/UScreen.h (+1/-0)
plugins/unityshell/src/WindowManager.cpp (+11/-1)
plugins/unityshell/src/WindowManager.h (+5/-2)
plugins/unityshell/src/unityshell.cpp (+8/-5)
tests/autopilot/autopilot/tests/test_launcher.py (+63/-0)
tests/autopilot/autopilot/tests/test_switcher.py (+45/-1)
To merge this branch: bzr merge lp:~unity-team/unity/3v1n0-quick-alt+tab-fixes
Reviewer Review Type Date Requested Status
Alex Launi (community) quality Needs Fixing on 2012-04-12
Tim Penhey (community) Needs Fixing on 2012-04-06
Sam Spilsbury (community) 2012-04-05 Approve on 2012-04-06
Review via email: mp+100911@code.launchpad.net

This proposal has been superseded by a proposal from 2012-04-15.

Commit Message

Fixes quick alt+tab and also fixes clicking on a launcher icon to raise the last focused application.

Description of the Change

Grabbed 3v1n0's quick alt+tab fix branch:
https://code.launchpad.net/~3v1n0/unity/quick-alt+tab-fixes/+merge/85583 and merged it with trunk and fixed the conflicts. This problem is very similar to this bug: https://bugs.launchpad.net/unity/+bug/959339 which this branch also now fixes that bug!

== Problem ==
Quick alt+tab and clicking on a launcher icon raises all of the applications of that type.

== Fix ==
The fix was to add 'OnlyVisibleOnTop' to the enum WindowManager::FocusVisibility so when you want to only focus the top window use that.

To use Quick alt+tab you have to press alt+tab before a timer goes off. Right now it is set to 200ms, but is very easy to change.

Screencast of the fixed version: http://ubuntuone.com/7YaWciQnaZHfzr35asSz0N

== Test ==
There are autopilot test for both bugs.

To post a comment you must log in.
Marco Trevisan (Treviño) (3v1n0) wrote :

30 - if ((mapped && wm->IsWindowMapped(xid)) || !mapped)
31 + if ((mapped && wm->IsWindowMapped(xid) && !bamf_window_get_transient(BAMF_WINDOW(view))) || !mapped)
32 {

About this, I think I included that change mostly for testing purposes, I'm not sure it's actually wanted so move it out.

I didn't work too much on my branch lately since I didn't know if that was still the wanted desig, but if now it is, I'll be happy to get this merged :)

Brandon Schaefer (brandontschaefer) wrote :

I ran all the autopilot test that I thought these changes would effect.

Launcher Autopilot tests:
Ran 43 tests in 296.560s
OK

Switcher Autopilot tests:
Ran 21 tests in 187.666s
OK

Dash Autopilot tests:
Ran 32 tests in 225.549s
OK

Sam Spilsbury (smspillaz) wrote :

Tests OK, no iconic window regressions (which is what I was a little concerned about)

review: Approve
Tim Penhey (thumper) wrote :

Clicking on the launcher to reveal only the top most one works.

However the quick alt-tab one does not work.

If I have two terminal windows and one gedit. Focus gedit and quick alt-tab, it raises both terminals.

review: Needs Fixing
Marco Trevisan (Treviño) (3v1n0) wrote :

Probably it is caused by the fact that now we use a very small delay for the Alt+Tab.
A workaround could be to use another time reference to consider an Alt+Tab quick, more than the only window visibility.

I mean, even if the window is shown for 100ms or less, the Alt+Tab is surely a quick one (as there's no time to look to the content of the window).

1785. By Brandon Schaefer on 2012-04-06

* Merged trunk

Brandon Schaefer (brandontschaefer) wrote :

I just ended up making a timer called quick_tab_timer_, which will go for 200ms if you hold on to alt for any longer it makes quick_tab = false. Seems like a nice and customizable way.

1786. By Brandon Schaefer on 2012-04-06

* Added a timer for quick tab

1787. By Brandon Schaefer on 2012-04-06

* fixed manual test I messed up

1788. By Brandon Schaefer on 2012-04-07

* Added 2 autopilot test showing quick tab is true when pressed fast enough

1789. By Brandon Schaefer on 2012-04-10

* merged trunk

1790. By Brandon Schaefer on 2012-04-11

* merged trunk

Alex Launi (alexlauni) wrote :

It shouldn't be too difficult to automate the manual tests. Please do not merge this with the manual tests.

review: Needs Fixing (quality)
1791. By Brandon Schaefer on 2012-04-12

* Added more autopilot test for quick alt+tab

1792. By Brandon Schaefer on 2012-04-13

* Add autopilot test for both bugs!

1793. By Brandon Schaefer on 2012-04-13

* removed random dash '-'

1794. By Brandon Schaefer on 2012-04-13

* merged trunk

Brandon Schaefer (brandontschaefer) wrote :

@Alex

Sorry about having the manual test in there. I was trying to get this branch in 5.10 and was rushing to get it done. Never a good sign when it comes to quality. There are now autopilot test for each bug!

1795. By Brandon Schaefer on 2012-04-13

* Fixed the No new line error diff was reporting

1796. By Brandon Schaefer on 2012-04-13

* remove extra line

Brandon Schaefer (brandontschaefer) wrote :

So I guess diff continutes to complain about there not being a new line...I even took the trunk version of Switcher.txt and replaced it and it still gives that problem...

Marco Trevisan (Treviño) (3v1n0) wrote :

I've just checked this code again, there's a problem with the minimized windows when using the launcher icon.
Don't worry about that Brandon, I'll take care of that ;)

Brandon Schaefer (brandontschaefer) wrote :

Yeah, I just saw that. At lease we know what design wants now :). Thank you!

1797. By Marco Trevisan (Treviño) on 2012-04-14

PluginAdapter::FocusWindowGroup: add a parameter to define if focusing the on-top window only

This allow to be more monitor/VP safe

1798. By Marco Trevisan (Treviño) on 2012-04-14

unityshell: switcher, use UScreen to get the monitor value.

Not using this can cause inconsistences, due to the fact that compiz
numbers the devices in a different way.

1799. By Marco Trevisan (Treviño) on 2012-04-14

UScreen: allow to get the monitor for a given point

1800. By Marco Trevisan (Treviño) on 2012-04-14

WindowManager: add GetWindowMonitor method, and use UScreen to fetch it

This now used in PluginAdapter not to have inconsistences.

1801. By Marco Trevisan (Treviño) on 2012-04-14

SwitcherController: include the switcher monitor when activating a group

1802. By Marco Trevisan (Treviño) on 2012-04-14

Launcher: if the current launcher is used for all the monitors, don't filter windows per monitor

1803. By Marco Trevisan (Treviño) on 2012-04-14

BamfLauncherIcon: focus a window if the application is not active on the current monitor

1804. By Marco Trevisan (Treviño) on 2012-04-14

BamfLauncherIcon: don't consider an unmapped window as one in monitor

1805. By Marco Trevisan (Treviño) on 2012-04-14

BamfLauncherIcon: Also invisible windows shouldn't be counted as available in monitor

Now the spread works as expected, clicking on each monitor's panel! ;)

1806. By Marco Trevisan (Treviño) on 2012-04-14

autopilot: fixed the AP test

1807. By Marco Trevisan (Treviño) on 2012-04-14

SwitcherController: Removing the code for the Quick Alt+Tab, it should behave always at the same way

19:11:04 <JohnLea> so to summarize the above, when a app icon is selected
in Alt-Tab, the most recently focused window (on any monitor, but only in
the current workspace) of that application which is not minimised
should be focused

1808. By Marco Trevisan (Treviño) on 2012-04-14

Merging with branch changes

1809. By Marco Trevisan (Treviño) on 2012-04-14

PluginAdapter: removing debugging bits

1810. By Marco Trevisan (Treviño) on 2012-04-15

WindowManager: add method to get the active window.

1811. By Marco Trevisan (Treviño) on 2012-04-15

unityshell: show the Alt+Tab window in the monitor where is the active window

As per design.

1812. By Marco Trevisan (Treviño) on 2012-04-15

autopilot, test_switcher: updated against new updates

1813. By Marco Trevisan (Treviño) on 2012-04-15

autopilot, test_launcher: updated click test to check minimized windows too

Removed debug data

1814. By Marco Trevisan (Treviño) on 2012-04-15

WindowManager, BamfLauncherIcon: some code cleanup

1815. By Marco Trevisan (Treviño) on 2012-04-15

UScreen: use GetMonitorAtPosition in GetMonitorWithMouse

1816. By Marco Trevisan (Treviño) on 2012-04-15

Launcher: be more clear in comment (yeah?)

1817. By Marco Trevisan (Treviño) on 2012-04-15

PluginAdapter: avoid to raise and unminimize top_window if already done

1818. By Tim Penhey on 2012-04-15

Tweaks to the test.

1819. By Tim Penhey on 2012-04-15

More AP test tweaks.

1820. By Tim Penhey on 2012-04-16

Assert that the visible window stack is what we expect.

1821. By Tim Penhey on 2012-04-16

Add window stack assertions to the switcher tests.

1822. By Tim Penhey on 2012-04-16

Test the alt-tab appears on the monitor that has window focus.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'manual-tests/Switcher.txt'
2--- manual-tests/Switcher.txt 2012-03-23 15:14:42 +0000
3+++ manual-tests/Switcher.txt 2012-04-15 12:16:20 +0000
4@@ -37,4 +37,4 @@
5 When you press Alt+Tab to switch window, the application title in the top left
6 of the panel should change inline with changes in alt-tab focus.
7 Also the menus shouldn't ever show. Even if the mouse has been left over
8- the panel when starting the Alt+Tab.
9\ No newline at end of file
10+ the panel when starting the Alt+Tab.
11
12=== modified file 'plugins/unityshell/src/BamfLauncherIcon.cpp'
13--- plugins/unityshell/src/BamfLauncherIcon.cpp 2012-04-10 03:57:39 +0000
14+++ plugins/unityshell/src/BamfLauncherIcon.cpp 2012-04-15 12:16:20 +0000
15@@ -182,15 +182,15 @@
16 void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
17 {
18 SimpleLauncherIcon::ActivateLauncherIcon(arg);
19- bool scaleWasActive = WindowManager::Default()->IsScaleActive();
20- GList *l;
21+ WindowManager* wm = WindowManager::Default();
22+ bool scaleWasActive = wm->IsScaleActive();
23
24 bool active = IsActive();
25 bool user_visible = IsRunning();
26
27 if (arg.target && OwnsWindow(arg.target))
28 {
29- WindowManager::Default()->Activate(arg.target);
30+ wm->Activate(arg.target);
31 return;
32 }
33
34@@ -204,29 +204,48 @@
35 user_visible = bamf_view_user_visible(bamf_view);
36
37 bool any_visible = false;
38- GList *children = bamf_view_get_children(bamf_view);
39+ bool any_mapped = false;
40+ bool any_on_monitor = (arg.monitor < 0);
41+ int active_monitor = arg.monitor;
42+ GList* children = bamf_view_get_children(bamf_view);
43
44- for (l = children; l; l = l->next)
45+ for (GList* l = children; l; l = l->next)
46 {
47 if (!BAMF_IS_WINDOW(l->data))
48 continue;
49
50- Window xid = bamf_window_get_xid(static_cast<BamfWindow*>(l->data));
51+ auto view = static_cast<BamfView*>(l->data);
52+ auto win = static_cast<BamfWindow*>(l->data);
53+ Window xid = bamf_window_get_xid(win);
54
55- if (!any_visible && WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
56+ if (!any_visible && wm->IsWindowOnCurrentDesktop(xid))
57 {
58 any_visible = true;
59 }
60
61- if (active && !WindowManager::Default()->IsWindowMapped(xid))
62- {
63- active = false;
64+ if (!any_mapped && wm->IsWindowMapped(xid))
65+ {
66+ any_mapped = true;
67+ }
68+
69+ if (!any_on_monitor && bamf_window_get_monitor(win) == arg.monitor &&
70+ wm->IsWindowMapped(xid) && wm->IsWindowVisible(xid))
71+ {
72+ any_on_monitor = true;
73+ }
74+
75+ if (bamf_view_is_active(view))
76+ {
77+ active_monitor = bamf_window_get_monitor(win);
78 }
79 }
80
81 g_list_free(children);
82
83- if (!any_visible)
84+ if (!any_visible || !any_mapped)
85+ active = false;
86+
87+ if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor)
88 active = false;
89 }
90
91@@ -245,7 +264,7 @@
92
93 if (scaleWasActive)
94 {
95- WindowManager::Default()->TerminateScale();
96+ wm->TerminateScale();
97 }
98
99 SetQuirk(QUIRK_STARTING, true);
100@@ -257,7 +276,7 @@
101 {
102 if (scaleWasActive) // #5 above
103 {
104- WindowManager::Default()->TerminateScale();
105+ wm->TerminateScale();
106 Focus(arg);
107 }
108 else // #2 above
109@@ -272,7 +291,7 @@
110 {
111 if (scaleWasActive) // #4 above
112 {
113- WindowManager::Default()->TerminateScale();
114+ wm->TerminateScale();
115 Focus(arg);
116 if (arg.source != ActionArg::SWITCHER)
117 Spread(true, 0, false);
118@@ -290,9 +309,9 @@
119
120 std::vector<Window> BamfLauncherIcon::GetWindows(WindowFilterMask filter, int monitor)
121 {
122+ WindowManager* wm = WindowManager::Default();
123 std::vector<Window> results;
124 GList* children, *l;
125- WindowManager *wm = WindowManager::Default();
126
127 monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor;
128 bool mapped = (filter & WindowFilter::MAPPED);
129@@ -546,17 +565,16 @@
130
131 void BamfLauncherIcon::Focus(ActionArg arg)
132 {
133- GList* children, *l;
134 bool any_urgent = false;
135 bool any_visible = false;
136 bool any_user_visible = false;
137-
138- children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
139+ WindowManager* wm = WindowManager::Default();
140
141 std::vector<Window> windows;
142+ GList* children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
143
144 /* get the list of windows */
145- for (l = children; l; l = l->next)
146+ for (GList* l = children; l; l = l->next)
147 {
148 if (!BAMF_IS_WINDOW(l->data))
149 continue;
150@@ -590,32 +608,29 @@
151 windows.push_back(xid);
152 }
153
154- if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid) &&
155- WindowManager::Default()->IsWindowVisible(xid))
156+ if (wm->IsWindowOnCurrentDesktop(xid) && wm->IsWindowVisible(xid))
157 {
158 any_visible = true;
159 }
160 }
161+
162 g_list_free(children);
163
164+ auto visibility = WindowManager::FocusVisibility::OnlyVisible;
165+
166 if (arg.source != ActionArg::SWITCHER)
167 {
168 if (any_visible)
169 {
170- WindowManager::Default()->FocusWindowGroup(windows,
171- WindowManager::FocusVisibility::ForceUnminimizeInvisible, arg.monitor);
172+ visibility = WindowManager::FocusVisibility::ForceUnminimizeInvisible;
173 }
174 else
175 {
176- WindowManager::Default()->FocusWindowGroup(windows,
177- WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop, arg.monitor);
178+ visibility = WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop;
179 }
180 }
181- else
182- {
183- WindowManager::Default()->FocusWindowGroup(windows,
184- WindowManager::FocusVisibility::OnlyVisible, arg.monitor);
185- }
186+
187+ wm->FocusWindowGroup(windows, visibility, arg.monitor);
188 }
189
190 bool BamfLauncherIcon::Spread(bool current_desktop, int state, bool force)
191
192=== modified file 'plugins/unityshell/src/Launcher.cpp'
193--- plugins/unityshell/src/Launcher.cpp 2012-04-10 01:41:16 +0000
194+++ plugins/unityshell/src/Launcher.cpp 2012-04-15 12:16:20 +0000
195@@ -2553,7 +2553,9 @@
196
197 if (GetActionState() == ACTION_NONE)
198 {
199- _icon_mouse_down->mouse_click.emit(nux::GetEventButton(button_flags), monitor);
200+ /* This will inform the icon if the action is valid for all the monitors */
201+ int action_monitor = options()->show_for_all ? -1 : monitor;
202+ _icon_mouse_down->mouse_click.emit(nux::GetEventButton(button_flags), action_monitor);
203 }
204 }
205
206
207=== modified file 'plugins/unityshell/src/PluginAdapter.cpp'
208--- plugins/unityshell/src/PluginAdapter.cpp 2012-04-02 10:45:47 +0000
209+++ plugins/unityshell/src/PluginAdapter.cpp 2012-04-15 12:16:20 +0000
210@@ -20,6 +20,7 @@
211 #include <glib.h>
212 #include <sstream>
213 #include "PluginAdapter.h"
214+#include "UScreen.h"
215
216 #include <NuxCore/Logger.h>
217
218@@ -392,6 +393,12 @@
219 }
220
221 // WindowManager implementation
222+guint32
223+PluginAdapter::GetActiveWindow()
224+{
225+ return m_Screen->activeWindow();
226+}
227+
228 bool
229 PluginAdapter::IsWindowMaximized(guint xid)
230 {
231@@ -618,11 +625,12 @@
232 }
233
234 void
235-PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility focus_visibility, int monitor)
236+PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility focus_visibility, int monitor, bool only_top_win)
237 {
238 CompPoint target_vp = m_Screen->vp();
239- CompWindow* top_window = NULL;
240- CompWindow* top_window_on_monitor = NULL;
241+ CompWindow* top_window = nullptr;
242+ CompWindow* top_monitor_win = nullptr;
243+
244 bool any_on_current = false;
245 bool any_mapped = false;
246 bool any_mapped_on_current = false;
247@@ -661,11 +669,12 @@
248
249 if (!any_on_current)
250 {
251- for (auto it = windows.rbegin(); it != windows.rend(); it++)
252+ for (auto it = windows.rbegin(); it != windows.rend(); ++it)
253 {
254- if ((any_mapped && !(*it)->minimized()) || !any_mapped)
255+ CompWindow* win = *it;
256+ if ((any_mapped && !win->minimized()) || !any_mapped)
257 {
258- target_vp = (*it)->defaultViewport();
259+ target_vp = win->defaultViewport();
260 break;
261 }
262 }
263@@ -675,46 +684,56 @@
264 {
265 if (win->defaultViewport() == target_vp)
266 {
267- /* Any window which is actually unmapped is
268- * not going to be accessible by either switcher
269- * or scale, so unconditionally unminimize those
270- * windows when the launcher icon is activated */
271- if ((focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop &&
272- target_vp == m_Screen->vp()) ||
273- (focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeInvisible &&
274- win->mapNum () == 0))
275- {
276- bool is_mapped = win->mapNum () != 0;
277- top_window = win;
278- if (monitor >= 0 && win->outputDevice() == monitor)
279- top_window_on_monitor = win;
280- win->unminimize ();
281-
282- forced_unminimize = true;
283-
284- /* Initially minimized windows dont get raised */
285- if (!is_mapped)
286- win->raise ();
287- }
288- else if ((any_mapped_on_current && !win->minimized()) || !any_mapped_on_current)
289- {
290- if (!forced_unminimize || target_vp == m_Screen->vp())
291- {
292- win->raise();
293- top_window = win;
294- if (monitor >= 0 && win->outputDevice() == monitor)
295- top_window_on_monitor = win;
296- }
297- }
298+ int win_monitor = GetWindowMonitor(win->id());
299+
300+ /* Any window which is actually unmapped is
301+ * not going to be accessible by either switcher
302+ * or scale, so unconditionally unminimize those
303+ * windows when the launcher icon is activated */
304+ if ((focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop &&
305+ target_vp == m_Screen->vp()) ||
306+ (focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeInvisible &&
307+ win->mapNum() == 0))
308+ {
309+ top_window = win;
310+ forced_unminimize = true;
311+
312+ if (monitor >= 0 && win_monitor == monitor)
313+ top_monitor_win = win;
314+
315+ if (!only_top_win)
316+ {
317+ bool is_mapped = (win->mapNum() != 0);
318+ win->unminimize();
319+
320+ /* Initially minimized windows dont get raised */
321+ if (!is_mapped)
322+ win->raise();
323+ }
324+ }
325+ else if ((any_mapped_on_current && !win->minimized()) || !any_mapped_on_current)
326+ {
327+ if (!forced_unminimize || target_vp == m_Screen->vp())
328+ {
329+ top_window = win;
330+
331+ if (monitor >= 0 && win_monitor == monitor)
332+ top_monitor_win = win;
333+
334+ if (!only_top_win)
335+ win->raise();
336+ }
337+ }
338 }
339 }
340
341- if (monitor > 0 && top_window_on_monitor)
342- {
343- top_window_on_monitor->activate();
344- }
345- else if (top_window)
346- {
347+ if (monitor >= 0 && top_monitor_win)
348+ top_window = top_monitor_win;
349+
350+ if (top_window)
351+ {
352+ top_window->unminimize();
353+ top_window->raise();
354 top_window->activate();
355 }
356 }
357@@ -768,12 +787,29 @@
358 _in_show_desktop = false;
359 }
360
361+int
362+PluginAdapter::GetWindowMonitor(guint32 xid) const
363+{
364+ // FIXME, we should use window->outputDevice() but this is not UScreen friendly
365+ nux::Geometry const& geo = GetWindowGeometry(xid);
366+
367+ if (!geo.IsNull())
368+ {
369+ int x = geo.x + geo.width/2;
370+ int y = geo.y + geo.height/2;
371+
372+ return UScreen::GetDefault()->GetMonitorAtPosition(x, y);
373+ }
374+
375+ return -1;
376+}
377+
378 nux::Geometry
379 PluginAdapter::GetWindowGeometry(guint32 xid) const
380 {
381 Window win = xid;
382 CompWindow* window;
383- nux::Geometry geo(0, 0, 1, 1);
384+ nux::Geometry geo;
385
386 window = m_Screen->findWindow(win);
387 if (window)
388
389=== modified file 'plugins/unityshell/src/PluginAdapter.h'
390--- plugins/unityshell/src/PluginAdapter.h 2012-04-02 10:45:47 +0000
391+++ plugins/unityshell/src/PluginAdapter.h 2012-04-15 12:16:20 +0000
392@@ -109,6 +109,8 @@
393 void NotifyCompizEvent(const char* plugin, const char* event, CompOption::Vector& option);
394 void NotifyNewDecorationState(guint32 xid);
395
396+ guint32 GetActiveWindow();
397+
398 void Decorate(guint32 xid);
399 void Undecorate(guint32 xid);
400
401@@ -132,7 +134,7 @@
402
403 void SetWindowIconGeometry(Window window, nux::Geometry const& geo);
404
405- void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1);
406+ void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1, bool only_top_win = true);
407 bool ScaleWindowGroup(std::vector<Window> windows, int state, bool force);
408
409 bool IsScreenGrabbed();
410@@ -142,6 +144,7 @@
411
412 bool MaximizeIfBigEnough(CompWindow* window);
413
414+ int GetWindowMonitor(guint32 xid) const;
415 nux::Geometry GetWindowGeometry(guint32 xid) const;
416 nux::Geometry GetWindowSavedGeometry(guint32 xid) const;
417 nux::Geometry GetScreenGeometry() const;
418
419=== modified file 'plugins/unityshell/src/UScreen.cpp'
420--- plugins/unityshell/src/UScreen.cpp 2012-03-29 20:07:45 +0000
421+++ plugins/unityshell/src/UScreen.cpp 2012-04-15 12:16:20 +0000
422@@ -59,19 +59,17 @@
423 int
424 UScreen::GetMonitorWithMouse()
425 {
426- GdkScreen* screen;
427 GdkDevice* device;
428 GdkDisplay *display;
429 int x;
430 int y;
431
432- screen = gdk_screen_get_default();
433 display = gdk_display_get_default();
434 device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(display));
435
436 gdk_device_get_position(device, NULL, &x, &y);
437
438- return gdk_screen_get_monitor_at_point(screen, x, y);
439+ return GetMonitorAtPosition(x, y);
440 }
441
442 int
443@@ -80,6 +78,14 @@
444 return primary_;
445 }
446
447+int
448+UScreen::GetMonitorAtPosition(int x, int y)
449+{
450+ GdkScreen* screen = gdk_screen_get_default();
451+
452+ return gdk_screen_get_monitor_at_point(screen, x, y);
453+}
454+
455 nux::Geometry&
456 UScreen::GetMonitorGeometry(int monitor)
457 {
458
459=== modified file 'plugins/unityshell/src/UScreen.h'
460--- plugins/unityshell/src/UScreen.h 2012-03-29 20:07:45 +0000
461+++ plugins/unityshell/src/UScreen.h 2012-04-15 12:16:20 +0000
462@@ -36,6 +36,7 @@
463
464 int GetPrimaryMonitor();
465 int GetMonitorWithMouse();
466+ int GetMonitorAtPosition(int x, int y);
467 nux::Geometry& GetMonitorGeometry(int monitor);
468
469 std::vector<nux::Geometry>& GetMonitors();
470
471=== modified file 'plugins/unityshell/src/WindowManager.cpp'
472--- plugins/unityshell/src/WindowManager.cpp 2012-04-02 10:45:47 +0000
473+++ plugins/unityshell/src/WindowManager.cpp 2012-04-15 12:16:20 +0000
474@@ -23,6 +23,11 @@
475
476 class WindowManagerDummy : public WindowManager
477 {
478+ guint32 GetActiveWindow()
479+ {
480+ return 0;
481+ }
482+
483 unsigned long long GetWindowActiveNumber (guint32 xid)
484 {
485 return 0;
486@@ -113,7 +118,7 @@
487 g_debug("%s", G_STRFUNC);
488 }
489
490- void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor)
491+ void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor, bool only_top_win)
492 {
493 g_debug("%s", G_STRFUNC);
494 }
495@@ -124,6 +129,11 @@
496 return false;
497 }
498
499+ int GetWindowMonitor(guint32 xid) const
500+ {
501+ return -1;
502+ }
503+
504 nux::Geometry GetWindowGeometry(guint xid) const
505 {
506 int width = (guint32)xid >> 16;
507
508=== modified file 'plugins/unityshell/src/WindowManager.h'
509--- plugins/unityshell/src/WindowManager.h 2012-04-02 10:45:47 +0000
510+++ plugins/unityshell/src/WindowManager.h 2012-04-15 12:16:20 +0000
511@@ -53,7 +53,9 @@
512 };
513
514 static WindowManager* Default();
515- static void SetDefault(WindowManager* manager);
516+ static void SetDefault(WindowManager* manager);
517+
518+ virtual guint32 GetActiveWindow() = 0;
519
520 virtual bool IsWindowMaximized(guint32 xid) = 0;
521 virtual bool IsWindowDecorated(guint32 xid) = 0;
522@@ -81,7 +83,7 @@
523 virtual void InitiateExpo() = 0;
524 virtual bool IsExpoActive() = 0;
525
526- virtual void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1) = 0;
527+ virtual void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1, bool only_top_win = true) = 0;
528 virtual bool ScaleWindowGroup(std::vector<Window> windows, int state, bool force) = 0;
529
530 virtual void Decorate(guint32 xid) {};
531@@ -93,6 +95,7 @@
532 virtual void MoveResizeWindow(guint32 xid, nux::Geometry geometry) = 0;
533 void StartMove(guint32 xid, int, int);
534
535+ virtual int GetWindowMonitor(guint32 xid) const = 0;
536 virtual nux::Geometry GetWindowGeometry(guint32 xid) const = 0;
537 virtual nux::Geometry GetWindowSavedGeometry(guint32 xid) const = 0;
538 virtual nux::Geometry GetScreenGeometry() const = 0;
539
540=== modified file 'plugins/unityshell/src/unityshell.cpp'
541--- plugins/unityshell/src/unityshell.cpp 2012-04-11 16:29:31 +0000
542+++ plugins/unityshell/src/unityshell.cpp 2012-04-15 12:16:20 +0000
543@@ -1711,11 +1711,14 @@
544
545 // maybe check launcher position/hide state?
546
547- int device = screen->outputDeviceForPoint (pointerX, pointerY);
548- switcher_controller_->SetWorkspace(nux::Geometry(screen->outputDevs()[device].x1() + 100,
549- screen->outputDevs()[device].y1() + 100,
550- screen->outputDevs()[device].width() - 200,
551- screen->outputDevs()[device].height() - 200), device);
552+ WindowManager *wm = WindowManager::Default();
553+ int monitor = wm->GetWindowMonitor(wm->GetActiveWindow());
554+ nux::Geometry monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor);
555+ monitor_geo.x += 100;
556+ monitor_geo.y += 100;
557+ monitor_geo.width -= 200;
558+ monitor_geo.height -= 200;
559+ switcher_controller_->SetWorkspace(monitor_geo, monitor);
560
561 if (!optionGetAltTabBiasViewport())
562 {
563
564=== modified file 'tests/autopilot/autopilot/tests/test_launcher.py'
565--- tests/autopilot/autopilot/tests/test_launcher.py 2012-04-06 07:31:45 +0000
566+++ tests/autopilot/autopilot/tests/test_launcher.py 2012-04-15 12:16:20 +0000
567@@ -403,6 +403,69 @@
568 self.assertThat(self.launcher.key_nav_is_active, Equals(False))
569
570
571+class LauncherIconsBehaviorTests(LauncherTestCase):
572+ """Test the launcher icons interactions"""
573+
574+ def test_launcher_activate_last_focused_window(self):
575+ """This tests shows that when you activate a launcher icon only the last
576+ focused instance of that application is rasied.
577+
578+ This is tested by opening 2 Mahjongg and a Calculator.
579+ Then we activate the Calculator launcher icon.
580+ Then we actiavte the Mahjongg launcher icon.
581+ Then we minimize the focused applications.
582+ This should give focus to the next window on the stack.
583+ Then we activate the Mahjongg launcher icon
584+ This should bring to focus the non-minimized window.
585+ If only 1 instance is raised then the Calculator gets the focus.
586+ If ALL the instances are raised then the second Mahjongg gets the focus.
587+
588+ """
589+ self.close_all_app("Mahjongg")
590+ self.close_all_app("Calculator")
591+
592+ mahj = self.start_app("Mahjongg")
593+ wins = mahj.get_windows()
594+ self.assertThat(len(wins), Equals(1))
595+ mah_win1 = wins[0]
596+ self.assertTrue(mah_win1.is_focused)
597+
598+ calc = self.start_app("Calculator")
599+ wins = calc.get_windows()
600+ self.assertThat(len(wins), Equals(1))
601+ calc_win = wins[0]
602+ self.assertTrue(calc_win.is_focused)
603+
604+ self.start_app("Mahjongg")
605+ sleep(1)
606+ wins = filter(lambda w: w.x_id != mah_win1.x_id, mahj.get_windows())
607+ self.assertThat(len(wins), Equals(1))
608+ mah_win2 = wins[0]
609+ self.assertTrue(mah_win2.is_focused)
610+
611+ mahj_icon = self.launcher.model.get_icon_by_desktop_id(mahj.desktop_file)
612+ calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file)
613+
614+ self.launcher_instance.click_launcher_icon(calc_icon)
615+ sleep(1)
616+ self.assertTrue(calc_win.is_focused)
617+
618+ self.launcher_instance.click_launcher_icon(mahj_icon)
619+ sleep(1)
620+ self.assertTrue(mah_win2.is_focused)
621+
622+ self.keybinding("window/minimize")
623+ sleep(1)
624+
625+ self.assertTrue(mah_win2.is_hidden)
626+ self.assertTrue(calc_win.is_focused)
627+
628+ self.launcher_instance.click_launcher_icon(mahj_icon)
629+ sleep(1)
630+ self.assertTrue(mah_win1.is_focused)
631+ self.assertTrue(mah_win2.is_hidden)
632+
633+
634 class LauncherRevealTests(LauncherTestCase):
635 """Test the launcher reveal bahavior when in autohide mode."""
636
637
638=== modified file 'tests/autopilot/autopilot/tests/test_switcher.py'
639--- tests/autopilot/autopilot/tests/test_switcher.py 2012-04-03 13:48:39 +0000
640+++ tests/autopilot/autopilot/tests/test_switcher.py 2012-04-15 12:16:20 +0000
641@@ -198,6 +198,51 @@
642 self.assertThat(self.switcher.get_is_visible(), Equals(False))
643
644
645+class SwitcherWindowsManagementTests(AutopilotTestCase):
646+ """Test the switcher window management."""
647+
648+ def test_switcher_raises_only_last_focused_window(self):
649+ """Tests that when we do an alt+tab only the previously focused window
650+ is raised.
651+ This is tests by opening 2 Calculators and a Mahjongg.
652+ Then we do a quick alt+tab twice.
653+ Then we close the currently focused window.
654+ """
655+ self.close_all_app("Mahjongg")
656+ self.close_all_app("Calculator")
657+
658+ calc = self.start_app("Calculator")
659+ wins = calc.get_windows()
660+ self.assertThat(len(wins), Equals(1))
661+ calc_win1 = wins[0]
662+ self.assertTrue(calc_win1.is_focused)
663+
664+ mahj = self.start_app("Mahjongg")
665+ wins = mahj.get_windows()
666+ self.assertThat(len(wins), Equals(1))
667+ mahj_win = wins[0]
668+ self.assertTrue(mahj_win.is_focused)
669+
670+ self.start_app("Calculator")
671+ sleep(1)
672+ wins = filter(lambda w: w.x_id != calc_win1.x_id, calc.get_windows())
673+ self.assertThat(len(wins), Equals(1))
674+ calc_win2 = wins[0]
675+ self.assertTrue(calc_win2.is_focused)
676+
677+ self.keybinding("switcher/reveal_normal")
678+ sleep(1)
679+ self.assertTrue(mahj_win.is_focused)
680+
681+ self.keybinding("switcher/reveal_normal")
682+ sleep(1)
683+ self.assertTrue(calc_win2.is_focused)
684+
685+ self.keybinding("window/close")
686+ sleep(1)
687+
688+ self.assertTrue(mahj_win.is_focused)
689+
690 class SwitcherDetailsTests(AutopilotTestCase):
691 """Test the details mode for the switcher."""
692
693@@ -364,4 +409,3 @@
694 # current workspace and ask that one if it is hidden.
695 self.assertFalse(wins[0].is_hidden)
696 self.assertFalse(wins[1].is_hidden)
697-