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

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: 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 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.
23 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.
24 Mod2Mask, // NUM_LOCK
25 LockMask, // CAPS_LOCK
26 Mod5Mask, // SCROLL_LOCK
27 Mod2Mask | LockMask,
28 Mod2Mask | Mod5Mask,
29 LockMask | Mod5Mask,
30 Mod2Mask | LockMask | Mod5Mask
31 };
32
33 int GetNativeModifiers(const ui::Accelerator& accelerator) {
34 int modifiers = 0;
35 modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0;
36 modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0;
37 modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0;
38
39 return modifiers;
40 }
41
42 } // namespace
43
44 namespace extensions {
45
46 // static
47 GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
48 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
49 return instance.Pointer();
50 }
51
52 GlobalShortcutListenerGtk::GlobalShortcutListenerGtk()
53 : is_listening_(false) {
54 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
55 }
56
57 GlobalShortcutListenerGtk::~GlobalShortcutListenerGtk() {
58 if (is_listening_)
59 StopListening();
60 }
61
62 void GlobalShortcutListenerGtk::StartListening() {
63 DCHECK(!is_listening_); // Don't start twice.
64 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.
65 gdk_window_add_filter(gdk_get_default_root_window(),
66 &GlobalShortcutListenerGtk::OnXEventThunk,
67 this);
68 is_listening_ = true;
69 }
70 }
71
72 void GlobalShortcutListenerGtk::StopListening() {
73 DCHECK(is_listening_); // No point if we are not already listening.
74
75 if (is_listening_) {
76 gdk_window_remove_filter(NULL,
77 &GlobalShortcutListenerGtk::OnXEventThunk,
78 this);
79 is_listening_ = false;
80 }
81 }
82
83 void GlobalShortcutListenerGtk::RegisterAccelerator(
84 const ui::Accelerator& accelerator,
85 GlobalShortcutListener::Observer* observer) {
86 Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
87 int modifiers = GetNativeModifiers(accelerator);
88 KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
89 base::X11ErrorTracker err_tracker;
90
91 // 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
92 // our hot keys with modifiers that we want to ignore, including NUM_LOCK,
93 // CAPS_LOCK, SCROLL_LOCK.
94 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
95 XGrabKey(display, keycode, modifiers | kModifiersMasks[i],
96 gdk_x11_get_default_root_xwindow(), False,
97 GrabModeAsync, GrabModeAsync);
98 }
99
100 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.
101 LOG(ERROR) << "X failed to grab global hotkey: "
102 << 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'
103
104 // We may have part of the hotkeys registered, clean up.
105 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
106 XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
107 gdk_x11_get_default_root_xwindow());
108 }
109 } else {
110 registered_hot_keys_.insert(accelerator);
111 GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
112 }
113 }
114
115 void GlobalShortcutListenerGtk::UnregisterAccelerator(
116 const ui::Accelerator& accelerator,
117 GlobalShortcutListener::Observer* observer) {
118 if (registered_hot_keys_.find(accelerator) == registered_hot_keys_.end())
119 return;
120
121 Display* display = GDK_WINDOW_XDISPLAY(gdk_get_default_root_window());
122 int modifiers = GetNativeModifiers(accelerator);
123 KeyCode keycode = XKeysymToKeycode(display, accelerator.key_code());
124
125 for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
126 XUngrabKey(display, keycode, modifiers | kModifiersMasks[i],
127 gdk_x11_get_default_root_xwindow());
128 }
129 registered_hot_keys_.erase(accelerator);
130 GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
131 }
132
133 GdkFilterReturn GlobalShortcutListenerGtk::OnXEvent(GdkXEvent* gdk_x_event,
134 GdkEvent* gdk_event) {
135 XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
136 if (x_event->type == KeyPress) {
137 int modifiers = 0;
138 modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0;
139 modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0;
140 modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0;
141
142 ui::Accelerator accelerator(
143 ui::KeyboardCodeFromXKeyEvent(x_event), modifiers);
144 instance.Get().NotifyKeyPressed(accelerator);
145 }
146
147 return GDK_FILTER_CONTINUE;
148 }
149
150 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698