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

Side by Side Diff: chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.cc

Issue 213283004: linux_aura: Port GtkKeybindingsHandler to Aura. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Move from ui/wm/ to ui/events/. Created 6 years, 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/ui/libgtk2ui/gtk2_key_bindings_handler.h"
6
7 #include <gdk/gdkkeysyms.h>
8 #include <X11/Xlib.h>
9 #include <X11/XKBlib.h>
10
11 #include <string>
12
13 #include "base/logging.h"
14 #include "base/strings/string_util.h"
15 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
16 #include "content/public/browser/native_web_keyboard_event.h"
17 #include "ui/base/x/x11_util.h"
18 #include "ui/events/event.h"
19
20 using ui::TextEditCommandX11;
21
22 // TODO(erg): Rewrite the old gtk_key_bindings_handler_unittest.cc and get them
23 // in a state that links. This code was adapted from the content layer GTK
24 // code, which had some simple unit tests. However, the changes in the public
25 // interface basically meant the tests need to be rewritten; this imposes weird
26 // linking requirements regarding GTK+ as we don't have a libgtk2ui_unittests
27 // yet. http://crbug.com/358297.
28
29 namespace libgtk2ui {
30
31 Gtk2KeyBindingsHandler::Gtk2KeyBindingsHandler()
32 : fake_window_(gtk_offscreen_window_new()),
33 handler_(CreateNewHandler()),
34 has_xkb_(false) {
35 gtk_container_add(GTK_CONTAINER(fake_window_), handler_.get());
36
37 int opcode, event, error;
38 int major = XkbMajorVersion;
39 int minor = XkbMinorVersion;
40 if (XkbQueryExtension(gfx::GetXDisplay(), &opcode, &event, &error,
sadrul 2014/03/31 22:58:56 has_xkb_ = XkbQueryExtension(....
41 &major, &minor))
42 has_xkb_ = true;
43 }
44
45 Gtk2KeyBindingsHandler::~Gtk2KeyBindingsHandler() {
46 handler_.Destroy();
47 gtk_widget_destroy(fake_window_);
48 }
49
50 bool Gtk2KeyBindingsHandler::MatchEvent(
51 const ui::Event& event,
52 std::vector<TextEditCommandX11>* edit_commands) {
53 if (!event.IsKeyEvent())
sadrul 2014/03/31 22:58:56 Looks like this is only called from places that sh
Elliot Glaysher 2014/03/31 23:16:25 Done.
54 return false;
55
56 const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
57 if (key_event.is_char() || !key_event.native_event())
sadrul 2014/03/31 22:58:56 Is the native-event preserved once it goes through
Elliot Glaysher 2014/03/31 23:16:25 It should be; this is copied straight from the GTK
58 return false;
59
60 GdkEventKey gdk_event;
61 BuildGdkEventKeyFromXEvent(key_event.native_event(), &gdk_event);
62
63 edit_commands_.clear();
64 // If this key event matches a predefined key binding, corresponding signal
65 // will be emitted.
66 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &gdk_event);
67
68 bool matched = !edit_commands_.empty();
69 if (edit_commands)
70 edit_commands->swap(edit_commands_);
71 return matched;
72 }
73
74 GtkWidget* Gtk2KeyBindingsHandler::CreateNewHandler() {
75 Handler* handler =
76 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL));
77
78 handler->owner = this;
79
80 // We don't need to show the |handler| object on screen, so set its size to
81 // zero.
82 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0);
83
84 // Prevents it from handling any events by itself.
85 gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE);
86 gtk_widget_set_events(GTK_WIDGET(handler), 0);
87 gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE);
88
89 return GTK_WIDGET(handler);
90 }
91
92 void Gtk2KeyBindingsHandler::EditCommandMatched(
93 TextEditCommandX11::CommandId id,
94 const std::string& value,
95 bool extend_selection) {
96 edit_commands_.push_back(TextEditCommandX11(id, value, extend_selection));
97 }
98
99 void Gtk2KeyBindingsHandler::BuildGdkEventKeyFromXEvent(
100 const base::NativeEvent& xevent,
101 GdkEventKey* gdk_event) {
102 GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
sadrul 2014/03/31 22:58:56 We create our own connection to the display in the
Elliot Glaysher 2014/03/31 23:16:25 I haven't seen any problems in local testing, or o
103 GdkModifierType consumed, state;
104
105 gdk_event->type = xevent->xany.type == KeyPress ?
106 GDK_KEY_PRESS : GDK_KEY_RELEASE;
107 gdk_event->time = xevent->xkey.time;
108 gdk_event->state = static_cast<GdkModifierType>(xevent->xkey.state);
109 gdk_event->hardware_keycode = xevent->xkey.keycode;
110
111 if (has_xkb_) {
112 gdk_event->group = XkbGroupForCoreState(xevent->xkey.state);
113 } else {
114 // The overwhelming majority of people will be using X servers that support
115 // XKB. GDK has a fallback here that does some complicated stuff to detect
116 // whether a modifier key affects the keybinding, but that should be
117 // extremely rare.
118 NOTIMPLEMENTED();
119 gdk_event->group = 0;
120 }
121
122 gdk_event->keyval = GDK_VoidSymbol;
123 gdk_keymap_translate_keyboard_state(
124 keymap,
125 gdk_event->hardware_keycode,
126 static_cast<GdkModifierType>(gdk_event->state),
127 gdk_event->group,
128 &gdk_event->keyval,
129 NULL, NULL, &consumed);
130
131 state = static_cast<GdkModifierType>(gdk_event->state & ~consumed);
132 gdk_keymap_add_virtual_modifiers(keymap, &state);
133 gdk_event->state |= state;
134 }
135
136 void Gtk2KeyBindingsHandler::HandlerInit(Handler *self) {
137 self->owner = NULL;
138 }
139
140 void Gtk2KeyBindingsHandler::HandlerClassInit(HandlerClass *klass) {
141 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass);
142 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
143
144 // Overrides all virtual methods related to editor key bindings.
145 text_view_class->backspace = BackSpace;
146 text_view_class->copy_clipboard = CopyClipboard;
147 text_view_class->cut_clipboard = CutClipboard;
148 text_view_class->delete_from_cursor = DeleteFromCursor;
149 text_view_class->insert_at_cursor = InsertAtCursor;
150 text_view_class->move_cursor = MoveCursor;
151 text_view_class->paste_clipboard = PasteClipboard;
152 text_view_class->set_anchor = SetAnchor;
153 text_view_class->toggle_overwrite = ToggleOverwrite;
154 widget_class->show_help = ShowHelp;
155
156 // "move-focus", "move-viewport", "select-all" and "toggle-cursor-visible"
157 // have no corresponding virtual methods. Since glib 2.18 (gtk 2.14),
158 // g_signal_override_class_handler() is introduced to override a signal
159 // handler.
160 g_signal_override_class_handler("move-focus",
161 G_TYPE_FROM_CLASS(klass),
162 G_CALLBACK(MoveFocus));
163
164 g_signal_override_class_handler("move-viewport",
165 G_TYPE_FROM_CLASS(klass),
166 G_CALLBACK(MoveViewport));
167
168 g_signal_override_class_handler("select-all",
169 G_TYPE_FROM_CLASS(klass),
170 G_CALLBACK(SelectAll));
171
172 g_signal_override_class_handler("toggle-cursor-visible",
173 G_TYPE_FROM_CLASS(klass),
174 G_CALLBACK(ToggleCursorVisible));
175 }
176
177 GType Gtk2KeyBindingsHandler::HandlerGetType() {
178 static volatile gsize type_id_volatile = 0;
179 if (g_once_init_enter(&type_id_volatile)) {
180 GType type_id = g_type_register_static_simple(
181 GTK_TYPE_TEXT_VIEW,
182 g_intern_static_string("Gtk2KeyBindingsHandler"),
183 sizeof(HandlerClass),
184 reinterpret_cast<GClassInitFunc>(HandlerClassInit),
185 sizeof(Handler),
186 reinterpret_cast<GInstanceInitFunc>(HandlerInit),
187 static_cast<GTypeFlags>(0));
188 g_once_init_leave(&type_id_volatile, type_id);
189 }
190 return type_id_volatile;
191 }
192
193 Gtk2KeyBindingsHandler* Gtk2KeyBindingsHandler::GetHandlerOwner(
194 GtkTextView* text_view) {
195 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST(
196 text_view, HandlerGetType(), Handler);
197 DCHECK(handler);
198 return handler->owner;
199 }
200
201 void Gtk2KeyBindingsHandler::BackSpace(GtkTextView* text_view) {
202 GetHandlerOwner(text_view)
203 ->EditCommandMatched(
204 TextEditCommandX11::DELETE_BACKWARD, std::string(), false);
205 }
206
207 void Gtk2KeyBindingsHandler::CopyClipboard(GtkTextView* text_view) {
208 GetHandlerOwner(text_view)->EditCommandMatched(
209 TextEditCommandX11::COPY, std::string(), false);
210 }
211
212 void Gtk2KeyBindingsHandler::CutClipboard(GtkTextView* text_view) {
213 GetHandlerOwner(text_view)->EditCommandMatched(
214 TextEditCommandX11::CUT, std::string(), false);
215 }
216
217 void Gtk2KeyBindingsHandler::DeleteFromCursor(
218 GtkTextView* text_view, GtkDeleteType type, gint count) {
219 if (!count)
220 return;
221
222 TextEditCommandX11::CommandId commands[2] = {
223 TextEditCommandX11::INVALID_COMMAND,
224 TextEditCommandX11::INVALID_COMMAND,
225 };
226 switch (type) {
227 case GTK_DELETE_CHARS:
228 commands[0] = (count > 0 ?
229 TextEditCommandX11::DELETE_FORWARD :
230 TextEditCommandX11::DELETE_BACKWARD);
231 break;
232 case GTK_DELETE_WORD_ENDS:
233 commands[0] = (count > 0 ?
234 TextEditCommandX11::DELETE_WORD_FORWARD :
235 TextEditCommandX11::DELETE_WORD_BACKWARD);
236 break;
237 case GTK_DELETE_WORDS:
238 if (count > 0) {
239 commands[0] = TextEditCommandX11::MOVE_WORD_FORWARD;
240 commands[1] = TextEditCommandX11::DELETE_WORD_BACKWARD;
241 } else {
242 commands[0] = TextEditCommandX11::MOVE_WORD_BACKWARD;
243 commands[1] = TextEditCommandX11::DELETE_WORD_FORWARD;
244 }
245 break;
246 case GTK_DELETE_DISPLAY_LINES:
247 commands[0] = TextEditCommandX11::MOVE_TO_BEGINING_OF_LINE;
248 commands[1] = TextEditCommandX11::DELETE_TO_END_OF_LINE;
249 break;
250 case GTK_DELETE_DISPLAY_LINE_ENDS:
251 commands[0] = (count > 0 ?
252 TextEditCommandX11::DELETE_TO_END_OF_LINE :
253 TextEditCommandX11::DELETE_TO_BEGINING_OF_LINE);
254 break;
255 case GTK_DELETE_PARAGRAPH_ENDS:
256 commands[0] = (count > 0 ?
257 TextEditCommandX11::DELETE_TO_END_OF_PARAGRAPH :
258 TextEditCommandX11::DELETE_TO_BEGINING_OF_PARAGRAPH);
259 break;
260 case GTK_DELETE_PARAGRAPHS:
261 commands[0] =
262 TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH;
263 commands[1] =
264 TextEditCommandX11::DELETE_TO_END_OF_PARAGRAPH;
265 break;
266 default:
267 // GTK_DELETE_WHITESPACE has no corresponding editor command.
268 return;
269 }
270
271 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view);
272 if (count < 0)
273 count = -count;
274 for (; count > 0; --count) {
275 for (size_t i = 0; i < arraysize(commands); ++i)
276 if (commands[i] != TextEditCommandX11::INVALID_COMMAND)
277 owner->EditCommandMatched(commands[i], std::string(), false);
278 }
279 }
280
281 void Gtk2KeyBindingsHandler::InsertAtCursor(GtkTextView* text_view,
282 const gchar* str) {
283 if (str && *str)
284 GetHandlerOwner(text_view)->EditCommandMatched(
285 TextEditCommandX11::INSERT_TEXT, str, false);
286 }
287
288 void Gtk2KeyBindingsHandler::MoveCursor(
289 GtkTextView* text_view, GtkMovementStep step, gint count,
290 gboolean extend_selection) {
291 if (!count)
292 return;
293
294 TextEditCommandX11::CommandId command;
295 switch (step) {
296 case GTK_MOVEMENT_LOGICAL_POSITIONS:
297 command = (count > 0 ?
298 TextEditCommandX11::MOVE_FORWARD :
299 TextEditCommandX11::MOVE_BACKWARD);
300 break;
301 case GTK_MOVEMENT_VISUAL_POSITIONS:
302 command = (count > 0 ?
303 TextEditCommandX11::MOVE_RIGHT :
304 TextEditCommandX11::MOVE_LEFT);
305 break;
306 case GTK_MOVEMENT_WORDS:
307 command = (count > 0 ?
308 TextEditCommandX11::MOVE_WORD_RIGHT :
309 TextEditCommandX11::MOVE_WORD_LEFT);
310 break;
311 case GTK_MOVEMENT_DISPLAY_LINES:
312 command = (count > 0 ?
313 TextEditCommandX11::MOVE_DOWN : TextEditCommandX11::MOVE_UP);
314 break;
315 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
316 command = (count > 0 ?
317 TextEditCommandX11::MOVE_TO_END_OF_LINE :
318 TextEditCommandX11::MOVE_TO_BEGINING_OF_LINE);
319 break;
320 case GTK_MOVEMENT_PARAGRAPH_ENDS:
321 command = (count > 0 ?
322 TextEditCommandX11::MOVE_TO_END_OF_PARAGRAPH :
323 TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH);
324 break;
325 case GTK_MOVEMENT_PAGES:
326 command = (count > 0 ? TextEditCommandX11::MOVE_PAGE_DOWN :
327 TextEditCommandX11::MOVE_PAGE_UP);
328 break;
329 case GTK_MOVEMENT_BUFFER_ENDS:
330 command = (count > 0 ? TextEditCommandX11::MOVE_TO_END_OF_DOCUMENT :
331 TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH);
332 break;
333 default:
334 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have
335 // no corresponding editor commands.
336 return;
337 }
338
339 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view);
340 if (count < 0)
341 count = -count;
342 for (; count > 0; --count)
343 owner->EditCommandMatched(command, std::string(), extend_selection);
344 }
345
346 void Gtk2KeyBindingsHandler::MoveViewport(
347 GtkTextView* text_view, GtkScrollStep step, gint count) {
348 // Not supported by webkit.
349 }
350
351 void Gtk2KeyBindingsHandler::PasteClipboard(GtkTextView* text_view) {
352 GetHandlerOwner(text_view)->EditCommandMatched(
353 TextEditCommandX11::PASTE, std::string(), false);
354 }
355
356 void Gtk2KeyBindingsHandler::SelectAll(GtkTextView* text_view,
357 gboolean select) {
358 if (select) {
359 GetHandlerOwner(text_view)->EditCommandMatched(
360 TextEditCommandX11::SELECT_ALL, std::string(), false);
361 } else {
362 GetHandlerOwner(text_view)->EditCommandMatched(
363 TextEditCommandX11::UNSELECT, std::string(), false);
364 }
365 }
366
367 void Gtk2KeyBindingsHandler::SetAnchor(GtkTextView* text_view) {
368 GetHandlerOwner(text_view)->EditCommandMatched(
369 TextEditCommandX11::SET_MARK, std::string(), false);
370 }
371
372 void Gtk2KeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) {
373 // Not supported by webkit.
374 }
375
376 void Gtk2KeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) {
377 // Not supported by webkit.
378 }
379
380 gboolean Gtk2KeyBindingsHandler::ShowHelp(GtkWidget* widget,
381 GtkWidgetHelpType arg1) {
382 // Just for disabling the default handler.
383 return FALSE;
384 }
385
386 void Gtk2KeyBindingsHandler::MoveFocus(GtkWidget* widget,
387 GtkDirectionType arg1) {
388 // Just for disabling the default handler.
389 }
390
391 } // namespace libgtk2ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698