Merge lp:~3v1n0/unity/fix-load-icon-crash-926658 into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Superseded
Proposed branch: lp:~3v1n0/unity/fix-load-icon-crash-926658
Merge into: lp:unity
Diff against target: 1356 lines (+613/-180)
18 files modified
UnityCore/GLibSource.cpp (+1/-2)
dash/ResultRendererTile.cpp (+26/-22)
launcher/Decaymulator.h (+1/-3)
launcher/EdgeBarrierController.cpp (+88/-46)
launcher/EdgeBarrierController.h (+8/-7)
launcher/LauncherController.cpp (+4/-5)
launcher/LauncherHideMachine.cpp (+6/-8)
launcher/LauncherHideMachine.h (+1/-1)
launcher/LauncherHoverMachine.cpp (+1/-2)
launcher/LauncherOptions.cpp (+34/-34)
launcher/LauncherOptions.h (+1/-0)
launcher/PointerBarrier.cpp (+30/-23)
launcher/PointerBarrier.h (+17/-16)
plugins/unityshell/src/unityshell.cpp (+5/-0)
plugins/unityshell/unityshell.xml.in (+8/-0)
tests/CMakeLists.txt (+16/-11)
tests/test_edge_barrier_controller.cpp (+225/-0)
tests/test_pointer_barrier.cpp (+141/-0)
To merge this branch: bzr merge lp:~3v1n0/unity/fix-load-icon-crash-926658
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+116089@code.launchpad.net

This proposal has been superseded by a proposal from 2012-07-20.

Commit message

ResultRendererTile: fix a crash if row.renderer<TextureContainer*>() is null

Description of the change

In ResultRendererTile::LoadIcon we assumed that row.renderer<TextureContainer*>() is always not null; even if this should not happen because it has already just set into ResultRendererTile::Preload it looks like that there are cases that when doing row.set_renderer(new TextureContainer()); in the subsequent row.renderer<TextureContainer*>() returns null.
The implementation of that depends on dee_model_{set,get}_tag (it's basically like doing dee_model_set_tag and dee_model_get_tag), so it seems like that is failing. I've not been able to get a failure in stress tests, btw.

So, at this point, even if it would not the best solution, it's better to add a safety check to prevent crashes.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/GLibSource.cpp'
2--- UnityCore/GLibSource.cpp 2012-07-16 11:03:32 +0000
3+++ UnityCore/GLibSource.cpp 2012-07-20 23:00:30 +0000
4@@ -18,7 +18,6 @@
5 */
6
7 #include "GLibSource.h"
8-#include <boost/lexical_cast.hpp>
9
10 namespace unity
11 {
12@@ -225,7 +224,7 @@
13 if (source_nick.empty())
14 {
15 /* If we don't have a nick, we use the source pointer string as nick. */
16- source_nick = boost::lexical_cast<std::string>(source.get());
17+ source_nick = std::to_string(reinterpret_cast<uintptr_t>(source.get()));
18 }
19
20 auto old_source_it = sources_.find(source_nick);
21
22=== modified file 'dash/ResultRendererTile.cpp'
23--- dash/ResultRendererTile.cpp 2012-06-18 02:57:23 +0000
24+++ dash/ResultRendererTile.cpp 2012-07-20 23:00:30 +0000
25@@ -21,14 +21,10 @@
26 */
27
28
29-#include <sstream> // for ostringstream
30 #include "ResultRendererTile.h"
31
32-#include <boost/algorithm/string.hpp>
33-
34 #include <pango/pango.h>
35 #include <pango/pangocairo.h>
36-#include <gdk/gdk.h>
37 #include <gtk/gtk.h>
38
39 #include <NuxCore/Logger.h>
40@@ -51,6 +47,7 @@
41 namespace
42 {
43 nux::logging::Logger logger("unity.dash.results");
44+const std::string DEFAULT_GICON = ". GThemedIcon text-x-preview";
45
46 const int FONT_SIZE = 10;
47 }
48@@ -230,7 +227,7 @@
49
50 void ResultRendererTile::Preload(Result& row)
51 {
52- if (row.renderer<TextureContainer*>() == nullptr)
53+ if (!row.renderer<TextureContainer*>())
54 {
55 row.set_renderer(new TextureContainer());
56 LoadIcon(row);
57@@ -240,17 +237,25 @@
58
59 void ResultRendererTile::Unload(Result& row)
60 {
61- TextureContainer *container = row.renderer<TextureContainer*>();
62- delete container;
63+ delete row.renderer<TextureContainer*>();
64 row.set_renderer<TextureContainer*>(nullptr);
65 }
66
67 void ResultRendererTile::LoadIcon(Result& row)
68 {
69+ auto container = row.renderer<TextureContainer*>();
70+
71+ if (!container)
72+ {
73+ LOG_ERROR(logger) << "No valid container for Result " << row.name() << " with URI "
74+ << row.uri();
75+ return;
76+ }
77+
78 Style& style = Style::Instance();
79 std::string const& icon_hint = row.icon_hint;
80-#define DEFAULT_GICON ". GThemedIcon text-x-preview"
81 std::string icon_name;
82+
83 if (G_UNLIKELY(neko))
84 {
85 int tmp1 = style.GetTileIconSize() + (rand() % 16) - 8;
86@@ -266,26 +271,25 @@
87 icon_name = !icon_hint.empty() ? icon_hint : DEFAULT_GICON;
88 }
89
90- GIcon* icon = g_icon_new_for_string(icon_name.c_str(), NULL);
91- TextureContainer* container = row.renderer<TextureContainer*>();
92-
93- IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_hint, row);
94-
95- if (g_strrstr(icon_name.c_str(), "://"))
96+ auto slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_hint, row);
97+
98+ if (icon_name.find("://") != std::string::npos)
99 {
100 container->slot_handle = IconLoader::GetDefault().LoadFromURI(icon_name, style.GetTileIconSize(), slot);
101 }
102- else if (G_IS_ICON(icon))
103- {
104- container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, style.GetTileIconSize(), slot);
105- }
106 else
107 {
108- container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, style.GetTileIconSize(), slot);
109+ glib::Object<GIcon> icon(g_icon_new_for_string(icon_name.c_str(), nullptr));
110+
111+ if (icon.IsType(G_TYPE_ICON))
112+ {
113+ container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, style.GetTileIconSize(), slot);
114+ }
115+ else
116+ {
117+ container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, style.GetTileIconSize(), slot);
118+ }
119 }
120-
121- if (icon != NULL)
122- g_object_unref(icon);
123 }
124
125 nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& texid,
126
127=== modified file 'launcher/Decaymulator.h'
128--- launcher/Decaymulator.h 2012-06-18 02:57:23 +0000
129+++ launcher/Decaymulator.h 2012-07-20 23:00:30 +0000
130@@ -31,13 +31,11 @@
131 class Decaymulator
132 {
133 public:
134- typedef std::shared_ptr<Decaymulator> Ptr;
135+ Decaymulator();
136
137 nux::Property<int> rate_of_decay;
138 nux::Property<int> value;
139
140- Decaymulator();
141-
142 private:
143 void OnValueChanged(int value);
144 bool OnDecayTimeout();
145
146=== modified file 'launcher/EdgeBarrierController.cpp'
147--- launcher/EdgeBarrierController.cpp 2012-06-28 17:21:44 +0000
148+++ launcher/EdgeBarrierController.cpp 2012-07-20 23:00:30 +0000
149@@ -20,6 +20,7 @@
150 #include "EdgeBarrierController.h"
151 #include "Decaymulator.h"
152 #include "unity-shared/UScreen.h"
153+#include "UnityCore/GLibSource.h"
154
155 namespace unity {
156 namespace ui {
157@@ -27,23 +28,38 @@
158 struct EdgeBarrierController::Impl
159 {
160 Impl(EdgeBarrierController *parent);
161- ~Impl();
162
163 void ResizeBarrierList(std::vector<nux::Geometry> const& layout);
164 void SetupBarriers(std::vector<nux::Geometry> const& layout);
165
166- void OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event);
167+ void OnPointerBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event);
168+ void BarrierRelease(PointerBarrierWrapper* owner, int event);
169+
170+ bool StickyEdgeSetter(bool const& new_val)
171+ {
172+ if (parent_->options() && new_val != parent_->options()->edge_resist())
173+ {
174+ parent_->options()->edge_resist = new_val;
175+ return true;
176+ }
177+ return false;
178+ }
179+
180+ bool StickyEdgeGetter()
181+ {
182+ return parent_->options() ? parent_->options()->edge_resist() : false;
183+ }
184
185 std::vector<PointerBarrierWrapper::Ptr> barriers_;
186- Decaymulator::Ptr decaymulator_;
187+ std::vector<EdgeBarrierSubscriber*> subscribers_;
188+ Decaymulator decaymulator_;
189+ glib::Source::UniquePtr release_timeout_;
190 float edge_overcome_pressure_;
191 EdgeBarrierController* parent_;
192- std::vector<EdgeBarrierSubscriber*> subscribers_;
193 };
194
195 EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent)
196- : decaymulator_(Decaymulator::Ptr(new Decaymulator()))
197- , edge_overcome_pressure_(0)
198+ : edge_overcome_pressure_(0)
199 , parent_(parent)
200 {
201 UScreen *uscreen = UScreen::GetDefault();
202@@ -56,9 +72,23 @@
203 SetupBarriers(layout);
204 });
205
206- parent_->sticky_edges.changed.connect([&](bool value) {
207- SetupBarriers(UScreen::GetDefault()->GetMonitors());
208- });
209+ parent_->sticky_edges.SetGetterFunction(sigc::mem_fun(this, &Impl::StickyEdgeGetter));
210+ parent_->sticky_edges.SetSetterFunction(sigc::mem_fun(this, &Impl::StickyEdgeSetter));
211+
212+/* Set this back, once lp:~3v1n0/nux/use-std-function is merged
213+ parent_->sticky_edges.SetGetterFunction([parent_] {
214+ return parent_->options() ? parent_->options()->edge_resist() : false;
215+ });
216+
217+ parent_->sticky_edges.SetSetterFunction([parent_] (bool const& new_val) {
218+ if (parent_->options() && new_val != parent_->options()->edge_resist())
219+ {
220+ parent_->options()->edge_resist = new_val;
221+ return true;
222+ }
223+ return false;
224+ });
225+ */
226
227 parent_->options.changed.connect([&](launcher::Options::Ptr options) {
228 options->option_changed.connect([&]() {
229@@ -68,14 +98,9 @@
230 });
231 }
232
233-EdgeBarrierController::Impl::~Impl()
234-{
235-
236-}
237-
238 void EdgeBarrierController::Impl::ResizeBarrierList(std::vector<nux::Geometry> const& layout)
239 {
240- size_t num_monitors = layout.size();
241+ auto num_monitors = layout.size();
242 if (barriers_.size() > num_monitors)
243 {
244 barriers_.resize(num_monitors);
245@@ -83,7 +108,7 @@
246
247 while (barriers_.size() < num_monitors)
248 {
249- auto barrier = PointerBarrierWrapper::Ptr(new PointerBarrierWrapper());
250+ auto barrier = std::make_shared<PointerBarrierWrapper>();
251 barrier->barrier_event.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnPointerBarrierEvent));
252 barriers_.push_back(barrier);
253 }
254@@ -91,10 +116,9 @@
255
256 void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const& layout)
257 {
258- bool edge_resist = parent_->options()->edge_resist();
259+ bool edge_resist = parent_->sticky_edges();
260
261- size_t size = layout.size();
262- for (size_t i = 0; i < size; i++)
263+ for (unsigned i = 0; i < layout.size(); i++)
264 {
265 auto barrier = barriers_[i];
266 auto monitor = layout[i];
267@@ -122,68 +146,86 @@
268 }
269
270 float decay_responsiveness_mult = ((parent_->options()->edge_responsiveness() - 1) * .3f) + 1;
271- decaymulator_->rate_of_decay = parent_->options()->edge_decay_rate() * decay_responsiveness_mult;
272-
273+ decaymulator_.rate_of_decay = parent_->options()->edge_decay_rate() * decay_responsiveness_mult;
274+
275 float overcome_responsiveness_mult = ((parent_->options()->edge_responsiveness() - 1) * 1.0f) + 1;
276 edge_overcome_pressure_ = parent_->options()->edge_overcome_pressure() * overcome_responsiveness_mult;
277 }
278
279-void EdgeBarrierController::Impl::OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event)
280+void EdgeBarrierController::Impl::OnPointerBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event)
281 {
282- int monitor = owner->index;
283+ unsigned int monitor = owner->index;
284 bool process = true;
285
286- if ((size_t)monitor <= subscribers_.size())
287+ if (monitor <= subscribers_.size())
288 {
289 auto subscriber = subscribers_[monitor];
290+
291 if (subscriber && subscriber->HandleBarrierEvent(owner, event))
292 process = false;
293 }
294
295- if (process && owner->x1 > 0)
296- {
297- decaymulator_->value = decaymulator_->value + event->velocity;
298- if (decaymulator_->value > edge_overcome_pressure_ || (!parent_->options()->edge_resist() && !subscribers_[monitor]))
299+ if (process && owner->released)
300+ {
301+ BarrierRelease(owner, event->event_id);
302+ }
303+ else if (process && owner->x1 > 0)
304+ {
305+ decaymulator_.value = decaymulator_.value + event->velocity;
306+
307+ if (decaymulator_.value > edge_overcome_pressure_ || (!parent_->sticky_edges() && !subscribers_[monitor]))
308 {
309- owner->ReleaseBarrier(event->event_id);
310- decaymulator_->value = 0;
311+ BarrierRelease(owner, event->event_id);
312 }
313 }
314 else
315 {
316- decaymulator_->value = 0;
317+ decaymulator_.value = 0;
318 }
319 }
320
321+void EdgeBarrierController::Impl::BarrierRelease(PointerBarrierWrapper* owner, int event)
322+{
323+ owner->ReleaseBarrier(event);
324+ owner->released = true;
325+ decaymulator_.value = 0;
326+
327+ unsigned duration = parent_->options()->edge_passed_disabled_ms;
328+ release_timeout_.reset(new glib::Timeout(duration, [owner] {
329+ owner->released = false;
330+ return false;
331+ }));
332+}
333+
334 EdgeBarrierController::EdgeBarrierController()
335- : sticky_edges(false)
336- , pimpl(new Impl(this))
337-{
338-}
339+ : pimpl(new Impl(this))
340+{}
341
342 EdgeBarrierController::~EdgeBarrierController()
343-{
344-
345-}
346-
347-void EdgeBarrierController::Subscribe(EdgeBarrierSubscriber* subscriber, int monitor)
348-{
349- if (pimpl->subscribers_.size() <= (size_t)monitor)
350+{}
351+
352+void EdgeBarrierController::Subscribe(EdgeBarrierSubscriber* subscriber, unsigned int monitor)
353+{
354+ if (pimpl->subscribers_.size() <= monitor)
355 pimpl->subscribers_.resize(monitor + 1);
356+
357 pimpl->subscribers_[monitor] = subscriber;
358-
359 pimpl->SetupBarriers(UScreen::GetDefault()->GetMonitors());
360 }
361
362-void EdgeBarrierController::Unsubscribe(EdgeBarrierSubscriber* subscriber, int monitor)
363+void EdgeBarrierController::Unsubscribe(EdgeBarrierSubscriber* subscriber, unsigned int monitor)
364 {
365- if (pimpl->subscribers_.size() < (size_t)monitor || pimpl->subscribers_[monitor] != subscriber)
366+ if (pimpl->subscribers_.size() < monitor || pimpl->subscribers_[monitor] != subscriber)
367 return;
368+
369 pimpl->subscribers_[monitor] = nullptr;
370-
371 pimpl->SetupBarriers(UScreen::GetDefault()->GetMonitors());
372 }
373
374+void EdgeBarrierController::ProcessBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event)
375+{
376+ pimpl->OnPointerBarrierEvent(owner, event);
377+}
378
379 }
380 }
381
382=== modified file 'launcher/EdgeBarrierController.h'
383--- launcher/EdgeBarrierController.h 2012-05-07 19:52:54 +0000
384+++ launcher/EdgeBarrierController.h 2012-07-20 23:00:30 +0000
385@@ -29,26 +29,27 @@
386 class EdgeBarrierSubscriber
387 {
388 public:
389- virtual bool HandleBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event) { return false; };
390+ virtual bool HandleBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event) = 0;
391 };
392
393 class EdgeBarrierController : public sigc::trackable
394 {
395 public:
396- typedef std::shared_ptr<EdgeBarrierController> Ptr;
397-
398 EdgeBarrierController();
399 ~EdgeBarrierController();
400
401- nux::Property<bool> sticky_edges;
402+ nux::RWProperty<bool> sticky_edges;
403 nux::Property<launcher::Options::Ptr> options;
404
405- void Subscribe(EdgeBarrierSubscriber* subscriber, int monitor);
406- void Unsubscribe(EdgeBarrierSubscriber* subscriber, int monitor);
407+ void Subscribe(EdgeBarrierSubscriber* subscriber, unsigned int monitor);
408+ void Unsubscribe(EdgeBarrierSubscriber* subscriber, unsigned int monitor);
409+
410+protected:
411+ void ProcessBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event);
412
413 private:
414 struct Impl;
415- Impl* pimpl;
416+ std::unique_ptr<Impl> pimpl;
417 };
418
419 }
420
421=== modified file 'launcher/LauncherController.cpp'
422--- launcher/LauncherController.cpp 2012-07-18 17:51:56 +0000
423+++ launcher/LauncherController.cpp 2012-07-20 23:00:30 +0000
424@@ -194,7 +194,7 @@
425 int launcher_key_press_time_;
426 unsigned int dbus_owner_;
427
428- ui::EdgeBarrierController::Ptr edge_barriers_;
429+ ui::EdgeBarrierController edge_barriers_;
430
431 LauncherList launchers;
432
433@@ -219,10 +219,9 @@
434 , device_section_(volume_monitor_)
435 , show_desktop_icon_(false)
436 , display_(display)
437- , edge_barriers_(new ui::EdgeBarrierController())
438 , matcher_(bamf_matcher_get_default())
439 {
440- edge_barriers_->options = parent_->options();
441+ edge_barriers_.options = parent_->options();
442
443 UScreen* uscreen = UScreen::GetDefault();
444 auto monitors = uscreen->GetMonitors();
445@@ -355,7 +354,7 @@
446 {
447 parent_->RemoveChild(launcher.GetPointer());
448 launcher->GetParent()->UnReference();
449- edge_barriers_->Unsubscribe(launcher.GetPointer(), launcher->monitor);
450+ edge_barriers_.Unsubscribe(launcher.GetPointer(), launcher->monitor);
451 }
452 }
453
454@@ -363,7 +362,7 @@
455
456 for (size_t i = 0; i < launchers.size(); ++i)
457 {
458- edge_barriers_->Subscribe(launchers[i].GetPointer(), launchers[i]->monitor);
459+ edge_barriers_.Subscribe(launchers[i].GetPointer(), launchers[i]->monitor);
460 }
461 }
462
463
464=== modified file 'launcher/LauncherHideMachine.cpp'
465--- launcher/LauncherHideMachine.cpp 2012-06-18 02:57:23 +0000
466+++ launcher/LauncherHideMachine.cpp 2012-07-20 23:00:30 +0000
467@@ -19,7 +19,6 @@
468
469 #include "LauncherHideMachine.h"
470
471-#include <boost/lexical_cast.hpp>
472 #include <NuxCore/Logger.h>
473
474 namespace unity
475@@ -35,30 +34,29 @@
476
477 LauncherHideMachine::LauncherHideMachine()
478 : reveal_progress(0)
479- , decaymulator_(new ui::Decaymulator())
480 , _mode(HIDE_NEVER)
481 , _quirks(DEFAULT)
482 , _should_hide(false)
483 , _latest_emit_should_hide(false)
484 {
485- decaymulator_->value.changed.connect([&](int value) { reveal_progress = value / static_cast<float>(reveal_pressure); });
486+ decaymulator_.value.changed.connect([&](int value) { reveal_progress = value / static_cast<float>(reveal_pressure); });
487 edge_decay_rate.changed.connect(sigc::mem_fun (this, &LauncherHideMachine::OnDecayRateChanged));
488 }
489
490 void LauncherHideMachine::OnDecayRateChanged(int value)
491 {
492- decaymulator_->rate_of_decay = value;
493+ decaymulator_.rate_of_decay = value;
494 }
495
496 void LauncherHideMachine::AddRevealPressure(int pressure)
497 {
498- decaymulator_->value = decaymulator_->value + pressure;
499+ decaymulator_.value = decaymulator_.value + pressure;
500
501- if (decaymulator_->value > reveal_pressure)
502+ if (decaymulator_.value > reveal_pressure)
503 {
504 SetQuirk(REVEAL_PRESSURE_PASS, true);
505 SetQuirk(MOUSE_MOVE_POST_REVEAL, true);
506- decaymulator_->value = 0;
507+ decaymulator_.value = 0;
508 }
509 }
510
511@@ -240,7 +238,7 @@
512 {
513 // Although I do wonder why we are returning a string representation
514 // of the enum value as an integer anyway.
515- return boost::lexical_cast<std::string>(_quirks);
516+ return std::to_string(_quirks);
517 }
518
519 } // namespace launcher
520
521=== modified file 'launcher/LauncherHideMachine.h'
522--- launcher/LauncherHideMachine.h 2012-06-18 02:57:23 +0000
523+++ launcher/LauncherHideMachine.h 2012-07-20 23:00:30 +0000
524@@ -93,7 +93,7 @@
525
526 void OnDecayRateChanged (int value);
527
528- ui::Decaymulator::Ptr decaymulator_;
529+ ui::Decaymulator decaymulator_;
530 HideMode _mode;
531 HideQuirk _quirks;
532 bool _should_hide;
533
534=== modified file 'launcher/LauncherHoverMachine.cpp'
535--- launcher/LauncherHoverMachine.cpp 2012-06-18 02:57:23 +0000
536+++ launcher/LauncherHoverMachine.cpp 2012-07-20 23:00:30 +0000
537@@ -16,7 +16,6 @@
538 *
539 * Authored by: Didier Roche <didrocks@ubuntu.com>
540 */
541-#include <boost/lexical_cast.hpp>
542
543 #include "LauncherHoverMachine.h"
544
545@@ -110,7 +109,7 @@
546 {
547 // Although I do wonder why we are returning a string representation
548 // of the enum value as an integer anyway.
549- return boost::lexical_cast<std::string>(_quirks);
550+ return std::to_string(_quirks);
551 }
552
553 } //unity namespace
554
555=== modified file 'launcher/LauncherOptions.cpp'
556--- launcher/LauncherOptions.cpp 2012-05-07 19:52:54 +0000
557+++ launcher/LauncherOptions.cpp 2012-07-20 23:00:30 +0000
558@@ -26,42 +26,42 @@
559 {
560
561 Options::Options()
562+ // defaults from XML file
563+ : hide_mode(LAUNCHER_HIDE_NEVER)
564+ , launch_animation(LAUNCH_ANIMATION_PULSE)
565+ , urgent_animation(URGENT_ANIMATION_WIGGLE)
566+ , auto_hide_animation(FADE_AND_SLIDE)
567+ , backlight_mode(BACKLIGHT_ALWAYS_ON)
568+ , reveal_trigger(RevealTrigger::EDGE)
569+ , icon_size(48)
570+ , tile_size(54)
571+ , background_alpha(0.6667)
572+ , edge_decay_rate(1500)
573+ , edge_overcome_pressure(2000)
574+ , edge_stop_velocity(6500)
575+ , edge_reveal_pressure(2000)
576+ , edge_responsiveness(2.0f)
577+ , edge_passed_disabled_ms(1000)
578+ , edge_resist(true)
579+ , show_for_all(false)
580 {
581- // defaults from XML file
582- auto_hide_animation = FADE_AND_SLIDE;
583- background_alpha = 0.6667;
584- backlight_mode = BACKLIGHT_ALWAYS_ON;
585- edge_decay_rate = 1500;
586- edge_overcome_pressure = 2000;
587- edge_responsiveness = 2.0f;
588- edge_reveal_pressure = 2000;
589- edge_stop_velocity = 6500;
590- hide_mode = LAUNCHER_HIDE_NEVER;
591- icon_size = 48;
592- launch_animation = LAUNCH_ANIMATION_PULSE;
593- reveal_trigger = RevealTrigger::EDGE;
594- tile_size = 54;
595- urgent_animation = URGENT_ANIMATION_WIGGLE;
596- edge_resist = true;
597- show_for_all = false;
598-
599- auto_hide_animation.changed.connect ([&] (AutoHideAnimation value)-> void { option_changed.emit(); });
600- background_alpha.changed.connect ([&] (float value) -> void { option_changed.emit(); });
601- backlight_mode.changed.connect ([&] (BacklightMode value) -> void { option_changed.emit(); });
602- edge_decay_rate.changed.connect ([&] (int value) -> void { option_changed.emit(); });
603- edge_overcome_pressure.changed.connect([&] (int value) -> void { option_changed.emit(); });
604- edge_responsiveness.changed.connect ([&] (float value) -> void { option_changed.emit(); });
605- edge_reveal_pressure.changed.connect ([&] (int value) -> void { option_changed.emit(); });
606- edge_stop_velocity.changed.connect ([&] (int value) -> void { option_changed.emit(); });
607- hide_mode.changed.connect ([&] (LauncherHideMode value) -> void { option_changed.emit(); });
608- icon_size.changed.connect ([&] (int value) -> void { option_changed.emit(); });
609- launch_animation.changed.connect ([&] (LaunchAnimation value) -> void { option_changed.emit(); });
610- reveal_trigger.changed.connect ([&] (RevealTrigger vallue) -> void { option_changed.emit(); });
611- tile_size.changed.connect ([&] (int value) -> void { option_changed.emit(); });
612- urgent_animation.changed.connect ([&] (UrgentAnimation value) -> void { option_changed.emit(); });
613- edge_resist.changed.connect ([&] (bool value) -> void { option_changed.emit(); });
614+ auto_hide_animation.changed.connect ([this] (AutoHideAnimation value) { option_changed.emit(); });
615+ background_alpha.changed.connect ([this] (float value) { option_changed.emit(); });
616+ backlight_mode.changed.connect ([this] (BacklightMode value) { option_changed.emit(); });
617+ edge_decay_rate.changed.connect ([this] (int value) { option_changed.emit(); });
618+ edge_overcome_pressure.changed.connect ([this] (int value) { option_changed.emit(); });
619+ edge_responsiveness.changed.connect ([this] (float value) { option_changed.emit(); });
620+ edge_reveal_pressure.changed.connect ([this] (int value) { option_changed.emit(); });
621+ edge_stop_velocity.changed.connect ([this] (int value) { option_changed.emit(); });
622+ edge_passed_disabled_ms.changed.connect([this] (unsigned value) { option_changed.emit(); });
623+ hide_mode.changed.connect ([this] (LauncherHideMode value) { option_changed.emit(); });
624+ icon_size.changed.connect ([this] (int value) { option_changed.emit(); });
625+ launch_animation.changed.connect ([this] (LaunchAnimation value) { option_changed.emit(); });
626+ reveal_trigger.changed.connect ([this] (RevealTrigger vallue) { option_changed.emit(); });
627+ tile_size.changed.connect ([this] (int value) { option_changed.emit(); });
628+ urgent_animation.changed.connect ([this] (UrgentAnimation value) { option_changed.emit(); });
629+ edge_resist.changed.connect ([this] (bool value) { option_changed.emit(); });
630 }
631-
632
633 }
634 }
635
636=== modified file 'launcher/LauncherOptions.h'
637--- launcher/LauncherOptions.h 2012-05-07 19:52:54 +0000
638+++ launcher/LauncherOptions.h 2012-07-20 23:00:30 +0000
639@@ -97,6 +97,7 @@
640 nux::Property<int> edge_stop_velocity;
641 nux::Property<int> edge_reveal_pressure;
642 nux::Property<float> edge_responsiveness;
643+ nux::Property<unsigned> edge_passed_disabled_ms;
644 nux::Property<bool> edge_resist;
645 nux::Property<bool> show_for_all;
646
647
648=== modified file 'launcher/PointerBarrier.cpp'
649--- launcher/PointerBarrier.cpp 2012-06-18 02:57:23 +0000
650+++ launcher/PointerBarrier.cpp 2012-07-20 23:00:30 +0000
651@@ -37,12 +37,12 @@
652
653 PointerBarrierWrapper::PointerBarrierWrapper()
654 : active(false)
655+ , released(false)
656 , smoothing(75)
657 , max_velocity_multiplier(1.0f)
658 , direction(BOTH)
659- , last_event_(0)
660- , last_x_(0)
661- , last_y_(0)
662+ , event_base_(0)
663+ , barrier(0)
664 , smoothing_count_(0)
665 , smoothing_accum_(0)
666 {}
667@@ -59,7 +59,8 @@
668
669 Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
670
671- XFixesQueryExtension(dpy, &event_base_, &error_base_);
672+ int error_base;
673+ XFixesQueryExtension(dpy, &event_base_, &error_base);
674
675 int maj,min;
676 XFixesQueryVersion(dpy, &maj, &min);
677@@ -68,7 +69,7 @@
678 DefaultRootWindow(dpy),
679 x1, y1,
680 x2, y2,
681- (int) direction,
682+ static_cast<int>(direction),
683 threshold,
684 0,
685 NULL);
686@@ -103,19 +104,16 @@
687
688 void PointerBarrierWrapper::ReleaseBarrier(int event_id)
689 {
690- XFixesBarrierReleasePointer (nux::GetGraphicsDisplay()->GetX11Display(), barrier, event_id);
691+ XFixesBarrierReleasePointer(nux::GetGraphicsDisplay()->GetX11Display(), barrier, event_id);
692 }
693
694-void PointerBarrierWrapper::EmitCurrentData()
695+void PointerBarrierWrapper::EmitCurrentData(int event_id, int x, int y)
696 {
697 if (smoothing_count_ <= 0)
698 return;
699
700- BarrierEvent::Ptr event (new BarrierEvent());
701- event->x = last_x_;
702- event->y = last_y_;
703- event->velocity = std::min<int> (600 * max_velocity_multiplier, smoothing_accum_ / smoothing_count_);
704- event->event_id = last_event_;
705+ int velocity = std::min<int>(600 * max_velocity_multiplier, smoothing_accum_ / smoothing_count_);
706+ auto event = std::make_shared<BarrierEvent>(x, y, velocity, event_id);
707
708 barrier_event.emit(this, event);
709
710@@ -125,31 +123,40 @@
711
712 bool PointerBarrierWrapper::HandleEvent(XEvent xevent)
713 {
714- if(xevent.type - event_base_ == XFixesBarrierNotify)
715+ if (xevent.type - event_base_ == XFixesBarrierNotify)
716 {
717- XFixesBarrierNotifyEvent *notify_event = (XFixesBarrierNotifyEvent *)&xevent;
718+ auto notify_event = reinterpret_cast<XFixesBarrierNotifyEvent*>(&xevent);
719
720 if (notify_event->barrier == barrier && notify_event->subtype == XFixesBarrierHitNotify)
721 {
722- last_x_ = notify_event->x;
723- last_y_ = notify_event->y;
724- last_event_ = notify_event->event_id;
725 smoothing_accum_ += notify_event->velocity;
726 smoothing_count_++;
727
728- if (!smoothing_timeout_)
729- {
730- auto smoothing_cb = [&] ()
731+ if (released)
732+ {
733+ /* If the barrier is released, just emit the current event without
734+ * waiting, so there won't be any delay on releasing the barrier. */
735+ smoothing_timeout_.reset();
736+ auto event = std::make_shared<BarrierEvent>(notify_event->x, notify_event->y,
737+ notify_event->velocity, notify_event->event_id);
738+ barrier_event.emit(this, event);
739+ }
740+ else if (!smoothing_timeout_)
741+ {
742+ int x = notify_event->x;
743+ int y = notify_event->y;
744+ int event = notify_event->event_id;
745+
746+ auto smoothing_cb = [&, event, x, y] ()
747 {
748- EmitCurrentData();
749+ EmitCurrentData(event, x, y);
750
751 smoothing_timeout_.reset();
752 return false;
753 };
754
755- smoothing_timeout_.reset(new glib::Timeout(smoothing(), smoothing_cb));
756+ smoothing_timeout_.reset(new glib::Timeout(smoothing, smoothing_cb));
757 }
758-
759 }
760
761 return notify_event->barrier == barrier;
762
763=== modified file 'launcher/PointerBarrier.h'
764--- launcher/PointerBarrier.h 2012-06-18 02:57:23 +0000
765+++ launcher/PointerBarrier.h 2012-07-20 23:00:30 +0000
766@@ -30,11 +30,14 @@
767 namespace ui
768 {
769
770-class BarrierEvent
771+struct BarrierEvent
772 {
773-public:
774 typedef std::shared_ptr<BarrierEvent> Ptr;
775
776+ BarrierEvent(int x_, int y_, int velocity_, int event_id_)
777+ : x(x_), y(y_), velocity(velocity_), event_id(event_id_)
778+ {}
779+
780 int x;
781 int y;
782 int velocity;
783@@ -55,6 +58,9 @@
784 public:
785 typedef std::shared_ptr<PointerBarrierWrapper> Ptr;
786
787+ PointerBarrierWrapper();
788+ virtual ~PointerBarrierWrapper();
789+
790 nux::Property<int> x1;
791 nux::Property<int> x2;
792 nux::Property<int> y1;
793@@ -63,6 +69,7 @@
794 nux::Property<int> threshold;
795
796 nux::Property<bool> active;
797+ nux::Property<bool> released;
798
799 nux::Property<int> smoothing;
800
801@@ -72,28 +79,22 @@
802
803 nux::Property<BarrierDirection> direction;
804
805- PointerBarrierWrapper();
806- ~PointerBarrierWrapper();
807-
808- void ConstructBarrier();
809- void DestroyBarrier();
810- void ReleaseBarrier(int event_id);
811+ virtual void ConstructBarrier();
812+ virtual void DestroyBarrier();
813+ virtual void ReleaseBarrier(int event_id);
814
815 sigc::signal<void, PointerBarrierWrapper*, BarrierEvent::Ptr> barrier_event;
816
817+protected:
818+ void EmitCurrentData(int event_id, int x, int y);
819+ bool HandleEvent(XEvent event);
820+
821 private:
822- void EmitCurrentData();
823- bool HandleEvent (XEvent event);
824 static bool HandleEventWrapper(XEvent event, void* data);
825
826- int last_event_;
827- int last_x_;
828- int last_y_;
829-
830 int event_base_;
831- int error_base_;
832 PointerBarrier barrier;
833-
834+
835 int smoothing_count_;
836 int smoothing_accum_;
837 glib::Source::UniquePtr smoothing_timeout_;
838
839=== modified file 'plugins/unityshell/src/unityshell.cpp'
840--- plugins/unityshell/src/unityshell.cpp 2012-07-16 11:28:24 +0000
841+++ plugins/unityshell/src/unityshell.cpp 2012-07-20 23:00:30 +0000
842@@ -337,6 +337,7 @@
843 optionSetOvercomePressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
844 optionSetDecayRateNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
845 optionSetShowMinimizedWindowsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
846+ optionSetEdgePassedDisabledMsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
847
848 optionSetNumLaunchersNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
849 optionSetLauncherCaptureMouseNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
850@@ -2894,9 +2895,13 @@
851 break;
852 case UnityshellOptions::RevealPressure:
853 launcher_options->edge_reveal_pressure = optionGetRevealPressure() * 100;
854+ break;
855 case UnityshellOptions::EdgeResponsiveness:
856 launcher_options->edge_responsiveness = optionGetEdgeResponsiveness();
857 break;
858+ case UnityshellOptions::EdgePassedDisabledMs:
859+ launcher_options->edge_passed_disabled_ms = optionGetEdgePassedDisabledMs();
860+ break;
861 default:
862 break;
863 }
864
865=== modified file 'plugins/unityshell/unityshell.xml.in'
866--- plugins/unityshell/unityshell.xml.in 2012-03-23 15:30:56 +0000
867+++ plugins/unityshell/unityshell.xml.in 2012-07-20 23:00:30 +0000
868@@ -329,6 +329,14 @@
869 <max>1000</max>
870 <precision>1</precision>
871 </option>
872+ <option name="edge_passed_disabled_ms" type="int">
873+ <_short>Duration of Sticky Edge Release after Break</_short>
874+ <_long>Sticky edges deactivated for number of milliseconds after the user breaks the barrier</_long>
875+ <default>1000</default>
876+ <min>0</min>
877+ <max>5000</max>
878+ <precision>1</precision>
879+ </option>
880 <option name="autohide_animation" type="int">
881 <_short>Hide Animation</_short>
882 <_long>Animation played when the launcher is showing or hiding</_long>
883
884=== modified file 'tests/CMakeLists.txt'
885--- tests/CMakeLists.txt 2012-07-18 23:54:43 +0000
886+++ tests/CMakeLists.txt 2012-07-20 23:00:30 +0000
887@@ -124,6 +124,7 @@
888
889 # The actual test executable (xless) - do not put anything that requires X in here
890 add_executable(test-gtest-xless
891+ test_main_xless.cpp
892 test_animator.cpp
893 test_launcher_model.cpp
894 test_glib_object.cpp
895@@ -134,25 +135,25 @@
896 test_glib_signals_utils.h
897 test_glib_source.cpp
898 test_glib_variant.cpp
899+ test_grabhandle.cpp
900 test_desktop_utilities.cpp
901- ${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp
902+ test_hud_private.cpp
903 test_indicator.cpp
904 test_indicator_appmenu.cpp
905 test_indicator_entry.cpp
906 test_indicators.cpp
907+ test_introspection.cpp
908 test_favorite_store_gsettings.cpp
909 test_favorite_store_private.cpp
910 test_home_lens.cpp
911 test_launcher_entry_remote.cpp
912+ test_pointer_barrier.cpp
913 test_previews.cpp
914 test_shortcut_model.cpp
915 test_shortcut_private.cpp
916- test_introspection.cpp
917- test_main_xless.cpp
918- test_grabhandle.cpp
919+ test_showdesktop_handler.cpp
920 test_unityshell_private.cpp
921- test_showdesktop_handler.cpp
922- test_hud_private.cpp
923+ ${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp
924 ${CMAKE_SOURCE_DIR}/launcher/AbstractLauncherIcon.cpp
925 ${CMAKE_SOURCE_DIR}/unity-shared/Animator.cpp
926 ${UNITY_SRC}/DebugDBusInterface.cpp
927@@ -164,6 +165,7 @@
928 ${CMAKE_SOURCE_DIR}/launcher/LauncherEntryRemote.cpp
929 ${CMAKE_SOURCE_DIR}/launcher/MockLauncherIcon.cpp
930 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp
931+ ${CMAKE_SOURCE_DIR}/launcher/PointerBarrier.cpp
932 ${CMAKE_SOURCE_DIR}/shortcuts/ShortcutModel.cpp
933 ${CMAKE_SOURCE_DIR}/shortcuts/ShortcutHintPrivate.cpp
934 ${CMAKE_SOURCE_DIR}/unity-shared/Introspectable.cpp
935@@ -203,23 +205,24 @@
936
937 # Tests that require X
938 add_executable(test-gtest
939+ test_main.cpp
940 test_bamflaunchericon.cpp
941- test_hud_button.cpp
942- test_hud_controller.cpp
943 test_dashview_impl.cpp
944- test_texture_cache.cpp
945- test_main.cpp
946+ test_edge_barrier_controller.cpp
947 test_launcher.cpp
948 test_device_launcher_section.cpp
949 test_lensview_impl.cpp
950+ test_hud_button.cpp
951+ test_hud_controller.cpp
952+ test_hud_view.cpp
953 test_icon_loader.cpp
954 test_im_text_entry.cpp
955- test_hud_view.cpp
956 test_keyboard_util.cpp
957 test_resultviewgrid.cpp
958 test_single_monitor_launcher_icon.cpp
959 test_switcher_controller.cpp
960 test_switcher_model.cpp
961+ test_texture_cache.cpp
962 gmockvolume.c
963 ${CMAKE_SOURCE_DIR}/dash/AbstractPlacesGroup.cpp
964 ${CMAKE_SOURCE_DIR}/dash/DashViewPrivate.cpp
965@@ -243,6 +246,7 @@
966 ${CMAKE_SOURCE_DIR}/launcher/DeviceLauncherSection.cpp
967 ${CMAKE_SOURCE_DIR}/launcher/DevicesSettings.cpp
968 ${CMAKE_SOURCE_DIR}/launcher/DndData.cpp
969+ ${CMAKE_SOURCE_DIR}/launcher/EdgeBarrierController.cpp
970 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStore.cpp
971 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStoreGSettings.cpp
972 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp
973@@ -254,6 +258,7 @@
974 ${CMAKE_SOURCE_DIR}/launcher/LauncherHoverMachine.cpp
975 ${CMAKE_SOURCE_DIR}/launcher/LauncherIcon.cpp
976 ${CMAKE_SOURCE_DIR}/launcher/LauncherModel.cpp
977+ ${CMAKE_SOURCE_DIR}/launcher/LauncherOptions.cpp
978 ${CMAKE_SOURCE_DIR}/launcher/LayoutSystem.cpp
979 ${CMAKE_SOURCE_DIR}/launcher/MockLauncherIcon.cpp
980 ${CMAKE_SOURCE_DIR}/launcher/PointerBarrier.cpp
981
982=== added file 'tests/test_edge_barrier_controller.cpp'
983--- tests/test_edge_barrier_controller.cpp 1970-01-01 00:00:00 +0000
984+++ tests/test_edge_barrier_controller.cpp 2012-07-20 23:00:30 +0000
985@@ -0,0 +1,225 @@
986+/*
987+ * Copyright 2012 Canonical Ltd.
988+ *
989+ * This program is free software: you can redistribute it and/or modify it
990+ * under the terms of the GNU General Public License version 3, as published
991+ * by the Free Software Foundation.
992+ *
993+ * This program is distributed in the hope that it will be useful, but
994+ * WITHOUT ANY WARRANTY; without even the implied warranties of
995+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
996+ * PURPOSE. See the GNU General Public License for more details.
997+ *
998+ * You should have received a copy of the GNU General Public License
999+ * version 3 along with this program. If not, see
1000+ * <http://www.gnu.org/licenses/>
1001+ *
1002+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
1003+ *
1004+ */
1005+
1006+#include <gmock/gmock.h>
1007+#include "test_utils.h"
1008+
1009+#include "EdgeBarrierController.h"
1010+#include "MultiMonitor.h"
1011+
1012+using namespace unity;
1013+using namespace unity::ui;
1014+using namespace testing;
1015+
1016+namespace
1017+{
1018+
1019+class MockPointerBarrier : public PointerBarrierWrapper
1020+{
1021+public:
1022+ MockPointerBarrier(int monitor = 0, bool released_ = false)
1023+ {
1024+ index = monitor;
1025+ x1 = 1;
1026+ released = released_;
1027+ }
1028+
1029+ MOCK_METHOD0(ConstructBarrier, void());
1030+ MOCK_METHOD0(DestroyBarrier, void());
1031+ MOCK_METHOD1(ReleaseBarrier, void(int));
1032+};
1033+
1034+class MockEdgeBarrierController : public EdgeBarrierController
1035+{
1036+public:
1037+ void ProcessBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event)
1038+ {
1039+ EdgeBarrierController::ProcessBarrierEvent(owner, event);
1040+ }
1041+};
1042+
1043+class TestBarrierSubscriber : public EdgeBarrierSubscriber
1044+{
1045+public:
1046+ TestBarrierSubscriber(bool handles = false)
1047+ : handles_(handles)
1048+ {}
1049+
1050+ bool HandleBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event)
1051+ {
1052+ return handles_;
1053+ }
1054+
1055+ bool handles_;
1056+};
1057+
1058+class TestEdgeBarrierController : public Test
1059+{
1060+public:
1061+ virtual void SetUp()
1062+ {
1063+ bc.options = std::make_shared<launcher::Options>();
1064+ bc.options()->edge_resist = true;
1065+ bc.options()->edge_passed_disabled_ms = 150;
1066+
1067+ for (int i = 0; i < max_num_monitors; ++i)
1068+ {
1069+ // By default we assume that no subscriber handles the events!!!
1070+ bc.Subscribe(&subscribers_[i], i);
1071+ }
1072+ }
1073+
1074+ BarrierEvent::Ptr MakeBarrierEvent(int id, bool breaker)
1075+ {
1076+ int velocity = breaker ? std::numeric_limits<int>::max() : bc.options()->edge_overcome_pressure() - 1;
1077+ return std::make_shared<BarrierEvent>(0, 1, velocity, id);
1078+ }
1079+
1080+ TestBarrierSubscriber subscribers_[max_num_monitors];
1081+ MockEdgeBarrierController bc;
1082+};
1083+
1084+TEST_F(TestEdgeBarrierController, Construction)
1085+{
1086+ EXPECT_TRUE(bc.sticky_edges);
1087+}
1088+
1089+TEST_F(TestEdgeBarrierController, ProcessHandledEvent)
1090+{
1091+ int monitor = 0;
1092+
1093+ TestBarrierSubscriber handling_subscriber(true);
1094+ bc.Subscribe(&handling_subscriber, monitor);
1095+
1096+ MockPointerBarrier owner(monitor);
1097+ auto breaking_barrier_event = MakeBarrierEvent(0, true);
1098+
1099+ EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0);
1100+ bc.ProcessBarrierEvent(&owner, breaking_barrier_event);
1101+}
1102+
1103+TEST_F(TestEdgeBarrierController, ProcessHandledEventOnReleasedBarrier)
1104+{
1105+ int monitor = max_num_monitors-1;
1106+
1107+ TestBarrierSubscriber handling_subscriber(true);
1108+ bc.Subscribe(&handling_subscriber, monitor);
1109+
1110+ MockPointerBarrier owner(monitor, true);
1111+ auto breaking_barrier_event = MakeBarrierEvent(0, true);
1112+
1113+ EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0);
1114+ bc.ProcessBarrierEvent(&owner, breaking_barrier_event);
1115+}
1116+
1117+TEST_F(TestEdgeBarrierController, ProcessUnHandledEventBreakingBarrier)
1118+{
1119+ int monitor = 1;
1120+
1121+ MockPointerBarrier owner(monitor);
1122+ int breaking_id = 12345;
1123+ auto breaking_barrier_event = MakeBarrierEvent(breaking_id, true);
1124+
1125+ EXPECT_CALL(owner, ReleaseBarrier(breaking_id));
1126+ bc.ProcessBarrierEvent(&owner, breaking_barrier_event);
1127+}
1128+
1129+TEST_F(TestEdgeBarrierController, ProcessUnHandledEventNotBreakingBarrier)
1130+{
1131+ int monitor = 2;
1132+
1133+ MockPointerBarrier owner(monitor);
1134+ int not_breaking_id = 54321;
1135+ auto not_breaking_barrier_event = MakeBarrierEvent(not_breaking_id, false);
1136+
1137+ EXPECT_CALL(owner, ReleaseBarrier(not_breaking_id)).Times(0);
1138+ bc.ProcessBarrierEvent(&owner, not_breaking_barrier_event);
1139+}
1140+
1141+TEST_F(TestEdgeBarrierController, ProcessUnHandledEventOnReleasedBarrier)
1142+{
1143+ int monitor = 2;
1144+
1145+ MockPointerBarrier owner(monitor, true);
1146+ int not_breaking_id = 345678;
1147+ auto not_breaking_barrier_event = MakeBarrierEvent(not_breaking_id, false);
1148+
1149+ EXPECT_CALL(owner, ReleaseBarrier(not_breaking_id));
1150+ bc.ProcessBarrierEvent(&owner, not_breaking_barrier_event);
1151+}
1152+
1153+TEST_F(TestEdgeBarrierController, BreakingEdgeTemporaryReleasesBarrier)
1154+{
1155+ MockPointerBarrier owner;
1156+
1157+ EXPECT_CALL(owner, ReleaseBarrier(1));
1158+ bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(1, true));
1159+ ASSERT_TRUE(owner.released());
1160+
1161+ Utils::WaitForTimeoutMSec(bc.options()->edge_passed_disabled_ms);
1162+ EXPECT_FALSE(owner.released());
1163+}
1164+
1165+TEST_F(TestEdgeBarrierController, BreakingEdgeTemporaryReleasesBarrierForNotHandledEvents)
1166+{
1167+ MockPointerBarrier owner;
1168+ int monitor = 0;
1169+ subscribers_[monitor].handles_ = false;
1170+
1171+ EXPECT_CALL(owner, ReleaseBarrier(5));
1172+ bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(5, true));
1173+ ASSERT_TRUE(owner.released());
1174+
1175+ subscribers_[monitor].handles_ = false;
1176+ EXPECT_CALL(owner, ReleaseBarrier(6));
1177+ bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(6, false));
1178+}
1179+
1180+TEST_F(TestEdgeBarrierController, BreakingEdgeDontReleasesBarrierForHandledEvents)
1181+{
1182+ MockPointerBarrier owner;
1183+ int monitor = 0;
1184+ subscribers_[monitor].handles_ = false;
1185+
1186+ EXPECT_CALL(owner, ReleaseBarrier(5));
1187+ bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(5, true));
1188+ ASSERT_TRUE(owner.released());
1189+
1190+ subscribers_[monitor].handles_ = true;
1191+ EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0);
1192+ bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(6, true));
1193+}
1194+
1195+TEST_F(TestEdgeBarrierController, StickyEdgePropertyProxiesLauncherOption)
1196+{
1197+ bc.options()->edge_resist = false;
1198+ EXPECT_FALSE(bc.sticky_edges());
1199+
1200+ bc.options()->edge_resist = true;
1201+ EXPECT_TRUE(bc.sticky_edges());
1202+
1203+ bc.sticky_edges = false;
1204+ EXPECT_FALSE(bc.options()->edge_resist());
1205+
1206+ bc.sticky_edges = true;
1207+ EXPECT_TRUE(bc.options()->edge_resist());
1208+}
1209+
1210+}
1211
1212=== added file 'tests/test_pointer_barrier.cpp'
1213--- tests/test_pointer_barrier.cpp 1970-01-01 00:00:00 +0000
1214+++ tests/test_pointer_barrier.cpp 2012-07-20 23:00:30 +0000
1215@@ -0,0 +1,141 @@
1216+/*
1217+ * Copyright 2012 Canonical Ltd.
1218+ *
1219+ * This program is free software: you can redistribute it and/or modify it
1220+ * under the terms of the GNU General Public License version 3, as published
1221+ * by the Free Software Foundation.
1222+ *
1223+ * This program is distributed in the hope that it will be useful, but
1224+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1225+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
1226+ * PURPOSE. See the GNU General Public License for more details.
1227+ *
1228+ * You should have received a copy of the GNU General Public License
1229+ * version 3 along with this program. If not, see
1230+ * <http://www.gnu.org/licenses/>
1231+ *
1232+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
1233+ *
1234+ */
1235+
1236+#include <gtest/gtest.h>
1237+#include <limits>
1238+
1239+#include "test_utils.h"
1240+#include "PointerBarrier.h"
1241+
1242+using namespace unity::ui;
1243+
1244+namespace
1245+{
1246+
1247+class MockPointerBarrier : public PointerBarrierWrapper
1248+{
1249+public:
1250+ bool HandleEvent(XEvent ev) { return PointerBarrierWrapper::HandleEvent(ev); }
1251+};
1252+
1253+TEST(TestPointerBarrier, Construction)
1254+{
1255+ PointerBarrierWrapper pb;
1256+
1257+ EXPECT_EQ(pb.active, false);
1258+ EXPECT_EQ(pb.released, false);
1259+ EXPECT_EQ(pb.smoothing, 75);
1260+ EXPECT_EQ(pb.max_velocity_multiplier, 1.0f);
1261+ EXPECT_EQ(pb.direction, BOTH);
1262+}
1263+
1264+TEST(TestPointerBarrier, EventConstruction)
1265+{
1266+ BarrierEvent bev(1, 2, 3, 4);
1267+ EXPECT_EQ(bev.x, 1);
1268+ EXPECT_EQ(bev.y, 2);
1269+ EXPECT_EQ(bev.velocity, 3);
1270+ EXPECT_EQ(bev.event_id, 4);
1271+}
1272+
1273+TEST(TestPointerBarrier, HandleInvalidEvents)
1274+{
1275+ MockPointerBarrier pb;
1276+ XFixesBarrierNotifyEvent ev;
1277+ auto xev = reinterpret_cast<XEvent*>(&ev);
1278+
1279+ ev.type = XFixesBarrierNotify + 1;
1280+ EXPECT_FALSE(pb.HandleEvent(*xev));
1281+
1282+ ev.type = XFixesBarrierNotify;
1283+ ev.subtype = XFixesBarrierHitNotify + 1;
1284+ ev.barrier = 1;
1285+ EXPECT_FALSE(pb.HandleEvent(*xev));
1286+
1287+ ev.barrier = 0;
1288+ EXPECT_TRUE(pb.HandleEvent(*xev));
1289+}
1290+
1291+TEST(TestPointerBarrier, HandleHitNotifyEvents)
1292+{
1293+ MockPointerBarrier pb;
1294+ XFixesBarrierNotifyEvent ev;
1295+ auto xev = reinterpret_cast<XEvent*>(&ev);
1296+
1297+ ev.type = XFixesBarrierNotify;
1298+ ev.subtype = XFixesBarrierHitNotify;
1299+ ev.barrier = 0;
1300+ ev.event_id = 0xdeadbeef;
1301+ ev.x = 555;
1302+ ev.y = 333;
1303+ ev.velocity = std::numeric_limits<int>::max();
1304+
1305+ bool got_event = false;
1306+
1307+ pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
1308+ got_event = true;
1309+
1310+ EXPECT_EQ(pbw, &pb);
1311+ EXPECT_EQ(bev->x, ev.x);
1312+ EXPECT_EQ(bev->y, ev.y);
1313+ EXPECT_EQ(bev->velocity, 600 * pb.max_velocity_multiplier);
1314+ EXPECT_EQ(bev->event_id, ev.event_id);
1315+ });
1316+
1317+ EXPECT_TRUE(pb.HandleEvent(*xev));
1318+ EXPECT_FALSE(got_event);
1319+
1320+ Utils::WaitForTimeoutMSec(pb.smoothing());
1321+
1322+ EXPECT_TRUE(got_event);
1323+}
1324+
1325+TEST(TestPointerBarrier, HandleHitNotifyReleasedEvents)
1326+{
1327+ MockPointerBarrier pb;
1328+ XFixesBarrierNotifyEvent ev;
1329+ auto xev = reinterpret_cast<XEvent*>(&ev);
1330+
1331+ ev.type = XFixesBarrierNotify;
1332+ ev.subtype = XFixesBarrierHitNotify;
1333+ ev.barrier = 0;
1334+ ev.event_id = 0xabba;
1335+ ev.x = 3333;
1336+ ev.y = 5555;
1337+ ev.velocity = std::numeric_limits<int>::max();
1338+
1339+ bool got_event = false;
1340+
1341+ pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
1342+ got_event = true;
1343+
1344+ EXPECT_EQ(pbw, &pb);
1345+ EXPECT_EQ(bev->x, ev.x);
1346+ EXPECT_EQ(bev->y, ev.y);
1347+ EXPECT_EQ(bev->velocity, ev.velocity);
1348+ EXPECT_EQ(bev->event_id, ev.event_id);
1349+ });
1350+
1351+ pb.released = true;
1352+ EXPECT_TRUE(pb.HandleEvent(*xev));
1353+ EXPECT_TRUE(got_event);
1354+}
1355+
1356+}