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

Side by Side 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, 2 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/global_shortcut_listener_gtk.h"
6
7 #include <gdk/gdkx.h>
8 #include <X11/Xlib.h>
9
10 #include "base/x11/x11_error_tracker.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "ui/base/accelerators/accelerator.h"
13 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
14
15 using content::BrowserThread;
16
17 namespace {
18
19 static base::LazyInstance<extensions::GlobalShortcutListenerGtk> instance =
20 LAZY_INSTANCE_INITIALIZER;
21
22 // The modifiers masks used for grabing keys. Due to XGrabKey only working on
23 // exact modifiers, we need to grab all key combination including zero or more
24 // of the following: Num lock, Caps lock and Scroll lock. So that we can make
25 // sure the behavior of global shortcuts is consistent on all platforms.
26 static const unsigned int kModifiersMasks[] = {
27 0, // No additional modifier.
28 Mod2Mask, // Num lock
29 LockMask, // Caps lock
30 Mod5Mask, // Scroll lock
31 Mod2Mask | LockMask,
32 Mod2Mask | Mod5Mask,
33 LockMask | Mod5Mask,
34 Mod2Mask | LockMask | Mod5Mask
35 };
36
37 int GetNativeModifiers(const ui::Accelerator& accelerator) {
38 int modifiers = 0;
39 modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0;
40 modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0;
41 modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0;
42
43 return modifiers;
44 }
45
46 } // namespace
47
48 namespace extensions {
49
50 // static
51 GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
52 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53 return instance.Pointer();
54 }
55
56 GlobalShortcutListenerGtk::GlobalShortcutListenerGtk()
57 : is_listening_(false) {
58 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 }
60
61 GlobalShortcutListenerGtk::~GlobalShortcutListenerGtk() {
62 if (is_listening_)
63 StopListening();
64 }
65
66 void GlobalShortcutListenerGtk::StartListening() {
67 DCHECK(!is_listening_); // Don't start twice.
68 DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is
69 // registered.
70
71 gdk_window_add_filter(gdk_get_default_root_window(),
72 &GlobalShortcutListenerGtk::OnXEventThunk,
73 this);
74 is_listening_ = true;
75 }
76
77 void GlobalShortcutListenerGtk::StopListening() {
78 DCHECK(is_listening_); // No point if we are not already listening.
79 DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before
80 // ending.
81
82 gdk_window_remove_filter(NULL,
83 &GlobalShortcutListenerGtk::OnXEventThunk,
84 this);
85 is_listening_ = false;
86 }
87
88 void GlobalShortcutListenerGtk::RegisterAccelerator(
89 const ui::Accelerator& accelerator,
90 GlobalShortcutListener::Observer* observer) {
91 Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
92 int modifiers = GetNativeModifiers(accelerator);
93 KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
94 base::X11ErrorTracker err_tracker;
95
96 // Because XGrabKey only works on the exact modifiers mask, we should register
97 // our hot keys with modifiers that we want to ignore, including Num lock,
98 // Caps lock, Scroll lock. See comment about |kModifiersMasks|.
99 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
100 XGrabKey(display, keycode, modifiers | kModifiersMasks[i],
101 gdk_x11_get_default_root_xwindow(), False,
102 GrabModeAsync, GrabModeAsync);
103 }
104
105 if (err_tracker.FoundNewError()) {
106 LOG(ERROR) << "X failed to grab global hotkey: "
107 << accelerator.GetShortcutText();
108
109 // We may have part of the hotkeys registered, clean up.
110 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
111 XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
112 gdk_x11_get_default_root_xwindow());
113 }
114 } else {
115 registered_hot_keys_.insert(accelerator);
116 GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
117 }
118 }
119
120 void GlobalShortcutListenerGtk::UnregisterAccelerator(
121 const ui::Accelerator& accelerator,
122 GlobalShortcutListener::Observer* observer) {
123 if (registered_hot_keys_.find(accelerator) == registered_hot_keys_.end())
124 return;
125
126 Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
127 int modifiers = GetNativeModifiers(accelerator);
128 KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
129
130 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
131 XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
132 gdk_x11_get_default_root_xwindow());
133 }
134 registered_hot_keys_.erase(accelerator);
135 GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
136 }
137
138 GdkFilterReturn GlobalShortcutListenerGtk::OnXEvent(GdkXEvent* gdk_x_event,
139 GdkEvent* gdk_event) {
140 XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
141 if (x_event->type == KeyPress) {
142 int modifiers = 0;
143 modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0;
144 modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0;
145 modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0;
146
147 ui::Accelerator accelerator(
148 ui::KeyboardCodeFromXKeyEvent(x_event), modifiers);
149 instance.Get().NotifyKeyPressed(accelerator);
150 }
151
152 return GDK_FILTER_CONTINUE;
153 }
154
155 } // namespace extensions
OLDNEW
« 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