Merge lp:~jassmith/unity/unity.sticky-edges into lp:unity

Proposed by Jason Smith
Status: Merged
Approved by: Jason Smith
Approved revision: no longer in the source branch.
Merged at revision: 2222
Proposed branch: lp:~jassmith/unity/unity.sticky-edges
Merge into: lp:unity
Diff against target: 606 lines (+394/-50)
8 files modified
plugins/unityshell/src/EdgeBarrierController.cpp (+189/-0)
plugins/unityshell/src/EdgeBarrierController.h (+57/-0)
plugins/unityshell/src/Launcher.cpp (+12/-44)
plugins/unityshell/src/Launcher.h (+3/-5)
plugins/unityshell/src/LauncherController.cpp (+12/-0)
plugins/unityshell/src/PointerBarrier.cpp (+2/-1)
plugins/unityshell/src/PointerBarrier.h (+13/-0)
tests/autopilot/autopilot/tests/test_launcher.py (+106/-0)
To merge this branch: bzr merge lp:~jassmith/unity/unity.sticky-edges
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
Review via email: mp+100844@code.launchpad.net

Commit message

Implement sticky edge behavior as requested by design. Add EdgeBarrierController class to handle complexity of edge barriers.

Description of the change

== Problem ==
Launcher behavior with edge stickiness is inconsisten with design. Further details available with bug #961285

== Solution ==
Implement behavior consisten with design. A new class was created to control all barrier edges and launchers are subscribed to that class as needed.

== Testing ==
Autopilot tests are in place to test new behavior.

To post a comment you must log in.
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

ResizeBarrierList should pass it's std::vector by const ref:

void ResizeBarrierList(std::vector<nux::Geometry> const& layout);

same with SetupBarriers:

void SetupBarriers(std::vector<nux::Geometry> const& layout);

Should probably fix this, just to bzr / lp don't complain:

194 \ No newline at end of file

...and definitely fix this one:

257 \ No newline at end of file

Is a lack of newline character at the end of header files can cause real problems.

Pro tip - this:

edge_barriers_(new ui::EdgeBarrierController())

Is better written as this:

edge_barriers_(std::make_shared<ui::EdgeBarrierController>())

std::make_shared returns a std::shared_ptr<T> constructed with the arguments you pass it, but it does it in only one memory allocation. Using "edge_barriers_(new ui::EdgeBarrierController())" requires at least two. Also, I believe that make_shared is exception safe, whereas the other method may throw if you cannot allocate an object (TBH though, if you get into that situation you're pretty screwed anyway). I don't mind if you choose to ignore this - it's something that I've started doing.

471 +enum BarrierDirection
472 +{
473 + BOTH = 0,
474 + LEFT = 1,
475 + RIGHT = 4,
476 +};

0, 1, 4? If you want this to be a bitmask, shouldn't RIGHT = 2?

500 +from autopilot.emulators.X11 import Mouse
512 + mouse = Mouse()

You don't need these two lines - all Autopilot test classes have access to 'self.mouse' already.

509 +class LauncherCaptureTests(ScenariodLauncherTests):

I don't think you want to derive from ScenariodLauncherTests - deriving from this class ensures that your tests get called several times with different sets of launcher options. It seems to me that your tests specify the options under which they'll work already? If that is in fact the case, just derive from AutopilotTestCase instead.

530 + if self.screen_geo.get_num_monitors() <= 1:
531 + return

Instead of returning, please do this:

self.skipTest("Cannot run this test with a single monitor configured.")

... obviously this applies to all the tests.

539 + self.assertThat(x_fin, NotEquals(x - width / 2))

Try not to do negative assertions - it's too easy to have the test pass when it shouldn't. Should the mouse value be less than, or greater than x_fin? Use GreaterThan / LessThen matchers instead (you may need to import them).

This code:

565 + self.set_unity_option('launcher_hide_mode', 1)
567 +
568 + launcher = self.get_launcher()
569 + for counter in range(10):
570 + sleep(1)
571 + if launcher.hidemode == 1:
572 + break
573 + self.assertThat(launcher.hidemode, Equals(1),
574 + "Launcher did not enter hidden mode.")

Should go in a method, so you can call it as often as you want from the setUp method and from within your tests.

Looking good though (apart from the issues above).

Cheers,

609 + self.assertThat(x_fin, NotEquals(x + width * 1.5))

Same thing as before with the negative assertions. Better to use Equals, or GreatherThan or LessTHan to test what you really mean.

review: Needs Fixing
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

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/src/EdgeBarrierController.cpp'
2--- plugins/unityshell/src/EdgeBarrierController.cpp 1970-01-01 00:00:00 +0000
3+++ plugins/unityshell/src/EdgeBarrierController.cpp 2012-04-04 23:48:21 +0000
4@@ -0,0 +1,189 @@
5+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
6+/*
7+ * Copyright (C) 2012 Canonical Ltd
8+ *
9+ * This program is free software: you can redistribute it and/or modify
10+ * it under the terms of the GNU General Public License version 3 as
11+ * published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ * GNU General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU General Public License
19+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
20+ *
21+ * Authored by: Jason Smith <jason.smith@canonical.com>
22+ */
23+
24+#include "EdgeBarrierController.h"
25+#include "Decaymulator.h"
26+#include "UScreen.h"
27+
28+namespace unity {
29+namespace ui {
30+
31+struct EdgeBarrierController::Impl
32+{
33+ Impl(EdgeBarrierController *parent);
34+ ~Impl();
35+
36+ void ResizeBarrierList(std::vector<nux::Geometry> const& layout);
37+ void SetupBarriers(std::vector<nux::Geometry> const& layout);
38+
39+ void OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event);
40+
41+ std::vector<PointerBarrierWrapper::Ptr> barriers_;
42+ Decaymulator::Ptr decaymulator_;
43+ float edge_overcome_pressure_;
44+ EdgeBarrierController* parent_;
45+ std::vector<EdgeBarrierSubscriber*> subscribers_;
46+};
47+
48+EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent)
49+ : decaymulator_(Decaymulator::Ptr(new Decaymulator()))
50+ , edge_overcome_pressure_(0)
51+ , parent_(parent)
52+{
53+ UScreen *uscreen = UScreen::GetDefault();
54+
55+ auto monitors = uscreen->GetMonitors();
56+ ResizeBarrierList(monitors);
57+
58+ uscreen->changed.connect([&](int primary, std::vector<nux::Geometry>& layout) {
59+ ResizeBarrierList(layout);
60+ SetupBarriers(layout);
61+ });
62+
63+ parent_->sticky_edges.changed.connect([&](bool value) {
64+ SetupBarriers(UScreen::GetDefault()->GetMonitors());
65+ });
66+
67+ parent_->options.changed.connect([&](launcher::Options::Ptr options) {
68+ options->option_changed.connect([&]() {
69+ SetupBarriers(UScreen::GetDefault()->GetMonitors());
70+ });
71+ SetupBarriers(UScreen::GetDefault()->GetMonitors());
72+ });
73+}
74+
75+EdgeBarrierController::Impl::~Impl()
76+{
77+
78+}
79+
80+void EdgeBarrierController::Impl::ResizeBarrierList(std::vector<nux::Geometry> const& layout)
81+{
82+ size_t num_monitors = layout.size();
83+ if (barriers_.size() > num_monitors)
84+ {
85+ barriers_.resize(num_monitors);
86+ }
87+
88+ while (barriers_.size() < num_monitors)
89+ {
90+ auto barrier = PointerBarrierWrapper::Ptr(new PointerBarrierWrapper());
91+ barrier->barrier_event.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnPointerBarrierEvent));
92+ barriers_.push_back(barrier);
93+ }
94+}
95+
96+void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const& layout)
97+{
98+ bool edge_resist = parent_->options()->edge_resist();
99+
100+ size_t size = layout.size();
101+ for (size_t i = 0; i < size; i++)
102+ {
103+ auto barrier = barriers_[i];
104+ auto monitor = layout[i];
105+
106+ barrier->DestroyBarrier();
107+
108+ if (!edge_resist && (subscribers_[i] == nullptr || parent_->options()->hide_mode() == launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER))
109+ continue;
110+
111+ barrier->x1 = monitor.x;
112+ barrier->x2 = monitor.x;
113+ barrier->y1 = monitor.y;
114+ barrier->y2 = monitor.y + monitor.height;
115+ barrier->index = i;
116+
117+ barrier->threshold = parent_->options()->edge_stop_velocity();
118+ barrier->max_velocity_multiplier = parent_->options()->edge_responsiveness();
119+
120+ if (edge_resist)
121+ barrier->direction = BarrierDirection::BOTH;
122+ else
123+ barrier->direction = BarrierDirection::LEFT;
124+
125+ barrier->ConstructBarrier();
126+ }
127+
128+ float decay_responsiveness_mult = ((parent_->options()->edge_responsiveness() - 1) * .3f) + 1;
129+ decaymulator_->rate_of_decay = parent_->options()->edge_decay_rate() * decay_responsiveness_mult;
130+
131+ float overcome_responsiveness_mult = ((parent_->options()->edge_responsiveness() - 1) * 1.0f) + 1;
132+ edge_overcome_pressure_ = parent_->options()->edge_overcome_pressure() * overcome_responsiveness_mult;
133+}
134+
135+void EdgeBarrierController::Impl::OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event)
136+{
137+ int monitor = owner->index;
138+ bool process = true;
139+
140+ if ((size_t)monitor <= subscribers_.size())
141+ {
142+ auto subscriber = subscribers_[monitor];
143+ if (subscriber && subscriber->HandleBarrierEvent(owner, event))
144+ process = false;
145+ }
146+
147+ if (process && owner->x1 > 0)
148+ {
149+ decaymulator_->value = decaymulator_->value + event->velocity;
150+ if (decaymulator_->value > edge_overcome_pressure_ || !parent_->options()->edge_resist())
151+ {
152+ owner->ReleaseBarrier(event->event_id);
153+ decaymulator_->value = 0;
154+ }
155+ }
156+ else
157+ {
158+ decaymulator_->value = 0;
159+ }
160+}
161+
162+EdgeBarrierController::EdgeBarrierController()
163+ : sticky_edges(false)
164+ , pimpl(new Impl(this))
165+{
166+}
167+
168+EdgeBarrierController::~EdgeBarrierController()
169+{
170+
171+}
172+
173+void EdgeBarrierController::Subscribe(EdgeBarrierSubscriber* subscriber, int monitor)
174+{
175+ if (pimpl->subscribers_.size() <= (size_t)monitor)
176+ pimpl->subscribers_.resize(monitor + 1);
177+ pimpl->subscribers_[monitor] = subscriber;
178+
179+ pimpl->SetupBarriers(UScreen::GetDefault()->GetMonitors());
180+}
181+
182+void EdgeBarrierController::Unsubscribe(EdgeBarrierSubscriber* subscriber, int monitor)
183+{
184+ if (pimpl->subscribers_.size() < (size_t)monitor || pimpl->subscribers_[monitor] != subscriber)
185+ return;
186+ pimpl->subscribers_[monitor] = nullptr;
187+
188+ pimpl->SetupBarriers(UScreen::GetDefault()->GetMonitors());
189+}
190+
191+
192+}
193+}
194
195=== added file 'plugins/unityshell/src/EdgeBarrierController.h'
196--- plugins/unityshell/src/EdgeBarrierController.h 1970-01-01 00:00:00 +0000
197+++ plugins/unityshell/src/EdgeBarrierController.h 2012-04-04 23:48:21 +0000
198@@ -0,0 +1,57 @@
199+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
200+/*
201+ * Copyright (C) 2012 Canonical Ltd
202+ *
203+ * This program is free software: you can redistribute it and/or modify
204+ * it under the terms of the GNU General Public License version 3 as
205+ * published by the Free Software Foundation.
206+ *
207+ * This program is distributed in the hope that it will be useful,
208+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
209+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
210+ * GNU General Public License for more details.
211+ *
212+ * You should have received a copy of the GNU General Public License
213+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
214+ *
215+ * Authored by: Jason Smith <jason.smith@canonical.com>
216+ */
217+
218+#ifndef UNITY_EDGEBARRIERCONTROLLER_H
219+#define UNITY_EDGEBARRIERCONTROLLER_H
220+
221+#include "PointerBarrier.h"
222+#include "LauncherOptions.h"
223+
224+namespace unity {
225+namespace ui {
226+
227+class EdgeBarrierSubscriber
228+{
229+public:
230+ virtual bool HandleBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event) { return false; };
231+};
232+
233+class EdgeBarrierController : public sigc::trackable
234+{
235+public:
236+ typedef std::shared_ptr<EdgeBarrierController> Ptr;
237+
238+ EdgeBarrierController();
239+ ~EdgeBarrierController();
240+
241+ nux::Property<bool> sticky_edges;
242+ nux::Property<launcher::Options::Ptr> options;
243+
244+ void Subscribe(EdgeBarrierSubscriber* subscriber, int monitor);
245+ void Unsubscribe(EdgeBarrierSubscriber* subscriber, int monitor);
246+
247+private:
248+ struct Impl;
249+ Impl* pimpl;
250+};
251+
252+}
253+}
254+
255+#endif
256
257=== modified file 'plugins/unityshell/src/Launcher.cpp'
258--- plugins/unityshell/src/Launcher.cpp 2012-04-04 21:30:56 +0000
259+++ plugins/unityshell/src/Launcher.cpp 2012-04-04 23:48:21 +0000
260@@ -74,7 +74,6 @@
261 namespace unity
262 {
263 using ui::RenderArg;
264-using ui::PointerBarrierWrapper;
265 using ui::Decaymulator;
266
267 namespace launcher
268@@ -294,11 +293,6 @@
269 launcher_sheen_ = cache.FindTexture("dash_sheen", 0, 0, cb);
270 launcher_pressure_effect_ = cache.FindTexture("launcher_pressure_effect", 0, 0, cb);
271
272- _pointer_barrier = PointerBarrierWrapper::Ptr(new PointerBarrierWrapper());
273- _pointer_barrier->barrier_event.connect(sigc::mem_fun(this, &Launcher::OnPointerBarrierEvent));
274-
275- decaymulator_ = Decaymulator::Ptr(new Decaymulator());
276-
277 options.changed.connect (sigc::mem_fun (this, &Launcher::OnOptionsChanged));
278 }
279
280@@ -1598,30 +1592,12 @@
281 void Launcher::ConfigureBarrier()
282 {
283 nux::Geometry geo = GetAbsoluteGeometry();
284- _pointer_barrier->DestroyBarrier();
285-
286- if (options()->edge_resist || geo.x == 0)
287- {
288- unity::panel::Style &panel_style = panel::Style::Instance();
289-
290- _pointer_barrier->x1 = geo.x;
291- _pointer_barrier->x2 = geo.x;
292- _pointer_barrier->y1 = geo.y - panel_style.panel_height;
293- _pointer_barrier->y2 = geo.y + geo.height;
294-
295- float decay_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .3f) + 1;
296- float reveal_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .025f) + 1;
297- float overcome_responsiveness_mult = ((options()->edge_responsiveness() - 1) * 1.0f) + 1;
298- decaymulator_->rate_of_decay = options()->edge_decay_rate() * decay_responsiveness_mult;
299- _edge_overcome_pressure = options()->edge_overcome_pressure() * overcome_responsiveness_mult;
300-
301- _pointer_barrier->threshold = options()->edge_stop_velocity();
302- _pointer_barrier->max_velocity_multiplier = options()->edge_responsiveness();
303- _pointer_barrier->ConstructBarrier();
304-
305- _hide_machine->reveal_pressure = options()->edge_reveal_pressure() * reveal_responsiveness_mult;
306- _hide_machine->edge_decay_rate = options()->edge_decay_rate() * decay_responsiveness_mult;
307- }
308+
309+ float decay_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .3f) + 1;
310+ float reveal_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .025f) + 1;
311+
312+ _hide_machine->reveal_pressure = options()->edge_reveal_pressure() * reveal_responsiveness_mult;
313+ _hide_machine->edge_decay_rate = options()->edge_decay_rate() * decay_responsiveness_mult;
314 }
315
316 void Launcher::SetHideMode(LauncherHideMode hidemode)
317@@ -2416,7 +2392,7 @@
318 EnsureAnimation();
319 }
320
321-void Launcher::OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event)
322+bool Launcher::HandleBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event)
323 {
324 nux::Geometry abs_geo = GetAbsoluteGeometry();
325
326@@ -2450,19 +2426,11 @@
327 }
328 }
329
330- if (apply_to_reveal)
331- {
332- _hide_machine->AddRevealPressure(event->velocity);
333- decaymulator_->value = 0;
334- }
335- else if (abs_geo.x > 0)
336- {
337- decaymulator_->value = decaymulator_->value + event->velocity;
338- if (decaymulator_->value > _edge_overcome_pressure)
339- {
340- _pointer_barrier->ReleaseBarrier(event->event_id);
341- }
342- }
343+ if (!apply_to_reveal)
344+ return false;
345+
346+ _hide_machine->AddRevealPressure(event->velocity);
347+ return true;
348 }
349
350 bool Launcher::IsInKeyNavMode() const
351
352=== modified file 'plugins/unityshell/src/Launcher.h'
353--- plugins/unityshell/src/Launcher.h 2012-03-30 04:00:05 +0000
354+++ plugins/unityshell/src/Launcher.h 2012-04-04 23:48:21 +0000
355@@ -33,6 +33,7 @@
356 #include "BackgroundEffectHelper.h"
357 #include "DNDCollectionWindow.h"
358 #include "DndData.h"
359+#include "EdgeBarrierController.h"
360 #include "GeisAdapter.h"
361 #include "Introspectable.h"
362 #include "LauncherOptions.h"
363@@ -50,7 +51,7 @@
364 class AbstractLauncherIcon;
365 class LauncherModel;
366
367-class Launcher : public unity::debug::Introspectable, public nux::View
368+class Launcher : public unity::debug::Introspectable, public nux::View, public ui::EdgeBarrierSubscriber
369 {
370 NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View);
371 public:
372@@ -187,7 +188,7 @@
373 void OnDragUpdate(GeisAdapter::GeisDragData* data);
374 void OnDragFinish(GeisAdapter::GeisDragData* data);
375
376- void OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event);
377+ bool HandleBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event);
378
379 void OnPluginStateChanged();
380
381@@ -342,9 +343,6 @@
382
383 nux::ObjectPtr<nux::IOpenGLBaseTexture> _offscreen_drag_texture;
384
385- ui::PointerBarrierWrapper::Ptr _pointer_barrier;
386- ui::Decaymulator::Ptr decaymulator_;
387-
388 int _space_between_icons;
389 int _icon_size;
390 int _icon_image_size;
391
392=== modified file 'plugins/unityshell/src/LauncherController.cpp'
393--- plugins/unityshell/src/LauncherController.cpp 2012-04-03 01:58:52 +0000
394+++ plugins/unityshell/src/LauncherController.cpp 2012-04-04 23:48:21 +0000
395@@ -32,6 +32,7 @@
396 #include "DesktopLauncherIcon.h"
397 #include "DeviceLauncherIcon.h"
398 #include "DeviceLauncherSection.h"
399+#include "EdgeBarrierController.h"
400 #include "FavoriteStore.h"
401 #include "HudLauncherIcon.h"
402 #include "Launcher.h"
403@@ -173,6 +174,8 @@
404
405 int launcher_key_press_time_;
406
407+ ui::EdgeBarrierController::Ptr edge_barriers_;
408+
409 LauncherList launchers;
410
411 sigc::connection on_expoicon_activate_connection_;
412@@ -188,7 +191,10 @@
413 , sort_priority_(0)
414 , show_desktop_icon_(false)
415 , display_(display)
416+ , edge_barriers_(new ui::EdgeBarrierController())
417 {
418+ edge_barriers_->options = parent_->options();
419+
420 UScreen* uscreen = UScreen::GetDefault();
421 auto monitors = uscreen->GetMonitors();
422 int primary = uscreen->GetPrimaryMonitor();
423@@ -331,10 +337,16 @@
424 {
425 parent_->RemoveChild(launcher.GetPointer());
426 launcher->GetParent()->UnReference();
427+ edge_barriers_->Unsubscribe(launcher.GetPointer(), launcher->monitor);
428 }
429 }
430
431 launchers.resize(num_launchers);
432+
433+ for (size_t i = 0; i < launchers.size(); ++i)
434+ {
435+ edge_barriers_->Subscribe(launchers[i].GetPointer(), launchers[i]->monitor);
436+ }
437 }
438
439 void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors)
440
441=== modified file 'plugins/unityshell/src/PointerBarrier.cpp'
442--- plugins/unityshell/src/PointerBarrier.cpp 2012-03-27 20:47:58 +0000
443+++ plugins/unityshell/src/PointerBarrier.cpp 2012-04-04 23:48:21 +0000
444@@ -37,6 +37,7 @@
445
446 PointerBarrierWrapper::PointerBarrierWrapper()
447 {
448+ direction = BOTH;
449 last_event_ = 0;
450 last_y_ = 0;
451 last_x_ = 0;
452@@ -72,7 +73,7 @@
453 DefaultRootWindow(dpy),
454 x1, y1,
455 x2, y2,
456- 0,
457+ (int) direction,
458 threshold,
459 0,
460 NULL);
461
462=== modified file 'plugins/unityshell/src/PointerBarrier.h'
463--- plugins/unityshell/src/PointerBarrier.h 2012-02-07 07:42:12 +0000
464+++ plugins/unityshell/src/PointerBarrier.h 2012-04-04 23:48:21 +0000
465@@ -41,6 +41,15 @@
466 int event_id;
467 };
468
469+
470+// values picked to match Xfixes values
471+enum BarrierDirection
472+{
473+ BOTH = 0,
474+ LEFT = 1,
475+ RIGHT = 4,
476+};
477+
478 class PointerBarrierWrapper
479 {
480 public:
481@@ -59,6 +68,10 @@
482
483 nux::Property<float> max_velocity_multiplier;
484
485+ nux::Property<int> index;
486+
487+ nux::Property<BarrierDirection> direction;
488+
489 PointerBarrierWrapper();
490 ~PointerBarrierWrapper();
491
492
493=== modified file 'tests/autopilot/autopilot/tests/test_launcher.py'
494--- tests/autopilot/autopilot/tests/test_launcher.py 2012-04-04 21:33:39 +0000
495+++ tests/autopilot/autopilot/tests/test_launcher.py 2012-04-04 23:48:21 +0000
496@@ -635,3 +635,109 @@
497 launcher_instance.mouse_reveal_launcher()
498 self.assertThat(launcher_instance.is_showing(), Equals(False))
499 self.mouse.release(1)
500+
501+class LauncherCaptureTests(AutopilotTestCase):
502+ """Test the launchers ability to capture/not capture the mouse."""
503+
504+ screen_geo = ScreenGeometry()
505+
506+ def setHideMode(self, mode):
507+ launcher = self.launcher.get_launcher_for_monitor(0)
508+ for counter in range(10):
509+ sleep(1)
510+ if launcher.hidemode == mode:
511+ break
512+ self.assertThat(launcher.hidemode, Equals(mode),
513+ "Launcher did not enter revealed mode.")
514+
515+ def leftMostMonitor(self):
516+ x1, y1, width, height = self.screen_geo.get_monitor_geometry(0)
517+ x2, y2, width, height = self.screen_geo.get_monitor_geometry(1)
518+
519+ if x1 < x2:
520+ return 0
521+ return 1
522+
523+ def rightMostMonitor(self):
524+ return 1 - self.leftMostMonitor()
525+
526+ def setUp(self):
527+ super(LauncherCaptureTests, self).setUp()
528+ self.set_unity_option('launcher_capture_mouse', True)
529+ self.set_unity_option('launcher_hide_mode', 0)
530+ self.set_unity_option('num_launchers', 0)
531+ self.setHideMode(0)
532+
533+ def test_launcher_captures_while_sticky_and_revealed(self):
534+ """Tests that the launcher captures the mouse when moving between monitors
535+ while revealed.
536+ """
537+ if self.screen_geo.get_num_monitors() <= 1:
538+ self.skipTest("Cannot run this test with a single monitor configured.")
539+
540+ x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor())
541+ self.mouse.move(x + width / 2, y + height / 2, False)
542+ self.mouse.move(x - width / 2, y + height / 2, True, 5, .002)
543+
544+ x_fin, y_fin = self.mouse.position()
545+ # The launcher should have held the mouse a little bit
546+ self.assertThat(x_fin, GreaterThan(x - width / 2))
547+
548+ def test_launcher_not_capture_while_not_sticky_and_revealed(self):
549+ """Tests that the launcher doesn't captures the mouse when moving between monitors
550+ while revealed and stick is off.
551+ """
552+ if self.screen_geo.get_num_monitors() <= 1:
553+ self.skipTest("Cannot run this test with a single monitor configured.")
554+
555+ self.set_unity_option('launcher_capture_mouse', False)
556+
557+ x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor())
558+ self.mouse.move(x + width / 2, y + height / 2, False)
559+ self.mouse.move(x - width / 2, y + height / 2, True, 5, .002)
560+
561+ x_fin, y_fin = self.mouse.position()
562+ # The launcher should have held the mouse a little bit
563+ self.assertThat(x_fin, Equals(x - width / 2))
564+
565+ def test_launcher_not_capture_while_not_sticky_and_hidden_moving_right(self):
566+ """Tests that the launcher doesn't capture the mouse when moving between monitors
567+ while hidden and sticky is off.
568+ """
569+ if self.screen_geo.get_num_monitors() <= 1:
570+ self.skipTest("Cannot run this test with a single monitor configured.")
571+
572+ self.set_unity_option('launcher_hide_mode', 1)
573+ self.set_unity_option('launcher_capture_mouse', False)
574+
575+ self.setHideMode(1)
576+
577+ x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor())
578+ self.mouse.move(x + width / 2, y + height / 2, False)
579+ sleep(1.5)
580+ self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002)
581+
582+ x_fin, y_fin = self.mouse.position()
583+ # The launcher should have held the mouse a little bit
584+ self.assertThat(x_fin, Equals(x + width * 1.5))
585+
586+ def test_launcher_capture_while_sticky_and_hidden_moving_right(self):
587+ """Tests that the launcher captures the mouse when moving between monitors
588+ while hidden.
589+ """
590+ if self.screen_geo.get_num_monitors() <= 1:
591+ self.skipTest("Cannot run this test with a single monitor configured.")
592+
593+ self.set_unity_option('launcher_hide_mode', 1)
594+
595+ self.setHideMode(1)
596+
597+ x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor())
598+ self.mouse.move(x + width / 2, y + height / 2, False)
599+ sleep(1.5)
600+ self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002)
601+
602+ x_fin, y_fin = self.mouse.position()
603+ # The launcher should have held the mouse a little bit
604+ self.assertThat(x_fin, LessThan(x + width * 1.5))
605+
606\ No newline at end of file