Merge lp:~azzar1/unity/fix-1035301 into lp:unity

Proposed by Andrea Azzarone
Status: Merged
Approved by: Andrea Azzarone
Approved revision: no longer in the source branch.
Merged at revision: 2929
Proposed branch: lp:~azzar1/unity/fix-1035301
Merge into: lp:unity
Diff against target: 1934 lines (+1075/-316)
31 files modified
launcher/AbstractLauncherIcon.h (+1/-0)
launcher/CMakeLists.txt (+4/-1)
launcher/DNDCollectionWindow.cpp (+0/-99)
launcher/DNDCollectionWindow.h (+0/-63)
launcher/Launcher.cpp (+86/-121)
launcher/Launcher.h (+7/-8)
launcher/LauncherController.cpp (+45/-4)
launcher/LauncherController.h (+2/-1)
launcher/LauncherControllerPrivate.h (+8/-1)
launcher/LauncherIcon.cpp (+2/-0)
launcher/StandaloneLauncher.cpp (+2/-2)
launcher/XdndCollectionWindow.h (+51/-0)
launcher/XdndCollectionWindowImp.cpp (+112/-0)
launcher/XdndCollectionWindowImp.h (+44/-0)
launcher/XdndManager.h (+43/-0)
launcher/XdndManagerImp.cpp (+98/-0)
launcher/XdndManagerImp.h (+54/-0)
launcher/XdndStartStopNotifier.cpp (+27/-0)
launcher/XdndStartStopNotifier.h (+41/-0)
launcher/XdndStartStopNotifierImp.cpp (+77/-0)
launcher/XdndStartStopNotifierImp.h (+47/-0)
plugins/unityshell/src/unitya11ytests.cpp (+1/-1)
plugins/unityshell/src/unityshell.cpp (+9/-1)
tests/CMakeLists.txt (+2/-0)
tests/test_launcher.cpp (+4/-9)
tests/test_launcher_controller.cpp (+56/-0)
tests/test_xdnd_manager_imp.cpp (+130/-0)
tests/test_xdnd_start_stop_notifier_imp.cpp (+107/-0)
unity-shared/UScreen.cpp (+7/-0)
unity-shared/UScreen.h (+1/-0)
unity-standalone/StandaloneUnity.cpp (+7/-5)
To merge this branch: bzr merge lp:~azzar1/unity/fix-1035301
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Brandon Schaefer (community) Approve
Review via email: mp+134533@code.launchpad.net

Commit message

Refactor xdnd launcher code.

Description of the change

== Problem ==
Dash, Multi-monitor - When Launcher is set to auto-hide, and the user starts dragging a item, only the Launcher on the monitor which currently contains the dragged item should reveal.

== Fix ==
Move xdnd launcher code from Launcher.cpp to different classes/files:
# XdndStartStopNotifier*
# XdndCollectionWindow*
# XdndManager*

== Test ==
Unit test added.

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

Overall I'm up for this new implementation... Few comments though:

603+Controller::Impl::Impl(Controller* parent, XdndManager::Ptr xdnd_manager)

 const& ? :)

xdnd_manager_->dnd_started.connect([this](std::string const& data, int monitor)

And other lambdas... Since they're quite long, mabye it's better to put them into methods.

806 +class XdndCollectionWindow : boost::noncopyable {

new line for {

820 +#endif
821 \ No newline at end of file

Add \n ;)

864 + SetGeometry(wm.GetScreenGeometry());

Shouldn't you update this value when the screen geometry changes?

971 + void Collect() /*override*/;
972 + void Deactivate() /*override*/;

I think you can re-enable them since now we use gcc-4.7 in jenkins too.

884 + auto display = nux::GetGraphicsDisplay()->GetX11Display();

You can check for this value only if window_id is the target one, isn't it?

900 + std::vector<std::string> data;
901 + for (auto mime : mimes)
902 + data.push_back(mime);

Can't be happen that std::list<char>

1082 + if (valid_dnd_in_progress_) {

Fix indentation

1096 + char target[] = "text/uri-list";

Adding a global const for this?

There's some commented code in TestXdndManager.SignalDndStarted, do you want to clean it up?

Revision history for this message
Andrea Azzarone (azzar1) wrote :

Ok thank you for the review :) Just one comment:

> 900 + std::vector<std::string> data;
> 901 + for (auto mime : mimes)
> 902 + data.push_back(mime);

> Can't be happen that std::list<char>

What? :)

Revision history for this message
Andrea Azzarone (azzar1) wrote :

>
> 1096 + char target[] = "text/uri-list";
>

No we can't. Because nux::...::GetDndData accept a char* not a const char*.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

> > Can't be happen that std::list<char>
>
> What? :)

Contains a nullptr?

> No we can't. Because nux::...::GetDndData accept a char* not a const char*.

Ok, we need to fix the API then.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> > > Can't be happen that std::list<char>
> >
> > What? :)
>
> Contains a nullptr?

Hmmm, it should not happen but it's better to check for null.

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

784 + controller.reset(new launcher::Controller(xdnd_manager));

Could we do a make_shared?

883 + SetBackgroundColor(nux::Color(0x00000000));

Could you make that nux::color::Transparent?

884 + SetOpacity(0.0f);

Do we need to set this if it is already transparent?

Revision history for this message
Andrea Azzarone (azzar1) wrote :

>
> 884 + SetOpacity(0.0f);
>
> Do we need to set this if it is already transparent?

Yeah there was a nvidia bug few month ago. Can't remember the bug number.

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Test pass now :). Looks good code wise, and works! +1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'launcher/AbstractLauncherIcon.h'
2--- launcher/AbstractLauncherIcon.h 2012-11-15 17:56:23 +0000
3+++ launcher/AbstractLauncherIcon.h 2012-11-24 14:30:27 +0000
4@@ -103,6 +103,7 @@
5 RUNNING,
6 URGENT,
7 PRESENTED,
8+ UNFOLDED,
9 STARTING,
10 SHIMMER,
11 CENTER_SAVED,
12
13=== modified file 'launcher/CMakeLists.txt'
14--- launcher/CMakeLists.txt 2012-11-15 18:44:55 +0000
15+++ launcher/CMakeLists.txt 2012-11-24 14:30:27 +0000
16@@ -33,7 +33,6 @@
17 ApplicationLauncherIcon.cpp
18 BFBLauncherIcon.cpp
19 CairoBaseWindow.cpp
20- DNDCollectionWindow.cpp
21 Decaymulator.cpp
22 DesktopLauncherIcon.cpp
23 DeviceLauncherSection.cpp
24@@ -73,6 +72,10 @@
25 VolumeImp.cpp
26 VolumeLauncherIcon.cpp
27 VolumeMonitorWrapper.cpp
28+ XdndCollectionWindowImp.cpp
29+ XdndManagerImp.cpp
30+ XdndStartStopNotifier.cpp
31+ XdndStartStopNotifierImp.cpp
32 )
33
34 if (ENABLE_X_SUPPORT)
35
36=== removed file 'launcher/DNDCollectionWindow.cpp'
37--- launcher/DNDCollectionWindow.cpp 2012-10-11 01:44:15 +0000
38+++ launcher/DNDCollectionWindow.cpp 1970-01-01 00:00:00 +0000
39@@ -1,99 +0,0 @@
40-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
41-/*
42-* Copyright (C) 2011 Canonical Ltd
43-*
44-* This program is free software: you can redistribute it and/or modify
45-* it under the terms of the GNU General Public License version 3 as
46-* published by the Free Software Foundation.
47-*
48-* This program is distributed in the hope that it will be useful,
49-* but WITHOUT ANY WARRANTY; without even the implied warranty of
50-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51-* GNU General Public License for more details.
52-*
53-* You should have received a copy of the GNU General Public License
54-* along with this program. If not, see <http://www.gnu.org/licenses/>.
55-*
56-* Authored by: Andrea Azzarone <azzaronea@gmail.com>
57-*/
58-
59-#include "DNDCollectionWindow.h"
60-
61-#include "unity-shared/WindowManager.h"
62-
63-namespace unity {
64-
65-NUX_IMPLEMENT_OBJECT_TYPE(DNDCollectionWindow);
66-
67-DNDCollectionWindow::DNDCollectionWindow()
68- : nux::BaseWindow("")
69- , display(NULL)
70-{
71- // Make it invisible...
72- SetBackgroundColor(nux::Color(0x00000000));
73- SetOpacity(0.0f);
74- // ... and as big as the whole screen.
75- WindowManager& wm = WindowManager::Default();
76- SetGeometry(wm.GetScreenGeometry());
77-
78- ShowWindow(true);
79- PushToBack();
80- // Hack to create the X Window as soon as possible.
81- EnableInputWindow(true, "DNDCollectionWindow");
82- EnableInputWindow(false, "DNDCollectionWindow");
83- SetDndEnabled(false, true);
84-
85- wm.window_moved.connect(sigc::mem_fun(this, &DNDCollectionWindow::OnWindowMoved));
86-}
87-
88-DNDCollectionWindow::~DNDCollectionWindow()
89-{
90- for (auto it : mimes_)
91- g_free(it);
92-}
93-
94-/**
95- * EnableInputWindow doesn't show the window immediately.
96- * Since nux::EnableInputWindow uses XMoveResizeWindow the best way to know if
97- * the X Window is really on/off screen is receiving WindowManager::window_moved
98- * signal. Please don't hate me!
99- **/
100-void DNDCollectionWindow::OnWindowMoved(Window window_id)
101-{
102- if (window_id == GetInputWindowId() && display() != NULL)
103- {
104- // Create a fake mouse move because sometimes an extra one is required.
105- XWarpPointer(display(), None, None, 0, 0, 0, 0, 0, 0);
106- XFlush(display());
107- }
108-}
109-
110-void DNDCollectionWindow::Collect()
111-{
112- // Using PushToFront we're sure that the window is shown over the panel window,
113- // the launcher window and the dash window. Don't forget to call PushToBack as
114- // soon as possible.
115- PushToFront();
116- EnableInputWindow(true, "DndCollectionWindow");
117-}
118-
119-void DNDCollectionWindow::ProcessDndMove(int x, int y, std::list<char*> mimes)
120-{
121- // Hide the window as soon as possible.
122- PushToBack();
123- EnableInputWindow(false, "DNDCollectionWindow");
124-
125- // Free mimes_ before fill it again.
126- for (auto it : mimes_)
127- g_free(it);
128- mimes_.clear();
129-
130- // Duplicate the list.
131- for (auto it : mimes)
132- mimes_.push_back(g_strdup(it));
133-
134- // Emit the collected signal.
135- collected.emit(mimes_);
136-}
137-
138-} // namespace unity
139
140=== removed file 'launcher/DNDCollectionWindow.h'
141--- launcher/DNDCollectionWindow.h 2012-10-11 01:44:15 +0000
142+++ launcher/DNDCollectionWindow.h 1970-01-01 00:00:00 +0000
143@@ -1,63 +0,0 @@
144-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
145-/*
146-* Copyright (C) 2011 Canonical Ltd
147-*
148-* This program is free software: you can redistribute it and/or modify
149-* it under the terms of the GNU General Public License version 3 as
150-* published by the Free Software Foundation.
151-*
152-* This program is distributed in the hope that it will be useful,
153-* but WITHOUT ANY WARRANTY; without even the implied warranty of
154-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155-* GNU General Public License for more details.
156-*
157-* You should have received a copy of the GNU General Public License
158-* along with this program. If not, see <http://www.gnu.org/licenses/>.
159-*
160-* Authored by: Andrea Azzarone <azzaronea@gmail.com>
161-*/
162-
163-#ifndef DNDCOLLECTIONWINDOW_H
164-#define DNDCOLLECTIONWINDOW_H
165-
166-#include <list>
167-
168-#include <Nux/Nux.h>
169-#include <Nux/BaseWindow.h>
170-#include <sigc++/sigc++.h>
171-
172-namespace unity {
173-
174-/**
175- * DNDCollectionWindow makes it possible to collect drag and drop (dnd) data as
176- * soon as dnd starts and not when the mouse pointer enter the x window.
177- **/
178-
179-class DNDCollectionWindow : public nux::BaseWindow
180-{
181-NUX_DECLARE_OBJECT_TYPE(DNDCollectionWindow, nux::BaseWindow);
182-
183-// Methods
184-public:
185- DNDCollectionWindow();
186- ~DNDCollectionWindow();
187-
188- void Collect();
189-
190-private:
191- void ProcessDndMove(int x, int y, std::list<char*> mimes);
192- void OnWindowMoved(Window window_id);
193-
194-// Members
195-public:
196- nux::Property<Display*> display;
197-
198- sigc::signal<void, const std::list<char*>&> collected;
199-
200-private:
201- std::list<char*> mimes_;
202-};
203-
204-} // namespace unity
205-
206-#endif // DNDCOLLECTIONWINDOW_H
207
208=== modified file 'launcher/Launcher.cpp'
209--- launcher/Launcher.cpp 2012-11-16 15:58:49 +0000
210+++ launcher/Launcher.cpp 2012-11-24 14:30:27 +0000
211@@ -91,7 +91,6 @@
212 const int MOUSE_DEADZONE = 15;
213 const float DRAG_OUT_PIXELS = 300.0f;
214
215-const std::string DND_CHECK_TIMEOUT = "dnd-check-timeout";
216 const std::string START_DRAGICON_TIMEOUT = "start-dragicon-timeout";
217 const std::string SCROLL_TIMEOUT = "scroll-timeout";
218 const std::string ANIMATION_IDLE = "animation-idle";
219@@ -103,7 +102,6 @@
220 const int Launcher::Launcher::ANIM_DURATION_SHORT = 125;
221
222 Launcher::Launcher(nux::BaseWindow* parent,
223- nux::ObjectPtr<DNDCollectionWindow> const& collection_window,
224 NUX_FILE_LINE_DECL)
225 : View(NUX_FILE_LINE_PARAM)
226 #ifdef USE_X11
227@@ -145,14 +143,11 @@
228 , _drag_out_delta_x(0.0f)
229 , _drag_gesture_ongoing(false)
230 , _last_reveal_progress(0.0f)
231- , _collection_window(collection_window)
232 , _selection_atom(0)
233 , _background_color(nux::color::DimGray)
234 {
235 m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION);
236
237- _collection_window->collected.connect(sigc::mem_fun(this, &Launcher::OnDNDDataCollected));
238-
239 bg_effect_helper_.owner = this;
240 bg_effect_helper_.enabled = false;
241
242@@ -180,18 +175,12 @@
243 ql_manager.quicklist_closed.connect(sigc::mem_fun(this, &Launcher::RecvQuicklistClosed));
244
245 WindowManager& wm = WindowManager::Default();
246- wm.window_mapped.connect(sigc::hide(sigc::mem_fun(this, &Launcher::DndTimeoutSetup)));
247- wm.window_unmapped.connect(sigc::hide(sigc::mem_fun(this, &Launcher::DndTimeoutSetup)));
248 wm.initiate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
249 wm.initiate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
250 wm.terminate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
251 wm.terminate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
252 wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &Launcher::EnsureAnimation));
253
254-#ifdef USE_X11
255- display.changed.connect(sigc::mem_fun(this, &Launcher::OnDisplayChanged));
256-#endif
257-
258 // 0 out timers to avoid wonky startups
259 for (int i = 0; i < TIME_LAST; ++i)
260 {
261@@ -227,11 +216,6 @@
262 return "Launcher";
263 }
264
265-void Launcher::OnDisplayChanged(Display* display)
266-{
267- _collection_window->display = display;
268-}
269-
270 #ifdef NUX_GESTURES_SUPPORT
271 void Launcher::OnDragStart(const nux::GestureEvent &event)
272 {
273@@ -399,6 +383,10 @@
274 if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
275 return true;
276
277+ time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::UNFOLDED);
278+ if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
279+ return true;
280+
281 time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::SHIMMER);
282 if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_LONG)
283 return true;
284@@ -552,6 +540,18 @@
285 return 1.0f - result;
286 }
287
288+float Launcher::IconUnfoldProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const
289+{
290+ struct timespec icon_unfold_time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::UNFOLDED);
291+ int ms = unity::TimeUtil::TimeDelta(&current, &icon_unfold_time);
292+ float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f);
293+
294+ if (icon->GetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED))
295+ return result;
296+ else
297+ return 1.0f - result;
298+}
299+
300 float Launcher::IconUrgentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const
301 {
302 struct timespec urgent_time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::URGENT);
303@@ -919,13 +919,14 @@
304
305 // goes for 0.0f when fully unfolded, to 1.0f folded
306 float folding_progress = CLAMP((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
307- float present_progress = IconPresentProgress(icon, current);
308+ float unfold_progress = IconUnfoldProgress(icon, current);
309
310- folding_progress *= 1.0f - present_progress;
311+ folding_progress *= 1.0f - unfold_progress;
312
313 float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress);
314 float icon_hide_offset = autohide_offset;
315
316+ float present_progress = IconPresentProgress(icon, current);
317 icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency());
318
319 // icon is crossing threshold, start folding
320@@ -1017,8 +1018,8 @@
321 // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
322 float magic_constant = 1.3f;
323
324- float present_progress = IconPresentProgress(*it, current);
325- folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress);
326+ float unfold_progress = IconUnfoldProgress(*it, current);
327+ folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress);
328 }
329
330 if (sum - _space_between_icons <= launcher_height)
331@@ -1366,59 +1367,6 @@
332 return _mouse_position.y;
333 }
334
335-bool Launcher::OnUpdateDragManagerTimeout()
336-{
337-#ifdef USE_X11
338- if (!display())
339- return false;
340-
341- if (!_selection_atom)
342- _selection_atom = XInternAtom(display(), "XdndSelection", false);
343-
344- Window drag_owner = XGetSelectionOwner(display(), _selection_atom);
345-
346- // evil hack because Qt does not release the seelction owner on drag finished
347- Window root_r, child_r;
348- int root_x_r, root_y_r, win_x_r, win_y_r;
349- unsigned int mask;
350- XQueryPointer(display(), DefaultRootWindow(display()), &root_r, &child_r, &root_x_r, &root_y_r, &win_x_r, &win_y_r, &mask);
351-
352- if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
353- {
354- if (_data_checked == false)
355- {
356- _data_checked = true;
357- _collection_window->Collect();
358- }
359-
360- return true;
361- }
362-
363- _data_checked = false;
364- _collection_window->PushToBack();
365- _collection_window->EnableInputWindow(false, "DNDCollectionWindow");
366-
367- if (IsOverlayOpen() && !_hovered)
368- DesaturateIcons();
369-
370- DndReset();
371- _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
372- _hide_machine.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, false);
373-#endif
374- return false;
375-}
376-
377-void Launcher::DndTimeoutSetup()
378-{
379-#ifdef USE_X11
380- if (sources_.GetSource(DND_CHECK_TIMEOUT))
381- return;
382-
383- auto cb_func = sigc::mem_fun(this, &Launcher::OnUpdateDragManagerTimeout);
384- sources_.AddTimeout(200, cb_func, DND_CHECK_TIMEOUT);
385-#endif
386-}
387-
388 void Launcher::OnPluginStateChanged()
389 {
390 WindowManager& wm = WindowManager::Default();
391@@ -2566,53 +2514,6 @@
392 return (boost::algorithm::ends_with(uri, ".desktop") || uri.find("device://") == 0);
393 }
394
395-void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
396-{
397-#ifdef USE_X11
398- _dnd_data.Reset();
399-
400- const std::string uri_list = "text/uri-list";
401- auto& display = nux::GetWindowThread()->GetGraphicsDisplay();
402-
403- for (auto const& mime : mimes)
404- {
405- if (mime != uri_list)
406- continue;
407-
408- _dnd_data.Fill(display.GetDndData(const_cast<char*>(uri_list.c_str())));
409- break;
410- }
411-
412- _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
413-
414- auto const& uris = _dnd_data.Uris();
415- if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
416- {return DndIsSpecialRequest(uri);}) != uris.end())
417- {
418- _steal_drag = true;
419-
420- if (IsOverlayOpen())
421- SaturateIcons();
422- }
423- else
424- {
425- for (auto const& it : *_model)
426- {
427- if (it->ShouldHighlightOnDrag(_dnd_data))
428- {
429- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false);
430- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, true);
431- }
432- else
433- {
434- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, true);
435- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, false);
436- }
437- }
438- }
439-#endif
440-}
441-
442 void Launcher::ProcessDndEnter()
443 {
444 #ifdef USE_X11
445@@ -2648,7 +2549,7 @@
446 it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, is_overlay_open && !_hovered);
447 }
448
449- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, false);
450+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false);
451 }
452
453 DndHoveredIconReset();
454@@ -2873,5 +2774,69 @@
455 return _launcher_drag_delta;
456 }
457
458+void Launcher::DndStarted(std::string const& data)
459+{
460+#ifdef USE_X11
461+ SetDndQuirk();
462+
463+ _dnd_data.Fill(data.c_str());
464+
465+ auto const& uris = _dnd_data.Uris();
466+ if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
467+ {return DndIsSpecialRequest(uri);}) != uris.end())
468+ {
469+ _steal_drag = true;
470+
471+ if (IsOverlayOpen())
472+ SaturateIcons();
473+ }
474+ else
475+ {
476+ for (auto const& it : *_model)
477+ {
478+ if (it->ShouldHighlightOnDrag(_dnd_data))
479+ {
480+ it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false);
481+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, true);
482+ }
483+ else
484+ {
485+ it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, true);
486+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false);
487+ }
488+ }
489+ }
490+#endif
491+}
492+
493+void Launcher::DndFinished()
494+{
495+#ifdef USE_X11
496+ UnsetDndQuirk();
497+
498+ _data_checked = false;
499+
500+ if (IsOverlayOpen() && !_hovered)
501+ DesaturateIcons();
502+
503+ DndReset();
504+#endif
505+}
506+
507+void Launcher::SetDndQuirk()
508+{
509+#ifdef USE_X11
510+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
511+#endif
512+}
513+
514+void Launcher::UnsetDndQuirk()
515+{
516+#ifdef USE_X11
517+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
518+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
519+#endif
520+}
521+
522 } // namespace launcher
523 } // namespace unity
524
525=== modified file 'launcher/Launcher.h'
526--- launcher/Launcher.h 2012-11-13 22:39:49 +0000
527+++ launcher/Launcher.h 2012-11-24 14:30:27 +0000
528@@ -32,7 +32,6 @@
529 #include "unity-shared/AbstractIconRenderer.h"
530 #include "unity-shared/BackgroundEffectHelper.h"
531 #include "DevicesSettings.h"
532-#include "DNDCollectionWindow.h"
533 #include "DndData.h"
534 #include "unity-shared/Introspectable.h"
535 #include "LauncherModel.h"
536@@ -66,7 +65,7 @@
537 NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View);
538 public:
539
540- Launcher(nux::BaseWindow* parent, nux::ObjectPtr<DNDCollectionWindow> const& collection_window, NUX_FILE_LINE_PROTO);
541+ Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_PROTO);
542
543 nux::Property<Display*> display;
544 nux::Property<int> monitor;
545@@ -127,6 +126,11 @@
546 int GetDragDelta() const;
547 void SetHover(bool hovered);
548
549+ void DndStarted(std::string const& mimes);
550+ void DndFinished();
551+ void SetDndQuirk();
552+ void UnsetDndQuirk();
553+
554 sigc::signal<void, std::string const&, AbstractLauncherIcon::Ptr const&> add_request;
555 sigc::signal<void, AbstractLauncherIcon::Ptr const&> remove_request;
556 sigc::signal<void> selection_change;
557@@ -213,7 +217,6 @@
558 bool StrutHack();
559 bool StartIconDragTimeout(int x, int y);
560 bool OnScrollTimeout();
561- bool OnUpdateDragManagerTimeout();
562
563 void SetMousePosition(int x, int y);
564
565@@ -248,6 +251,7 @@
566 float DragOutProgress(struct timespec const& current) const;
567 float IconDesatValue(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
568 float IconPresentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
569+ float IconUnfoldProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
570 float IconUrgentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
571 float IconShimmerProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
572 float IconUrgentPulseValue(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
573@@ -322,12 +326,8 @@
574
575 virtual long PostLayoutManagement(long LayoutResult);
576
577- void OnDisplayChanged(Display* display);
578- void OnDNDDataCollected(const std::list<char*>& mimes);
579-
580 void DndReset();
581 void DndHoveredIconReset();
582- void DndTimeoutSetup();
583 bool DndIsSpecialRequest(std::string const& uri) const;
584
585 LauncherModel::Ptr _model;
586@@ -383,7 +383,6 @@
587 nux::Point2 _mouse_position;
588 nux::ObjectPtr<nux::IOpenGLBaseTexture> _offscreen_drag_texture;
589 nux::ObjectPtr<LauncherDragWindow> _drag_window;
590- nux::ObjectPtr<unity::DNDCollectionWindow> _collection_window;
591 LauncherHideMachine _hide_machine;
592 LauncherHoverMachine _hover_machine;
593
594
595=== modified file 'launcher/LauncherController.cpp'
596--- launcher/LauncherController.cpp 2012-11-15 17:56:23 +0000
597+++ launcher/LauncherController.cpp 2012-11-24 14:30:27 +0000
598@@ -95,10 +95,11 @@
599 { Controller::Impl::OnDBusMethodCall, NULL, NULL};
600
601
602-Controller::Impl::Impl(Controller* parent)
603+Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager)
604 : parent_(parent)
605 , model_(std::make_shared<LauncherModel>())
606 , matcher_(bamf_matcher_get_default())
607+ , xdnd_manager_(xdnd_manager)
608 , device_section_(std::make_shared<VolumeMonitorWrapper>(), std::make_shared<DevicesSettingsImp>())
609 , expo_icon_(new ExpoLauncherIcon())
610 , desktop_icon_(new DesktopLauncherIcon())
611@@ -161,6 +162,10 @@
612 });
613
614 parent_->AddChild(model_.get());
615+
616+ xdnd_manager_->dnd_started.connect(sigc::mem_fun(this, &Impl::OnDndStarted));
617+ xdnd_manager_->dnd_finished.connect(sigc::mem_fun(this, &Impl::OnDndFinished));
618+ xdnd_manager_->monitor_changed.connect(sigc::mem_fun(this, &Impl::OnDndMonitorChanged));
619 }
620
621 Controller::Impl::~Impl()
622@@ -255,11 +260,47 @@
623 }
624 }
625
626+void Controller::Impl::OnDndStarted(std::string const& data, int monitor)
627+{
628+ if (parent_->multiple_launchers)
629+ {
630+ last_dnd_monitor_ = monitor;
631+ launchers[last_dnd_monitor_]->DndStarted(data);
632+ }
633+ else
634+ {
635+ launcher_->DndStarted(data);
636+ }
637+}
638+
639+void Controller::Impl::OnDndFinished()
640+{
641+ if (parent_->multiple_launchers)
642+ {
643+ launchers[last_dnd_monitor_]->DndFinished();
644+ last_dnd_monitor_ = -1;
645+ }
646+ else
647+ {
648+ launcher_->DndFinished();
649+ }
650+}
651+
652+void Controller::Impl::OnDndMonitorChanged(int monitor)
653+{
654+ if (parent_->multiple_launchers)
655+ {
656+ launchers[last_dnd_monitor_]->UnsetDndQuirk();
657+ last_dnd_monitor_ = monitor;
658+ launchers[last_dnd_monitor_]->SetDndQuirk();
659+ }
660+}
661+
662 Launcher* Controller::Impl::CreateLauncher(int monitor)
663 {
664 nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow"));
665
666- Launcher* launcher = new Launcher(launcher_window, nux::ObjectPtr<DNDCollectionWindow>(new DNDCollectionWindow));
667+ Launcher* launcher = new Launcher(launcher_window);
668 launcher->monitor = monitor;
669 launcher->options = parent_->options();
670 launcher->SetModel(model_);
671@@ -974,10 +1015,10 @@
672 g_variant_new("(sus)", "home.lens", dash::NOT_HANDLED, ""));
673 }
674
675-Controller::Controller()
676+Controller::Controller(XdndManager::Ptr const& xdnd_manager)
677 : options(Options::Ptr(new Options()))
678 , multiple_launchers(true)
679- , pimpl(new Impl(this))
680+ , pimpl(new Impl(this, xdnd_manager))
681 {
682 multiple_launchers.changed.connect([&](bool value) -> void {
683 UScreen* uscreen = UScreen::GetDefault();
684
685=== modified file 'launcher/LauncherController.h'
686--- launcher/LauncherController.h 2012-11-06 18:19:09 +0000
687+++ launcher/LauncherController.h 2012-11-24 14:30:27 +0000
688@@ -27,6 +27,7 @@
689
690 #include "LauncherOptions.h"
691 #include "SoftwareCenterLauncherIcon.h"
692+#include "XdndManager.h"
693
694 namespace unity
695 {
696@@ -47,7 +48,7 @@
697 nux::Property<Options::Ptr> options;
698 nux::Property<bool> multiple_launchers;
699
700- Controller();
701+ Controller(XdndManager::Ptr const& xdnd_manager);
702 ~Controller();
703
704 Launcher& launcher() const;
705
706=== modified file 'launcher/LauncherControllerPrivate.h'
707--- launcher/LauncherControllerPrivate.h 2012-11-15 17:56:23 +0000
708+++ launcher/LauncherControllerPrivate.h 2012-11-24 14:30:27 +0000
709@@ -39,6 +39,7 @@
710 #include "SoftwareCenterLauncherIcon.h"
711 #include "unity-shared/UBusWrapper.h"
712 #include "VolumeMonitorWrapper.h"
713+#include "XdndManager.h"
714
715 namespace unity
716 {
717@@ -48,7 +49,7 @@
718 class Controller::Impl
719 {
720 public:
721- Impl(Controller* parent);
722+ Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager);
723 ~Impl();
724
725 void UpdateNumWorkspaces(int workspaces);
726@@ -111,6 +112,10 @@
727
728 void OpenQuicklist();
729
730+ void OnDndStarted(std::string const& data, int monitor);
731+ void OnDndFinished();
732+ void OnDndMonitorChanged(int monitor);
733+
734 static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data);
735 static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, const gchar* object_path,
736 const gchar* interface_name, const gchar* method_name,
737@@ -124,6 +129,7 @@
738 glib::Object<BamfMatcher> matcher_;
739 nux::ObjectPtr<Launcher> launcher_;
740 nux::ObjectPtr<Launcher> keyboard_launcher_;
741+ XdndManager::Ptr xdnd_manager_;
742 DeviceLauncherSection device_section_;
743 LauncherEntryRemoteModel remote_model_;
744 AbstractLauncherIcon::Ptr expo_icon_;
745@@ -143,6 +149,7 @@
746 int reactivate_index;
747 bool keynav_restore_window_;
748 int launcher_key_press_time_;
749+ int last_dnd_monitor_;
750
751 unsigned dbus_owner_;
752 GDBusConnection* gdbus_connection_;
753
754=== modified file 'launcher/LauncherIcon.cpp'
755--- launcher/LauncherIcon.cpp 2012-11-15 17:56:23 +0000
756+++ launcher/LauncherIcon.cpp 2012-11-24 14:30:27 +0000
757@@ -801,6 +801,7 @@
758
759 _present_urgency = CLAMP(present_urgency, 0.0f, 1.0f);
760 SetQuirk(Quirk::PRESENTED, true);
761+ SetQuirk(Quirk::UNFOLDED, true);
762 }
763
764 void
765@@ -811,6 +812,7 @@
766
767 _source_manager.Remove(PRESENT_TIMEOUT);
768 SetQuirk(Quirk::PRESENTED, false);
769+ SetQuirk(Quirk::UNFOLDED, false);
770 }
771
772 void
773
774=== modified file 'launcher/StandaloneLauncher.cpp'
775--- launcher/StandaloneLauncher.cpp 2012-10-17 22:16:48 +0000
776+++ launcher/StandaloneLauncher.cpp 2012-11-24 14:30:27 +0000
777@@ -35,8 +35,8 @@
778
779 void ThreadWidgetInit(nux::NThread* thread, void* InitData)
780 {
781-// launcherWindow->SetGeometry (nux::Geometry(0, 0, 300, 800));
782- controller.reset(new launcher::Controller());
783+ auto xdnd_manager = std::make_shared<XdndManager>();
784+ controller = std::make_shared<launcher::Controller>(xdnd_manager);
785 }
786
787 int main(int argc, char** argv)
788
789=== added file 'launcher/XdndCollectionWindow.h'
790--- launcher/XdndCollectionWindow.h 1970-01-01 00:00:00 +0000
791+++ launcher/XdndCollectionWindow.h 2012-11-24 14:30:27 +0000
792@@ -0,0 +1,51 @@
793+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
794+/*
795+* Copyright (C) 2012 Canonical Ltd
796+*
797+* This program is free software: you can redistribute it and/or modify
798+* it under the terms of the GNU General Public License version 3 as
799+* published by the Free Software Foundation.
800+*
801+* This program is distributed in the hope that it will be useful,
802+* but WITHOUT ANY WARRANTY; without even the implied warranty of
803+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
804+* GNU General Public License for more details.
805+*
806+* You should have received a copy of the GNU General Public License
807+* along with this program. If not, see <http://www.gnu.org/licenses/>.
808+*
809+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
810+*/
811+
812+#ifndef UNITYSHELL_XDND_COLLECTION_WINDOW_H
813+#define UNITYSHELL_XDND_COLLECTION_WINDOW_H
814+
815+#include <boost/noncopyable.hpp>
816+#include <memory>
817+#include <sigc++/signal.h>
818+#include <string>
819+#include <vector>
820+
821+namespace unity {
822+
823+/**
824+ * XdndCollectionWindow makes it possible to collect drag and drop data as
825+ * soon as dnd starts and not when the mouse pointer enter the x window.
826+ **/
827+
828+class XdndCollectionWindow : boost::noncopyable
829+{
830+public:
831+ typedef std::shared_ptr<XdndCollectionWindow> Ptr;
832+
833+ virtual ~XdndCollectionWindow() {}
834+
835+ virtual void Collect() = 0;
836+ virtual void Deactivate() = 0;
837+
838+ sigc::signal<void, std::vector<std::string>> collected;
839+};
840+
841+}
842+
843+#endif
844
845=== added file 'launcher/XdndCollectionWindowImp.cpp'
846--- launcher/XdndCollectionWindowImp.cpp 1970-01-01 00:00:00 +0000
847+++ launcher/XdndCollectionWindowImp.cpp 2012-11-24 14:30:27 +0000
848@@ -0,0 +1,112 @@
849+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
850+/*
851+* Copyright (C) 2011 Canonical Ltd
852+*
853+* This program is free software: you can redistribute it and/or modify
854+* it under the terms of the GNU General Public License version 3 as
855+* published by the Free Software Foundation.
856+*
857+* This program is distributed in the hope that it will be useful,
858+* but WITHOUT ANY WARRANTY; without even the implied warranty of
859+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
860+* GNU General Public License for more details.
861+*
862+* You should have received a copy of the GNU General Public License
863+* along with this program. If not, see <http://www.gnu.org/licenses/>.
864+*
865+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
866+*/
867+
868+#include "XdndCollectionWindowImp.h"
869+#include "unity-shared/UScreen.h"
870+#include "unity-shared/WindowManager.h"
871+
872+namespace unity {
873+namespace {
874+
875+class PrivateWindow : public nux::BaseWindow
876+{
877+public:
878+ PrivateWindow(XdndCollectionWindowImp* parent)
879+ : nux::BaseWindow("")
880+ , parent_(parent)
881+ {
882+ // Make it invisible...
883+ SetBackgroundColor(nux::color::Transparent);
884+ SetOpacity(0.0f);
885+ // ... and as big as the whole screen.
886+ auto uscreen = UScreen::GetDefault();
887+ SetGeometry(uscreen->GetScreenGeometry());
888+
889+ ShowWindow(true);
890+ PushToBack();
891+ // Hack to create the X Window as soon as possible.
892+ EnableInputWindow(true, "XdndCollectionWindowImp");
893+ EnableInputWindow(false, "XdndCollectionWindowImp");
894+ SetDndEnabled(false, true);
895+
896+ uscreen->changed.connect(sigc::mem_fun(this, &PrivateWindow::OnScreenChanged));
897+ WindowManager::Default().window_moved.connect(sigc::mem_fun(this, &PrivateWindow::OnWindowMoved));
898+ }
899+
900+ void OnScreenChanged(int /*primary*/, std::vector<nux::Geometry>& /*monitors*/)
901+ {
902+ auto uscreen = UScreen::GetDefault();
903+ SetGeometry(uscreen->GetScreenGeometry());
904+ }
905+
906+ /**
907+ * EnableInputWindow doesn't show the window immediately.
908+ * Since nux::EnableInputWindow uses XMoveResizeWindow the best way to know if
909+ * the X Window is really on/off screen is receiving WindowManager::window_moved
910+ * signal. Please don't hate me!
911+ **/
912+ void OnWindowMoved(Window window_id)
913+ {
914+ if (G_LIKELY(window_id != GetInputWindowId()))
915+ return;
916+
917+ // Create a fake mouse move because sometimes an extra one is required.
918+ auto display = nux::GetGraphicsDisplay()->GetX11Display();
919+ XWarpPointer(display, None, None, 0, 0, 0, 0, 0, 0);
920+ XFlush(display);
921+ }
922+
923+ void ProcessDndMove(int x, int y, std::list<char*> mimes)
924+ {
925+ // Hide the window as soon as possible.
926+ PushToBack();
927+ EnableInputWindow(false, "XdndCollectionWindowImp");
928+
929+ std::vector<std::string> data;
930+ for (auto mime : mimes)
931+ if (mime) data.push_back(mime);
932+
933+ parent_->collected.emit(data);
934+ }
935+
936+ XdndCollectionWindowImp* parent_;
937+};
938+
939+}
940+
941+XdndCollectionWindowImp::XdndCollectionWindowImp()
942+ : window_(new PrivateWindow(this))
943+{}
944+
945+void XdndCollectionWindowImp::Collect()
946+{
947+ // Using PushToFront we're sure that the window is shown over the panel window,
948+ // the launcher window and the dash window. Don't forget to call PushToBack as
949+ // soon as possible.
950+ window_->PushToFront();
951+ window_->EnableInputWindow(true, "XdndCollectionWindowImp");
952+}
953+
954+void XdndCollectionWindowImp::Deactivate()
955+{
956+ window_->PushToBack();
957+ window_->EnableInputWindow(false, "XdndCollectionWindowImp");
958+}
959+
960+}
961
962=== added file 'launcher/XdndCollectionWindowImp.h'
963--- launcher/XdndCollectionWindowImp.h 1970-01-01 00:00:00 +0000
964+++ launcher/XdndCollectionWindowImp.h 2012-11-24 14:30:27 +0000
965@@ -0,0 +1,44 @@
966+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
967+/*
968+* Copyright (C) 2011-2012 Canonical Ltd
969+*
970+* This program is free software: you can redistribute it and/or modify
971+* it under the terms of the GNU General Public License version 3 as
972+* published by the Free Software Foundation.
973+*
974+* This program is distributed in the hope that it will be useful,
975+* but WITHOUT ANY WARRANTY; without even the implied warranty of
976+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
977+* GNU General Public License for more details.
978+*
979+* You should have received a copy of the GNU General Public License
980+* along with this program. If not, see <http://www.gnu.org/licenses/>.
981+*
982+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
983+*/
984+
985+#ifndef UNITYSHELL_XDND_COLLECTION_WINDOW_IMP_H
986+#define UNITYSHELL_XDND_COLLECTION_WINDOW_IMP_H
987+
988+#include "XdndCollectionWindow.h"
989+
990+#include <Nux/Nux.h>
991+#include <Nux/BaseWindow.h>
992+
993+namespace unity {
994+
995+class XdndCollectionWindowImp : public XdndCollectionWindow
996+{
997+public:
998+ XdndCollectionWindowImp();
999+
1000+ void Collect();
1001+ void Deactivate();
1002+
1003+private:
1004+ nux::ObjectPtr<nux::BaseWindow> window_;
1005+};
1006+
1007+}
1008+
1009+#endif
1010
1011=== added file 'launcher/XdndManager.h'
1012--- launcher/XdndManager.h 1970-01-01 00:00:00 +0000
1013+++ launcher/XdndManager.h 2012-11-24 14:30:27 +0000
1014@@ -0,0 +1,43 @@
1015+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1016+/*
1017+* Copyright (C) 2012 Canonical Ltd
1018+*
1019+* This program is free software: you can redistribute it and/or modify
1020+* it under the terms of the GNU General Public License version 3 as
1021+* published by the Free Software Foundation.
1022+*
1023+* This program is distributed in the hope that it will be useful,
1024+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1025+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1026+* GNU General Public License for more details.
1027+*
1028+* You should have received a copy of the GNU General Public License
1029+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1030+*
1031+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1032+*/
1033+
1034+#ifndef UNITYSHELL_XDND_MANAGER_H
1035+#define UNITYSHELL_XDND_MANAGER_H
1036+
1037+#include <boost/noncopyable.hpp>
1038+#include <memory>
1039+#include <sigc++/signal.h>
1040+#include <string>
1041+
1042+namespace unity {
1043+
1044+class XdndManager : boost::noncopyable {
1045+public:
1046+ typedef std::shared_ptr<XdndManager> Ptr;
1047+
1048+ virtual ~XdndManager() {}
1049+
1050+ sigc::signal<void, std::string, int> dnd_started;
1051+ sigc::signal<void> dnd_finished;
1052+ sigc::signal<void, int> monitor_changed;
1053+};
1054+
1055+}
1056+
1057+#endif
1058
1059=== added file 'launcher/XdndManagerImp.cpp'
1060--- launcher/XdndManagerImp.cpp 1970-01-01 00:00:00 +0000
1061+++ launcher/XdndManagerImp.cpp 2012-11-24 14:30:27 +0000
1062@@ -0,0 +1,98 @@
1063+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1064+/*
1065+* Copyright (C) 2012 Canonical Ltd
1066+*
1067+* This program is free software: you can redistribute it and/or modify
1068+* it under the terms of the GNU General Public License version 3 as
1069+* published by the Free Software Foundation.
1070+*
1071+* This program is distributed in the hope that it will be useful,
1072+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1073+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1074+* GNU General Public License for more details.
1075+*
1076+* You should have received a copy of the GNU General Public License
1077+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1078+*
1079+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1080+*/
1081+
1082+#include "XdndManagerImp.h"
1083+
1084+#include "unity-shared/UScreen.h"
1085+
1086+namespace unity {
1087+
1088+XdndManagerImp::XdndManagerImp(XdndStartStopNotifier::Ptr const& xdnd_start_stop_notifier,
1089+ XdndCollectionWindow::Ptr const& xdnd_collection_window)
1090+ : xdnd_start_stop_notifier_(xdnd_start_stop_notifier)
1091+ , xdnd_collection_window_(xdnd_collection_window)
1092+ , last_monitor_(-1)
1093+ , valid_dnd_in_progress_(false)
1094+{
1095+ xdnd_start_stop_notifier_->started.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndStarted));
1096+ xdnd_start_stop_notifier_->finished.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndFinished));
1097+
1098+ xdnd_collection_window_->collected.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndDataCollected));
1099+}
1100+
1101+void XdndManagerImp::OnDndStarted()
1102+{
1103+ xdnd_collection_window_->Collect();
1104+}
1105+
1106+void XdndManagerImp::OnDndFinished()
1107+{
1108+ xdnd_collection_window_->Deactivate();
1109+ mouse_poller_timeout_.reset();
1110+
1111+ if (valid_dnd_in_progress_)
1112+ {
1113+ valid_dnd_in_progress_ = false;
1114+ dnd_finished.emit();
1115+ }
1116+}
1117+
1118+void XdndManagerImp::OnDndDataCollected(std::vector<std::string> const& mimes)
1119+{
1120+ if (!IsAValidDnd(mimes))
1121+ return;
1122+
1123+ valid_dnd_in_progress_ = true;
1124+
1125+ auto& gp_display = nux::GetWindowThread()->GetGraphicsDisplay();
1126+ char target[] = "text/uri-list";
1127+ glib::String data(gp_display.GetDndData(target));
1128+
1129+ auto uscreen = UScreen::GetDefault();
1130+ last_monitor_ = uscreen->GetMonitorWithMouse();
1131+
1132+ mouse_poller_timeout_.reset(new glib::Timeout(20, sigc::mem_fun(this, &XdndManagerImp::CheckMousePosition)));
1133+
1134+ dnd_started.emit(data.Str(), last_monitor_);
1135+}
1136+
1137+bool XdndManagerImp::IsAValidDnd(std::vector<std::string> const& mimes)
1138+{
1139+ auto end = std::end(mimes);
1140+ auto it = std::find(std::begin(mimes), end, "text/uri-list");
1141+
1142+ return it != end;
1143+}
1144+
1145+bool XdndManagerImp::CheckMousePosition()
1146+{
1147+ auto uscreen = UScreen::GetDefault();
1148+ auto monitor = uscreen->GetMonitorWithMouse();
1149+
1150+ if (valid_dnd_in_progress_ && monitor != last_monitor_)
1151+ {
1152+ last_monitor_ = monitor;
1153+ monitor_changed.emit(last_monitor_);
1154+ }
1155+
1156+ return true;
1157+}
1158+
1159+}
1160+
1161
1162=== added file 'launcher/XdndManagerImp.h'
1163--- launcher/XdndManagerImp.h 1970-01-01 00:00:00 +0000
1164+++ launcher/XdndManagerImp.h 2012-11-24 14:30:27 +0000
1165@@ -0,0 +1,54 @@
1166+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1167+/*
1168+* Copyright (C) 2012 Canonical Ltd
1169+*
1170+* This program is free software: you can redistribute it and/or modify
1171+* it under the terms of the GNU General Public License version 3 as
1172+* published by the Free Software Foundation.
1173+*
1174+* This program is distributed in the hope that it will be useful,
1175+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1176+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1177+* GNU General Public License for more details.
1178+*
1179+* You should have received a copy of the GNU General Public License
1180+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1181+*
1182+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1183+*/
1184+
1185+#ifndef UNITYSHELL_XDND_MANAGER_IMP_H
1186+#define UNITYSHELL_XDND_MANAGER_IMP_H
1187+
1188+#include <sigc++/trackable.h>
1189+
1190+#include "XdndManager.h"
1191+
1192+#include "XdndCollectionWindow.h"
1193+#include "XdndStartStopNotifier.h"
1194+#include "UnityCore/GLibSource.h"
1195+
1196+namespace unity {
1197+
1198+class XdndManagerImp : public XdndManager, public sigc::trackable {
1199+public:
1200+ XdndManagerImp(XdndStartStopNotifier::Ptr const&, XdndCollectionWindow::Ptr const&);
1201+
1202+private:
1203+ void OnDndStarted();
1204+ void OnDndFinished();
1205+ void OnDndDataCollected(std::vector<std::string> const& mimes);
1206+ bool IsAValidDnd(std::vector<std::string> const& mimes);
1207+ bool CheckMousePosition();
1208+
1209+ XdndStartStopNotifier::Ptr xdnd_start_stop_notifier_;
1210+ XdndCollectionWindow::Ptr xdnd_collection_window_;
1211+ int last_monitor_;
1212+ bool valid_dnd_in_progress_;
1213+
1214+ glib::Source::UniquePtr mouse_poller_timeout_;
1215+};
1216+
1217+}
1218+
1219+#endif
1220
1221=== added file 'launcher/XdndStartStopNotifier.cpp'
1222--- launcher/XdndStartStopNotifier.cpp 1970-01-01 00:00:00 +0000
1223+++ launcher/XdndStartStopNotifier.cpp 2012-11-24 14:30:27 +0000
1224@@ -0,0 +1,27 @@
1225+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1226+/*
1227+* Copyright (C) 2012 Canonical Ltd
1228+*
1229+* This program is free software: you can redistribute it and/or modify
1230+* it under the terms of the GNU General Public License version 3 as
1231+* published by the Free Software Foundation.
1232+*
1233+* This program is distributed in the hope that it will be useful,
1234+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1235+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1236+* GNU General Public License for more details.
1237+*
1238+* You should have received a copy of the GNU General Public License
1239+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1240+*
1241+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1242+*/
1243+
1244+#include "XdndStartStopNotifier.h"
1245+
1246+namespace unity {
1247+
1248+XdndStartStopNotifier::~XdndStartStopNotifier()
1249+{}
1250+
1251+}
1252\ No newline at end of file
1253
1254=== added file 'launcher/XdndStartStopNotifier.h'
1255--- launcher/XdndStartStopNotifier.h 1970-01-01 00:00:00 +0000
1256+++ launcher/XdndStartStopNotifier.h 2012-11-24 14:30:27 +0000
1257@@ -0,0 +1,41 @@
1258+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1259+/*
1260+* Copyright (C) 2012 Canonical Ltd
1261+*
1262+* This program is free software: you can redistribute it and/or modify
1263+* it under the terms of the GNU General Public License version 3 as
1264+* published by the Free Software Foundation.
1265+*
1266+* This program is distributed in the hope that it will be useful,
1267+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1268+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1269+* GNU General Public License for more details.
1270+*
1271+* You should have received a copy of the GNU General Public License
1272+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1273+*
1274+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1275+*/
1276+
1277+#ifndef UNITYSHELL_XDND_START_STOP_NOTIFIER_H
1278+#define UNITYSHELL_XDND_START_STOP_NOTIFIER_H
1279+
1280+#include <boost/noncopyable.hpp>
1281+#include <memory>
1282+#include <sigc++/signal.h>
1283+
1284+namespace unity {
1285+
1286+class XdndStartStopNotifier : boost::noncopyable {
1287+public:
1288+ typedef std::shared_ptr<XdndStartStopNotifier> Ptr;
1289+
1290+ virtual ~XdndStartStopNotifier() = 0;
1291+
1292+ sigc::signal<void> started;
1293+ sigc::signal<void> finished;
1294+};
1295+
1296+}
1297+
1298+#endif
1299
1300=== added file 'launcher/XdndStartStopNotifierImp.cpp'
1301--- launcher/XdndStartStopNotifierImp.cpp 1970-01-01 00:00:00 +0000
1302+++ launcher/XdndStartStopNotifierImp.cpp 2012-11-24 14:30:27 +0000
1303@@ -0,0 +1,77 @@
1304+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1305+/*
1306+* Copyright (C) 2012 Canonical Ltd
1307+*
1308+* This program is free software: you can redistribute it and/or modify
1309+* it under the terms of the GNU General Public License version 3 as
1310+* published by the Free Software Foundation.
1311+*
1312+* This program is distributed in the hope that it will be useful,
1313+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1314+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1315+* GNU General Public License for more details.
1316+*
1317+* You should have received a copy of the GNU General Public License
1318+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1319+*
1320+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1321+*/
1322+
1323+#include "XdndStartStopNotifierImp.h"
1324+
1325+#include <Nux/Nux.h>
1326+
1327+#include "unity-shared/WindowManager.h"
1328+
1329+namespace unity {
1330+
1331+XdndStartStopNotifierImp::XdndStartStopNotifierImp()
1332+ : display_(nux::GetGraphicsDisplay()->GetX11Display())
1333+ , selection_(XInternAtom(display_, "XdndSelection", false))
1334+ , dnd_in_progress_(false)
1335+{
1336+ WindowManager& wm = WindowManager::Default();
1337+ wm.window_mapped.connect(sigc::hide(sigc::mem_fun(this, &XdndStartStopNotifierImp::DndTimeoutSetup)));
1338+ wm.window_unmapped.connect(sigc::hide(sigc::mem_fun(this, &XdndStartStopNotifierImp::DndTimeoutSetup)));
1339+ }
1340+
1341+void XdndStartStopNotifierImp::DndTimeoutSetup()
1342+{
1343+ if (timeout_ && timeout_->IsRunning())
1344+ return;
1345+
1346+ auto cb_func = sigc::mem_fun(this, &XdndStartStopNotifierImp::OnTimeout);
1347+ timeout_.reset(new glib::Timeout(200, cb_func));
1348+}
1349+
1350+bool XdndStartStopNotifierImp::OnTimeout()
1351+{
1352+ Window drag_owner = XGetSelectionOwner(display_, selection_);
1353+
1354+ // evil hack because Qt does not release the selction owner on drag finished
1355+ Window root_r, child_r;
1356+ int root_x_r, root_y_r, win_x_r, win_y_r;
1357+ unsigned int mask;
1358+ XQueryPointer(display_, DefaultRootWindow(display_), &root_r, &child_r, &root_x_r, &root_y_r, &win_x_r, &win_y_r, &mask);
1359+
1360+ if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
1361+ {
1362+ if (!dnd_in_progress_)
1363+ {
1364+ started.emit();
1365+ dnd_in_progress_ = true;
1366+ }
1367+
1368+ return true;
1369+ }
1370+
1371+ if (dnd_in_progress_)
1372+ {
1373+ finished.emit();
1374+ dnd_in_progress_ = false;
1375+ }
1376+
1377+ return false;
1378+}
1379+
1380+}
1381
1382=== added file 'launcher/XdndStartStopNotifierImp.h'
1383--- launcher/XdndStartStopNotifierImp.h 1970-01-01 00:00:00 +0000
1384+++ launcher/XdndStartStopNotifierImp.h 2012-11-24 14:30:27 +0000
1385@@ -0,0 +1,47 @@
1386+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1387+/*
1388+* Copyright (C) 2012 Canonical Ltd
1389+*
1390+* This program is free software: you can redistribute it and/or modify
1391+* it under the terms of the GNU General Public License version 3 as
1392+* published by the Free Software Foundation.
1393+*
1394+* This program is distributed in the hope that it will be useful,
1395+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1396+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1397+* GNU General Public License for more details.
1398+*
1399+* You should have received a copy of the GNU General Public License
1400+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1401+*
1402+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1403+*/
1404+
1405+#ifndef UNITYSHELL_XDND_START_STOP_NOTIFIER_IMP_H
1406+#define UNITYSHELL_XDND_START_STOP_NOTIFIER_IMP_H
1407+
1408+#include "XdndStartStopNotifier.h"
1409+
1410+#include <UnityCore/GLibSource.h>
1411+#include <X11/Xlib.h>
1412+
1413+namespace unity {
1414+
1415+class XdndStartStopNotifierImp : public XdndStartStopNotifier {
1416+public:
1417+ XdndStartStopNotifierImp();
1418+
1419+private:
1420+ void DndTimeoutSetup();
1421+ bool OnTimeout();
1422+
1423+ Display* display_;
1424+ Atom selection_;
1425+ bool dnd_in_progress_;
1426+
1427+ glib::Source::UniquePtr timeout_;
1428+};
1429+
1430+}
1431+
1432+#endif
1433\ No newline at end of file
1434
1435=== modified file 'plugins/unityshell/src/unitya11ytests.cpp'
1436--- plugins/unityshell/src/unitya11ytests.cpp 2012-08-15 14:05:18 +0000
1437+++ plugins/unityshell/src/unitya11ytests.cpp 2012-11-24 14:30:27 +0000
1438@@ -210,7 +210,7 @@
1439 AtkObject* launcher_icon_accessible = NULL;
1440
1441 window = new nux::BaseWindow(TEXT(""));
1442- launcher = new Launcher(window, nux::ObjectPtr<unity::DNDCollectionWindow>(new unity::DNDCollectionWindow), NULL);
1443+ launcher = new Launcher(window, NULL);
1444 launcher->SinkReference();
1445 launcher_accessible = unity_a11y_get_accessible(launcher);
1446
1447
1448=== modified file 'plugins/unityshell/src/unityshell.cpp'
1449--- plugins/unityshell/src/unityshell.cpp 2012-11-21 23:44:37 +0000
1450+++ plugins/unityshell/src/unityshell.cpp 2012-11-24 14:30:27 +0000
1451@@ -41,6 +41,9 @@
1452 #include "unityshell.h"
1453 #include "BackgroundEffectHelper.h"
1454 #include "UnityGestureBroker.h"
1455+#include "launcher/XdndCollectionWindowImp.h"
1456+#include "launcher/XdndManagerImp.h"
1457+#include "launcher/XdndStartStopNotifierImp.h"
1458
1459 #include <glib/gi18n-lib.h>
1460 #include <gtk/gtk.h>
1461@@ -3096,7 +3099,12 @@
1462 void UnityScreen::initLauncher()
1463 {
1464 Timer timer;
1465- launcher_controller_ = std::make_shared<launcher::Controller>();
1466+
1467+ auto xdnd_collection_window = std::make_shared<XdndCollectionWindowImp>();
1468+ auto xdnd_start_stop_notifier = std::make_shared<XdndStartStopNotifierImp>();
1469+ auto xdnd_manager = std::make_shared<XdndManagerImp>(xdnd_start_stop_notifier, xdnd_collection_window);
1470+
1471+ launcher_controller_ = std::make_shared<launcher::Controller>(xdnd_manager);
1472 AddChild(launcher_controller_.get());
1473
1474 switcher_controller_ = std::make_shared<switcher::Controller>();
1475
1476=== modified file 'tests/CMakeLists.txt'
1477--- tests/CMakeLists.txt 2012-11-23 23:49:46 +0000
1478+++ tests/CMakeLists.txt 2012-11-24 14:30:27 +0000
1479@@ -251,6 +251,8 @@
1480 test_unity_settings.cpp
1481 test_volume_imp.cpp
1482 test_volume_launcher_icon.cpp
1483+ test_xdnd_manager_imp.cpp
1484+ test_xdnd_start_stop_notifier_imp.cpp
1485 bamf-mock-application.c
1486 gmockmount.c
1487 gmockvolume.c
1488
1489=== modified file 'tests/test_launcher.cpp'
1490--- tests/test_launcher.cpp 2012-11-09 09:18:37 +0000
1491+++ tests/test_launcher.cpp 2012-11-24 14:30:27 +0000
1492@@ -26,7 +26,6 @@
1493 #include <Nux/Nux.h>
1494 #include <Nux/BaseWindow.h>
1495
1496-#include "launcher/DNDCollectionWindow.h"
1497 #include "launcher/MockLauncherIcon.h"
1498 #include "launcher/Launcher.h"
1499 #include "unity-shared/PanelStyle.h"
1500@@ -63,8 +62,8 @@
1501 class MockLauncher : public Launcher
1502 {
1503 public:
1504- MockLauncher(nux::BaseWindow* parent, nux::ObjectPtr<DNDCollectionWindow> const& collection_window)
1505- : Launcher(parent, collection_window)
1506+ MockLauncher(nux::BaseWindow* parent)
1507+ : Launcher(parent)
1508 {}
1509
1510 AbstractLauncherIcon::Ptr MouseIconIntersection(int x, int y) const
1511@@ -119,10 +118,9 @@
1512
1513 TestLauncher()
1514 : parent_window_(new nux::BaseWindow("TestLauncherWindow"))
1515- , dnd_collection_window_(new DNDCollectionWindow)
1516 , model_(new LauncherModel)
1517 , options_(new Options)
1518- , launcher_(new MockLauncher(parent_window_, dnd_collection_window_))
1519+ , launcher_(new MockLauncher(parent_window_))
1520 {
1521 launcher_->options = options_;
1522 launcher_->SetModel(model_);
1523@@ -153,7 +151,6 @@
1524
1525 MockUScreen uscreen;
1526 nux::BaseWindow* parent_window_;
1527- nux::ObjectPtr<DNDCollectionWindow> dnd_collection_window_;
1528 Settings settings;
1529 panel::Style panel_style;
1530 LauncherModel::Ptr model_;
1531@@ -189,9 +186,7 @@
1532 EXPECT_CALL(*third, ShouldHighlightOnDrag(_))
1533 .WillRepeatedly(Return(false));
1534
1535- std::list<char*> uris;
1536- dnd_collection_window_->collected.emit(uris);
1537-
1538+ launcher_->DndStarted("");
1539 Utils::WaitForTimeout(1);
1540
1541 EXPECT_FALSE(first->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT));
1542
1543=== modified file 'tests/test_launcher_controller.cpp'
1544--- tests/test_launcher_controller.cpp 2012-11-15 17:56:23 +0000
1545+++ tests/test_launcher_controller.cpp 2012-11-24 14:30:27 +0000
1546@@ -200,6 +200,11 @@
1547 {
1548 struct TestLauncherController : public testing::Test
1549 {
1550+ TestLauncherController()
1551+ : xdnd_manager_(std::make_shared<XdndManager>())
1552+ , lc(xdnd_manager_)
1553+ {}
1554+
1555 virtual void SetUp()
1556 {
1557 lc.multiple_launchers = true;
1558@@ -216,6 +221,10 @@
1559 protected:
1560 struct MockLauncherController : Controller
1561 {
1562+ MockLauncherController(XdndManager::Ptr const& xdnd_manager)
1563+ : Controller(xdnd_manager)
1564+ {}
1565+
1566 Controller::Impl* Impl() const { return pimpl.get(); }
1567
1568 AbstractLauncherIcon::Ptr GetIconByDesktop(std::string const& path) const
1569@@ -258,6 +267,7 @@
1570 Settings settings;
1571 panel::Style panel_style;
1572 MockFavoriteStore favorite_store;
1573+ XdndManager::Ptr xdnd_manager_;
1574 MockLauncherController lc;
1575 };
1576 }
1577@@ -1544,4 +1554,50 @@
1578 ASSERT_EQ(lc.Impl()->model_->Selection()->tooltip_text(), last_selection_change);
1579 }
1580
1581+TEST_F(TestLauncherController, DragAndDrop_MultipleLaunchers)
1582+{
1583+ lc.multiple_launchers = true;
1584+ uscreen.SetupFakeMultiMonitor();
1585+ lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
1586+
1587+ auto check_fn = [this](int index) {
1588+ return lc.launchers()[index]->Hidden();
1589+ };
1590+
1591+ xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
1592+
1593+ for (int i = 0; i < max_num_monitors; ++i)
1594+ Utils::WaitUntil(std::bind(check_fn, i), i != 0);
1595+
1596+ xdnd_manager_->monitor_changed.emit(3);
1597+
1598+ for (int i = 0; i < max_num_monitors; ++i)
1599+ Utils::WaitUntil(std::bind(check_fn, i), i != 3);
1600+
1601+ xdnd_manager_->dnd_finished.emit();
1602+
1603+ for (int i = 0; i < max_num_monitors; ++i)
1604+ Utils::WaitUntil(std::bind(check_fn, i), true);
1605+}
1606+
1607+TEST_F(TestLauncherController, DragAndDrop_SingleLauncher)
1608+{
1609+ lc.multiple_launchers = false;
1610+ uscreen.SetupFakeMultiMonitor(2);
1611+ lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
1612+
1613+ auto check_fn = [this]() {
1614+ return lc.launcher().Hidden();
1615+ };
1616+
1617+ xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
1618+ Utils::WaitUntil(check_fn, false);
1619+
1620+ xdnd_manager_->monitor_changed.emit(2);
1621+ Utils::WaitUntil(check_fn, false);
1622+
1623+ xdnd_manager_->dnd_finished.emit();
1624+ Utils::WaitUntil(check_fn, true);
1625+}
1626+
1627 }
1628
1629=== added file 'tests/test_xdnd_manager_imp.cpp'
1630--- tests/test_xdnd_manager_imp.cpp 1970-01-01 00:00:00 +0000
1631+++ tests/test_xdnd_manager_imp.cpp 2012-11-24 14:30:27 +0000
1632@@ -0,0 +1,130 @@
1633+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1634+/*
1635+* Copyright (C) 2012 Canonical Ltd
1636+*
1637+* This program is free software: you can redistribute it and/or modify
1638+* it under the terms of the GNU General Public License version 3 as
1639+* published by the Free Software Foundation.
1640+*
1641+* This program is distributed in the hope that it will be useful,
1642+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1643+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1644+* GNU General Public License for more details.
1645+*
1646+* You should have received a copy of the GNU General Public License
1647+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1648+*
1649+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1650+*/
1651+
1652+#include <gmock/gmock.h>
1653+using namespace testing;
1654+
1655+#include "launcher/XdndManagerImp.h"
1656+#include "launcher/XdndCollectionWindow.h"
1657+#include "launcher/XdndStartStopNotifier.h"
1658+
1659+#include "test_utils.h"
1660+
1661+#include <Nux/Nux.h>
1662+#include <X11/Xlib.h>
1663+
1664+namespace {
1665+
1666+class MockXdndStartStopNotifier : public unity::XdndStartStopNotifier {
1667+public:
1668+ typedef std::shared_ptr<MockXdndStartStopNotifier> Ptr;
1669+};
1670+
1671+class MockXdndCollectionWindow : public unity::XdndCollectionWindow {
1672+public:
1673+ typedef std::shared_ptr<MockXdndCollectionWindow> Ptr;
1674+
1675+ MOCK_METHOD0(Collect, void(void));
1676+ MOCK_METHOD0(Deactivate, void(void));
1677+};
1678+
1679+class TestXdndManager : public Test {
1680+public:
1681+ TestXdndManager()
1682+ : xdnd_start_stop_notifier_(new MockXdndStartStopNotifier())
1683+ , xdnd_collection_window_(new MockXdndCollectionWindow())
1684+ , xdnd_manager(xdnd_start_stop_notifier_, xdnd_collection_window_)
1685+ {}
1686+
1687+ void SetUp()
1688+ {
1689+ // Evil hack to avoid crashes.
1690+ XEvent xevent;
1691+ xevent.type = ClientMessage;
1692+ xevent.xany.display = nux::GetGraphicsDisplay()->GetX11Display();
1693+ xevent.xclient.message_type = XInternAtom(xevent.xany.display, "XdndEnter", false);
1694+ xevent.xclient.data.l[1] = 5 >> 24;
1695+
1696+ nux::GetGraphicsDisplay()->ProcessXEvent(xevent, true);
1697+ }
1698+
1699+ MockXdndStartStopNotifier::Ptr xdnd_start_stop_notifier_;
1700+ MockXdndCollectionWindow::Ptr xdnd_collection_window_;
1701+ unity::XdndManagerImp xdnd_manager;
1702+};
1703+
1704+TEST_F(TestXdndManager, SignalDndStartedAndFinished)
1705+{
1706+ std::vector<std::string> mimes;
1707+ mimes.push_back("text/uri-list");
1708+ mimes.push_back("hello/world");
1709+
1710+ auto emit_collected_signal = [&] () {
1711+ xdnd_collection_window_->collected.emit(mimes);
1712+ };
1713+
1714+ EXPECT_CALL(*xdnd_collection_window_, Collect())
1715+ .Times(1)
1716+ .WillOnce(Invoke(emit_collected_signal));
1717+
1718+ bool dnd_started_emitted = false;
1719+ xdnd_manager.dnd_started.connect([&] (std::string const& /*data*/, int /*monitor*/) {
1720+ dnd_started_emitted = true;
1721+ });
1722+
1723+ xdnd_start_stop_notifier_->started.emit();
1724+ Utils::WaitUntil(dnd_started_emitted);
1725+
1726+ EXPECT_CALL(*xdnd_collection_window_, Deactivate())
1727+ .Times(1);
1728+
1729+ bool dnd_finished_emitted = false;
1730+ xdnd_manager.dnd_finished.connect([&] () {
1731+ dnd_finished_emitted = true;
1732+ });
1733+
1734+ xdnd_start_stop_notifier_->finished.emit();
1735+ Utils::WaitUntil(dnd_finished_emitted);
1736+}
1737+
1738+TEST_F(TestXdndManager, SignalDndStarted_InvalidMimes)
1739+{
1740+ std::vector<std::string> mimes;
1741+ mimes.push_back("hello/world");
1742+ mimes.push_back("invalid/mimes");
1743+
1744+ auto emit_collected_signal = [&] () {
1745+ xdnd_collection_window_->collected.emit(mimes);
1746+ };
1747+
1748+ EXPECT_CALL(*xdnd_collection_window_, Collect())
1749+ .Times(1)
1750+ .WillOnce(Invoke(emit_collected_signal));
1751+
1752+ bool dnd_started_emitted = false;
1753+ xdnd_manager.dnd_started.connect([&] (std::string const& /*data*/, int /*monitor*/) {
1754+ dnd_started_emitted = true;
1755+ });
1756+
1757+ xdnd_start_stop_notifier_->started.emit();
1758+
1759+ EXPECT_FALSE(dnd_started_emitted);
1760+}
1761+
1762+}
1763
1764=== added file 'tests/test_xdnd_start_stop_notifier_imp.cpp'
1765--- tests/test_xdnd_start_stop_notifier_imp.cpp 1970-01-01 00:00:00 +0000
1766+++ tests/test_xdnd_start_stop_notifier_imp.cpp 2012-11-24 14:30:27 +0000
1767@@ -0,0 +1,107 @@
1768+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1769+/*
1770+* Copyright (C) 2012 Canonical Ltd
1771+*
1772+* This program is free software: you can redistribute it and/or modify
1773+* it under the terms of the GNU General Public License version 3 as
1774+* published by the Free Software Foundation.
1775+*
1776+* This program is distributed in the hope that it will be useful,
1777+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1778+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1779+* GNU General Public License for more details.
1780+*
1781+* You should have received a copy of the GNU General Public License
1782+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1783+*
1784+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1785+*/
1786+
1787+#include <gmock/gmock.h>
1788+using namespace testing;
1789+
1790+#include "XdndStartStopNotifierImp.h"
1791+
1792+#include <Nux/Nux.h>
1793+#include <X11/Xlib.h>
1794+//#include <X11/extensions/XTest.h>
1795+
1796+#include "unity-shared/WindowManager.h"
1797+#include "test_utils.h"
1798+
1799+namespace {
1800+
1801+struct TestXdndStartStopNotifierImp : public Test {
1802+ TestXdndStartStopNotifierImp()
1803+ : display_(nux::GetGraphicsDisplay()->GetX11Display())
1804+ , selection_(XInternAtom(display_, "XdndSelection", false))
1805+ {
1806+ Window root = DefaultRootWindow(display_);
1807+ owner_= XCreateSimpleWindow(display_, root, -1000, -1000, 10, 10, 0, 0, 0);
1808+ }
1809+
1810+ Display* display_;
1811+ Atom selection_;
1812+ Window owner_;
1813+
1814+ unity::XdndStartStopNotifierImp xdnd_start_stop_notifier;
1815+};
1816+
1817+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalStarted)
1818+{
1819+ bool signal_received = false;
1820+ xdnd_start_stop_notifier.started.connect([&](){
1821+ signal_received = true;
1822+ });
1823+
1824+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
1825+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
1826+ auto& wm = unity::WindowManager::Default();
1827+ wm.window_mapped.emit(0);
1828+
1829+ Utils::WaitUntil(signal_received);
1830+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
1831+}
1832+
1833+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalFinished)
1834+{
1835+ bool signal_received = false;
1836+ xdnd_start_stop_notifier.finished.connect([&](){
1837+ signal_received = true;
1838+ });
1839+
1840+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
1841+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
1842+ auto& wm = unity::WindowManager::Default();
1843+ wm.window_mapped.emit(0);
1844+
1845+ Utils::WaitForTimeoutMSec(500);
1846+
1847+ XSetSelectionOwner(display_, selection_, None, CurrentTime);
1848+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
1849+ wm.window_unmapped.emit(0);
1850+
1851+ Utils::WaitUntil(signal_received);
1852+}
1853+
1854+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalFinished_QT)
1855+{
1856+ bool signal_received = false;
1857+ xdnd_start_stop_notifier.finished.connect([&](){
1858+ signal_received = true;
1859+ });
1860+
1861+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
1862+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
1863+ auto& wm = unity::WindowManager::Default();
1864+ wm.window_mapped.emit(0);
1865+
1866+ Utils::WaitForTimeoutMSec(500);
1867+
1868+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
1869+ wm.window_unmapped.emit(0);
1870+
1871+ Utils::WaitUntil(signal_received);
1872+}
1873+
1874+}
1875
1876=== modified file 'unity-shared/UScreen.cpp'
1877--- unity-shared/UScreen.cpp 2012-10-29 09:34:54 +0000
1878+++ unity-shared/UScreen.cpp 2012-11-24 14:30:27 +0000
1879@@ -89,6 +89,13 @@
1880 return monitors_;
1881 }
1882
1883+nux::Geometry UScreen::GetScreenGeometry()
1884+{
1885+ int width = gdk_screen_get_width(screen_);
1886+ int height = gdk_screen_get_height(screen_);
1887+ return nux::Geometry(0, 0, width, height);
1888+}
1889+
1890 void UScreen::Changed(GdkScreen* screen)
1891 {
1892 if (refresh_idle_)
1893
1894=== modified file 'unity-shared/UScreen.h'
1895--- unity-shared/UScreen.h 2012-07-24 01:07:58 +0000
1896+++ unity-shared/UScreen.h 2012-11-24 14:30:27 +0000
1897@@ -46,6 +46,7 @@
1898 nux::Geometry& GetMonitorGeometry(int monitor);
1899
1900 std::vector<nux::Geometry>& GetMonitors();
1901+ nux::Geometry GetScreenGeometry();
1902
1903 // <void, primary_monitor, monitors>
1904 sigc::signal<void, int, std::vector<nux::Geometry>&> changed;
1905
1906=== modified file 'unity-standalone/StandaloneUnity.cpp'
1907--- unity-standalone/StandaloneUnity.cpp 2012-10-11 01:44:15 +0000
1908+++ unity-standalone/StandaloneUnity.cpp 2012-11-24 14:30:27 +0000
1909@@ -86,9 +86,10 @@
1910
1911 void UnityStandalone::Init ()
1912 {
1913- launcher_controller.reset(new launcher::Controller());
1914- panel_controller.reset(new panel::Controller());
1915- dash_controller.reset(new dash::Controller());
1916+ auto xdnd_manager = std::make_shared<XdndManager>();
1917+ launcher_controller = std::make_shared<launcher::Controller>(xdnd_manager);
1918+ panel_controller = std::make_shared<panel::Controller>();
1919+ dash_controller = std::make_shared<dash::Controller>();
1920
1921 dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
1922 panel_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
1923@@ -119,8 +120,9 @@
1924
1925 void UnityStandaloneTV::Init()
1926 {
1927- launcher_controller.reset(new launcher::Controller());
1928- dash_controller.reset(new dash::Controller());
1929+ auto xdnd_manager = std::make_shared<XdndManager>();
1930+ launcher_controller = std::make_shared<launcher::Controller>(xdnd_manager);
1931+ dash_controller = std::make_shared<dash::Controller>();
1932 dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
1933
1934 UBusManager().SendMessage(UBUS_DASH_EXTERNAL_ACTIVATION, nullptr);