diff options
Diffstat (limited to 'unity-shared')
| -rw-r--r-- | unity-shared/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | unity-shared/InputMonitor.cpp | 420 | ||||
| -rw-r--r-- | unity-shared/InputMonitor.h | 67 | ||||
| -rw-r--r-- | unity-shared/MenuManager.cpp | 163 | ||||
| -rw-r--r-- | unity-shared/MenuManager.h | 4 | ||||
| -rw-r--r-- | unity-shared/PluginAdapter.cpp | 2 | ||||
| -rw-r--r-- | unity-shared/SigcSlotHash.h | 70 | ||||
| -rw-r--r-- | unity-shared/StandaloneWindowManager.cpp | 3 | ||||
| -rw-r--r-- | unity-shared/StandaloneWindowManager.h | 1 | ||||
| -rw-r--r-- | unity-shared/UpstartWrapper.cpp | 2 | ||||
| -rw-r--r-- | unity-shared/WindowButtons.cpp | 15 | ||||
| -rw-r--r-- | unity-shared/WindowManager.h | 1 | ||||
| -rw-r--r-- | unity-shared/XWindowManager.cpp | 6 | ||||
| -rw-r--r-- | unity-shared/XWindowManager.h | 1 |
14 files changed, 752 insertions, 4 deletions
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; }; |
