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

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: 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..fd24e5fabdcbe50bc9b44f1dbe2cdc25f796f363
--- /dev/null
+++ b/chrome/browser/extensions/global_shortcut_listener_gtk.cc
@@ -0,0 +1,150 @@
+// 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;
+
+static const unsigned int kModifiersMasks[] = {
Finnur 2013/09/27 10:35:02 I would comment this with why we're keeping track
zhchbin 2013/09/27 13:47:20 Done.
+ 0, // only specified modifiers.
Finnur 2013/09/27 10:35:02 I would rephrase this: No additional modifier.
zhchbin 2013/09/27 13:47:20 Done.
+ 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.
+ if (!is_listening_) {
Finnur 2013/09/27 10:35:02 In general, we prefer: if (foo) return; bar();
zhchbin 2013/09/27 13:47:20 Done.
+ 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.
+
+ if (is_listening_) {
+ 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
Finnur 2013/09/27 10:35:02 Yikes. :) That's unfortunate. :) What about mod3 a
zhchbin 2013/09/27 13:47:20 Yeah, this problem has obsessed me since I working
+ // our hot keys with modifiers that we want to ignore, including NUM_LOCK,
+ // CAPS_LOCK, SCROLL_LOCK.
+ 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()) {
Finnur 2013/09/27 10:35:02 So, what are the possible error scenarios here? I
zhchbin 2013/09/27 13:47:20 Yes, we will get BadAccess if there is a conflict.
+ LOG(ERROR) << "X failed to grab global hotkey: "
+ << accelerator.GetShortcutText();
Finnur 2013/09/27 10:35:02 Add the error number?
zhchbin 2013/09/27 13:47:20 It seems that we couldn't get the error number if
Finnur 2013/09/27 14:01:27 I thought we had the error, but I guess not. That'
+
+ // 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

Powered by Google App Engine
This is Rietveld 408576698