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

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

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

Powered by Google App Engine
This is Rietveld 408576698