Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3122)

Unified Diff: chrome/browser/extensions/global_shortcut_listener_gtk.cc

Issue 25007002: Add GTK support for global Extension Commands (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Revise. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/global_shortcut_listener_gtk.cc
diff --git a/chrome/browser/extensions/global_shortcut_listener_gtk.cc b/chrome/browser/extensions/global_shortcut_listener_gtk.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3000219375dd9a83730a6bf8d6b5720e2013334f
--- /dev/null
+++ b/chrome/browser/extensions/global_shortcut_listener_gtk.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener_gtk.h"
+
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+
+#include "base/x11/x11_error_tracker.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+
+using content::BrowserThread;
+
+namespace {
+
+static base::LazyInstance<extensions::GlobalShortcutListenerGtk> instance =
+ LAZY_INSTANCE_INITIALIZER;
+
+// The modifiers masks used for grabing keys. Due to XGrabKey only working on
+// exact modifiers, we need to grab all key combination including zero or more
+// of the following: Num lock, Caps lock and Scroll lock. So that we can make
+// sure the behavior of global shortcuts is consistent on all platforms.
+static const unsigned int kModifiersMasks[] = {
+ 0, // No additional modifier.
+ Mod2Mask, // Num lock
+ LockMask, // Caps lock
+ Mod5Mask, // Scroll lock
+ Mod2Mask | LockMask,
+ Mod2Mask | Mod5Mask,
+ LockMask | Mod5Mask,
+ Mod2Mask | LockMask | Mod5Mask
+};
+
+int GetNativeModifiers(const ui::Accelerator& accelerator) {
+ int modifiers = 0;
+ modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0;
+ modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0;
+ modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0;
+
+ return modifiers;
+}
+
+} // namespace
+
+namespace extensions {
+
+// static
+GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return instance.Pointer();
+}
+
+GlobalShortcutListenerGtk::GlobalShortcutListenerGtk()
+ : is_listening_(false) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+GlobalShortcutListenerGtk::~GlobalShortcutListenerGtk() {
+ if (is_listening_)
+ StopListening();
+}
+
+void GlobalShortcutListenerGtk::StartListening() {
+ DCHECK(!is_listening_); // Don't start twice.
+ DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is
+ // registered.
+
+ gdk_window_add_filter(gdk_get_default_root_window(),
+ &GlobalShortcutListenerGtk::OnXEventThunk,
+ this);
+ is_listening_ = true;
+}
+
+void GlobalShortcutListenerGtk::StopListening() {
+ DCHECK(is_listening_); // No point if we are not already listening.
+ DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before
+ // ending.
+
+ gdk_window_remove_filter(NULL,
+ &GlobalShortcutListenerGtk::OnXEventThunk,
+ this);
+ is_listening_ = false;
+}
+
+void GlobalShortcutListenerGtk::RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
+ int modifiers = GetNativeModifiers(accelerator);
+ KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
+ base::X11ErrorTracker err_tracker;
+
+ // Because XGrabKey only works on the exact modifiers mask, we should register
+ // our hot keys with modifiers that we want to ignore, including Num lock,
+ // Caps lock, Scroll lock. See comment about |kModifiersMasks|.
+ for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
+ XGrabKey(display, keycode, modifiers | kModifiersMasks[i],
+ gdk_x11_get_default_root_xwindow(), False,
+ GrabModeAsync, GrabModeAsync);
+ }
+
+ if (err_tracker.FoundNewError()) {
+ LOG(ERROR) << "X failed to grab global hotkey: "
+ << accelerator.GetShortcutText();
+
+ // We may have part of the hotkeys registered, clean up.
+ for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
+ XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
+ gdk_x11_get_default_root_xwindow());
+ }
+ } else {
+ registered_hot_keys_.insert(accelerator);
+ GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
+ }
+}
+
+void GlobalShortcutListenerGtk::UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ if (registered_hot_keys_.find(accelerator) == registered_hot_keys_.end())
+ return;
+
+ Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
+ int modifiers = GetNativeModifiers(accelerator);
+ KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
+
+ for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
+ XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
+ gdk_x11_get_default_root_xwindow());
+ }
+ registered_hot_keys_.erase(accelerator);
+ GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
+}
+
+GdkFilterReturn GlobalShortcutListenerGtk::OnXEvent(GdkXEvent* gdk_x_event,
+ GdkEvent* gdk_event) {
+ XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
+ if (x_event->type == KeyPress) {
+ int modifiers = 0;
+ modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0;
+ modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0;
+ modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0;
+
+ ui::Accelerator accelerator(
+ ui::KeyboardCodeFromXKeyEvent(x_event), modifiers);
+ instance.Get().NotifyKeyPressed(accelerator);
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+} // namespace extensions
« no previous file with comments | « chrome/browser/extensions/global_shortcut_listener_gtk.h ('k') | chrome/browser/extensions/global_shortcut_listener_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698