diff options
| author | William Hua <william.hua@canonical.com> | 2014-01-29 19:53:28 -0500 |
|---|---|---|
| committer | William Hua <william.hua@canonical.com> | 2014-01-29 19:53:28 -0500 |
| commit | e9cd04a5e66720c51089916c8956be3d089639b9 (patch) | |
| tree | 7bf07ac106725a91c42a2e6a2cf117b58e703ec6 /unity-shared | |
| parent | 11e1982390846d8b6da92afca74b65599a8bf9d7 (diff) | |
MP fix-up.
(bzr r3608.4.14)
Diffstat (limited to 'unity-shared')
| -rw-r--r-- | unity-shared/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | unity-shared/GnomeKeyGrabber.cpp | 287 | ||||
| -rw-r--r-- | unity-shared/GnomeKeyGrabber.h | 56 | ||||
| -rw-r--r-- | unity-shared/GnomeKeyGrabberImpl.h | 73 |
4 files changed, 417 insertions, 0 deletions
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt index bb2e6e179..2927dff2b 100644 --- a/unity-shared/CMakeLists.txt +++ b/unity-shared/CMakeLists.txt @@ -98,6 +98,7 @@ if (ENABLE_X_SUPPORT) set (UNITY_SHARED_COMPIZ_SOURCES CompizUtils.cpp PluginAdapter.cpp + GnomeKeyGrabber.cpp ) find_package (PkgConfig) diff --git a/unity-shared/GnomeKeyGrabber.cpp b/unity-shared/GnomeKeyGrabber.cpp new file mode 100644 index 000000000..975626d3f --- /dev/null +++ b/unity-shared/GnomeKeyGrabber.cpp @@ -0,0 +1,287 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 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: William Hua <william.hua@canonical.com> + */ + +#include "GnomeKeyGrabberImpl.h" + +#include <NuxCore/Logger.h> + +namespace unity +{ +namespace grabber +{ +DECLARE_LOGGER(logger, "unity.grabber.gnome"); + +// Private implementation +namespace shell +{ +std::string const DBUS_NAME = "org.gnome.Shell"; +std::string const DBUS_INTERFACE = "org.gnome.Shell"; +std::string const DBUS_OBJECT_PATH = "/org/gnome/Shell"; +std::string const INTROSPECTION_XML = +R"(<node> + <interface name='org.gnome.Shell'> + <method name='GrabAccelerators'> + <arg type='a(su)' direction='in' name='accelerators'/> + <arg type='au' direction='out' name='actions'/> + </method> + <method name='GrabAccelerator'> + <arg type='s' direction='in' name='accelerator'/> + <arg type='u' direction='in' name='flags'/> + <arg type='u' direction='out' name='action'/> + </method> + <method name='UngrabAccelerator'> + <arg type='u' direction='in' name='action'/> + <arg type='b' direction='out' name='success'/> + </method> + <signal name='AcceleratorActivated'> + <arg type='u' name='action'/> + <arg type='u' name='device'/> + </signal> + </interface> +</node>)"; +} + +namespace testing +{ +std::string const DBUS_NAME = "com.canonical.Unity.Test.GnomeKeyGrabber"; +} + +bool GnomeKeyGrabber::Impl::BindingLess::operator() (CompAction::KeyBinding const& first, + CompAction::KeyBinding const& second) const +{ + int keycode1(first.keycode()); + int keycode2(second.keycode()); + + if (keycode1 == keycode2) + { + unsigned int modifiers1(first.modifiers()); + unsigned int modifiers2(second.modifiers()); + + return modifiers1 < modifiers2; + } + + return keycode1 < keycode2; +} + +GnomeKeyGrabber::Impl::Impl(CompScreen* screen, bool test_mode) + : test_mode_(test_mode) + , shell_server_(test_mode_ ? testing::DBUS_NAME : shell::DBUS_NAME) + , screen_(screen) + , current_action_id_(0) +{ + shell_server_.AddObjects(shell::INTROSPECTION_XML, shell::DBUS_OBJECT_PATH); + shell_object_ = shell_server_.GetObject(shell::DBUS_INTERFACE); + shell_object_->SetMethodsCallsHandler(sigc::mem_fun(this, &Impl::onShellMethodCall)); +} + +unsigned int GnomeKeyGrabber::Impl::addAction(CompAction const& action, bool addressable) +{ + ++current_action_id_; + actions_.push_back(action); + action_ids_.push_back(current_action_id_); + + if (addressable) + { + action_ids_by_action_[&action] = current_action_id_; + actions_by_action_id_[current_action_id_] = &action; + } + + auto& added(actions_.back()); + auto& grabs(grabs_by_binding_[added.key()]); + + if (grabs == 0) + screen_->addAction(&added); + + ++grabs; + + return current_action_id_; +} + +bool GnomeKeyGrabber::Impl::removeAction(CompAction const& action) +{ + auto i(action_ids_by_action_.find(&action)); + return i != action_ids_by_action_.end() && removeAction(i->second); +} + +bool GnomeKeyGrabber::Impl::removeAction(unsigned int action_id) +{ + auto i(std::find(action_ids_.begin(), action_ids_.end(), action_id)); + + if (i != action_ids_.end()) + { + auto j(actions_.begin() + (i - action_ids_.begin())); + auto k(actions_by_action_id_.find(action_id)); + auto& grabs(grabs_by_binding_[j->key()]); + + --grabs; + + if (grabs == 0) + screen_->removeAction(&(*j)); + + if (k != actions_by_action_id_.end()) + { + action_ids_by_action_.erase(k->second); + actions_by_action_id_.erase(k); + } + + action_ids_.erase(i); + actions_.erase(j); + return true; + } + + return false; +} + +GVariant* GnomeKeyGrabber::Impl::onShellMethodCall(std::string const& method, GVariant* parameters) +{ + LOG_DEBUG(logger) << "Called method '" << method << "'"; + + if (method == "GrabAccelerators") + { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(a(su))"))) + { + GVariant* variant; + GVariantBuilder builder; + GVariantIter* iterator; + gchar const* accelerator; + guint flags; + + g_variant_builder_init(&builder, G_VARIANT_TYPE("au")); + g_variant_get(parameters, "(a(su))", &iterator); + + while (g_variant_iter_next(iterator, "(&su)", &accelerator, &flags)) + g_variant_builder_add(&builder, "u", grabAccelerator(accelerator, flags)); + + g_variant_iter_free(iterator); + variant = g_variant_builder_end(&builder); + return g_variant_new_tuple(&variant, 1); + } + else + LOG_WARN(logger) << "Expected arguments of type (a(su))"; + } + else if (method == "GrabAccelerator") + { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(su)"))) + { + GVariant* variant; + gchar const* accelerator; + guint flags; + + g_variant_get(parameters, "(&su)", &accelerator, &flags); + variant = g_variant_new_uint32(grabAccelerator(accelerator, flags)); + return g_variant_new_tuple(&variant, 1); + } + else + LOG_WARN(logger) << "Expected arguments of type (su)"; + } + else if (method == "UngrabAccelerator") + { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(u)"))) + { + GVariant* variant; + guint action; + + g_variant_get(parameters, "(u)", &action); + variant = g_variant_new_boolean(removeAction(action)); + return g_variant_new_tuple(&variant, 1); + } + else + LOG_WARN(logger) << "Expected arguments of type (u)"; + } + + return nullptr; +} + +unsigned int GnomeKeyGrabber::Impl::grabAccelerator(char const* accelerator, unsigned int flags) +{ + CompAction action; + action.keyFromString(accelerator); + + if (!isActionPostponed(action)) + { + action.setState(CompAction::StateInitKey); + action.setInitiate([this](CompAction* action, CompAction::State state, CompOption::Vector& options) { + activateAction(action, 0); + return true; + }); + } + else + { + action.setState(CompAction::StateInitKey | CompAction::StateTermKey); + action.setTerminate([this](CompAction* action, CompAction::State state, CompOption::Vector& options) { + if (state & CompAction::StateTermTapped) + { + activateAction(action, 0); + return true; + } + + return false; + }); + } + + return addAction(action, false); +} + +void GnomeKeyGrabber::Impl::activateAction(CompAction const* action, unsigned int device) const +{ + ptrdiff_t i(action - &actions_.front()); + + if (0 <= i && i < static_cast<ptrdiff_t>(action_ids_.size())) + shell_object_->EmitSignal("AcceleratorActivated", g_variant_new("(uu)", action_ids_[i], device)); +} + +bool GnomeKeyGrabber::Impl::isActionPostponed(CompAction const& action) const +{ + int keycode(action.key().keycode()); + return keycode == 0 || modHandler->keycodeToModifiers(keycode) != 0; +} + +// Public implementation + +GnomeKeyGrabber::GnomeKeyGrabber(CompScreen* screen) + : impl_(new Impl(screen)) +{ +} + +GnomeKeyGrabber::GnomeKeyGrabber(CompScreen* screen, TestMode const& dummy) + : impl_(new Impl(screen, true)) +{ +} + +GnomeKeyGrabber::~GnomeKeyGrabber() +{ +} + +CompAction::Vector& GnomeKeyGrabber::getActions() +{ + return impl_->actions_; +} + +void GnomeKeyGrabber::addAction(CompAction const& action) +{ + impl_->addAction(action); +} + +void GnomeKeyGrabber::removeAction(CompAction const& action) +{ + impl_->removeAction(action); +} + +} // namespace grabber +} // namespace unity diff --git a/unity-shared/GnomeKeyGrabber.h b/unity-shared/GnomeKeyGrabber.h new file mode 100644 index 000000000..37cf2d378 --- /dev/null +++ b/unity-shared/GnomeKeyGrabber.h @@ -0,0 +1,56 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 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: William Hua <william.hua@canonical.com> +*/ + +#ifndef __GNOME_KEY_GRABBER_H__ +#define __GNOME_KEY_GRABBER_H__ + +#include <core/core.h> + +namespace unity +{ +namespace grabber +{ + +class GnomeKeyGrabber +{ +public: + + explicit GnomeKeyGrabber(CompScreen* screen); + virtual ~GnomeKeyGrabber(); + + CompAction::Vector& getActions(); + void addAction(CompAction const& action); + void removeAction(CompAction const& action); + + struct Impl; + +protected: + + struct TestMode {}; + GnomeKeyGrabber(CompScreen* screen, TestMode const& dummy); + +private: + + std::unique_ptr<Impl> impl_; +}; + +} // namespace grabber +} // namespace unity + +#endif // __GNOME_KEY_GRABBER_H__ diff --git a/unity-shared/GnomeKeyGrabberImpl.h b/unity-shared/GnomeKeyGrabberImpl.h new file mode 100644 index 000000000..0333a9909 --- /dev/null +++ b/unity-shared/GnomeKeyGrabberImpl.h @@ -0,0 +1,73 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 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: William Hua <william.hua@canonical.com> +*/ + +#ifndef __GNOME_KEY_GRABBER_IMPL_H__ +#define __GNOME_KEY_GRABBER_IMPL_H__ + +#include "GnomeKeyGrabber.h" + +#include <UnityCore/GLibDBusProxy.h> +#include <UnityCore/GLibDBusServer.h> + +namespace unity +{ +namespace grabber +{ + +struct GnomeKeyGrabber::Impl +{ + class BindingLess + { + public: + + bool operator()(CompAction::KeyBinding const& first, + CompAction::KeyBinding const& second) const; + }; + + bool test_mode_; + + glib::DBusServer shell_server_; + glib::DBusObject::Ptr shell_object_; + + CompScreen* screen_; + CompAction::Vector actions_; + std::vector<unsigned int> action_ids_; + unsigned int current_action_id_; + + std::map<CompAction const*, unsigned int> action_ids_by_action_; + std::map<unsigned int, CompAction const*> actions_by_action_id_; + std::map<CompAction::KeyBinding, unsigned int, BindingLess> grabs_by_binding_; + + explicit Impl(CompScreen* screen, bool test_mode = false); + + unsigned int addAction(CompAction const& action, bool addressable = true); + bool removeAction(CompAction const& action); + bool removeAction(unsigned int action_id); + + GVariant* onShellMethodCall(std::string const& method, GVariant* parameters); + unsigned int grabAccelerator(char const* accelerator, unsigned int flags); + void activateAction(CompAction const* action, unsigned int device) const; + + bool isActionPostponed(CompAction const& action) const; +}; + +} // namespace grabber +} // namespace unity + +#endif // __GNOME_KEY_GRABBER_IMPL_H__ |
