summaryrefslogtreecommitdiff
diff options
-rw-r--r--launcher/AbstractLauncherIcon.h1
-rw-r--r--launcher/CMakeLists.txt5
-rw-r--r--launcher/DNDCollectionWindow.cpp99
-rw-r--r--launcher/DNDCollectionWindow.h63
-rw-r--r--launcher/Launcher.cpp207
-rw-r--r--launcher/Launcher.h15
-rw-r--r--launcher/LauncherController.cpp49
-rw-r--r--launcher/LauncherController.h3
-rw-r--r--launcher/LauncherControllerPrivate.h9
-rw-r--r--launcher/LauncherIcon.cpp2
-rw-r--r--launcher/StandaloneLauncher.cpp4
-rw-r--r--launcher/XdndCollectionWindow.h51
-rw-r--r--launcher/XdndCollectionWindowImp.cpp112
-rw-r--r--launcher/XdndCollectionWindowImp.h44
-rw-r--r--launcher/XdndManager.h43
-rw-r--r--launcher/XdndManagerImp.cpp98
-rw-r--r--launcher/XdndManagerImp.h54
-rw-r--r--launcher/XdndStartStopNotifier.cpp27
-rw-r--r--launcher/XdndStartStopNotifier.h41
-rw-r--r--launcher/XdndStartStopNotifierImp.cpp77
-rw-r--r--launcher/XdndStartStopNotifierImp.h47
-rw-r--r--plugins/unityshell/src/unitya11ytests.cpp2
-rw-r--r--plugins/unityshell/src/unityshell.cpp10
-rw-r--r--tests/CMakeLists.txt2
-rw-r--r--tests/test_launcher.cpp13
-rw-r--r--tests/test_launcher_controller.cpp56
-rw-r--r--tests/test_xdnd_manager_imp.cpp130
-rw-r--r--tests/test_xdnd_start_stop_notifier_imp.cpp107
-rw-r--r--unity-shared/UScreen.cpp7
-rw-r--r--unity-shared/UScreen.h1
-rw-r--r--unity-standalone/StandaloneUnity.cpp12
31 files changed, 1075 insertions, 316 deletions
diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h
index bb58b7191..b0cb5f11b 100644
--- a/launcher/AbstractLauncherIcon.h
+++ b/launcher/AbstractLauncherIcon.h
@@ -103,6 +103,7 @@ public:
RUNNING,
URGENT,
PRESENTED,
+ UNFOLDED,
STARTING,
SHIMMER,
CENTER_SAVED,
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 54c3c8961..923aa8208 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -33,7 +33,6 @@ set (LAUNCHER_SOURCES
ApplicationLauncherIcon.cpp
BFBLauncherIcon.cpp
CairoBaseWindow.cpp
- DNDCollectionWindow.cpp
Decaymulator.cpp
DesktopLauncherIcon.cpp
DeviceLauncherSection.cpp
@@ -73,6 +72,10 @@ set (LAUNCHER_SOURCES
VolumeImp.cpp
VolumeLauncherIcon.cpp
VolumeMonitorWrapper.cpp
+ XdndCollectionWindowImp.cpp
+ XdndManagerImp.cpp
+ XdndStartStopNotifier.cpp
+ XdndStartStopNotifierImp.cpp
)
if (ENABLE_X_SUPPORT)
diff --git a/launcher/DNDCollectionWindow.cpp b/launcher/DNDCollectionWindow.cpp
deleted file mode 100644
index 6b0dac695..000000000
--- a/launcher/DNDCollectionWindow.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
-* Copyright (C) 2011 Canonical Ltd
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 3 as
-* published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*
-* Authored by: Andrea Azzarone <azzaronea@gmail.com>
-*/
-
-#include "DNDCollectionWindow.h"
-
-#include "unity-shared/WindowManager.h"
-
-namespace unity {
-
-NUX_IMPLEMENT_OBJECT_TYPE(DNDCollectionWindow);
-
-DNDCollectionWindow::DNDCollectionWindow()
- : nux::BaseWindow("")
- , display(NULL)
-{
- // Make it invisible...
- SetBackgroundColor(nux::Color(0x00000000));
- SetOpacity(0.0f);
- // ... and as big as the whole screen.
- WindowManager& wm = WindowManager::Default();
- SetGeometry(wm.GetScreenGeometry());
-
- ShowWindow(true);
- PushToBack();
- // Hack to create the X Window as soon as possible.
- EnableInputWindow(true, "DNDCollectionWindow");
- EnableInputWindow(false, "DNDCollectionWindow");
- SetDndEnabled(false, true);
-
- wm.window_moved.connect(sigc::mem_fun(this, &DNDCollectionWindow::OnWindowMoved));
-}
-
-DNDCollectionWindow::~DNDCollectionWindow()
-{
- for (auto it : mimes_)
- g_free(it);
-}
-
-/**
- * EnableInputWindow doesn't show the window immediately.
- * Since nux::EnableInputWindow uses XMoveResizeWindow the best way to know if
- * the X Window is really on/off screen is receiving WindowManager::window_moved
- * signal. Please don't hate me!
- **/
-void DNDCollectionWindow::OnWindowMoved(Window window_id)
-{
- if (window_id == GetInputWindowId() && display() != NULL)
- {
- // Create a fake mouse move because sometimes an extra one is required.
- XWarpPointer(display(), None, None, 0, 0, 0, 0, 0, 0);
- XFlush(display());
- }
-}
-
-void DNDCollectionWindow::Collect()
-{
- // Using PushToFront we're sure that the window is shown over the panel window,
- // the launcher window and the dash window. Don't forget to call PushToBack as
- // soon as possible.
- PushToFront();
- EnableInputWindow(true, "DndCollectionWindow");
-}
-
-void DNDCollectionWindow::ProcessDndMove(int x, int y, std::list<char*> mimes)
-{
- // Hide the window as soon as possible.
- PushToBack();
- EnableInputWindow(false, "DNDCollectionWindow");
-
- // Free mimes_ before fill it again.
- for (auto it : mimes_)
- g_free(it);
- mimes_.clear();
-
- // Duplicate the list.
- for (auto it : mimes)
- mimes_.push_back(g_strdup(it));
-
- // Emit the collected signal.
- collected.emit(mimes_);
-}
-
-} // namespace unity
diff --git a/launcher/DNDCollectionWindow.h b/launcher/DNDCollectionWindow.h
deleted file mode 100644
index a899d3cde..000000000
--- a/launcher/DNDCollectionWindow.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
-* Copyright (C) 2011 Canonical Ltd
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 3 as
-* published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*
-* Authored by: Andrea Azzarone <azzaronea@gmail.com>
-*/
-
-#ifndef DNDCOLLECTIONWINDOW_H
-#define DNDCOLLECTIONWINDOW_H
-
-#include <list>
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <sigc++/sigc++.h>
-
-namespace unity {
-
-/**
- * DNDCollectionWindow makes it possible to collect drag and drop (dnd) data as
- * soon as dnd starts and not when the mouse pointer enter the x window.
- **/
-
-class DNDCollectionWindow : public nux::BaseWindow
-{
-NUX_DECLARE_OBJECT_TYPE(DNDCollectionWindow, nux::BaseWindow);
-
-// Methods
-public:
- DNDCollectionWindow();
- ~DNDCollectionWindow();
-
- void Collect();
-
-private:
- void ProcessDndMove(int x, int y, std::list<char*> mimes);
- void OnWindowMoved(Window window_id);
-
-// Members
-public:
- nux::Property<Display*> display;
-
- sigc::signal<void, const std::list<char*>&> collected;
-
-private:
- std::list<char*> mimes_;
-};
-
-} // namespace unity
-
-#endif // DNDCOLLECTIONWINDOW_H
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index 25d4588c4..95072c72c 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -91,7 +91,6 @@ const int START_DRAGICON_DURATION = 250;
const int MOUSE_DEADZONE = 15;
const float DRAG_OUT_PIXELS = 300.0f;
-const std::string DND_CHECK_TIMEOUT = "dnd-check-timeout";
const std::string START_DRAGICON_TIMEOUT = "start-dragicon-timeout";
const std::string SCROLL_TIMEOUT = "scroll-timeout";
const std::string ANIMATION_IDLE = "animation-idle";
@@ -103,7 +102,6 @@ NUX_IMPLEMENT_OBJECT_TYPE(Launcher);
const int Launcher::Launcher::ANIM_DURATION_SHORT = 125;
Launcher::Launcher(nux::BaseWindow* parent,
- nux::ObjectPtr<DNDCollectionWindow> const& collection_window,
NUX_FILE_LINE_DECL)
: View(NUX_FILE_LINE_PARAM)
#ifdef USE_X11
@@ -145,14 +143,11 @@ Launcher::Launcher(nux::BaseWindow* parent,
, _drag_out_delta_x(0.0f)
, _drag_gesture_ongoing(false)
, _last_reveal_progress(0.0f)
- , _collection_window(collection_window)
, _selection_atom(0)
, _background_color(nux::color::DimGray)
{
m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION);
- _collection_window->collected.connect(sigc::mem_fun(this, &Launcher::OnDNDDataCollected));
-
bg_effect_helper_.owner = this;
bg_effect_helper_.enabled = false;
@@ -180,18 +175,12 @@ Launcher::Launcher(nux::BaseWindow* parent,
ql_manager.quicklist_closed.connect(sigc::mem_fun(this, &Launcher::RecvQuicklistClosed));
WindowManager& wm = WindowManager::Default();
- wm.window_mapped.connect(sigc::hide(sigc::mem_fun(this, &Launcher::DndTimeoutSetup)));
- wm.window_unmapped.connect(sigc::hide(sigc::mem_fun(this, &Launcher::DndTimeoutSetup)));
wm.initiate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
wm.initiate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
wm.terminate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
wm.terminate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &Launcher::EnsureAnimation));
-#ifdef USE_X11
- display.changed.connect(sigc::mem_fun(this, &Launcher::OnDisplayChanged));
-#endif
-
// 0 out timers to avoid wonky startups
for (int i = 0; i < TIME_LAST; ++i)
{
@@ -227,11 +216,6 @@ std::string Launcher::GetName() const
return "Launcher";
}
-void Launcher::OnDisplayChanged(Display* display)
-{
- _collection_window->display = display;
-}
-
#ifdef NUX_GESTURES_SUPPORT
void Launcher::OnDragStart(const nux::GestureEvent &event)
{
@@ -399,6 +383,10 @@ bool Launcher::IconNeedsAnimation(AbstractLauncherIcon::Ptr const& icon, struct
if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
return true;
+ time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::UNFOLDED);
+ if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
+ return true;
+
time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::SHIMMER);
if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_LONG)
return true;
@@ -552,6 +540,18 @@ float Launcher::IconPresentProgress(AbstractLauncherIcon::Ptr const& icon, struc
return 1.0f - result;
}
+float Launcher::IconUnfoldProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const
+{
+ struct timespec icon_unfold_time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::UNFOLDED);
+ int ms = unity::TimeUtil::TimeDelta(&current, &icon_unfold_time);
+ float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f);
+
+ if (icon->GetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED))
+ return result;
+ else
+ return 1.0f - result;
+}
+
float Launcher::IconUrgentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const
{
struct timespec urgent_time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::URGENT);
@@ -919,13 +919,14 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr const& icon,
// goes for 0.0f when fully unfolded, to 1.0f folded
float folding_progress = CLAMP((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
- float present_progress = IconPresentProgress(icon, current);
+ float unfold_progress = IconUnfoldProgress(icon, current);
- folding_progress *= 1.0f - present_progress;
+ folding_progress *= 1.0f - unfold_progress;
float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress);
float icon_hide_offset = autohide_offset;
+ float present_progress = IconPresentProgress(icon, current);
icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency());
// icon is crossing threshold, start folding
@@ -1017,8 +1018,8 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args,
// magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
float magic_constant = 1.3f;
- float present_progress = IconPresentProgress(*it, current);
- folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress);
+ float unfold_progress = IconUnfoldProgress(*it, current);
+ folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress);
}
if (sum - _space_between_icons <= launcher_height)
@@ -1366,59 +1367,6 @@ int Launcher::GetMouseY() const
return _mouse_position.y;
}
-bool Launcher::OnUpdateDragManagerTimeout()
-{
-#ifdef USE_X11
- if (!display())
- return false;
-
- if (!_selection_atom)
- _selection_atom = XInternAtom(display(), "XdndSelection", false);
-
- Window drag_owner = XGetSelectionOwner(display(), _selection_atom);
-
- // evil hack because Qt does not release the seelction owner on drag finished
- Window root_r, child_r;
- int root_x_r, root_y_r, win_x_r, win_y_r;
- unsigned int mask;
- XQueryPointer(display(), DefaultRootWindow(display()), &root_r, &child_r, &root_x_r, &root_y_r, &win_x_r, &win_y_r, &mask);
-
- if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
- {
- if (_data_checked == false)
- {
- _data_checked = true;
- _collection_window->Collect();
- }
-
- return true;
- }
-
- _data_checked = false;
- _collection_window->PushToBack();
- _collection_window->EnableInputWindow(false, "DNDCollectionWindow");
-
- if (IsOverlayOpen() && !_hovered)
- DesaturateIcons();
-
- DndReset();
- _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
- _hide_machine.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, false);
-#endif
- return false;
-}
-
-void Launcher::DndTimeoutSetup()
-{
-#ifdef USE_X11
- if (sources_.GetSource(DND_CHECK_TIMEOUT))
- return;
-
- auto cb_func = sigc::mem_fun(this, &Launcher::OnUpdateDragManagerTimeout);
- sources_.AddTimeout(200, cb_func, DND_CHECK_TIMEOUT);
-#endif
-}
-
void Launcher::OnPluginStateChanged()
{
WindowManager& wm = WindowManager::Default();
@@ -2566,53 +2514,6 @@ bool Launcher::DndIsSpecialRequest(std::string const& uri) const
return (boost::algorithm::ends_with(uri, ".desktop") || uri.find("device://") == 0);
}
-void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
-{
-#ifdef USE_X11
- _dnd_data.Reset();
-
- const std::string uri_list = "text/uri-list";
- auto& display = nux::GetWindowThread()->GetGraphicsDisplay();
-
- for (auto const& mime : mimes)
- {
- if (mime != uri_list)
- continue;
-
- _dnd_data.Fill(display.GetDndData(const_cast<char*>(uri_list.c_str())));
- break;
- }
-
- _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
-
- auto const& uris = _dnd_data.Uris();
- if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
- {return DndIsSpecialRequest(uri);}) != uris.end())
- {
- _steal_drag = true;
-
- if (IsOverlayOpen())
- SaturateIcons();
- }
- else
- {
- for (auto const& it : *_model)
- {
- if (it->ShouldHighlightOnDrag(_dnd_data))
- {
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false);
- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, true);
- }
- else
- {
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, true);
- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, false);
- }
- }
- }
-#endif
-}
-
void Launcher::ProcessDndEnter()
{
#ifdef USE_X11
@@ -2648,7 +2549,7 @@ void Launcher::DndReset()
it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, is_overlay_open && !_hovered);
}
- it->SetQuirk(AbstractLauncherIcon::Quirk::PRESENTED, false);
+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false);
}
DndHoveredIconReset();
@@ -2873,5 +2774,69 @@ int Launcher::GetDragDelta() const
return _launcher_drag_delta;
}
+void Launcher::DndStarted(std::string const& data)
+{
+#ifdef USE_X11
+ SetDndQuirk();
+
+ _dnd_data.Fill(data.c_str());
+
+ auto const& uris = _dnd_data.Uris();
+ if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
+ {return DndIsSpecialRequest(uri);}) != uris.end())
+ {
+ _steal_drag = true;
+
+ if (IsOverlayOpen())
+ SaturateIcons();
+ }
+ else
+ {
+ for (auto const& it : *_model)
+ {
+ if (it->ShouldHighlightOnDrag(_dnd_data))
+ {
+ it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false);
+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, true);
+ }
+ else
+ {
+ it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, true);
+ it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false);
+ }
+ }
+ }
+#endif
+}
+
+void Launcher::DndFinished()
+{
+#ifdef USE_X11
+ UnsetDndQuirk();
+
+ _data_checked = false;
+
+ if (IsOverlayOpen() && !_hovered)
+ DesaturateIcons();
+
+ DndReset();
+#endif
+}
+
+void Launcher::SetDndQuirk()
+{
+#ifdef USE_X11
+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
+#endif
+}
+
+void Launcher::UnsetDndQuirk()
+{
+#ifdef USE_X11
+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
+ _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
+#endif
+}
+
} // namespace launcher
} // namespace unity
diff --git a/launcher/Launcher.h b/launcher/Launcher.h
index 99e8ca9d2..aa871ffc8 100644
--- a/launcher/Launcher.h
+++ b/launcher/Launcher.h
@@ -32,7 +32,6 @@
#include "unity-shared/AbstractIconRenderer.h"
#include "unity-shared/BackgroundEffectHelper.h"
#include "DevicesSettings.h"
-#include "DNDCollectionWindow.h"
#include "DndData.h"
#include "unity-shared/Introspectable.h"
#include "LauncherModel.h"
@@ -66,7 +65,7 @@ class Launcher : public unity::debug::Introspectable,
NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View);
public:
- Launcher(nux::BaseWindow* parent, nux::ObjectPtr<DNDCollectionWindow> const& collection_window, NUX_FILE_LINE_PROTO);
+ Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_PROTO);
nux::Property<Display*> display;
nux::Property<int> monitor;
@@ -127,6 +126,11 @@ public:
int GetDragDelta() const;
void SetHover(bool hovered);
+ void DndStarted(std::string const& mimes);
+ void DndFinished();
+ void SetDndQuirk();
+ void UnsetDndQuirk();
+
sigc::signal<void, std::string const&, AbstractLauncherIcon::Ptr const&> add_request;
sigc::signal<void, AbstractLauncherIcon::Ptr const&> remove_request;
sigc::signal<void> selection_change;
@@ -213,7 +217,6 @@ private:
bool StrutHack();
bool StartIconDragTimeout(int x, int y);
bool OnScrollTimeout();
- bool OnUpdateDragManagerTimeout();
void SetMousePosition(int x, int y);
@@ -248,6 +251,7 @@ private:
float DragOutProgress(struct timespec const& current) const;
float IconDesatValue(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
float IconPresentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
+ float IconUnfoldProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
float IconUrgentProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
float IconShimmerProgress(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
float IconUrgentPulseValue(AbstractLauncherIcon::Ptr const& icon, struct timespec const& current) const;
@@ -322,12 +326,8 @@ private:
virtual long PostLayoutManagement(long LayoutResult);
- void OnDisplayChanged(Display* display);
- void OnDNDDataCollected(const std::list<char*>& mimes);
-
void DndReset();
void DndHoveredIconReset();
- void DndTimeoutSetup();
bool DndIsSpecialRequest(std::string const& uri) const;
LauncherModel::Ptr _model;
@@ -383,7 +383,6 @@ private:
nux::Point2 _mouse_position;
nux::ObjectPtr<nux::IOpenGLBaseTexture> _offscreen_drag_texture;
nux::ObjectPtr<LauncherDragWindow> _drag_window;
- nux::ObjectPtr<unity::DNDCollectionWindow> _collection_window;
LauncherHideMachine _hide_machine;
LauncherHoverMachine _hover_machine;
diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp
index a23498101..a257b2dff 100644
--- a/launcher/LauncherController.cpp
+++ b/launcher/LauncherController.cpp
@@ -95,10 +95,11 @@ GDBusInterfaceVTable Controller::Impl::interface_vtable =
{ Controller::Impl::OnDBusMethodCall, NULL, NULL};
-Controller::Impl::Impl(Controller* parent)
+Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager)
: parent_(parent)
, model_(std::make_shared<LauncherModel>())
, matcher_(bamf_matcher_get_default())
+ , xdnd_manager_(xdnd_manager)
, device_section_(std::make_shared<VolumeMonitorWrapper>(), std::make_shared<DevicesSettingsImp>())
, expo_icon_(new ExpoLauncherIcon())
, desktop_icon_(new DesktopLauncherIcon())
@@ -161,6 +162,10 @@ Controller::Impl::Impl(Controller* parent)
});
parent_->AddChild(model_.get());
+
+ xdnd_manager_->dnd_started.connect(sigc::mem_fun(this, &Impl::OnDndStarted));
+ xdnd_manager_->dnd_finished.connect(sigc::mem_fun(this, &Impl::OnDndFinished));
+ xdnd_manager_->monitor_changed.connect(sigc::mem_fun(this, &Impl::OnDndMonitorChanged));
}
Controller::Impl::~Impl()
@@ -255,11 +260,47 @@ void Controller::Impl::OnWindowFocusChanged(guint32 xid)
}
}
+void Controller::Impl::OnDndStarted(std::string const& data, int monitor)
+{
+ if (parent_->multiple_launchers)
+ {
+ last_dnd_monitor_ = monitor;
+ launchers[last_dnd_monitor_]->DndStarted(data);
+ }
+ else
+ {
+ launcher_->DndStarted(data);
+ }
+}
+
+void Controller::Impl::OnDndFinished()
+{
+ if (parent_->multiple_launchers)
+ {
+ launchers[last_dnd_monitor_]->DndFinished();
+ last_dnd_monitor_ = -1;
+ }
+ else
+ {
+ launcher_->DndFinished();
+ }
+}
+
+void Controller::Impl::OnDndMonitorChanged(int monitor)
+{
+ if (parent_->multiple_launchers)
+ {
+ launchers[last_dnd_monitor_]->UnsetDndQuirk();
+ last_dnd_monitor_ = monitor;
+ launchers[last_dnd_monitor_]->SetDndQuirk();
+ }
+}
+
Launcher* Controller::Impl::CreateLauncher(int monitor)
{
nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow"));
- Launcher* launcher = new Launcher(launcher_window, nux::ObjectPtr<DNDCollectionWindow>(new DNDCollectionWindow));
+ Launcher* launcher = new Launcher(launcher_window);
launcher->monitor = monitor;
launcher->options = parent_->options();
launcher->SetModel(model_);
@@ -974,10 +1015,10 @@ void Controller::Impl::SendHomeActivationRequest()
g_variant_new("(sus)", "home.lens", dash::NOT_HANDLED, ""));
}
-Controller::Controller()
+Controller::Controller(XdndManager::Ptr const& xdnd_manager)
: options(Options::Ptr(new Options()))
, multiple_launchers(true)
- , pimpl(new Impl(this))
+ , pimpl(new Impl(this, xdnd_manager))
{
multiple_launchers.changed.connect([&](bool value) -> void {
UScreen* uscreen = UScreen::GetDefault();
diff --git a/launcher/LauncherController.h b/launcher/LauncherController.h
index ec203ec8f..72995e5ce 100644
--- a/launcher/LauncherController.h
+++ b/launcher/LauncherController.h
@@ -27,6 +27,7 @@
#include "LauncherOptions.h"
#include "SoftwareCenterLauncherIcon.h"
+#include "XdndManager.h"
namespace unity
{
@@ -47,7 +48,7 @@ public:
nux::Property<Options::Ptr> options;
nux::Property<bool> multiple_launchers;
- Controller();
+ Controller(XdndManager::Ptr const& xdnd_manager);
~Controller();
Launcher& launcher() const;
diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h
index 210cedeb0..6e35f182e 100644
--- a/launcher/LauncherControllerPrivate.h
+++ b/launcher/LauncherControllerPrivate.h
@@ -39,6 +39,7 @@
#include "SoftwareCenterLauncherIcon.h"
#include "unity-shared/UBusWrapper.h"
#include "VolumeMonitorWrapper.h"
+#include "XdndManager.h"
namespace unity
{
@@ -48,7 +49,7 @@ namespace launcher
class Controller::Impl
{
public:
- Impl(Controller* parent);
+ Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager);
~Impl();
void UpdateNumWorkspaces(int workspaces);
@@ -111,6 +112,10 @@ public:
void OpenQuicklist();
+ void OnDndStarted(std::string const& data, int monitor);
+ void OnDndFinished();
+ void OnDndMonitorChanged(int monitor);
+
static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data);
static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, const gchar* object_path,
const gchar* interface_name, const gchar* method_name,
@@ -124,6 +129,7 @@ public:
glib::Object<BamfMatcher> matcher_;
nux::ObjectPtr<Launcher> launcher_;
nux::ObjectPtr<Launcher> keyboard_launcher_;
+ XdndManager::Ptr xdnd_manager_;
DeviceLauncherSection device_section_;
LauncherEntryRemoteModel remote_model_;
AbstractLauncherIcon::Ptr expo_icon_;
@@ -143,6 +149,7 @@ public:
int reactivate_index;
bool keynav_restore_window_;
int launcher_key_press_time_;
+ int last_dnd_monitor_;
unsigned dbus_owner_;
GDBusConnection* gdbus_connection_;
diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp
index 9f6bb8b55..d893a7458 100644
--- a/launcher/LauncherIcon.cpp
+++ b/launcher/LauncherIcon.cpp
@@ -801,6 +801,7 @@ LauncherIcon::Present(float present_urgency, int length)
_present_urgency = CLAMP(present_urgency, 0.0f, 1.0f);
SetQuirk(Quirk::PRESENTED, true);
+ SetQuirk(Quirk::UNFOLDED, true);
}
void
@@ -811,6 +812,7 @@ LauncherIcon::Unpresent()
_source_manager.Remove(PRESENT_TIMEOUT);
SetQuirk(Quirk::PRESENTED, false);
+ SetQuirk(Quirk::UNFOLDED, false);
}
void
diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp
index 04869b605..2172d2695 100644
--- a/launcher/StandaloneLauncher.cpp
+++ b/launcher/StandaloneLauncher.cpp
@@ -35,8 +35,8 @@ static launcher::Controller::Ptr controller;
void ThreadWidgetInit(nux::NThread* thread, void* InitData)
{
-// launcherWindow->SetGeometry (nux::Geometry(0, 0, 300, 800));
- controller.reset(new launcher::Controller());
+ auto xdnd_manager = std::make_shared<XdndManager>();
+ controller = std::make_shared<launcher::Controller>(xdnd_manager);
}
int main(int argc, char** argv)
diff --git a/launcher/XdndCollectionWindow.h b/launcher/XdndCollectionWindow.h
new file mode 100644
index 000000000..ce5a5681b
--- /dev/null
+++ b/launcher/XdndCollectionWindow.h
@@ -0,0 +1,51 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_COLLECTION_WINDOW_H
+#define UNITYSHELL_XDND_COLLECTION_WINDOW_H
+
+#include <boost/noncopyable.hpp>
+#include <memory>
+#include <sigc++/signal.h>
+#include <string>
+#include <vector>
+
+namespace unity {
+
+/**
+ * XdndCollectionWindow makes it possible to collect drag and drop data as
+ * soon as dnd starts and not when the mouse pointer enter the x window.
+ **/
+
+class XdndCollectionWindow : boost::noncopyable
+{
+public:
+ typedef std::shared_ptr<XdndCollectionWindow> Ptr;
+
+ virtual ~XdndCollectionWindow() {}
+
+ virtual void Collect() = 0;
+ virtual void Deactivate() = 0;
+
+ sigc::signal<void, std::vector<std::string>> collected;
+};
+
+}
+
+#endif
diff --git a/launcher/XdndCollectionWindowImp.cpp b/launcher/XdndCollectionWindowImp.cpp
new file mode 100644
index 000000000..e39f373a7
--- /dev/null
+++ b/launcher/XdndCollectionWindowImp.cpp
@@ -0,0 +1,112 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2011 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
+*/
+
+#include "XdndCollectionWindowImp.h"
+#include "unity-shared/UScreen.h"
+#include "unity-shared/WindowManager.h"
+
+namespace unity {
+namespace {
+
+class PrivateWindow : public nux::BaseWindow
+{
+public:
+ PrivateWindow(XdndCollectionWindowImp* parent)
+ : nux::BaseWindow("")
+ , parent_(parent)
+ {
+ // Make it invisible...
+ SetBackgroundColor(nux::color::Transparent);
+ SetOpacity(0.0f);
+ // ... and as big as the whole screen.
+ auto uscreen = UScreen::GetDefault();
+ SetGeometry(uscreen->GetScreenGeometry());
+
+ ShowWindow(true);
+ PushToBack();
+ // Hack to create the X Window as soon as possible.
+ EnableInputWindow(true, "XdndCollectionWindowImp");
+ EnableInputWindow(false, "XdndCollectionWindowImp");
+ SetDndEnabled(false, true);
+
+ uscreen->changed.connect(sigc::mem_fun(this, &PrivateWindow::OnScreenChanged));
+ WindowManager::Default().window_moved.connect(sigc::mem_fun(this, &PrivateWindow::OnWindowMoved));
+ }
+
+ void OnScreenChanged(int /*primary*/, std::vector<nux::Geometry>& /*monitors*/)
+ {
+ auto uscreen = UScreen::GetDefault();
+ SetGeometry(uscreen->GetScreenGeometry());
+ }
+
+ /**
+ * EnableInputWindow doesn't show the window immediately.
+ * Since nux::EnableInputWindow uses XMoveResizeWindow the best way to know if
+ * the X Window is really on/off screen is receiving WindowManager::window_moved
+ * signal. Please don't hate me!
+ **/
+ void OnWindowMoved(Window window_id)
+ {
+ if (G_LIKELY(window_id != GetInputWindowId()))
+ return;
+
+ // Create a fake mouse move because sometimes an extra one is required.
+ auto display = nux::GetGraphicsDisplay()->GetX11Display();
+ XWarpPointer(display, None, None, 0, 0, 0, 0, 0, 0);
+ XFlush(display);
+ }
+
+ void ProcessDndMove(int x, int y, std::list<char*> mimes)
+ {
+ // Hide the window as soon as possible.
+ PushToBack();
+ EnableInputWindow(false, "XdndCollectionWindowImp");
+
+ std::vector<std::string> data;
+ for (auto mime : mimes)
+ if (mime) data.push_back(mime);
+
+ parent_->collected.emit(data);
+ }
+
+ XdndCollectionWindowImp* parent_;
+};
+
+}
+
+XdndCollectionWindowImp::XdndCollectionWindowImp()
+ : window_(new PrivateWindow(this))
+{}
+
+void XdndCollectionWindowImp::Collect()
+{
+ // Using PushToFront we're sure that the window is shown over the panel window,
+ // the launcher window and the dash window. Don't forget to call PushToBack as
+ // soon as possible.
+ window_->PushToFront();
+ window_->EnableInputWindow(true, "XdndCollectionWindowImp");
+}
+
+void XdndCollectionWindowImp::Deactivate()
+{
+ window_->PushToBack();
+ window_->EnableInputWindow(false, "XdndCollectionWindowImp");
+}
+
+}
diff --git a/launcher/XdndCollectionWindowImp.h b/launcher/XdndCollectionWindowImp.h
new file mode 100644
index 000000000..bf0468471
--- /dev/null
+++ b/launcher/XdndCollectionWindowImp.h
@@ -0,0 +1,44 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2011-2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_COLLECTION_WINDOW_IMP_H
+#define UNITYSHELL_XDND_COLLECTION_WINDOW_IMP_H
+
+#include "XdndCollectionWindow.h"
+
+#include <Nux/Nux.h>
+#include <Nux/BaseWindow.h>
+
+namespace unity {
+
+class XdndCollectionWindowImp : public XdndCollectionWindow
+{
+public:
+ XdndCollectionWindowImp();
+
+ void Collect();
+ void Deactivate();
+
+private:
+ nux::ObjectPtr<nux::BaseWindow> window_;
+};
+
+}
+
+#endif
diff --git a/launcher/XdndManager.h b/launcher/XdndManager.h
new file mode 100644
index 000000000..ffd3f1f00
--- /dev/null
+++ b/launcher/XdndManager.h
@@ -0,0 +1,43 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_MANAGER_H
+#define UNITYSHELL_XDND_MANAGER_H
+
+#include <boost/noncopyable.hpp>
+#include <memory>
+#include <sigc++/signal.h>
+#include <string>
+
+namespace unity {
+
+class XdndManager : boost::noncopyable {
+public:
+ typedef std::shared_ptr<XdndManager> Ptr;
+
+ virtual ~XdndManager() {}
+
+ sigc::signal<void, std::string, int> dnd_started;
+ sigc::signal<void> dnd_finished;
+ sigc::signal<void, int> monitor_changed;
+};
+
+}
+
+#endif
diff --git a/launcher/XdndManagerImp.cpp b/launcher/XdndManagerImp.cpp
new file mode 100644
index 000000000..5bbd224e6
--- /dev/null
+++ b/launcher/XdndManagerImp.cpp
@@ -0,0 +1,98 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#include "XdndManagerImp.h"
+
+#include "unity-shared/UScreen.h"
+
+namespace unity {
+
+XdndManagerImp::XdndManagerImp(XdndStartStopNotifier::Ptr const& xdnd_start_stop_notifier,
+ XdndCollectionWindow::Ptr const& xdnd_collection_window)
+ : xdnd_start_stop_notifier_(xdnd_start_stop_notifier)
+ , xdnd_collection_window_(xdnd_collection_window)
+ , last_monitor_(-1)
+ , valid_dnd_in_progress_(false)
+{
+ xdnd_start_stop_notifier_->started.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndStarted));
+ xdnd_start_stop_notifier_->finished.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndFinished));
+
+ xdnd_collection_window_->collected.connect(sigc::mem_fun(this, &XdndManagerImp::OnDndDataCollected));
+}
+
+void XdndManagerImp::OnDndStarted()
+{
+ xdnd_collection_window_->Collect();
+}
+
+void XdndManagerImp::OnDndFinished()
+{
+ xdnd_collection_window_->Deactivate();
+ mouse_poller_timeout_.reset();
+
+ if (valid_dnd_in_progress_)
+ {
+ valid_dnd_in_progress_ = false;
+ dnd_finished.emit();
+ }
+}
+
+void XdndManagerImp::OnDndDataCollected(std::vector<std::string> const& mimes)
+{
+ if (!IsAValidDnd(mimes))
+ return;
+
+ valid_dnd_in_progress_ = true;
+
+ auto& gp_display = nux::GetWindowThread()->GetGraphicsDisplay();
+ char target[] = "text/uri-list";
+ glib::String data(gp_display.GetDndData(target));
+
+ auto uscreen = UScreen::GetDefault();
+ last_monitor_ = uscreen->GetMonitorWithMouse();
+
+ mouse_poller_timeout_.reset(new glib::Timeout(20, sigc::mem_fun(this, &XdndManagerImp::CheckMousePosition)));
+
+ dnd_started.emit(data.Str(), last_monitor_);
+}
+
+bool XdndManagerImp::IsAValidDnd(std::vector<std::string> const& mimes)
+{
+ auto end = std::end(mimes);
+ auto it = std::find(std::begin(mimes), end, "text/uri-list");
+
+ return it != end;
+}
+
+bool XdndManagerImp::CheckMousePosition()
+{
+ auto uscreen = UScreen::GetDefault();
+ auto monitor = uscreen->GetMonitorWithMouse();
+
+ if (valid_dnd_in_progress_ && monitor != last_monitor_)
+ {
+ last_monitor_ = monitor;
+ monitor_changed.emit(last_monitor_);
+ }
+
+ return true;
+}
+
+}
+
diff --git a/launcher/XdndManagerImp.h b/launcher/XdndManagerImp.h
new file mode 100644
index 000000000..e3e237e72
--- /dev/null
+++ b/launcher/XdndManagerImp.h
@@ -0,0 +1,54 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_MANAGER_IMP_H
+#define UNITYSHELL_XDND_MANAGER_IMP_H
+
+#include <sigc++/trackable.h>
+
+#include "XdndManager.h"
+
+#include "XdndCollectionWindow.h"
+#include "XdndStartStopNotifier.h"
+#include "UnityCore/GLibSource.h"
+
+namespace unity {
+
+class XdndManagerImp : public XdndManager, public sigc::trackable {
+public:
+ XdndManagerImp(XdndStartStopNotifier::Ptr const&, XdndCollectionWindow::Ptr const&);
+
+private:
+ void OnDndStarted();
+ void OnDndFinished();
+ void OnDndDataCollected(std::vector<std::string> const& mimes);
+ bool IsAValidDnd(std::vector<std::string> const& mimes);
+ bool CheckMousePosition();
+
+ XdndStartStopNotifier::Ptr xdnd_start_stop_notifier_;
+ XdndCollectionWindow::Ptr xdnd_collection_window_;
+ int last_monitor_;
+ bool valid_dnd_in_progress_;
+
+ glib::Source::UniquePtr mouse_poller_timeout_;
+};
+
+}
+
+#endif
diff --git a/launcher/XdndStartStopNotifier.cpp b/launcher/XdndStartStopNotifier.cpp
new file mode 100644
index 000000000..18d7119cc
--- /dev/null
+++ b/launcher/XdndStartStopNotifier.cpp
@@ -0,0 +1,27 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#include "XdndStartStopNotifier.h"
+
+namespace unity {
+
+XdndStartStopNotifier::~XdndStartStopNotifier()
+{}
+
+} \ No newline at end of file
diff --git a/launcher/XdndStartStopNotifier.h b/launcher/XdndStartStopNotifier.h
new file mode 100644
index 000000000..ed5d5087d
--- /dev/null
+++ b/launcher/XdndStartStopNotifier.h
@@ -0,0 +1,41 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_START_STOP_NOTIFIER_H
+#define UNITYSHELL_XDND_START_STOP_NOTIFIER_H
+
+#include <boost/noncopyable.hpp>
+#include <memory>
+#include <sigc++/signal.h>
+
+namespace unity {
+
+class XdndStartStopNotifier : boost::noncopyable {
+public:
+ typedef std::shared_ptr<XdndStartStopNotifier> Ptr;
+
+ virtual ~XdndStartStopNotifier() = 0;
+
+ sigc::signal<void> started;
+ sigc::signal<void> finished;
+};
+
+}
+
+#endif
diff --git a/launcher/XdndStartStopNotifierImp.cpp b/launcher/XdndStartStopNotifierImp.cpp
new file mode 100644
index 000000000..19201ff55
--- /dev/null
+++ b/launcher/XdndStartStopNotifierImp.cpp
@@ -0,0 +1,77 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#include "XdndStartStopNotifierImp.h"
+
+#include <Nux/Nux.h>
+
+#include "unity-shared/WindowManager.h"
+
+namespace unity {
+
+XdndStartStopNotifierImp::XdndStartStopNotifierImp()
+ : display_(nux::GetGraphicsDisplay()->GetX11Display())
+ , selection_(XInternAtom(display_, "XdndSelection", false))
+ , dnd_in_progress_(false)
+{
+ WindowManager& wm = WindowManager::Default();
+ wm.window_mapped.connect(sigc::hide(sigc::mem_fun(this, &XdndStartStopNotifierImp::DndTimeoutSetup)));
+ wm.window_unmapped.connect(sigc::hide(sigc::mem_fun(this, &XdndStartStopNotifierImp::DndTimeoutSetup)));
+ }
+
+void XdndStartStopNotifierImp::DndTimeoutSetup()
+{
+ if (timeout_ && timeout_->IsRunning())
+ return;
+
+ auto cb_func = sigc::mem_fun(this, &XdndStartStopNotifierImp::OnTimeout);
+ timeout_.reset(new glib::Timeout(200, cb_func));
+}
+
+bool XdndStartStopNotifierImp::OnTimeout()
+{
+ Window drag_owner = XGetSelectionOwner(display_, selection_);
+
+ // evil hack because Qt does not release the selction owner on drag finished
+ Window root_r, child_r;
+ int root_x_r, root_y_r, win_x_r, win_y_r;
+ unsigned int mask;
+ XQueryPointer(display_, DefaultRootWindow(display_), &root_r, &child_r, &root_x_r, &root_y_r, &win_x_r, &win_y_r, &mask);
+
+ if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
+ {
+ if (!dnd_in_progress_)
+ {
+ started.emit();
+ dnd_in_progress_ = true;
+ }
+
+ return true;
+ }
+
+ if (dnd_in_progress_)
+ {
+ finished.emit();
+ dnd_in_progress_ = false;
+ }
+
+ return false;
+}
+
+}
diff --git a/launcher/XdndStartStopNotifierImp.h b/launcher/XdndStartStopNotifierImp.h
new file mode 100644
index 000000000..d51cfd53d
--- /dev/null
+++ b/launcher/XdndStartStopNotifierImp.h
@@ -0,0 +1,47 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#ifndef UNITYSHELL_XDND_START_STOP_NOTIFIER_IMP_H
+#define UNITYSHELL_XDND_START_STOP_NOTIFIER_IMP_H
+
+#include "XdndStartStopNotifier.h"
+
+#include <UnityCore/GLibSource.h>
+#include <X11/Xlib.h>
+
+namespace unity {
+
+class XdndStartStopNotifierImp : public XdndStartStopNotifier {
+public:
+ XdndStartStopNotifierImp();
+
+private:
+ void DndTimeoutSetup();
+ bool OnTimeout();
+
+ Display* display_;
+ Atom selection_;
+ bool dnd_in_progress_;
+
+ glib::Source::UniquePtr timeout_;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/plugins/unityshell/src/unitya11ytests.cpp b/plugins/unityshell/src/unitya11ytests.cpp
index 1ec2c1af0..425a32468 100644
--- a/plugins/unityshell/src/unitya11ytests.cpp
+++ b/plugins/unityshell/src/unitya11ytests.cpp
@@ -210,7 +210,7 @@ a11y_unit_test_launcher_connection(void)
AtkObject* launcher_icon_accessible = NULL;
window = new nux::BaseWindow(TEXT(""));
- launcher = new Launcher(window, nux::ObjectPtr<unity::DNDCollectionWindow>(new unity::DNDCollectionWindow), NULL);
+ launcher = new Launcher(window, NULL);
launcher->SinkReference();
launcher_accessible = unity_a11y_get_accessible(launcher);
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index fdfa714bf..e3181452f 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -41,6 +41,9 @@
#include "unityshell.h"
#include "BackgroundEffectHelper.h"
#include "UnityGestureBroker.h"
+#include "launcher/XdndCollectionWindowImp.h"
+#include "launcher/XdndManagerImp.h"
+#include "launcher/XdndStartStopNotifierImp.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
@@ -3096,7 +3099,12 @@ void UnityScreen::OnDashRealized ()
void UnityScreen::initLauncher()
{
Timer timer;
- launcher_controller_ = std::make_shared<launcher::Controller>();
+
+ auto xdnd_collection_window = std::make_shared<XdndCollectionWindowImp>();
+ auto xdnd_start_stop_notifier = std::make_shared<XdndStartStopNotifierImp>();
+ auto xdnd_manager = std::make_shared<XdndManagerImp>(xdnd_start_stop_notifier, xdnd_collection_window);
+
+ launcher_controller_ = std::make_shared<launcher::Controller>(xdnd_manager);
AddChild(launcher_controller_.get());
switcher_controller_ = std::make_shared<switcher::Controller>();
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5b36e4a3d..7f35cdebb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -251,6 +251,8 @@ if (ENABLE_X_SUPPORT)
test_unity_settings.cpp
test_volume_imp.cpp
test_volume_launcher_icon.cpp
+ test_xdnd_manager_imp.cpp
+ test_xdnd_start_stop_notifier_imp.cpp
bamf-mock-application.c
gmockmount.c
gmockvolume.c
diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp
index d41a1ece3..9e76866a2 100644
--- a/tests/test_launcher.cpp
+++ b/tests/test_launcher.cpp
@@ -26,7 +26,6 @@ using namespace testing;
#include <Nux/Nux.h>
#include <Nux/BaseWindow.h>
-#include "launcher/DNDCollectionWindow.h"
#include "launcher/MockLauncherIcon.h"
#include "launcher/Launcher.h"
#include "unity-shared/PanelStyle.h"
@@ -63,8 +62,8 @@ public:
class MockLauncher : public Launcher
{
public:
- MockLauncher(nux::BaseWindow* parent, nux::ObjectPtr<DNDCollectionWindow> const& collection_window)
- : Launcher(parent, collection_window)
+ MockLauncher(nux::BaseWindow* parent)
+ : Launcher(parent)
{}
AbstractLauncherIcon::Ptr MouseIconIntersection(int x, int y) const
@@ -119,10 +118,9 @@ public:
TestLauncher()
: parent_window_(new nux::BaseWindow("TestLauncherWindow"))
- , dnd_collection_window_(new DNDCollectionWindow)
, model_(new LauncherModel)
, options_(new Options)
- , launcher_(new MockLauncher(parent_window_, dnd_collection_window_))
+ , launcher_(new MockLauncher(parent_window_))
{
launcher_->options = options_;
launcher_->SetModel(model_);
@@ -153,7 +151,6 @@ public:
MockUScreen uscreen;
nux::BaseWindow* parent_window_;
- nux::ObjectPtr<DNDCollectionWindow> dnd_collection_window_;
Settings settings;
panel::Style panel_style;
LauncherModel::Ptr model_;
@@ -189,9 +186,7 @@ TEST_F(TestLauncher, TestQuirksDuringDnd)
EXPECT_CALL(*third, ShouldHighlightOnDrag(_))
.WillRepeatedly(Return(false));
- std::list<char*> uris;
- dnd_collection_window_->collected.emit(uris);
-
+ launcher_->DndStarted("");
Utils::WaitForTimeout(1);
EXPECT_FALSE(first->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT));
diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp
index 8f033b9ba..516125484 100644
--- a/tests/test_launcher_controller.cpp
+++ b/tests/test_launcher_controller.cpp
@@ -200,6 +200,11 @@ namespace launcher
{
struct TestLauncherController : public testing::Test
{
+ TestLauncherController()
+ : xdnd_manager_(std::make_shared<XdndManager>())
+ , lc(xdnd_manager_)
+ {}
+
virtual void SetUp()
{
lc.multiple_launchers = true;
@@ -216,6 +221,10 @@ struct TestLauncherController : public testing::Test
protected:
struct MockLauncherController : Controller
{
+ MockLauncherController(XdndManager::Ptr const& xdnd_manager)
+ : Controller(xdnd_manager)
+ {}
+
Controller::Impl* Impl() const { return pimpl.get(); }
AbstractLauncherIcon::Ptr GetIconByDesktop(std::string const& path) const
@@ -258,6 +267,7 @@ protected:
Settings settings;
panel::Style panel_style;
MockFavoriteStore favorite_store;
+ XdndManager::Ptr xdnd_manager_;
MockLauncherController lc;
};
}
@@ -1544,4 +1554,50 @@ TEST_F(TestLauncherController, UpdateSelectionChanged)
ASSERT_EQ(lc.Impl()->model_->Selection()->tooltip_text(), last_selection_change);
}
+TEST_F(TestLauncherController, DragAndDrop_MultipleLaunchers)
+{
+ lc.multiple_launchers = true;
+ uscreen.SetupFakeMultiMonitor();
+ lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
+
+ auto check_fn = [this](int index) {
+ return lc.launchers()[index]->Hidden();
+ };
+
+ xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
+
+ for (int i = 0; i < max_num_monitors; ++i)
+ Utils::WaitUntil(std::bind(check_fn, i), i != 0);
+
+ xdnd_manager_->monitor_changed.emit(3);
+
+ for (int i = 0; i < max_num_monitors; ++i)
+ Utils::WaitUntil(std::bind(check_fn, i), i != 3);
+
+ xdnd_manager_->dnd_finished.emit();
+
+ for (int i = 0; i < max_num_monitors; ++i)
+ Utils::WaitUntil(std::bind(check_fn, i), true);
+}
+
+TEST_F(TestLauncherController, DragAndDrop_SingleLauncher)
+{
+ lc.multiple_launchers = false;
+ uscreen.SetupFakeMultiMonitor(2);
+ lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
+
+ auto check_fn = [this]() {
+ return lc.launcher().Hidden();
+ };
+
+ xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
+ Utils::WaitUntil(check_fn, false);
+
+ xdnd_manager_->monitor_changed.emit(2);
+ Utils::WaitUntil(check_fn, false);
+
+ xdnd_manager_->dnd_finished.emit();
+ Utils::WaitUntil(check_fn, true);
+}
+
}
diff --git a/tests/test_xdnd_manager_imp.cpp b/tests/test_xdnd_manager_imp.cpp
new file mode 100644
index 000000000..1e4f3a8ab
--- /dev/null
+++ b/tests/test_xdnd_manager_imp.cpp
@@ -0,0 +1,130 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#include <gmock/gmock.h>
+using namespace testing;
+
+#include "launcher/XdndManagerImp.h"
+#include "launcher/XdndCollectionWindow.h"
+#include "launcher/XdndStartStopNotifier.h"
+
+#include "test_utils.h"
+
+#include <Nux/Nux.h>
+#include <X11/Xlib.h>
+
+namespace {
+
+class MockXdndStartStopNotifier : public unity::XdndStartStopNotifier {
+public:
+ typedef std::shared_ptr<MockXdndStartStopNotifier> Ptr;
+};
+
+class MockXdndCollectionWindow : public unity::XdndCollectionWindow {
+public:
+ typedef std::shared_ptr<MockXdndCollectionWindow> Ptr;
+
+ MOCK_METHOD0(Collect, void(void));
+ MOCK_METHOD0(Deactivate, void(void));
+};
+
+class TestXdndManager : public Test {
+public:
+ TestXdndManager()
+ : xdnd_start_stop_notifier_(new MockXdndStartStopNotifier())
+ , xdnd_collection_window_(new MockXdndCollectionWindow())
+ , xdnd_manager(xdnd_start_stop_notifier_, xdnd_collection_window_)
+ {}
+
+ void SetUp()
+ {
+ // Evil hack to avoid crashes.
+ XEvent xevent;
+ xevent.type = ClientMessage;
+ xevent.xany.display = nux::GetGraphicsDisplay()->GetX11Display();
+ xevent.xclient.message_type = XInternAtom(xevent.xany.display, "XdndEnter", false);
+ xevent.xclient.data.l[1] = 5 >> 24;
+
+ nux::GetGraphicsDisplay()->ProcessXEvent(xevent, true);
+ }
+
+ MockXdndStartStopNotifier::Ptr xdnd_start_stop_notifier_;
+ MockXdndCollectionWindow::Ptr xdnd_collection_window_;
+ unity::XdndManagerImp xdnd_manager;
+};
+
+TEST_F(TestXdndManager, SignalDndStartedAndFinished)
+{
+ std::vector<std::string> mimes;
+ mimes.push_back("text/uri-list");
+ mimes.push_back("hello/world");
+
+ auto emit_collected_signal = [&] () {
+ xdnd_collection_window_->collected.emit(mimes);
+ };
+
+ EXPECT_CALL(*xdnd_collection_window_, Collect())
+ .Times(1)
+ .WillOnce(Invoke(emit_collected_signal));
+
+ bool dnd_started_emitted = false;
+ xdnd_manager.dnd_started.connect([&] (std::string const& /*data*/, int /*monitor*/) {
+ dnd_started_emitted = true;
+ });
+
+ xdnd_start_stop_notifier_->started.emit();
+ Utils::WaitUntil(dnd_started_emitted);
+
+ EXPECT_CALL(*xdnd_collection_window_, Deactivate())
+ .Times(1);
+
+ bool dnd_finished_emitted = false;
+ xdnd_manager.dnd_finished.connect([&] () {
+ dnd_finished_emitted = true;
+ });
+
+ xdnd_start_stop_notifier_->finished.emit();
+ Utils::WaitUntil(dnd_finished_emitted);
+}
+
+TEST_F(TestXdndManager, SignalDndStarted_InvalidMimes)
+{
+ std::vector<std::string> mimes;
+ mimes.push_back("hello/world");
+ mimes.push_back("invalid/mimes");
+
+ auto emit_collected_signal = [&] () {
+ xdnd_collection_window_->collected.emit(mimes);
+ };
+
+ EXPECT_CALL(*xdnd_collection_window_, Collect())
+ .Times(1)
+ .WillOnce(Invoke(emit_collected_signal));
+
+ bool dnd_started_emitted = false;
+ xdnd_manager.dnd_started.connect([&] (std::string const& /*data*/, int /*monitor*/) {
+ dnd_started_emitted = true;
+ });
+
+ xdnd_start_stop_notifier_->started.emit();
+
+ EXPECT_FALSE(dnd_started_emitted);
+}
+
+}
diff --git a/tests/test_xdnd_start_stop_notifier_imp.cpp b/tests/test_xdnd_start_stop_notifier_imp.cpp
new file mode 100644
index 000000000..621010447
--- /dev/null
+++ b/tests/test_xdnd_start_stop_notifier_imp.cpp
@@ -0,0 +1,107 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2012 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+*/
+
+#include <gmock/gmock.h>
+using namespace testing;
+
+#include "XdndStartStopNotifierImp.h"
+
+#include <Nux/Nux.h>
+#include <X11/Xlib.h>
+//#include <X11/extensions/XTest.h>
+
+#include "unity-shared/WindowManager.h"
+#include "test_utils.h"
+
+namespace {
+
+struct TestXdndStartStopNotifierImp : public Test {
+ TestXdndStartStopNotifierImp()
+ : display_(nux::GetGraphicsDisplay()->GetX11Display())
+ , selection_(XInternAtom(display_, "XdndSelection", false))
+ {
+ Window root = DefaultRootWindow(display_);
+ owner_= XCreateSimpleWindow(display_, root, -1000, -1000, 10, 10, 0, 0, 0);
+ }
+
+ Display* display_;
+ Atom selection_;
+ Window owner_;
+
+ unity::XdndStartStopNotifierImp xdnd_start_stop_notifier;
+};
+
+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalStarted)
+{
+ bool signal_received = false;
+ xdnd_start_stop_notifier.started.connect([&](){
+ signal_received = true;
+ });
+
+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
+ auto& wm = unity::WindowManager::Default();
+ wm.window_mapped.emit(0);
+
+ Utils::WaitUntil(signal_received);
+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
+}
+
+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalFinished)
+{
+ bool signal_received = false;
+ xdnd_start_stop_notifier.finished.connect([&](){
+ signal_received = true;
+ });
+
+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
+ auto& wm = unity::WindowManager::Default();
+ wm.window_mapped.emit(0);
+
+ Utils::WaitForTimeoutMSec(500);
+
+ XSetSelectionOwner(display_, selection_, None, CurrentTime);
+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
+ wm.window_unmapped.emit(0);
+
+ Utils::WaitUntil(signal_received);
+}
+
+TEST_F(TestXdndStartStopNotifierImp, DISABLED_SignalFinished_QT)
+{
+ bool signal_received = false;
+ xdnd_start_stop_notifier.finished.connect([&](){
+ signal_received = true;
+ });
+
+ XSetSelectionOwner(display_, selection_, owner_, CurrentTime);
+ //XTestFakeButtonEvent(display_, 1, True, CurrentTime);
+ auto& wm = unity::WindowManager::Default();
+ wm.window_mapped.emit(0);
+
+ Utils::WaitForTimeoutMSec(500);
+
+ //XTestFakeButtonEvent(display_, 1, False, CurrentTime);
+ wm.window_unmapped.emit(0);
+
+ Utils::WaitUntil(signal_received);
+}
+
+}
diff --git a/unity-shared/UScreen.cpp b/unity-shared/UScreen.cpp
index 4faa1bc56..6812a8325 100644
--- a/unity-shared/UScreen.cpp
+++ b/unity-shared/UScreen.cpp
@@ -89,6 +89,13 @@ std::vector<nux::Geometry>& UScreen::GetMonitors()
return monitors_;
}
+nux::Geometry UScreen::GetScreenGeometry()
+{
+ int width = gdk_screen_get_width(screen_);
+ int height = gdk_screen_get_height(screen_);
+ return nux::Geometry(0, 0, width, height);
+}
+
void UScreen::Changed(GdkScreen* screen)
{
if (refresh_idle_)
diff --git a/unity-shared/UScreen.h b/unity-shared/UScreen.h
index f66e07d7a..ff33d8e0a 100644
--- a/unity-shared/UScreen.h
+++ b/unity-shared/UScreen.h
@@ -46,6 +46,7 @@ public:
nux::Geometry& GetMonitorGeometry(int monitor);
std::vector<nux::Geometry>& GetMonitors();
+ nux::Geometry GetScreenGeometry();
// <void, primary_monitor, monitors>
sigc::signal<void, int, std::vector<nux::Geometry>&> changed;
diff --git a/unity-standalone/StandaloneUnity.cpp b/unity-standalone/StandaloneUnity.cpp
index ebc649a96..593af9f61 100644
--- a/unity-standalone/StandaloneUnity.cpp
+++ b/unity-standalone/StandaloneUnity.cpp
@@ -86,9 +86,10 @@ UnityStandalone::~UnityStandalone ()
void UnityStandalone::Init ()
{
- launcher_controller.reset(new launcher::Controller());
- panel_controller.reset(new panel::Controller());
- dash_controller.reset(new dash::Controller());
+ auto xdnd_manager = std::make_shared<XdndManager>();
+ launcher_controller = std::make_shared<launcher::Controller>(xdnd_manager);
+ panel_controller = std::make_shared<panel::Controller>();
+ dash_controller = std::make_shared<dash::Controller>();
dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
panel_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
@@ -119,8 +120,9 @@ UnityStandaloneTV::~UnityStandaloneTV() {};
void UnityStandaloneTV::Init()
{
- launcher_controller.reset(new launcher::Controller());
- dash_controller.reset(new dash::Controller());
+ auto xdnd_manager = std::make_shared<XdndManager>();
+ launcher_controller = std::make_shared<launcher::Controller>(xdnd_manager);
+ dash_controller = std::make_shared<dash::Controller>();
dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
UBusManager().SendMessage(UBUS_DASH_EXTERNAL_ACTIVATION, nullptr);