summaryrefslogtreecommitdiff
diff options
authorMarco Trevisan (Treviño) <mail@3v1n0.net>2016-09-02 15:36:37 +0200
committerMarco Trevisan (Treviño) <mail@3v1n0.net>2016-09-02 15:36:37 +0200
commit1a8d47d4f27026ee9f7050fc6ab2bd6f1078ceec (patch)
treebc8c8b8026a2b1f3f3336c4fcd787e3e1baa2b00
parent00d68bd94b4269ddfc55bdc862d41170e688a964 (diff)
parent858e4ed48b5a2a96ef6227b36017a419b9ad69dd (diff)
Merging with trunk
(bzr r4153.9.53)
-rw-r--r--debian/changelog38
-rw-r--r--decorations/DecoratedWindow.cpp11
-rw-r--r--decorations/DecorationsMenuLayout.cpp68
-rw-r--r--decorations/DecorationsMenuLayout.h5
-rw-r--r--decorations/DecorationsPriv.h1
-rw-r--r--launcher/EdgeBarrierController.cpp141
-rw-r--r--launcher/EdgeBarrierControllerPrivate.h7
-rw-r--r--lockscreen/KylinLockScreenShield.cpp2
-rw-r--r--lockscreen/LockScreenBaseShield.cpp2
-rw-r--r--lockscreen/LockScreenBaseShield.h7
-rw-r--r--lockscreen/LockScreenController.cpp6
-rw-r--r--lockscreen/LockScreenController.h3
-rw-r--r--lockscreen/LockScreenPanel.cpp81
-rw-r--r--lockscreen/LockScreenPanel.h14
-rw-r--r--lockscreen/LockScreenShield.cpp13
-rw-r--r--lockscreen/LockScreenShield.h7
-rw-r--r--lockscreen/LockScreenShieldFactory.cpp4
-rw-r--r--lockscreen/LockScreenShieldFactory.h6
-rw-r--r--panel/PanelIndicatorEntryView.cpp10
-rw-r--r--panel/PanelMenuView.cpp10
-rw-r--r--panel/PanelMenuView.h2
-rw-r--r--panel/PanelView.cpp124
-rw-r--r--panel/PanelView.h15
-rw-r--r--plugins/unityshell/src/unityshell.cpp1
-rw-r--r--plugins/unityshell/src/unityshell.h2
-rw-r--r--services/panel-service.c88
-rw-r--r--tests/test_edge_barrier_controller.cpp2
-rw-r--r--tests/test_launcher_controller.cpp2
-rw-r--r--tests/test_lockscreen_controller.cpp4
-rw-r--r--tests/test_panel_controller.cpp2
-rw-r--r--tests/test_panel_view.cpp2
-rw-r--r--unity-shared/CMakeLists.txt1
-rw-r--r--unity-shared/InputMonitor.cpp420
-rw-r--r--unity-shared/InputMonitor.h67
-rw-r--r--unity-shared/MenuManager.cpp163
-rw-r--r--unity-shared/MenuManager.h4
-rw-r--r--unity-shared/PluginAdapter.cpp2
-rw-r--r--unity-shared/SigcSlotHash.h70
-rw-r--r--unity-shared/StandaloneWindowManager.cpp3
-rw-r--r--unity-shared/StandaloneWindowManager.h1
-rw-r--r--unity-shared/UpstartWrapper.cpp2
-rw-r--r--unity-shared/WindowButtons.cpp15
-rw-r--r--unity-shared/WindowManager.h1
-rw-r--r--unity-shared/XWindowManager.cpp6
-rw-r--r--unity-shared/XWindowManager.h1
45 files changed, 1023 insertions, 413 deletions
diff --git a/debian/changelog b/debian/changelog
index e7ebde877..c366a2dc3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,41 @@
+unity (7.5.0+16.10.20160901.2-0ubuntu1) yakkety; urgency=medium
+
+ [ Andrea Azzarone ]
+ * Disable menu discovery animation if MenusDiscoveryDuration is 0.
+ (LP: #942962)
+ * Redraw fake decorations on window resize. (LP: #940470)
+
+ [ Marco Trevisan (Treviño) ]
+ * InputMonitor: add an unity class that monitors XInput2 events and
+ converts them to XEvent
+ * EdgeBarrierController: use InputMonitor to get the barrier events
+ instead of relying on its implementation
+ * DecorationsMenuLayout: use input monitor for menu scrubbing (LP:
+ #1614597)
+ * PanelView: use InputMonitor to track menu events
+ * LockScreenPanel: use InputMonitor events instead of mouse polling
+ for menu scrubbing
+ * MenuManager: add support for mouse trackers with triangle algorithm
+ support (LP: #1618405)
+ * PanelView: scale gradient refinement properly
+ * PanelService: don't allow to deactivate menus if they've been opened
+ too shortly
+ * WindowButton: properly partially unmaximize a window when
+ middle/left clicking in the restore button (LP: #1616136)
+ * CMake: move data and setting files in proper folder, define shared
+ libdir variables
+
+ -- Marco Trevisan (Treviño) <mail@3v1n0.net> Thu, 01 Sep 2016 23:59:15 +0000
+
+unity (7.5.0+16.10.20160819-0ubuntu1) yakkety; urgency=medium
+
+ [ Andrea Azzarone ]
+ * Use compiz::Window::serverNext instead of compiz::Window::next in
+ IsWindowObscured as the latter can be outdated just after
+ scale/spread terminates. (LP: #1614116)
+
+ -- Marco Trevisan (Treviño) <mail@3v1n0.net> Fri, 19 Aug 2016 13:15:09 +0000
+
unity (7.5.0+16.10.20160817.1-0ubuntu1) yakkety; urgency=medium
[ Andrea Azzarone ]
diff --git a/decorations/DecoratedWindow.cpp b/decorations/DecoratedWindow.cpp
index 6ded32011..fe294dc83 100644
--- a/decorations/DecoratedWindow.cpp
+++ b/decorations/DecoratedWindow.cpp
@@ -37,7 +37,6 @@ namespace decoration
{
namespace
{
-const std::string MENUS_PANEL_NAME = "WindowLIM";
const int SHADOW_BLUR_MARGIN_FACTOR = 2;
}
@@ -55,7 +54,6 @@ Window::Impl::Impl(Window* parent, CompWindow* win)
, deco_elements_(cu::DecorationElement::NONE)
, last_mwm_decor_(win_->mwmDecor())
, last_actions_(win_->actions())
- , panel_id_(MENUS_PANEL_NAME + std::to_string(win_->id()))
, cv_(Settings::Instance().em())
{
active.changed.connect([this] (bool active) {
@@ -932,18 +930,13 @@ void Window::Impl::UpdateAppMenuVisibility()
sliding_layout->mouse_owner = grab_edge_->mouse_owner();
}
-inline std::string const& Window::Impl::GetMenusPanelID() const
-{
- return panel_id_;
-}
-
void Window::Impl::UnsetAppMenu()
{
if (!menus_)
return;
auto const& indicators = manager_->impl_->menu_manager_->Indicators();
- indicators->SyncGeometries(GetMenusPanelID(), indicator::EntryLocationMap());
+ indicators->SyncGeometries(menus_->MenubarId(), indicator::EntryLocationMap());
sliding_layout_->SetInputItem(nullptr);
grab_mouse_changed_->disconnect();
}
@@ -956,7 +949,7 @@ void Window::Impl::SyncMenusGeometries() const
auto const& indicators = manager_->impl_->menu_manager_->Indicators();
indicator::EntryLocationMap map;
menus_->ChildrenGeometries(map);
- indicators->SyncGeometries(GetMenusPanelID(), map);
+ indicators->SyncGeometries(menus_->MenubarId(), map);
}
bool Window::Impl::ActivateMenu(std::string const& entry_id)
diff --git a/decorations/DecorationsMenuLayout.cpp b/decorations/DecorationsMenuLayout.cpp
index 252fd7d0d..e31a766df 100644
--- a/decorations/DecorationsMenuLayout.cpp
+++ b/decorations/DecorationsMenuLayout.cpp
@@ -25,6 +25,10 @@ namespace unity
{
namespace decoration
{
+namespace
+{
+const std::string MENUS_PANEL_NAME = "WindowLIM";
+}
using namespace indicator;
@@ -33,8 +37,8 @@ MenuLayout::MenuLayout(menu::Manager::Ptr const& menu, CompWindow* win)
, show_now(false)
, menu_manager_(menu)
, win_(win)
- , last_pointer_(-1, -1)
, dropdown_(std::make_shared<MenuDropdown>(menu_manager_->Indicators(), win))
+ , menubar_id_(MENUS_PANEL_NAME + std::to_string(win_->id()))
{
visible = false;
}
@@ -91,6 +95,11 @@ void MenuLayout::Setup()
Relayout();
}
+std::string const& MenuLayout::MenubarId() const
+{
+ return menubar_id_;
+}
+
bool MenuLayout::ActivateMenu(std::string const& entry_id)
{
MenuEntry::Ptr target;
@@ -117,14 +126,27 @@ bool MenuLayout::ActivateMenu(std::string const& entry_id)
if (!activated)
activated = dropdown_->ActivateChild(target);
- if (activated)
+ return activated;
+}
+
+bool MenuLayout::ActivateMenu(CompPoint const& pos)
+{
+ if (!Geometry().contains(pos))
+ return false;
+
+ for (auto const& item : items_)
{
- // Since this generally happens on keyboard activation we need to avoid that
- // the mouse position would interfere with this
- last_pointer_.set(pointerX, pointerY);
+ if (!item->visible() || !item->sensitive())
+ continue;
+
+ if (item->Geometry().contains(pos))
+ {
+ std::static_pointer_cast<MenuEntry>(item)->ShowMenu(1);
+ return true;
+ }
}
- return activated;
+ return false;
}
void MenuLayout::OnEntryMouseOwnershipChanged(bool owner)
@@ -154,39 +176,15 @@ void MenuLayout::OnEntryActiveChanged(bool actived)
{
active = actived;
- if (active && !pointer_tracker_ && items_.size() > 1)
+ if (active && items_.size() > 1)
{
- pointer_tracker_.reset(new glib::Timeout(16));
- pointer_tracker_->Run([this] {
- Window win;
- int i, x, y;
- unsigned int ui;
-
- XQueryPointer(screen->dpy(), screen->root(), &win, &win, &x, &y, &i, &i, &ui);
-
- if (last_pointer_.x() != x || last_pointer_.y() != y)
- {
- last_pointer_.set(x, y);
-
- for (auto const& item : items_)
- {
- if (!item->visible() || !item->sensitive())
- continue;
-
- if (item->Geometry().contains(last_pointer_))
- {
- std::static_pointer_cast<MenuEntry>(item)->ShowMenu(1);
- break;
- }
- }
- }
-
- return true;
- });
+ menu_manager_->RegisterTracker(menubar_id_, (sigc::track_obj([this] (int x, int y, double speed) {
+ ActivateMenu(CompPoint(x, y));
+ }, *this)));
}
else if (!active)
{
- pointer_tracker_.reset();
+ menu_manager_->UnregisterTracker(menubar_id_);
}
}
diff --git a/decorations/DecorationsMenuLayout.h b/decorations/DecorationsMenuLayout.h
index 9fc787186..df80c3e4c 100644
--- a/decorations/DecorationsMenuLayout.h
+++ b/decorations/DecorationsMenuLayout.h
@@ -42,7 +42,9 @@ public:
void Setup();
bool ActivateMenu(std::string const& entry_id);
+ bool ActivateMenu(CompPoint const&);
void ChildrenGeometries(indicator::EntryLocationMap&) const;
+ std::string const& MenubarId() const;
protected:
void DoRelayout() override;
@@ -55,10 +57,9 @@ private:
menu::Manager::Ptr menu_manager_;
CompWindow* win_;
- CompPoint last_pointer_;
- glib::Source::UniquePtr pointer_tracker_;
glib::Source::UniquePtr show_now_timeout_;
std::shared_ptr<MenuDropdown> dropdown_;
+ std::string menubar_id_;
};
} // decoration namespace
diff --git a/decorations/DecorationsPriv.h b/decorations/DecorationsPriv.h
index 5199d2927..c8c5a39ec 100644
--- a/decorations/DecorationsPriv.h
+++ b/decorations/DecorationsPriv.h
@@ -162,7 +162,6 @@ private:
connection::Wrapper dpi_changed_;
connection::Wrapper grab_mouse_changed_;
std::string last_title_;
- std::string panel_id_;
std::vector<cu::SimpleTextureQuad> bg_textures_;
cu::PixmapTexture::Ptr shaped_shadow_pixmap_;
std::shared_ptr<ForceQuitDialog> force_quit_;
diff --git a/launcher/EdgeBarrierController.cpp b/launcher/EdgeBarrierController.cpp
index a0354f585..42d509eb3 100644
--- a/launcher/EdgeBarrierController.cpp
+++ b/launcher/EdgeBarrierController.cpp
@@ -25,6 +25,7 @@
#include <NuxCore/Logger.h>
#include "unity-shared/UnitySettings.h"
#include "unity-shared/UScreen.h"
+#include "unity-shared/InputMonitor.h"
#include "UnityCore/GLibSource.h"
namespace unity
@@ -36,50 +37,10 @@ namespace
{
int const Y_BREAK_BUFFER = 20;
int const X_BREAK_BUFFER = 20;
- int const MAJOR = 2;
- int const MINOR = 3;
-}
-
-DECLARE_LOGGER(logger, "unity.edge_barrier_controller");
-
-int GetXI2OpCode()
-{
- Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
-
- int opcode, event_base, error_base;
- if (!XQueryExtension(dpy, "XFIXES",
- &opcode,
- &event_base,
- &error_base))
- {
- LOG_ERROR(logger) << "Missing XFixes";
- return -1;
- }
-
- if (!XQueryExtension (dpy, "XInputExtension",
- &opcode,
- &event_base,
- &error_base))
- {
- LOG_ERROR(logger) << "Missing XInput";
- return -1;
- }
-
- int maj = MAJOR;
- int min = MINOR;
-
- if (XIQueryVersion(dpy, &maj, &min) == BadRequest)
- {
- LOG_ERROR(logger) << "Need XInput version 2.3";
- return -1;
- }
-
- return opcode;
}
EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent)
- : xi2_opcode_(-1)
- , edge_overcome_pressure_(0)
+ : edge_overcome_pressure_(0)
, parent_(parent)
{
UScreen *uscreen = UScreen::GetDefault();
@@ -119,8 +80,6 @@ EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent)
options->option_changed.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnOptionsChanged));
SetupBarriers(UScreen::GetDefault()->GetMonitors());
});
-
- xi2_opcode_ = GetXI2OpCode();
}
EdgeBarrierController::Impl::~Impl()
@@ -202,36 +161,30 @@ void EdgeBarrierController::Impl::ResizeBarrierList(std::vector<nux::Geometry> c
}
}
-void SetupXI2Events()
-{
- Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
-
- unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
- XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
-
- XISetMask(mask.mask, XI_BarrierHit);
- XISetMask(mask.mask, XI_BarrierLeave);
- XISelectEvents (dpy, DefaultRootWindow(dpy), &mask, 1);
-}
-
void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const& layout)
{
if (parent_->force_disable())
return;
- bool edge_resist = parent_->sticky_edges();
+ size_t monitors_size = layout.size();
auto launcher_position = Settings::Instance().launcher_position();
+ bool edge_resist = parent_->sticky_edges();
+ bool needs_barrier = edge_resist && monitors_size > 1;
+ bool needs_vertical_barrier = needs_barrier;
+
+ if (parent_->options()->hide_mode() != launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER)
+ needs_vertical_barrier = true;
- for (unsigned i = 0; i < layout.size(); i++)
+ for (unsigned i = 0; i < layout.size(); ++i)
{
- auto vertical_barrier = vertical_barriers_[i];
- auto horizontal_barrier = horizontal_barriers_[i];
- auto monitor = layout[i];
+ auto const& vertical_barrier = vertical_barriers_[i];
+ auto const& horizontal_barrier = horizontal_barriers_[i];
+ auto const& monitor = layout[i];
vertical_barrier->DestroyBarrier();
horizontal_barrier->DestroyBarrier();
- if (edge_resist)
+ if (needs_barrier)
{
horizontal_barrier->x1 = monitor.x;
horizontal_barrier->x2 = monitor.x + monitor.width;
@@ -246,7 +199,7 @@ void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const
horizontal_barrier->ConstructBarrier();
}
- if (!edge_resist && parent_->options()->hide_mode() == launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER)
+ if (!needs_vertical_barrier)
continue;
if (launcher_position == LauncherPosition::LEFT)
@@ -273,8 +226,10 @@ void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const
vertical_barrier->ConstructBarrier();
}
- SetupXI2Events();
- AddEventFilter();
+ if (needs_barrier || needs_vertical_barrier)
+ input::Monitor::Get().RegisterClient(input::Events::BARRIER, sigc::mem_fun(this, &Impl::HandleEvent));
+ else
+ input::Monitor::Get().UnregisterClient(sigc::mem_fun(this, &Impl::HandleEvent));
float decay_responsiveness_mult = ((parent_->options()->edge_responsiveness() - 1) * .3f) + 1;
decaymulator_.rate_of_decay = parent_->options()->edge_decay_rate() * decay_responsiveness_mult;
@@ -283,65 +238,25 @@ void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const
edge_overcome_pressure_ = parent_->options()->edge_overcome_pressure() * overcome_responsiveness_mult;
}
-void EdgeBarrierController::Impl::AddEventFilter()
-{
- // Remove an old one, if it exists
- nux::GetGraphicsDisplay()->RemoveEventFilter(this);
-
- nux::GraphicsDisplay::EventFilterArg event_filter;
- event_filter.filter = &HandleEventCB;
- event_filter.data = this;
-
- nux::GetGraphicsDisplay()->AddEventFilter(event_filter);
-}
-
-bool EdgeBarrierController::Impl::HandleEvent(XEvent xevent)
-{
- Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
- XGenericEventCookie *cookie = &xevent.xcookie;
- bool ret = false;
-
- switch (cookie->evtype)
- {
- case (XI_BarrierHit):
- {
- if (XGetEventData(dpy, cookie))
- {
- XIBarrierEvent* barrier_event = (XIBarrierEvent*)cookie->data;
- PointerBarrierWrapper::Ptr wrapper = FindBarrierEventOwner(barrier_event);
-
- if (wrapper)
- ret = wrapper->HandleBarrierEvent(barrier_event);
- }
-
- XFreeEventData(dpy, cookie);
- break;
- }
- default:
- break;
- }
-
- return ret;
-}
-
-bool EdgeBarrierController::Impl::HandleEventCB(XEvent xevent, void* data)
+void EdgeBarrierController::Impl::HandleEvent(XEvent const& xevent)
{
- auto edge_barrier_controller = static_cast<EdgeBarrierController::Impl*>(data);
- int const xi2_opcode = edge_barrier_controller->xi2_opcode_;
+ if (xevent.xcookie.evtype != XI_BarrierHit)
+ return;
- if (xevent.type != GenericEvent || xevent.xcookie.extension != xi2_opcode)
- return false;
+ auto* barrier_event = reinterpret_cast<XIBarrierEvent*>(xevent.xcookie.data);
+ PointerBarrierWrapper::Ptr const& wrapper = FindBarrierEventOwner(barrier_event);
- return edge_barrier_controller->HandleEvent(xevent);
+ if (wrapper)
+ wrapper->HandleBarrierEvent(barrier_event);
}
PointerBarrierWrapper::Ptr EdgeBarrierController::Impl::FindBarrierEventOwner(XIBarrierEvent* barrier_event)
{
- for (auto barrier : vertical_barriers_)
+ for (auto const& barrier : vertical_barriers_)
if (barrier->OwnsBarrierEvent(barrier_event->barrier))
return barrier;
- for (auto barrier : horizontal_barriers_)
+ for (auto const& barrier : horizontal_barriers_)
if (barrier->OwnsBarrierEvent(barrier_event->barrier))
return barrier;
diff --git a/launcher/EdgeBarrierControllerPrivate.h b/launcher/EdgeBarrierControllerPrivate.h
index df852bcd0..1de19822c 100644
--- a/launcher/EdgeBarrierControllerPrivate.h
+++ b/launcher/EdgeBarrierControllerPrivate.h
@@ -53,12 +53,8 @@ struct EdgeBarrierController::Impl : public sigc::trackable
bool EventIsInsideYBreakZone(BarrierEvent::Ptr const& event);
bool EventIsInsideXBreakZone(BarrierEvent::Ptr const& event);
- void AddEventFilter();
-
PointerBarrierWrapper::Ptr FindBarrierEventOwner(XIBarrierEvent* barrier_event);
-
- static bool HandleEventCB(XEvent event, void* data);
- bool HandleEvent(XEvent event);
+ void HandleEvent(XEvent const&);
std::vector<PointerBarrierWrapper::Ptr> vertical_barriers_;
std::vector<PointerBarrierWrapper::Ptr> horizontal_barriers_;
@@ -68,7 +64,6 @@ struct EdgeBarrierController::Impl : public sigc::trackable
Decaymulator decaymulator_;
glib::Source::UniquePtr release_timeout_;
- int xi2_opcode_;
float edge_overcome_pressure_;
EdgeBarrierController* parent_;
};
diff --git a/lockscreen/KylinLockScreenShield.cpp b/lockscreen/KylinLockScreenShield.cpp
index 5f2211827..2545fabb7 100644
--- a/lockscreen/KylinLockScreenShield.cpp
+++ b/lockscreen/KylinLockScreenShield.cpp
@@ -37,7 +37,7 @@ KylinShield::KylinShield(session::Manager::Ptr const& session_manager,
Accelerators::Ptr const& accelerators,
nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
int monitor_num, bool is_primary)
- : BaseShield(session_manager, nullptr, accelerators, prompt_view, monitor_num, is_primary)
+ : BaseShield(session_manager, accelerators, prompt_view, monitor_num, is_primary)
{
is_primary ? ShowPrimaryView() : ShowSecondaryView();
EnableInputWindow(true);
diff --git a/lockscreen/LockScreenBaseShield.cpp b/lockscreen/LockScreenBaseShield.cpp
index 0d65550c3..a3154c654 100644
--- a/lockscreen/LockScreenBaseShield.cpp
+++ b/lockscreen/LockScreenBaseShield.cpp
@@ -38,7 +38,6 @@ const unsigned MAX_GRAB_WAIT = 100;
}
BaseShield::BaseShield(session::Manager::Ptr const& session,
- indicator::Indicators::Ptr const& indicators,
Accelerators::Ptr const& accelerators,
nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
int monitor_num, bool is_primary)
@@ -47,7 +46,6 @@ BaseShield::BaseShield(session::Manager::Ptr const& session,
, monitor(monitor_num)
, scale(1.0)
, session_manager_(session)
- , indicators_(indicators)
, accelerators_(accelerators)
, prompt_view_(prompt_view)
, bg_settings_(std::make_shared<BackgroundSettings>())
diff --git a/lockscreen/LockScreenBaseShield.h b/lockscreen/LockScreenBaseShield.h
index 06f47b21b..bf2ff0288 100644
--- a/lockscreen/LockScreenBaseShield.h
+++ b/lockscreen/LockScreenBaseShield.h
@@ -21,8 +21,8 @@
#define UNITY_LOCKSCREEN_BASE_SHIELD_H
#include <NuxCore/Property.h>
+#include "UnityCore/ConnectionManager.h"
#include "UnityCore/SessionManager.h"
-#include "UnityCore/Indicators.h"
#include "UnityCore/GLibSource.h"
#include "unity-shared/MockableBaseWindow.h"
@@ -39,8 +39,8 @@ class CofView;
class BaseShield : public MockableBaseWindow
{
public:
- BaseShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&,
- Accelerators::Ptr const&, nux::ObjectPtr<AbstractUserPromptView> const&,
+ BaseShield(session::Manager::Ptr const&, Accelerators::Ptr const&,
+ nux::ObjectPtr<AbstractUserPromptView> const&,
int monitor_num, bool is_primary);
nux::Property<bool> primary;
@@ -69,7 +69,6 @@ protected:
void UpdateScale();
session::Manager::Ptr session_manager_;
- indicator::Indicators::Ptr indicators_;
Accelerators::Ptr accelerators_;
nux::ObjectPtr<AbstractUserPromptView> prompt_view_;
std::shared_ptr<BackgroundSettings> bg_settings_;
diff --git a/lockscreen/LockScreenController.cpp b/lockscreen/LockScreenController.cpp
index d8cf9f567..10df852bc 100644
--- a/lockscreen/LockScreenController.cpp
+++ b/lockscreen/LockScreenController.cpp
@@ -134,7 +134,7 @@ Controller::Controller(DBusManager::Ptr const& dbus_manager,
upstart_wrapper_->Emit("desktop-unlock");
systemd_wrapper_->Stop(SYSTEMD_LOCK_TARGET);
accelerator_controller_.reset();
- indicators_.reset();
+ menu_manager_.reset();
}
else if (!prompt_activation_)
{
@@ -256,7 +256,7 @@ void Controller::EnsureShields(std::vector<nux::Geometry> const& monitors)
if (i >= shields_size)
{
- shield = shield_factory_->CreateShield(session_manager_, indicators_, accelerator_controller_->GetAccelerators(), prompt_view, i, i == primary);
+ shield = shield_factory_->CreateShield(session_manager_, menu_manager_, accelerator_controller_->GetAccelerators(), prompt_view, i, i == primary);
is_new = true;
}
@@ -466,7 +466,7 @@ void Controller::OnScreenSaverActivationRequest(bool activate)
void Controller::LockScreen()
{
- indicators_ = std::make_shared<indicator::LockScreenDBusIndicators>();
+ menu_manager_ = std::make_shared<menu::Manager>(std::make_shared<indicator::LockScreenDBusIndicators>(), key_grabber_);
upstart_wrapper_->Emit("desktop-lock");
systemd_wrapper_->Start(SYSTEMD_LOCK_TARGET);
diff --git a/lockscreen/LockScreenController.h b/lockscreen/LockScreenController.h
index 8f7cbf3c5..552dba0ed 100644
--- a/lockscreen/LockScreenController.h
+++ b/lockscreen/LockScreenController.h
@@ -30,7 +30,6 @@
#include "SuspendInhibitorManager.h"
#include "ScreenSaverDBusManager.h"
#include "unity-shared/BackgroundEffectHelper.h"
-#include "unity-shared/KeyGrabber.h"
#include "unity-shared/SystemdWrapper.h"
#include "unity-shared/UpstartWrapper.h"
@@ -87,8 +86,8 @@ private:
DBusManager::Ptr dbus_manager_;
session::Manager::Ptr session_manager_;
+ menu::Manager::Ptr menu_manager_;
key::Grabber::Ptr key_grabber_;
- indicator::Indicators::Ptr indicators_;
AcceleratorController::Ptr accelerator_controller_;
SystemdWrapper::Ptr systemd_wrapper_;
UpstartWrapper::Ptr upstart_wrapper_;
diff --git a/lockscreen/LockScreenPanel.cpp b/lockscreen/LockScreenPanel.cpp
index d2fbc8d39..168a46c6e 100644
--- a/lockscreen/LockScreenPanel.cpp
+++ b/lockscreen/LockScreenPanel.cpp
@@ -24,7 +24,7 @@
#include "LockScreenSettings.h"
#include "panel/PanelIndicatorsView.h"
-#include "unity-shared/CairoTexture.h"
+#include "unity-shared/InputMonitor.h"
#include "unity-shared/StaticCairoText.h"
#include "unity-shared/PanelStyle.h"
#include "unity-shared/RawPixel.h"
@@ -38,24 +38,24 @@ namespace lockscreen
namespace
{
const RawPixel PADDING = 5_em;
+const nux::Color BG_COLOR(0.1, 0.1, 0.1, 0.4);
}
using namespace indicator;
using namespace panel;
-Panel::Panel(int monitor_, Indicators::Ptr const& indicators, session::Manager::Ptr const& session_manager)
+Panel::Panel(int monitor_, menu::Manager::Ptr const& menu_manager, session::Manager::Ptr const& session_manager)
: nux::View(NUX_TRACKER_LOCATION)
, active(false)
, monitor(monitor_)
- , indicators_(indicators)
+ , menu_manager_(menu_manager)
, needs_geo_sync_(true)
{
double scale = unity::Settings::Instance().em(monitor)->DPIScale();
auto* layout = new nux::HLayout();
layout->SetLeftAndRightPadding(PADDING.CP(scale), 0);
SetLayout(layout);
-
- BuildTexture();
+ UpdateSize();
// Add setting
auto *hostname = new StaticCairoText(session_manager->HostName());
@@ -72,34 +72,33 @@ Panel::Panel(int monitor_, Indicators::Ptr const& indicators, session::Manager::
indicators_view_->on_indicator_updated.connect(sigc::mem_fun(this, &Panel::OnIndicatorViewUpdated));
layout->AddView(indicators_view_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
- for (auto const& indicator : indicators_->GetIndicators())
+ auto indicators = menu_manager_->Indicators();
+ menu_manager_->RegisterTracker(GetPanelName(), (sigc::track_obj([this] (int x, int y, double speed) {
+ indicators_view_->ActivateEntryAt(x, y);
+ }, *this)));
+
+ for (auto const& indicator : indicators->GetIndicators())
AddIndicator(indicator);
- indicators_->on_object_added.connect(sigc::mem_fun(this, &Panel::AddIndicator));
- indicators_->on_object_removed.connect(sigc::mem_fun(this, &Panel::RemoveIndicator));
- indicators_->on_entry_show_menu.connect(sigc::mem_fun(this, &Panel::OnEntryShowMenu));
- indicators_->on_entry_activated.connect(sigc::mem_fun(this, &Panel::OnEntryActivated));
- indicators_->on_entry_activate_request.connect(sigc::mem_fun(this, &Panel::OnEntryActivateRequest));
+ indicators->on_object_added.connect(sigc::mem_fun(this, &Panel::AddIndicator));
+ indicators->on_object_removed.connect(sigc::mem_fun(this, &Panel::RemoveIndicator));
+ indicators->on_entry_show_menu.connect(sigc::mem_fun(this, &Panel::OnEntryShowMenu));
+ indicators->on_entry_activated.connect(sigc::mem_fun(this, &Panel::OnEntryActivated));
+ indicators->on_entry_activate_request.connect(sigc::mem_fun(this, &Panel::OnEntryActivateRequest));
monitor.changed.connect([this, hostname] (int monitor) {
double scale = unity::Settings::Instance().em(monitor)->DPIScale();
hostname->SetScale(scale);
static_cast<nux::HLayout*>(GetLayout())->SetLeftAndRightPadding(PADDING.CP(scale), 0);
indicators_view_->SetMonitor(monitor);
- BuildTexture();
+ UpdateSize();
QueueRelayout();
});
}
-void Panel::BuildTexture()
+void Panel::UpdateSize()
{
int height = panel::Style::Instance().PanelHeight(monitor);
- nux::CairoGraphics context(CAIRO_FORMAT_ARGB32, 1, height);
- auto* cr = context.GetInternalContext();
- cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
- cairo_paint_with_alpha(cr, 0.4);
- bg_texture_ = texture_ptr_from_cairo_graphics(context);
-
view_layout_->SetMinimumHeight(height);
view_layout_->SetMaximumHeight(height);
}
@@ -165,12 +164,7 @@ void Panel::OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, in
if (!GetInputEventSensitivity())
return;
- if (!active)
- {
- // This is ugly... But Nux fault!
- WindowManager::Default().UnGrabMousePointer(CurrentTime, button, x, y);
- active = true;
- }
+ active = true;
}
void Panel::OnEntryActivateRequest(std::string const& entry_id)
@@ -184,36 +178,16 @@ void Panel::OnEntryActivated(std::string const& panel, std::string const& entry_
if (!GetInputEventSensitivity() || (!panel.empty() && panel != GetPanelName()))
return;
- bool active = !entry_id.empty();
+ bool valid_entry = !entry_id.empty();
- if (active && !WindowManager::Default().IsScreenGrabbed())
+ if (valid_entry && !WindowManager::Default().IsScreenGrabbed())
{
// The menu didn't grab the keyboard, let's take it back.
nux::GetWindowCompositor().GrabKeyboardAdd(static_cast<nux::BaseWindow*>(GetTopLevelViewWindow()));
}
- if (active && !track_menu_pointer_timeout_)
- {
- track_menu_pointer_timeout_.reset(new glib::Timeout(16));
- track_menu_pointer_timeout_->Run([this] {
- nux::Point const& mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
- if (tracked_pointer_pos_ != mouse)
- {
- if (GetAbsoluteGeometry().IsPointInside(mouse.x, mouse.y))
- indicators_view_->ActivateEntryAt(mouse.x, mouse.y);
-
- tracked_pointer_pos_ = mouse;
- }
-
- return true;
- });
- }
- else if (!active)
- {
- track_menu_pointer_timeout_.reset();
- tracked_pointer_pos_ = {-1, -1};
- this->active = false;
- }
+ if (!valid_entry)
+ active = valid_entry;
}
void Panel::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
@@ -227,12 +201,7 @@ void Panel::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
graphics_engine.PushClippingRectangle(geo);
nux::GetPainter().PaintBackground(graphics_engine, geo);
- nux::TexCoordXForm texxform;
- texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_CLAMP);
- graphics_engine.QRP_1Tex(geo.x, geo.y, geo.width, geo.height,
- bg_texture_->GetDeviceTexture(), texxform,
- nux::color::White);
-
+ graphics_engine.QRP_Color(geo.x, geo.y, geo.width, geo.height, BG_COLOR);
view_layout_->ProcessDraw(graphics_engine, force_draw);
graphics_engine.PopClippingRectangle();
@@ -242,7 +211,7 @@ void Panel::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
{
EntryLocationMap locations;
indicators_view_->GetGeometryForSync(locations);
- indicators_->SyncGeometries(GetPanelName(), locations);
+ menu_manager_->Indicators()->SyncGeometries(GetPanelName(), locations);
needs_geo_sync_ = false;
}
}
diff --git a/lockscreen/LockScreenPanel.h b/lockscreen/LockScreenPanel.h
index 664eccf50..cab2ae3ae 100644
--- a/lockscreen/LockScreenPanel.h
+++ b/lockscreen/LockScreenPanel.h
@@ -22,9 +22,9 @@
#include <Nux/Nux.h>
#include <Nux/View.h>
-#include "UnityCore/Indicators.h"
#include "UnityCore/GLibSource.h"
#include "UnityCore/SessionManager.h"
+#include "unity-shared/MenuManager.h"
namespace unity
{
@@ -39,7 +39,7 @@ namespace lockscreen
class Panel : public nux::View
{
public:
- Panel(int monitor, indicator::Indicators::Ptr const&, session::Manager::Ptr const&);
+ Panel(int monitor, menu::Manager::Ptr const&, session::Manager::Ptr const&);
nux::Property<bool> active;
nux::Property<int> monitor;
@@ -55,20 +55,16 @@ private:
void AddIndicator(indicator::Indicator::Ptr const&);
void RemoveIndicator(indicator::Indicator::Ptr const&);
void OnIndicatorViewUpdated();
- void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& geo);
+ void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const&);
void OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button);
void OnEntryActivateRequest(std::string const& entry_id);
- void BuildTexture();
+ void UpdateSize();
std::string GetPanelName() const;
- indicator::Indicators::Ptr indicators_;
+ menu::Manager::Ptr menu_manager_;
panel::PanelIndicatorsView* indicators_view_;
- nux::ObjectPtr<nux::BaseTexture> bg_texture_;
-
bool needs_geo_sync_;
- nux::Point tracked_pointer_pos_;
- glib::Source::UniquePtr track_menu_pointer_timeout_;
};
} // lockscreen namespace
diff --git a/lockscreen/LockScreenShield.cpp b/lockscreen/LockScreenShield.cpp
index 264cf7132..ba6275eaa 100644
--- a/lockscreen/LockScreenShield.cpp
+++ b/lockscreen/LockScreenShield.cpp
@@ -32,11 +32,12 @@ namespace lockscreen
{
Shield::Shield(session::Manager::Ptr const& session_manager,
- indicator::Indicators::Ptr const& indicators,
+ menu::Manager::Ptr const& menu_manager,
Accelerators::Ptr const& accelerators,
nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
int monitor_num, bool is_primary)
- : BaseShield(session_manager, indicators, accelerators, prompt_view, monitor_num, is_primary)
+ : BaseShield(session_manager, accelerators, prompt_view, monitor_num, is_primary)
+ , menu_manager_(menu_manager)
, panel_view_(nullptr)
{
is_primary ? ShowPrimaryView() : ShowSecondaryView();
@@ -91,11 +92,11 @@ void Shield::ShowPrimaryView()
Panel* Shield::CreatePanel()
{
- if (!indicators_ || !session_manager_)
+ if (!menu_manager_ || !session_manager_)
return nullptr;
- panel_view_ = new Panel(monitor, indicators_, session_manager_);
- panel_active_conn_ = panel_view_->active.changed.connect([this] (bool active) {
+ panel_view_ = new Panel(monitor, menu_manager_, session_manager_);
+ panel_view_->active.changed.connect(sigc::track_obj([this] (bool active) {
if (primary())
{
if (active)
@@ -109,7 +110,7 @@ Panel* Shield::CreatePanel()
GrabScreen(false);
}
}
- });
+ }, *this));
return panel_view_;
}
diff --git a/lockscreen/LockScreenShield.h b/lockscreen/LockScreenShield.h
index 053e0102f..3df1ba837 100644
--- a/lockscreen/LockScreenShield.h
+++ b/lockscreen/LockScreenShield.h
@@ -20,8 +20,9 @@
#ifndef UNITY_LOCKSCREEN_SHIELD_H
#define UNITY_LOCKSCREEN_SHIELD_H
-#include <UnityCore/ConnectionManager.h>
#include "LockScreenBaseShield.h"
+#include "unity-shared/MenuManager.h"
+
namespace unity
{
@@ -35,7 +36,7 @@ class Shield : public BaseShield
{
public:
Shield(session::Manager::Ptr const&,
- indicator::Indicators::Ptr const&,
+ menu::Manager::Ptr const&,
Accelerators::Ptr const&,
nux::ObjectPtr<AbstractUserPromptView> const&,
int monitor, bool is_primary);
@@ -50,7 +51,7 @@ private:
void ShowPrimaryView() override;
Panel* CreatePanel();
- connection::Wrapper panel_active_conn_;
+ menu::Manager::Ptr menu_manager_;
Panel* panel_view_;
};
diff --git a/lockscreen/LockScreenShieldFactory.cpp b/lockscreen/LockScreenShieldFactory.cpp
index 4f8d51ade..45f4cccc0 100644
--- a/lockscreen/LockScreenShieldFactory.cpp
+++ b/lockscreen/LockScreenShieldFactory.cpp
@@ -28,7 +28,7 @@ namespace lockscreen
{
nux::ObjectPtr<BaseShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager,
- indicator::Indicators::Ptr const& indicators,
+ menu::Manager::Ptr const& menu_manager,
Accelerators::Ptr const& accelerators,
nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
int monitor, bool is_primary)
@@ -38,7 +38,7 @@ nux::ObjectPtr<BaseShield> ShieldFactory::CreateShield(session::Manager::Ptr con
if (Settings::Instance().desktop_type() == DesktopType::UBUNTUKYLIN)
shield = new KylinShield(session_manager, accelerators, prompt_view, monitor, is_primary);
else
- shield = new Shield(session_manager, indicators, accelerators, prompt_view, monitor, is_primary);
+ shield = new Shield(session_manager, menu_manager, accelerators, prompt_view, monitor, is_primary);
return shield;
}
diff --git a/lockscreen/LockScreenShieldFactory.h b/lockscreen/LockScreenShieldFactory.h
index 6910e097c..de3c52968 100644
--- a/lockscreen/LockScreenShieldFactory.h
+++ b/lockscreen/LockScreenShieldFactory.h
@@ -22,7 +22,7 @@
#include <NuxCore/NuxCore.h>
#include "UnityCore/SessionManager.h"
-#include "UnityCore/Indicators.h"
+#include "unity-shared/MenuManager.h"
#include "LockScreenAccelerators.h"
namespace unity
@@ -41,7 +41,7 @@ struct ShieldFactoryInterface
virtual ~ShieldFactoryInterface() = default;
virtual nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
- indicator::Indicators::Ptr const&,
+ menu::Manager::Ptr const&,
Accelerators::Ptr const&,
nux::ObjectPtr<AbstractUserPromptView> const&,
int monitor, bool is_primary) = 0;
@@ -50,7 +50,7 @@ struct ShieldFactoryInterface
struct ShieldFactory : ShieldFactoryInterface
{
nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
- indicator::Indicators::Ptr const&,
+ menu::Manager::Ptr const&,
Accelerators::Ptr const&,
nux::ObjectPtr<AbstractUserPromptView> const&,
int monitor, bool is_primary) override;
diff --git a/panel/PanelIndicatorEntryView.cpp b/panel/PanelIndicatorEntryView.cpp
index 67a80956b..da5635c99 100644
--- a/panel/PanelIndicatorEntryView.cpp
+++ b/panel/PanelIndicatorEntryView.cpp
@@ -33,6 +33,8 @@
#include "unity-shared/RawPixel.h"
#include "unity-shared/WindowManager.h"
#include "unity-shared/ThemeSettings.h"
+#include "unity-shared/UBusWrapper.h"
+#include "unity-shared/UBusMessages.h"
#include "unity-shared/UnitySettings.h"
namespace unity
@@ -117,6 +119,9 @@ void PanelIndicatorEntryView::OnMouseDown(int x, int y, long button_flags, long
}
else
{
+ if (overlay_showing_)
+ UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
+
WindowManager& wm = WindowManager::Default();
if (wm.IsExpoActive())
@@ -140,6 +145,11 @@ void PanelIndicatorEntryView::OnMouseDown(int x, int y, long button_flags, long
wm.TerminateScale();
}
+ // This is ugly... But Nux fault!
+ auto const& abs_geo = GetAbsoluteGeometry();
+ guint64 timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp;
+ WindowManager::Default().UnGrabMousePointer(timestamp, button, abs_geo.x, abs_geo.y);
+
Activate(button);
}
}
diff --git a/panel/PanelMenuView.cpp b/panel/PanelMenuView.cpp
index f2aa86053..2bcdd494c 100644
--- a/panel/PanelMenuView.cpp
+++ b/panel/PanelMenuView.cpp
@@ -102,7 +102,6 @@ PanelMenuView::PanelMenuView(menu::Manager::Ptr const& menus)
, ignore_menu_visibility_(false)
, integrated_menus_(menu_manager_->integrated_menus())
, always_show_menus_(menu_manager_->always_show_menus())
- , ignore_leave_events_(false)
, desktop_name_(get_current_desktop())
{
if (ApplicationWindowPtr const& win = ApplicationManager::Default().GetActiveWindow())
@@ -724,7 +723,7 @@ void PanelMenuView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw
if (new_application_ && !is_inside_)
{
- if (opacity() != 1.0f)
+ if (opacity() != 1.0f && menu_manager_->discovery() > 0)
StartFadeIn(menu_manager_->discovery_fadein());
}
else
@@ -1814,14 +1813,9 @@ void PanelMenuView::OnPanelViewMouseEnter(int x, int y, unsigned long mouse_butt
}
}
-void PanelMenuView::IgnoreLeaveEvents(bool ignore)
-{
- ignore_leave_events_ = ignore;
-}
-
void PanelMenuView::OnPanelViewMouseLeave(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state)
{
- if (always_show_menus_ || ignore_leave_events_)
+ if (always_show_menus_)
return;
if (is_inside_)
diff --git a/panel/PanelMenuView.h b/panel/PanelMenuView.h
index 93310d10a..7d3effb84 100644
--- a/panel/PanelMenuView.h
+++ b/panel/PanelMenuView.h
@@ -56,7 +56,6 @@ public:
bool HasKeyActivableMenus() const;
void NotifyAllMenusClosed();
- void IgnoreLeaveEvents(bool);
virtual void AddIndicator(indicator::Indicator::Ptr const& indicator);
@@ -192,7 +191,6 @@ private:
bool ignore_menu_visibility_;
bool integrated_menus_;
bool always_show_menus_;
- bool ignore_leave_events_;
nux::Geometry monitor_geo_;
const std::string desktop_name_;
diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp
index 3bf0c691e..cd08c46cd 100644
--- a/panel/PanelView.cpp
+++ b/panel/PanelView.cpp
@@ -42,7 +42,8 @@ namespace panel
namespace
{
const RawPixel TRIANGLE_THRESHOLD = 5_em;
-const int refine_gradient_midpoint = 959;
+const double SCRUB_VELOCITY_THRESHOLD = 0.05;
+const RawPixel REFINE_GRADIENT_MIDPOINT = 959;
}
@@ -113,10 +114,9 @@ PanelView::PanelView(MockableBaseWindow* parent, menu::Manager::Ptr const& menus
remote_->on_object_added.connect(sigc::mem_fun(this, &PanelView::OnObjectAdded));
remote_->on_object_removed.connect(sigc::mem_fun(this, &PanelView::OnObjectRemoved));
- remote_->on_entry_activated.connect(sigc::mem_fun(this, &PanelView::OnEntryActivated));
- remote_->on_entry_show_menu.connect(sigc::mem_fun(this, &PanelView::OnEntryShowMenu));
menus->key_activate_entry.connect(sigc::mem_fun(this, &PanelView::ActivateEntry));
menus->open_first.connect(sigc::mem_fun(this, &PanelView::ActivateFirstSensitive));
+ menus->RegisterTracker(GetPanelName(), sigc::mem_fun(this, &PanelView::OnMenuPointerMoved));
ubus_manager_.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &PanelView::OnOverlayHidden));
ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &PanelView::OnOverlayShown));
@@ -374,7 +374,7 @@ PanelView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
GfxContext.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
nux::TexCoordXForm refine_texxform;
- int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint);
+ int refine_x_pos = geo.x + (stored_dash_width_ - REFINE_GRADIENT_MIDPOINT.CP(Settings::Instance().em(monitor_)));
if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_);
@@ -473,7 +473,7 @@ PanelView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
nux::Geometry refine_geo = geo;
- int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint);
+ int refine_x_pos = geo.x + (stored_dash_width_ - REFINE_GRADIENT_MIDPOINT.CP(Settings::Instance().em(monitor_)));
if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_);
@@ -627,7 +627,7 @@ void PanelView::OnIndicatorViewUpdated()
QueueDraw();
}
-void PanelView::OnMenuPointerMoved(int x, int y)
+void PanelView::OnMenuPointerMoved(int x, int y, double speed)
{
nux::Geometry const& geo = GetAbsoluteGeometry();
@@ -648,116 +648,6 @@ void PanelView::OnMenuPointerMoved(int x, int y)
}
}
-static bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
-{
- int s = t0.y * t2.x - t0.x * t2.y + (t2.y - t0.y) * p.x + (t0.x - t2.x) * p.y;
- int t = t0.x * t1.y - t0.y * t1.x + (t0.y - t1.y) * p.x + (t1.x - t0.x) * p.y;
-
- if ((s < 0) != (t < 0))
- return false;
-
- int A = -t1.y * t2.x + t0.y * (t2.x - t1.x) + t0.x * (t1.y - t2.y) + t1.x * t2.y;
- if (A < 0)
- {
- s = -s;
- t = -t;
- A = -A;
- }
-
- return s > 0 && t > 0 && (s + t) < A;
-}
-
-static double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, util::Timer &timer)
-{
- int dx, dy;
- double speed;
- auto millis = timer.ElapsedMicroSeconds();
-
- if (millis == 0)
- return 1;
-
- dx = p0.x - p1.x;
- dy = p0.y - p1.y;
-
- speed = sqrt(dx * dx + dy * dy) / millis * 1000;
-
- return speed;
-}
-
-bool PanelView::TrackMenuPointer()
-{
- nux::Point const& mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
- double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, mouse_tracker_timer_);
-
- mouse_tracker_timer_.Reset();
- tracked_pointer_pos_ = mouse;
-
- double scale = Settings::Instance().em(monitor_)->DPIScale();
- if (speed > 0 && PointInTriangle(mouse,
- nux::Point(triangle_top_corner_.x, std::max(triangle_top_corner_.y - TRIANGLE_THRESHOLD.CP(scale), 0)),
- nux::Point(menu_geo_.x, menu_geo_.y),
- nux::Point(menu_geo_.x + menu_geo_.width, menu_geo_.y)))
- {
- return true;
- }
-
- if (mouse != triangle_top_corner_)
- {
- triangle_top_corner_ = mouse;
- OnMenuPointerMoved(mouse.x, mouse.y);
- }
-
- return true;
-}
-
-void PanelView::OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& menu_geo)
-{
- if (!panel.empty() && panel != GetPanelName())
- return;
-
- menu_geo_ = menu_geo;
-
- bool active = !entry_id.empty();
- if (active && !track_menu_pointer_timeout_)
- {
- //
- // Track menus being scrubbed at 60Hz (about every 16 millisec)
- // It might sound ugly, but it's far nicer (and more responsive) than the
- // code it replaces which used to capture motion events in another process
- // (unity-panel-service) and send them to us over dbus.
- // NOTE: The reason why we have to use a timer instead of tracking motion
- // events is because the motion events will never be delivered to this
- // process. All the motion events will go to unity-panel-service while
- // scrubbing because the active panel menu has (needs) the pointer grab.
- //
- mouse_tracker_timer_.Reset();
- triangle_top_corner_ = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
- track_menu_pointer_timeout_.reset(new glib::Timeout(16));
- track_menu_pointer_timeout_->Run(sigc::mem_fun(this, &PanelView::TrackMenuPointer));
- }
- else if (!active)
- {
- track_menu_pointer_timeout_.reset();
- menu_view_->NotifyAllMenusClosed();
- tracked_pointer_pos_ = {-1, -1};
- }
-
- if (overlay_is_open_)
- ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
-}
-
-void PanelView::OnEntryShowMenu(std::string const& entry_id, unsigned xid,
- int x, int y, unsigned button)
-{
- if (!track_menu_pointer_timeout_)
- {
- // This is ugly... But Nux fault!
- menu_view_->IgnoreLeaveEvents(true);
- WindowManager::Default().UnGrabMousePointer(CurrentTime, button, x, y);
- menu_view_->IgnoreLeaveEvents(false);
- }
-}
-
bool PanelView::ActivateFirstSensitive()
{
if (!IsActive())
@@ -768,7 +658,6 @@ bool PanelView::ActivateFirstSensitive()
{
// Since this only happens on keyboard events, we need to prevent that the
// pointer tracker would select another entry.
- tracked_pointer_pos_ = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
return true;
}
@@ -785,7 +674,6 @@ bool PanelView::ActivateEntry(std::string const& entry_id)
{
// Since this only happens on keyboard events, we need to prevent that the
// pointer tracker would select another entry.
- tracked_pointer_pos_ = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
return true;
}
diff --git a/panel/PanelView.h b/panel/PanelView.h
index c25d251e5..48a6a4bed 100644
--- a/panel/PanelView.h
+++ b/panel/PanelView.h
@@ -35,7 +35,6 @@
#include "unity-shared/Introspectable.h"
#include "unity-shared/MenuManager.h"
#include "unity-shared/MockableBaseWindow.h"
-#include "unity-shared/Timer.h"
#include "PanelMenuView.h"
#include "PanelTray.h"
#include "PanelIndicatorsView.h"
@@ -88,9 +87,6 @@ protected:
void OnObjectAdded(indicator::Indicator::Ptr const& proxy);
void OnObjectRemoved(indicator::Indicator::Ptr const& proxy);
void OnIndicatorViewUpdated();
- void OnMenuPointerMoved(int x, int y);
- void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& geo);
- void OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button);
private:
std::string GetPanelName() const;
@@ -100,6 +96,8 @@ private:
void OnSpreadInitiate();
void OnSpreadTerminate();
void OnLowGfxChanged();
+ void OnMenuPointerMoved(int x, int y, double speed);
+ void OnActiveEntryEvent(XEvent const&);
void EnableOverlayMode(bool);
void LoadTextures();
@@ -109,7 +107,6 @@ private:
bool IsTransparent();
void UpdateBackground();
void ForceUpdateBackground();
- bool TrackMenuPointer();
void SyncGeometries();
void AddPanelView(PanelIndicatorsView* child, unsigned int stretchFactor);
@@ -133,10 +130,6 @@ private:
BaseTexturePtr bg_refine_single_column_tex_;
std::unique_ptr<nux::AbstractPaintLayer> bg_refine_single_column_layer_;
- std::string active_overlay_;
- nux::Point tracked_pointer_pos_, triangle_top_corner_;
- util::Timer mouse_tracker_timer_;
-
bool is_dirty_;
bool opacity_maximized_toggle_;
bool needs_geo_sync_;
@@ -144,15 +137,13 @@ private:
float opacity_;
int monitor_;
int stored_dash_width_;
-
- nux::Geometry menu_geo_;
+ std::string active_overlay_;
connection::Manager on_indicator_updated_connections_;
connection::Manager maximized_opacity_toggle_connections_;
BackgroundEffectHelper bg_effect_helper_;
nux::ObjectPtr<nux::IOpenGLBaseTexture> bg_blur_texture_;
UBusManager ubus_manager_;
- glib::Source::UniquePtr track_menu_pointer_timeout_;
};
} // namespace panel
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index 9f34cd03a..ca920df0c 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -3473,6 +3473,7 @@ void UnityWindow::moveNotify(int x, int y, bool immediate)
void UnityWindow::resizeNotify(int x, int y, int w, int h)
{
deco_win_->UpdateDecorationPositionDelayed();
+ CleanupCachedTextures();
PluginAdapter::Default().NotifyResized(window, x, y, w, h);
window->resizeNotify(x, y, w, h);
}
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index d11a2322a..43df66e72 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -56,6 +56,7 @@
#include "DashStyle.h"
#include "EdgeBarrierController.h"
#include "FavoriteStoreGSettings.h"
+#include "InputMonitor.h"
#include "ShortcutController.h"
#include "LauncherController.h"
#include "LockScreenController.h"
@@ -317,6 +318,7 @@ private:
internal::FavoriteStoreGSettings favorite_store_;
ThumbnailGenerator thumbnail_generator_;
lockscreen::Settings lockscreen_settings_;
+ input::Monitor input_monitor_;
/* The window thread should be the last thing removed, as c++ does it in reverse order */
std::unique_ptr<nux::WindowThread> wt;
diff --git a/services/panel-service.c b/services/panel-service.c
index b9b86cd7f..4451fffa5 100644
--- a/services/panel-service.c
+++ b/services/panel-service.c
@@ -80,6 +80,7 @@ struct _PanelServicePrivate
gint last_right;
gint last_bottom;
guint32 last_menu_button;
+ guint64 last_open_time;
GSettings *gsettings;
KeyBinding menu_toggle;
@@ -92,6 +93,7 @@ struct _PanelServicePrivate
/* Globals */
static gboolean suppress_signals = FALSE;
+static void (*default_menu_shell_deactivate) (GtkMenuShell *menu_shell);
enum
{
@@ -138,6 +140,7 @@ static void sort_indicators (PanelService *);
static void notify_object (IndicatorObject *object);
static void update_keybinding (GSettings *, const gchar *, gpointer);
static void emit_upstart_event (const gchar *);
+static void menu_shell_deactivate_override (GtkMenuShell *menu_shell);
static gchar * get_indicator_entry_id_by_entry (IndicatorObjectEntry *entry);
static IndicatorObjectEntry * get_indicator_entry_by_id (PanelService *self, const gchar *entry_id);
static GdkFilterReturn event_filter (GdkXEvent *, GdkEvent *, PanelService *);
@@ -161,7 +164,7 @@ panel_service_class_dispose (GObject *self)
if (GTK_IS_WIDGET (priv->last_menu) &&
gtk_widget_get_realized (GTK_WIDGET (priv->last_menu)))
{
- gtk_menu_popdown (GTK_MENU (priv->last_menu));
+ panel_service_close_active_entry (PANEL_SERVICE (self));
g_signal_handlers_disconnect_by_data (priv->last_menu, self);
priv->last_menu = NULL;
}
@@ -435,6 +438,25 @@ get_indicator_entry_by_id (PanelService *self, const gchar *entry_id)
return entry;
}
+static const gchar *
+get_indicator_entry_id_by_menu (PanelService *self, GtkMenu *menu)
+{
+ GHashTableIter iter;
+ IndicatorObjectEntry* entry;
+ gchar *id;
+
+ g_hash_table_iter_init (&iter, self->priv->id2entry_hash);
+ while (g_hash_table_iter_next (&iter, (gpointer*) &id, (gpointer*) &entry))
+ {
+ if (entry && entry->menu == menu)
+ {
+ return id;
+ }
+ }
+
+ return NULL;
+}
+
static void
ensure_entry_menu_is_closed (PanelService *self,
const gchar *panel_id,
@@ -446,7 +468,9 @@ ensure_entry_menu_is_closed (PanelService *self,
if (GTK_IS_MENU (priv->last_menu) && priv->last_menu == entry->menu)
{
if (!priv->last_panel || !panel_id || g_strcmp0 (priv->last_panel, panel_id) == 0)
- gtk_menu_popdown (entry->menu);
+ {
+ panel_service_close_active_entry (self);
+ }
}
}
@@ -590,17 +614,15 @@ event_filter (GdkXEvent *ev, GdkEvent *gev, PanelService *self)
event_matches_keybinding (event->mods.base, keysym, &priv->show_dash) ||
event_matches_keybinding (event->mods.base, keysym, &priv->show_hud))
{
- if (GTK_IS_MENU (priv->last_menu))
- gtk_menu_popdown (GTK_MENU (priv->last_menu));
-
+ panel_service_close_active_entry (self);
ret = GDK_FILTER_REMOVE;
}
else if (event->mods.base != GDK_CONTROL_MASK)
{
if (!IsModifierKey (keysym) && (event->mods.base != 0 || is_allowed_keysym (keysym)))
{
- if (GTK_IS_MENU (priv->last_menu) && !is_control_keysym (keysym))
- gtk_menu_popdown (GTK_MENU (priv->last_menu));
+ if (!is_control_keysym (keysym))
+ panel_service_close_active_entry (self);
reinject_key_event_to_root_window (event);
ret = GDK_FILTER_REMOVE;
@@ -1370,9 +1392,7 @@ on_indicator_menu_show (IndicatorObject *object,
if (!entry)
{
- if (GTK_IS_MENU (self->priv->last_menu))
- gtk_menu_popdown (GTK_MENU (self->priv->last_menu));
-
+ panel_service_close_active_entry (self);
return;
}
@@ -1840,8 +1860,16 @@ static void
on_active_menu_hidden (GtkMenu *menu, PanelService *self)
{
PanelServicePrivate *priv = self->priv;
+ GtkMenuShellClass *menu_shell_class = GTK_MENU_SHELL_GET_CLASS (priv->last_menu);
+
g_signal_handlers_disconnect_by_data (priv->last_menu, self);
+ if (menu_shell_class && default_menu_shell_deactivate &&
+ menu_shell_class->deactivate != default_menu_shell_deactivate)
+ {
+ menu_shell_class->deactivate = default_menu_shell_deactivate;
+ }
+
priv->last_x = 0;
priv->last_y = 0;
priv->last_menu_button = 0;
@@ -1853,6 +1881,7 @@ on_active_menu_hidden (GtkMenu *menu, PanelService *self)
priv->last_right = 0;
priv->last_top = 0;
priv->last_bottom = 0;
+ priv->last_open_time = 0;
priv->use_event = FALSE;
priv->pressed_entry = NULL;
@@ -2270,6 +2299,34 @@ menuitem_activated (GtkWidget *menuitem, IndicatorObjectEntry *entry)
}
static void
+menu_shell_deactivate_override (GtkMenuShell *menu_shell)
+{
+ PanelService *self = panel_service_get_default ();
+ const gchar *entry_id;
+
+ if (gtk_get_current_event () && GTK_MENU (menu_shell) == self->priv->last_menu)
+ {
+ guint64 ms_open = (g_get_monotonic_time () - self->priv->last_open_time) / 1000;
+
+ if (ms_open < 50)
+ {
+ /* If the menu shell deactivation was requested by an event, we ensure this
+ * didn't happen too early to activation, or there could be a race causing
+ * no menu to appear. Also since the item is now marked as inactive, we should
+ * manually highlight it. */
+ entry_id = get_indicator_entry_id_by_menu (self, self->priv->last_menu);
+
+ if (entry_id)
+ g_signal_emit (self, _service_signals[ENTRY_ACTIVATE_REQUEST], 0, entry_id);
+
+ return;
+ }
+ }
+
+ default_menu_shell_deactivate (menu_shell);
+}
+
+static void
panel_service_show_entry_common (PanelService *self,
IndicatorObject *object,
IndicatorObjectEntry *entry,
@@ -2281,6 +2338,7 @@ panel_service_show_entry_common (PanelService *self,
{
PanelServicePrivate *priv;
GtkWidget *last_menu;
+ GtkMenuShellClass *menu_shell_class;
g_return_if_fail (PANEL_IS_SERVICE (self));
g_return_if_fail (INDICATOR_IS_OBJECT (object));
@@ -2350,6 +2408,14 @@ panel_service_show_entry_common (PanelService *self,
g_signal_connect_after (priv->last_menu, "move-current",
G_CALLBACK (on_active_menu_move_current), self);
+ /* Override the menu deactivation in order to prevent it to close too early */
+ menu_shell_class = GTK_MENU_SHELL_GET_CLASS (priv->last_menu);
+ if (menu_shell_class && menu_shell_class->deactivate != menu_shell_deactivate_override)
+ {
+ default_menu_shell_deactivate = menu_shell_class->deactivate;
+ menu_shell_class->deactivate = menu_shell_deactivate_override;
+ }
+
gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->last_menu), TRUE);
gtk_menu_popup (priv->last_menu, NULL, NULL, positon_menu, self, button, CurrentTime);
gboolean visible = gtk_widget_is_visible (GTK_WIDGET (priv->last_menu));
@@ -2382,6 +2448,7 @@ panel_service_show_entry_common (PanelService *self,
priv->last_right = left + width -1;
priv->last_top = top;
priv->last_bottom = top + height -1;
+ priv->last_open_time = g_get_monotonic_time ();
}
else
{
@@ -2626,6 +2693,7 @@ panel_service_close_active_entry (PanelService *self)
if (GTK_IS_MENU (self->priv->last_menu))
{
+ self->priv->last_open_time = 0;
gtk_menu_popdown (GTK_MENU (self->priv->last_menu));
}
}
diff --git a/tests/test_edge_barrier_controller.cpp b/tests/test_edge_barrier_controller.cpp
index 0aa069da4..4dae2cc80 100644
--- a/tests/test_edge_barrier_controller.cpp
+++ b/tests/test_edge_barrier_controller.cpp
@@ -25,6 +25,7 @@
#include "EdgeBarrierController.h"
#include "EdgeBarrierControllerPrivate.h"
+#include "InputMonitor.h"
using namespace unity;
using namespace unity::ui;
@@ -108,6 +109,7 @@ public:
TestBarrierSubscriber horizontal_subscribers_[monitors::MAX];
TestBarrierSubscriber vertical_subscribers_[monitors::MAX];
+ input::Monitor im;
MockUScreen uscreen;
EdgeBarrierController bc;
};
diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp
index 7faea517c..6a335bf8c 100644
--- a/tests/test_launcher_controller.cpp
+++ b/tests/test_launcher_controller.cpp
@@ -25,6 +25,7 @@
#include "ExpoLauncherIcon.h"
#include "DesktopLauncherIcon.h"
#include "DesktopUtilities.h"
+#include "InputMonitor.h"
#include "MockableBaseWindow.h"
#include "MockLauncherIcon.h"
#include "BFBLauncherIcon.h"
@@ -286,6 +287,7 @@ protected:
std::shared_ptr<helper::CaptureLogOutput> logger_output_;
MockUScreen uscreen;
panel::Style panel_style;
+ input::Monitor im_;
MockFavoriteStore favorite_store;
MockXdndManager::Ptr xdnd_manager_;
ui::EdgeBarrierController::Ptr edge_barriers_;
diff --git a/tests/test_lockscreen_controller.cpp b/tests/test_lockscreen_controller.cpp
index 75d5519c9..c7db68fd2 100644
--- a/tests/test_lockscreen_controller.cpp
+++ b/tests/test_lockscreen_controller.cpp
@@ -55,7 +55,7 @@ const unsigned TICK_DURATION = 10 * 1000;
struct MockShield : BaseShield
{
MockShield()
- : BaseShield(nullptr, nullptr, nullptr, nux::ObjectPtr<AbstractUserPromptView>(), 0, false)
+ : BaseShield(nullptr, nullptr, nux::ObjectPtr<AbstractUserPromptView>(), 0, false)
{}
MOCK_CONST_METHOD0(IsIndicatorOpen, bool());
@@ -67,7 +67,7 @@ struct MockShield : BaseShield
struct ShieldFactoryMock : ShieldFactoryInterface
{
nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
- indicator::Indicators::Ptr const&,
+ menu::Manager::Ptr const&,
Accelerators::Ptr const&,
nux::ObjectPtr<AbstractUserPromptView> const&,
int, bool) override
diff --git a/tests/test_panel_controller.cpp b/tests/test_panel_controller.cpp
index eea0f2fe1..af7fe9534 100644
--- a/tests/test_panel_controller.cpp
+++ b/tests/test_panel_controller.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
+#include "InputMonitor.h"
#include "PanelController.h"
#include "PanelStyle.h"
#include "PanelView.h"
@@ -46,6 +47,7 @@ struct TestPanelController : public testing::Test
menu::MockManager::Ptr menus;
ui::EdgeBarrierController::Ptr edge_barriers;
launcher::Options::Ptr options;
+ input::Monitor im;
};
TEST_F(TestPanelController, Construction)
diff --git a/tests/test_panel_view.cpp b/tests/test_panel_view.cpp
index 82fdf55b3..4eeb37993 100644
--- a/tests/test_panel_view.cpp
+++ b/tests/test_panel_view.cpp
@@ -25,6 +25,7 @@
#include "unity-shared/PanelStyle.h"
#include "unity-shared/UBusMessages.h"
#include "unity-shared/UBusWrapper.h"
+ #include "InputMonitor.h"
#include "mock_menu_manager.h"
#include "test_standalone_wm.h"
@@ -43,6 +44,7 @@ public:
nux::ObjectPtr<MockableBaseWindow> window_;
nux::ObjectPtr<PanelView> panel_view_;
testwrapper::StandaloneWM WM;
+ input::Monitor im;
TestPanelView()
: window_(new MockableBaseWindow())
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt
index 216e54c25..b0ac7b12c 100644
--- a/unity-shared/CMakeLists.txt
+++ b/unity-shared/CMakeLists.txt
@@ -83,6 +83,7 @@ if(ENABLE_X_SUPPORT)
set (UNITY_SHARED_SOURCES
XKeyboardUtil.cpp
XWindowManager.cpp
+ InputMonitor.cpp
${UNITY_SHARED_SOURCES}
)
else()
diff --git a/unity-shared/InputMonitor.cpp b/unity-shared/InputMonitor.cpp
new file mode 100644
index 000000000..465c5afad
--- /dev/null
+++ b/unity-shared/InputMonitor.cpp
@@ -0,0 +1,420 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2014 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: Marco Trevisan <marco.trevisan@canonical.com>
+ */
+
+#include "InputMonitor.h"
+#include "SigcSlotHash.h"
+
+#include <Nux/Nux.h>
+#include <NuxCore/Logger.h>
+#include <X11/extensions/XInput2.h>
+#include <UnityCore/GLibSource.h>
+#include <unordered_set>
+#include <gdk/gdkx.h>
+#include <glib.h>
+
+namespace unity
+{
+namespace input
+{
+namespace
+{
+DECLARE_LOGGER(logger, "unity.input.monitor");
+
+Monitor* instance_ = nullptr;
+
+const unsigned XINPUT_MAJOR_VERSION = 2;
+const unsigned XINPUT_MINOR_VERSION = 3;
+
+bool operator&(Events l, Events r)
+{
+ typedef std::underlying_type<Events>::type ut;
+ return static_cast<ut>(static_cast<ut>(l) & static_cast<ut>(r));
+}
+
+Events& operator|=(Events& l, Events r)
+{
+ typedef std::underlying_type<Events>::type ut;
+ return l = static_cast<Events>(static_cast<ut>(l) | static_cast<ut>(r));
+}
+
+template <typename EVENT>
+void initialize_event_common(EVENT* ev, XIDeviceEvent* xiev)
+{
+ ev->serial = xiev->serial;
+ ev->send_event = xiev->send_event;
+ ev->display = xiev->display;
+ ev->window = xiev->event;
+ ev->root = xiev->root;
+ ev->subwindow = xiev->child;
+ ev->time = xiev->time;
+ ev->x = std::round(xiev->event_x);
+ ev->y = std::round(xiev->event_y);
+ ev->x_root = std::round(xiev->root_x);
+ ev->y_root = std::round(xiev->root_y);
+ ev->state = xiev->mods.effective;
+ ev->same_screen = True;
+}
+
+template <typename EVENT_TYPE, typename NATIVE_TYPE>
+void initialize_event(XEvent* ev, NATIVE_TYPE* xiev);
+
+template <>
+void initialize_event<XButtonEvent>(XEvent* ev, XIDeviceEvent* xiev)
+{
+ XButtonEvent* bev = &ev->xbutton;
+ ev->type = (xiev->evtype == XI_ButtonPress) ? ButtonPress : ButtonRelease;
+ initialize_event_common(bev, xiev);
+ bev->button = xiev->detail;
+}
+
+template <>
+void initialize_event<XKeyEvent>(XEvent* ev, XIDeviceEvent* xiev)
+{
+ XKeyEvent* kev = &ev->xkey;
+ ev->type = (xiev->evtype == XI_KeyPress) ? KeyPress : KeyRelease;
+ initialize_event_common(kev, xiev);
+ kev->keycode = xiev->detail;
+}
+
+template <>
+void initialize_event<XMotionEvent>(XEvent* ev, XIDeviceEvent* xiev)
+{
+ XMotionEvent* mev = &ev->xmotion;
+ ev->type = MotionNotify;
+ initialize_event_common(mev, xiev);
+ mev->is_hint = NotifyNormal;
+
+ for (int i = 0; i < xiev->buttons.mask_len * 8; ++i)
+ {
+ if (XIMaskIsSet(xiev->buttons.mask, i))
+ {
+ mev->is_hint = NotifyHint;
+ break;
+ }
+ }
+}
+
+template <>
+void initialize_event<XGenericEventCookie>(XEvent* ev, XIBarrierEvent* xiev)
+{
+ XGenericEventCookie* cev = &ev->xcookie;
+ cev->type = GenericEvent;
+ cev->serial = xiev->serial;
+ cev->send_event = xiev->send_event;
+ cev->display = xiev->display;
+ cev->evtype = xiev->evtype;
+ cev->data = xiev;
+}
+}
+
+struct Monitor::Impl
+{
+#if __GNUC__ < 6
+ using EventCallbackSet = std::unordered_set<EventCallback>;
+#else
+ using EventCallbackSet = std::unordered_set<EventCallback, std::hash<sigc::slot_base>>;
+#endif
+
+ Impl()
+ : xi_opcode_(0)
+ , event_filter_set_(false)
+ , invoking_callbacks_(false)
+ {
+ Display *dpy = gdk_x11_get_default_xdisplay();
+ int event_base, error_base;
+
+ if (XQueryExtension(dpy, "XInputExtension", &xi_opcode_, &event_base, &error_base))
+ {
+ int maj = XINPUT_MAJOR_VERSION;
+ int min = XINPUT_MINOR_VERSION;
+
+ if (XIQueryVersion(dpy, &maj, &min) == BadRequest)
+ {
+ LOG_ERROR(logger) << "Need XInput version "<< maj << "." << min << ", "
+ << "impossible, to setup an InputMonitor";
+ }
+ }
+ else
+ {
+ LOG_ERROR(logger) << "Missing XInput, impossible to setup an InputMonitor";
+ }
+ }
+
+ ~Impl()
+ {
+ if (event_filter_set_)
+ {
+ pointer_callbacks_.clear();
+ key_callbacks_.clear();
+ barrier_callbacks_.clear();
+ UpdateEventMonitor();
+ }
+ }
+
+ bool RegisterClient(Events type, EventCallback const& cb)
+ {
+ bool added = false;
+
+ if (type & Events::POINTER)
+ added = pointer_callbacks_.insert(cb).second || added;
+
+ if (type & Events::KEYS)
+ added = key_callbacks_.insert(cb).second || added;
+
+ if (type & Events::BARRIER)
+ added = barrier_callbacks_.insert(cb).second || added;
+
+ if (added)
+ UpdateEventMonitor();
+
+ return added;
+ }
+
+ bool UnregisterClient(EventCallback const& cb)
+ {
+ if (invoking_callbacks_)
+ {
+ // Delay the event removal if we're currently invoking a callback
+ // not to break the callbacks loop
+ removal_queue_.insert(cb);
+ return false;
+ }
+
+ bool removed = false;
+ removed = pointer_callbacks_.erase(cb) > 0 || removed;
+ removed = key_callbacks_.erase(cb) > 0 || removed;
+ removed = barrier_callbacks_.erase(cb) > 0 || removed;
+
+ if (removed)
+ UpdateEventMonitor();
+
+ return removed;
+ }
+
+ Events RegisteredEvents(EventCallback const& cb) const
+ {
+ Events events = Events::NONE;
+
+ if (pointer_callbacks_.find(cb) != end(pointer_callbacks_))
+ events |= Events::POINTER;
+
+ if (key_callbacks_.find(cb) != end(key_callbacks_))
+ events |= Events::KEYS;
+
+ if (barrier_callbacks_.find(cb) != end(barrier_callbacks_))
+ events |= Events::BARRIER;
+
+ return events;
+ }
+
+ void UpdateEventMonitor()
+ {
+ auto* dpy = nux::GetGraphicsDisplay()->GetX11Display();
+ Window root = DefaultRootWindow(dpy);
+
+ unsigned char master_dev_bits[XIMaskLen(XI_LASTEVENT)] = { 0 };
+ XIEventMask master_dev = { XIAllMasterDevices, sizeof(master_dev_bits), master_dev_bits };
+
+ if (!barrier_callbacks_.empty())
+ {
+ XISetMask(master_dev.mask, XI_BarrierHit);
+ XISetMask(master_dev.mask, XI_BarrierLeave);
+ }
+
+ unsigned char all_devs_bits[XIMaskLen(XI_LASTEVENT)] = { 0 };
+ XIEventMask all_devs = { XIAllDevices, sizeof(all_devs_bits), all_devs_bits };
+
+ if (!pointer_callbacks_.empty())
+ {
+ XISetMask(all_devs.mask, XI_Motion);
+ XISetMask(all_devs.mask, XI_ButtonPress);
+ XISetMask(all_devs.mask, XI_ButtonRelease);
+ }
+
+ if (!key_callbacks_.empty())
+ {
+ XISetMask(all_devs.mask, XI_KeyPress);
+ XISetMask(all_devs.mask, XI_KeyRelease);
+ }
+
+ XIEventMask selected[] = {master_dev, all_devs};
+ XISelectEvents(dpy, root, selected, G_N_ELEMENTS(selected));
+ XSync(dpy, False);
+
+ LOG_DEBUG(logger) << "Pointer clients: " << pointer_callbacks_.size() << ", "
+ << "Key clients: " << key_callbacks_.size() << ", "
+ << "Barrier clients: " << barrier_callbacks_.size();
+
+ if (!pointer_callbacks_.empty() || !key_callbacks_.empty() || !barrier_callbacks_.empty())
+ {
+ if (!event_filter_set_)
+ {
+ nux::GetGraphicsDisplay()->AddEventFilter({[] (XEvent event, void* data) {
+ return static_cast<Impl*>(data)->HandleEvent(event);
+ }, this});
+
+ event_filter_set_ = true;
+ LOG_DEBUG(logger) << "Event filter enabled";
+ }
+ }
+ else if (event_filter_set_)
+ {
+ nux::GetGraphicsDisplay()->RemoveEventFilter(this);
+ event_filter_set_ = false;
+ LOG_DEBUG(logger) << "Event filter disabled";
+ }
+ }
+
+ bool HandleEvent(XEvent& event)
+ {
+ bool handled = false;
+
+ if (event.type != GenericEvent || event.xcookie.extension != xi_opcode_)
+ return handled;
+
+ switch (event.xcookie.evtype)
+ {
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ handled = InvokeCallbacks<XButtonEvent>(pointer_callbacks_, event);
+ break;
+ case XI_Motion:
+ handled = InvokeCallbacks<XMotionEvent>(pointer_callbacks_, event);
+ break;
+ case XI_KeyPress:
+ case XI_KeyRelease:
+ handled = InvokeCallbacks<XKeyEvent>(key_callbacks_, event);
+ break;
+ case XI_BarrierHit:
+ case XI_BarrierLeave:
+ handled = InvokeCallbacks<XGenericEventCookie, XIBarrierEvent>(barrier_callbacks_, event);
+ break;
+ }
+
+ return handled;
+ }
+
+ template <typename EVENT_TYPE, typename NATIVE_TYPE = XIDeviceEvent>
+ bool InvokeCallbacks(EventCallbackSet& callbacks, XEvent& xiev)
+ {
+ XGenericEventCookie *cookie = &xiev.xcookie;
+
+ if (!XGetEventData(xiev.xany.display, cookie))
+ return false;
+
+ XEvent event;
+ initialize_event<EVENT_TYPE>(&event, reinterpret_cast<NATIVE_TYPE*>(cookie->data));
+ invoking_callbacks_ = true;
+
+ for (auto it = callbacks.begin(); it != callbacks.end();)
+ {
+ if (it->empty())
+ {
+ it = callbacks.erase(it);
+ continue;
+ }
+
+ (*it)(event);
+ ++it;
+ }
+
+ XFreeEventData(xiev.xany.display, cookie);
+ invoking_callbacks_ = false;
+
+ // A callback might unregister itself on the event callback, causing the
+ // above callbacks loop to crash, so in this case we save the event in the
+ // removal queue and eventually we unregistered these callbacks.
+ bool update_event_monitor = false;
+ for (auto it = removal_queue_.begin(); it != removal_queue_.end(); it = removal_queue_.erase(it))
+ {
+ auto const& cb = *it;
+ pointer_callbacks_.erase(cb);
+ key_callbacks_.erase(cb);
+ barrier_callbacks_.erase(cb);
+ update_event_monitor = true;
+ }
+
+ if (callbacks.empty() || update_event_monitor)
+ {
+ idle_removal_.reset(new glib::Idle([this] {
+ UpdateEventMonitor();
+ return false;
+ }));
+
+ return false;
+ }
+
+ return true;
+ }
+
+ int xi_opcode_;
+ bool event_filter_set_;
+ bool invoking_callbacks_;
+ glib::Source::UniquePtr idle_removal_;
+ EventCallbackSet pointer_callbacks_;
+ EventCallbackSet key_callbacks_;
+ EventCallbackSet barrier_callbacks_;
+ EventCallbackSet removal_queue_;
+};
+
+Monitor::Monitor()
+{
+ if (instance_)
+ {
+ LOG_WARN(logger) << "More than one input::Monitor created.";
+ return;
+ }
+
+ instance_ = this;
+ impl_.reset(new Impl());
+}
+
+Monitor::~Monitor()
+{
+ if (this == instance_)
+ instance_ = nullptr;
+}
+
+Monitor& Monitor::Get()
+{
+ if (!instance_)
+ {
+ LOG_ERROR(logger) << "No input::Monitor created yet.";
+ }
+
+ return *instance_;
+}
+
+bool Monitor::RegisterClient(Events events, EventCallback const& cb)
+{
+ return impl_->RegisterClient(events, cb);
+}
+
+bool Monitor::UnregisterClient(EventCallback const& cb)
+{
+ return impl_->UnregisterClient(cb);
+}
+
+Events Monitor::RegisteredEvents(EventCallback const& cb) const
+{
+ return impl_->RegisteredEvents(cb);
+}
+
+} // input namespace
+} // unity namespace
diff --git a/unity-shared/InputMonitor.h b/unity-shared/InputMonitor.h
new file mode 100644
index 000000000..23ff8ceff
--- /dev/null
+++ b/unity-shared/InputMonitor.h
@@ -0,0 +1,67 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2014 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: Marco Trevisan <marco.trevisan@canonical.com>
+ */
+
+#ifndef __UNITY_INPUT_MONITOR__
+#define __UNITY_INPUT_MONITOR__
+
+#include <X11/Xlib.h>
+#include <sigc++/slot.h>
+#include <memory>
+
+namespace unity
+{
+namespace input
+{
+enum class Events : unsigned
+{
+ NONE = 0,
+ POINTER = (1 << 0),
+ KEYS = (1 << 1),
+ BARRIER = (1 << 2),
+ INPUT = POINTER | KEYS,
+ ALL = POINTER | KEYS | BARRIER
+};
+
+class Monitor : public sigc::trackable
+{
+public:
+ typedef sigc::slot<void, XEvent const&> EventCallback;
+
+ static Monitor& Get();
+
+ Monitor();
+ ~Monitor();
+
+ bool RegisterClient(Events, EventCallback const&);
+ bool UnregisterClient(EventCallback const&);
+
+ Events RegisteredEvents(EventCallback const&) const;
+
+private:
+ Monitor(Monitor const&) = delete;
+ Monitor& operator=(Monitor const&) = delete;
+
+ struct Impl;
+ std::unique_ptr<Impl> impl_;
+};
+
+} // input namespace
+} // unity namespace
+
+#endif // __UNITY_INPUT_MONITOR__
diff --git a/unity-shared/MenuManager.cpp b/unity-shared/MenuManager.cpp
index f00887ce8..77828700d 100644
--- a/unity-shared/MenuManager.cpp
+++ b/unity-shared/MenuManager.cpp
@@ -21,11 +21,17 @@
#include <gtk/gtk.h>
#include <NuxCore/Logger.h>
#include <UnityCore/GLibSignal.h>
+#include <UnityCore/GLibSource.h>
#include <UnityCore/GLibWrapper.h>
#include <UnityCore/DBusIndicators.h>
#include <unordered_map>
#include "MenuManager.h"
+#include "InputMonitor.h"
+#include "RawPixel.h"
+#include "SigcSlotHash.h"
+#include "UnitySettings.h"
+#include "UScreen.h"
#include "WindowManager.h"
namespace unity
@@ -40,6 +46,10 @@ const std::string SETTINGS_NAME = "com.canonical.Unity";
const std::string LIM_KEY = "integrated-menus";
const std::string SHOW_MENUS_NOW_DELAY = "show-menus-now-delay";
const std::string ALWAYS_SHOW_MENUS_KEY = "always-show-menus";
+
+const RawPixel TRIANGLE_THRESHOLD = 5_em;
+const double SCRUB_VELOCITY_THRESHOLD = 0.05;
+const unsigned MENU_OPEN_MOUSE_WAIT = 150;
}
using namespace indicator;
@@ -51,6 +61,7 @@ struct Manager::Impl : sigc::trackable
, indicators_(indicators)
, key_grabber_(grabber)
, show_now_window_(0)
+ , last_pointer_time_(0)
, settings_(g_settings_new(SETTINGS_NAME.c_str()))
{
for (auto const& indicator : indicators_->GetIndicators())
@@ -182,9 +193,15 @@ struct Manager::Impl : sigc::trackable
parent_->key_activate_entry.emit(entry_id);
}
- void EntryActivated(std::string const&, std::string const&, nux::Rect const& geo)
+ void EntryActivated(std::string const& menubar, std::string const&, nux::Rect const& geo)
{
parent_->menu_open = !geo.IsNull();
+
+ if (active_menubar_ != menubar)
+ {
+ active_menubar_ = menubar;
+ UpdateActiveTracker();
+ }
}
void SetShowNowForWindow(Window xid, bool show)
@@ -231,15 +248,148 @@ struct Manager::Impl : sigc::trackable
gtk_icon_theme_set_search_path(gtk_icon_theme_get_default(), gicon_paths.data(), gicon_paths.size());
}
+ bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
+ {
+ int s = t0.y * t2.x - t0.x * t2.y + (t2.y - t0.y) * p.x + (t0.x - t2.x) * p.y;
+ int t = t0.x * t1.y - t0.y * t1.x + (t0.y - t1.y) * p.x + (t1.x - t0.x) * p.y;
+
+ if ((s < 0) != (t < 0))
+ return false;
+
+ int A = -t1.y * t2.x + t0.y * (t2.x - t1.x) + t0.x * (t1.y - t2.y) + t1.x * t2.y;
+ if (A < 0)
+ {
+ s = -s;
+ t = -t;
+ A = -A;
+ }
+
+ return s > 0 && t > 0 && (s + t) < A;
+ }
+
+ double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, Time time_delta)
+ {
+ int dx, dy;
+ double speed;
+
+ if (time_delta == 0)
+ return 1;
+
+ dx = p0.x - p1.x;
+ dy = p0.y - p1.y;
+
+ speed = sqrt(dx * dx + dy * dy) / time_delta;
+
+ return speed;
+ }
+
+ void OnActiveEntryEvent(XEvent const& e)
+ {
+ if (e.type != MotionNotify)
+ return;
+
+ auto const& active_entry = indicators_->GetActiveEntry();
+
+ if (!active_entry)
+ return;
+
+ nux::Point mouse(e.xmotion.x_root, e.xmotion.y_root);
+ auto monitor = UScreen::GetDefault()->GetMonitorAtPosition(mouse.x, mouse.y);
+ double scale = Settings::Instance().em(monitor)->DPIScale();
+ double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, e.xmotion.time - last_pointer_time_);
+ auto menu_geo = active_entry->geometry();
+
+ tracked_pointer_pos_ = mouse;
+ last_pointer_time_ = e.xmotion.time;
+
+ if (speed > SCRUB_VELOCITY_THRESHOLD &&
+ PointInTriangle(mouse, {mouse.x, std::max(mouse.y - TRIANGLE_THRESHOLD.CP(scale), 0)},
+ menu_geo.GetPosition(), {menu_geo.x + menu_geo.width, menu_geo.y}))
+ {
+ pointer_movement_timeout_ = std::make_shared<glib::Timeout>(MENU_OPEN_MOUSE_WAIT, [this, mouse, speed] {
+ if (active_tracker_)
+ active_tracker_(mouse.x, mouse.y, speed);
+
+ return false;
+ });
+
+ return;
+ }
+
+ if (active_tracker_)
+ {
+ pointer_movement_timeout_.reset();
+ active_tracker_(mouse.x, mouse.y, speed);
+ }
+ }
+
+ bool RegisterTracker(std::string const& menubar, PositionTracker const& cb)
+ {
+ auto it = position_trackers_.find(menubar);
+
+ if (it != end(position_trackers_))
+ return false;
+
+ position_trackers_.insert({menubar, cb});
+
+ if (active_menubar_ == menubar)
+ UpdateActiveTracker();
+
+ return true;
+ }
+
+ bool UnregisterTracker(std::string const& menubar, PositionTracker const& cb)
+ {
+ auto it = position_trackers_.find(menubar);
+
+ if (it == end(position_trackers_))
+ return false;
+
+ if (!cb || (cb && it->second == cb))
+ {
+ position_trackers_.erase(it);
+ UpdateActiveTracker();
+ return true;
+ }
+
+ return false;
+ }
+
+ void UpdateActiveTracker()
+ {
+ auto it = position_trackers_.find(active_menubar_);
+ active_tracker_ = (it != end(position_trackers_)) ? it->second : PositionTracker();
+ pointer_movement_timeout_.reset();
+
+ if (active_tracker_)
+ {
+ if (input::Monitor::Get().RegisterClient(input::Events::POINTER, sigc::mem_fun(this, &Impl::OnActiveEntryEvent)))
+ last_pointer_time_ = 0;
+ }
+ else
+ {
+ input::Monitor::Get().UnregisterClient(sigc::mem_fun(this, &Impl::OnActiveEntryEvent));
+
+ if (it != end(position_trackers_))
+ position_trackers_.erase(it);
+ }
+ }
+
Manager* parent_;
Indicators::Ptr indicators_;
AppmenuIndicator::Ptr appmenu_;
key::Grabber::Ptr key_grabber_;
Window show_now_window_;
+ std::string active_menubar_;
+ PositionTracker active_tracker_;
+ nux::Point tracked_pointer_pos_;
+ Time last_pointer_time_;
+ glib::Source::Ptr pointer_movement_timeout_;
connection::Manager appmenu_connections_;
connection::Wrapper active_win_conn_;
glib::Object<GSettings> settings_;
glib::SignalManager signals_;
+ std::unordered_map<std::string, PositionTracker> position_trackers_;
std::unordered_map<indicator::Entry::Ptr, uint32_t> entry_actions_;
};
@@ -278,5 +428,16 @@ key::Grabber::Ptr const& Manager::KeyGrabber() const
return impl_->key_grabber_;
}
+bool Manager::RegisterTracker(std::string const& menubar, PositionTracker const& cb)
+{
+ return impl_->RegisterTracker(menubar, cb);
+}
+
+bool Manager::UnregisterTracker(std::string const& menubar, PositionTracker const& cb)
+{
+ return impl_->UnregisterTracker(menubar, cb);
+}
+
+
} // menu namespace
} // unity namespace
diff --git a/unity-shared/MenuManager.h b/unity-shared/MenuManager.h
index 20432db73..ad0f177e2 100644
--- a/unity-shared/MenuManager.h
+++ b/unity-shared/MenuManager.h
@@ -67,6 +67,10 @@ public:
key::Grabber::Ptr const& KeyGrabber() const;
+ typedef sigc::slot<void, int /*x*/, int /*y*/, double /*speed*/> PositionTracker;
+ bool RegisterTracker(std::string const& menubar, PositionTracker const&);
+ bool UnregisterTracker(std::string const& menubar, PositionTracker const& = PositionTracker());
+
sigc::signal<void> appmenu_added;
sigc::signal<void> appmenu_removed;
sigc::signal<bool>::accumulated<any_true> open_first;
diff --git a/unity-shared/PluginAdapter.cpp b/unity-shared/PluginAdapter.cpp
index e439ca332..324bf54b1 100644
--- a/unity-shared/PluginAdapter.cpp
+++ b/unity-shared/PluginAdapter.cpp
@@ -608,7 +608,7 @@ bool PluginAdapter::IsWindowObscured(Window window_id) const
CompPoint window_vp = window->defaultViewport();
// Check if any windows above this one are blocking it
- for (CompWindow* sibling = window->next; sibling != NULL; sibling = sibling->next)
+ for (CompWindow* sibling = window->serverNext; sibling != NULL; sibling = sibling->serverNext)
{
if (sibling->defaultViewport() == window_vp
&& !sibling->minimized()
diff --git a/unity-shared/SigcSlotHash.h b/unity-shared/SigcSlotHash.h
new file mode 100644
index 000000000..c7058c3b8
--- /dev/null
+++ b/unity-shared/SigcSlotHash.h
@@ -0,0 +1,70 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2016 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: Marco Trevisan <marco.trevisan@canonical.com>
+ */
+
+#ifndef __UNITY_SIGC_SLOT_HASHER__
+#define __UNITY_SIGC_SLOT_HASHER__
+
+#include <sigc++/slot.h>
+
+namespace sigc
+{
+inline bool operator==(slot_base const& lhs, slot_base const& rhs)
+{
+ if (!lhs.rep_ || !rhs.rep_)
+ return (lhs.rep_ == rhs.rep_);
+
+ return (lhs.rep_->call_ == rhs.rep_->call_);
+}
+
+inline bool operator!=(slot_base const& lhs, slot_base const& rhs)
+{
+ return !(lhs == rhs);
+}
+} // sigc namespace
+
+namespace std
+{
+
+template<>
+struct hash<sigc::slot_base>
+{
+ size_t operator()(sigc::slot_base const& cb) const
+ {
+ if (cb.rep_)
+ return hash<size_t>()(reinterpret_cast<size_t>(cb.rep_->call_));
+
+ return hash<size_t>()(reinterpret_cast<size_t>(cb.rep_));
+ }
+};
+
+#if __GNUC__ < 6
+template<class T>
+struct hash
+{
+ size_t operator()(T const& cb) const
+ {
+ static_assert(std::is_base_of<sigc::slot_base, T>::value, "Type is not derived from sigc::slot_base");
+ return hash<sigc::slot_base>()(cb);
+ }
+};
+#endif
+
+} // std namespace
+
+#endif // __UNITY_SIGC_SLOT_HASHER__
diff --git a/unity-shared/StandaloneWindowManager.cpp b/unity-shared/StandaloneWindowManager.cpp
index 44aa839d6..43eef13c7 100644
--- a/unity-shared/StandaloneWindowManager.cpp
+++ b/unity-shared/StandaloneWindowManager.cpp
@@ -624,6 +624,9 @@ std::string StandaloneWindowManager::GetStringProperty(Window, Atom) const
return std::string();
}
+void StandaloneWindowManager::SetCardinalProperty(Window, Atom, std::vector<long> const&)
+{}
+
std::vector<long> StandaloneWindowManager::GetCardinalProperty(Window, Atom) const
{
return std::vector<long>();
diff --git a/unity-shared/StandaloneWindowManager.h b/unity-shared/StandaloneWindowManager.h
index 8b2775233..60bb78824 100644
--- a/unity-shared/StandaloneWindowManager.h
+++ b/unity-shared/StandaloneWindowManager.h
@@ -165,6 +165,7 @@ public:
virtual std::string GetWindowName(Window window_id) const;
virtual bool IsOnscreenKeyboard(Window window_id) const;
virtual std::string GetStringProperty(Window window_id, Atom) const;
+ virtual void SetCardinalProperty(Window window_id, Atom, std::vector<long> const&);
virtual std::vector<long> GetCardinalProperty(Window window_id, Atom) const;
// Mock functions
diff --git a/unity-shared/UpstartWrapper.cpp b/unity-shared/UpstartWrapper.cpp
index b5986b918..284668b41 100644
--- a/unity-shared/UpstartWrapper.cpp
+++ b/unity-shared/UpstartWrapper.cpp
@@ -53,7 +53,7 @@ void UpstartWrapper::Impl::Emit(std::string const& name)
DBUS_PATH_UPSTART, DBUS_INTERFACE_UPSTART,
G_BUS_TYPE_SESSION, flags);
- proxy->Call("EmitEvent", g_variant_new("(sasb)", name.c_str(), nullptr, 0), [proxy] (GVariant*) {});
+ proxy->CallBegin("EmitEvent", g_variant_new("(sasb)", name.c_str(), nullptr, 0), [proxy] (GVariant*, glib::Error const&) {});
}
//
diff --git a/unity-shared/WindowButtons.cpp b/unity-shared/WindowButtons.cpp
index af2bf512e..bd88aaf1d 100644
--- a/unity-shared/WindowButtons.cpp
+++ b/unity-shared/WindowButtons.cpp
@@ -420,10 +420,23 @@ void WindowButtons::OnRestoreClicked(nux::Button *button)
{
WindowManager& wm = WindowManager::Default();
Window to_restore = controlled_window();
+ int button = nux::GetGraphicsDisplay()->GetCurrentEvent().GetEventButton();
wm.Raise(to_restore);
wm.Activate(to_restore);
- wm.Restore(to_restore);
+
+ if (button == nux::NUX_MOUSE_BUTTON1)
+ {
+ wm.Restore(to_restore);
+ }
+ else if (button == nux::NUX_MOUSE_BUTTON2)
+ {
+ wm.VerticallyMaximize(to_restore);
+ }
+ else if (button == nux::NUX_MOUSE_BUTTON3)
+ {
+ wm.HorizontallyMaximize(to_restore);
+ }
}
restore_clicked.emit();
diff --git a/unity-shared/WindowManager.h b/unity-shared/WindowManager.h
index 3502941d0..cb38aea77 100644
--- a/unity-shared/WindowManager.h
+++ b/unity-shared/WindowManager.h
@@ -170,6 +170,7 @@ public:
virtual bool IsOnscreenKeyboard(Window window_id) const = 0;
virtual std::string GetStringProperty(Window, Atom) const = 0;
+ virtual void SetCardinalProperty(Window, Atom, std::vector<long> const&) = 0;
virtual std::vector<long> GetCardinalProperty(Window, Atom) const = 0;
virtual Cursor GetCachedCursor(unsigned int cursor_name) const = 0;
diff --git a/unity-shared/XWindowManager.cpp b/unity-shared/XWindowManager.cpp
index 71b20ffd6..d6222f8b8 100644
--- a/unity-shared/XWindowManager.cpp
+++ b/unity-shared/XWindowManager.cpp
@@ -123,6 +123,12 @@ std::string XWindowManager::GetStringProperty(Window window_id, Atom atom) const
return std::string(val, n_items);
}
+void XWindowManager::SetCardinalProperty(Window window_id, Atom atom, std::vector<long> const& values)
+{
+ XChangeProperty(screen->dpy(), window_id, atom, XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) values.data(), values.size());
+}
+
std::vector<long> XWindowManager::GetCardinalProperty(Window window_id, Atom atom) const
{
Atom type;
diff --git a/unity-shared/XWindowManager.h b/unity-shared/XWindowManager.h
index 211d92029..f6c4bbd04 100644
--- a/unity-shared/XWindowManager.h
+++ b/unity-shared/XWindowManager.h
@@ -36,6 +36,7 @@ public:
std::string GetWindowName(Window window_id) const;
bool IsOnscreenKeyboard(Window window_id) const;
std::string GetStringProperty(Window window_id, Atom atom) const;
+ void SetCardinalProperty(Window, Atom, std::vector<long> const&);
std::vector<long> GetCardinalProperty(Window, Atom) const;
};