| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/gtk_key_bindings_handler.h" | 5 #include "chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.h" |
| 6 | 6 |
| 7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
| 8 #include <X11/Xlib.h> |
| 9 #include <X11/XKBlib.h> |
| 8 | 10 |
| 9 #include <string> | 11 #include <string> |
| 10 | 12 |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h" |
| 13 #include "content/public/browser/native_web_keyboard_event.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" |
| 14 | 19 |
| 15 namespace content { | 20 namespace libgtk2ui { |
| 16 | 21 |
| 17 GtkKeyBindingsHandler::GtkKeyBindingsHandler(GtkWidget* parent_widget) | 22 Gtk2KeyBindingsHandler::Gtk2KeyBindingsHandler() |
| 18 : handler_(CreateNewHandler()) { | 23 : fake_window_(gtk_offscreen_window_new()), |
| 19 DCHECK(GTK_IS_FIXED(parent_widget)); | 24 handler_(CreateNewHandler()), |
| 20 // We need add the |handler_| object into gtk widget hierarchy, so that | 25 has_xkb_(false) { |
| 21 // gtk_bindings_activate_event() can find correct display and keymaps from | 26 gtk_container_add(GTK_CONTAINER(fake_window_), handler_.get()); |
| 22 // the |handler_| object. | 27 |
| 23 gtk_fixed_put(GTK_FIXED(parent_widget), handler_.get(), -1, -1); | 28 int opcode, event, error; |
| 29 int major = XkbMajorVersion; |
| 30 int minor = XkbMinorVersion; |
| 31 if (XkbQueryExtension(gfx::GetXDisplay(), &opcode, &event, &error, |
| 32 &major, &minor)) |
| 33 has_xkb_ = true; |
| 24 } | 34 } |
| 25 | 35 |
| 26 GtkKeyBindingsHandler::~GtkKeyBindingsHandler() { | 36 Gtk2KeyBindingsHandler::~Gtk2KeyBindingsHandler() { |
| 27 handler_.Destroy(); | 37 handler_.Destroy(); |
| 38 gtk_widget_destroy(fake_window_); |
| 28 } | 39 } |
| 29 | 40 |
| 30 bool GtkKeyBindingsHandler::Match(const NativeWebKeyboardEvent& wke, | 41 bool Gtk2KeyBindingsHandler::Match(const content::NativeWebKeyboardEvent& wke, |
| 31 EditCommands* edit_commands) { | 42 content::EditCommands* edit_commands) { |
| 32 if (wke.type == blink::WebInputEvent::Char || !wke.os_event) | 43 if (wke.type == blink::WebInputEvent::Char || !wke.os_event) |
| 33 return false; | 44 return false; |
| 34 | 45 |
| 46 GdkEventKey gdk_event; |
| 47 BuildGdkEventKeyFromXEvent(wke.os_event->native_event(), &gdk_event); |
| 48 |
| 35 edit_commands_.clear(); | 49 edit_commands_.clear(); |
| 36 // If this key event matches a predefined key binding, corresponding signal | 50 // If this key event matches a predefined key binding, corresponding signal |
| 37 // will be emitted. | 51 // will be emitted. |
| 38 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &wke.os_event->key); | 52 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &gdk_event); |
| 39 | 53 |
| 40 bool matched = !edit_commands_.empty(); | 54 bool matched = !edit_commands_.empty(); |
| 41 if (edit_commands) | 55 if (edit_commands) |
| 42 edit_commands->swap(edit_commands_); | 56 edit_commands->swap(edit_commands_); |
| 43 return matched; | 57 return matched; |
| 44 } | 58 } |
| 45 | 59 |
| 46 GtkWidget* GtkKeyBindingsHandler::CreateNewHandler() { | 60 GtkWidget* Gtk2KeyBindingsHandler::CreateNewHandler() { |
| 47 Handler* handler = | 61 Handler* handler = |
| 48 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); | 62 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); |
| 49 | 63 |
| 50 handler->owner = this; | 64 handler->owner = this; |
| 51 | 65 |
| 52 // We don't need to show the |handler| object on screen, so set its size to | 66 // We don't need to show the |handler| object on screen, so set its size to |
| 53 // zero. | 67 // zero. |
| 54 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); | 68 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); |
| 55 | 69 |
| 56 // Prevents it from handling any events by itself. | 70 // Prevents it from handling any events by itself. |
| 57 gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE); | 71 gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE); |
| 58 gtk_widget_set_events(GTK_WIDGET(handler), 0); | 72 gtk_widget_set_events(GTK_WIDGET(handler), 0); |
| 59 gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE); | 73 gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE); |
| 60 | 74 |
| 61 return GTK_WIDGET(handler); | 75 return GTK_WIDGET(handler); |
| 62 } | 76 } |
| 63 | 77 |
| 64 void GtkKeyBindingsHandler::EditCommandMatched( | 78 void Gtk2KeyBindingsHandler::EditCommandMatched( |
| 65 const std::string& name, const std::string& value) { | 79 const std::string& name, const std::string& value) { |
| 66 edit_commands_.push_back(EditCommand(name, value)); | 80 edit_commands_.push_back(content::EditCommand(name, value)); |
| 67 } | 81 } |
| 68 | 82 |
| 69 void GtkKeyBindingsHandler::HandlerInit(Handler *self) { | 83 void Gtk2KeyBindingsHandler::BuildGdkEventKeyFromXEvent( |
| 84 const base::NativeEvent& xevent, |
| 85 GdkEventKey* gdk_event) { |
| 86 GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default()); |
| 87 GdkModifierType consumed, state; |
| 88 |
| 89 gdk_event->type = xevent->xany.type == KeyPress ? |
| 90 GDK_KEY_PRESS : GDK_KEY_RELEASE; |
| 91 gdk_event->time = xevent->xkey.time; |
| 92 gdk_event->state = static_cast<GdkModifierType>(xevent->xkey.state); |
| 93 gdk_event->hardware_keycode = xevent->xkey.keycode; |
| 94 |
| 95 if (has_xkb_) { |
| 96 gdk_event->group = XkbGroupForCoreState(xevent->xkey.state); |
| 97 } else { |
| 98 // TODO(erg): I don't understand what this is for. I read through parts of |
| 99 // gdkevent-x11.c. Just calling XkbGroupForCoreState() if we have XKB is |
| 100 // simple enough, but I don't understand X11 input handling enough to know |
| 101 // what this is for, and reading through what GDK does to try to calculate |
| 102 // this was not enlightening. |
| 103 // |
| 104 // Also, does anyone actually have servers that don't support XKB at this |
| 105 // point? |
| 106 NOTIMPLEMENTED(); |
| 107 gdk_event->group = 0; |
| 108 } |
| 109 |
| 110 gdk_event->keyval = GDK_VoidSymbol; |
| 111 gdk_keymap_translate_keyboard_state( |
| 112 keymap, |
| 113 gdk_event->hardware_keycode, |
| 114 static_cast<GdkModifierType>(gdk_event->state), |
| 115 gdk_event->group, |
| 116 &gdk_event->keyval, |
| 117 NULL, NULL, &consumed); |
| 118 |
| 119 state = static_cast<GdkModifierType>(gdk_event->state & ~consumed); |
| 120 gdk_keymap_add_virtual_modifiers(keymap, &state); |
| 121 gdk_event->state |= state; |
| 122 } |
| 123 |
| 124 void Gtk2KeyBindingsHandler::HandlerInit(Handler *self) { |
| 70 self->owner = NULL; | 125 self->owner = NULL; |
| 71 } | 126 } |
| 72 | 127 |
| 73 void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { | 128 void Gtk2KeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { |
| 74 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); | 129 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); |
| 75 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); | 130 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); |
| 76 | 131 |
| 77 // Overrides all virtual methods related to editor key bindings. | 132 // Overrides all virtual methods related to editor key bindings. |
| 78 text_view_class->backspace = BackSpace; | 133 text_view_class->backspace = BackSpace; |
| 79 text_view_class->copy_clipboard = CopyClipboard; | 134 text_view_class->copy_clipboard = CopyClipboard; |
| 80 text_view_class->cut_clipboard = CutClipboard; | 135 text_view_class->cut_clipboard = CutClipboard; |
| 81 text_view_class->delete_from_cursor = DeleteFromCursor; | 136 text_view_class->delete_from_cursor = DeleteFromCursor; |
| 82 text_view_class->insert_at_cursor = InsertAtCursor; | 137 text_view_class->insert_at_cursor = InsertAtCursor; |
| 83 text_view_class->move_cursor = MoveCursor; | 138 text_view_class->move_cursor = MoveCursor; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 100 | 155 |
| 101 g_signal_override_class_handler("select-all", | 156 g_signal_override_class_handler("select-all", |
| 102 G_TYPE_FROM_CLASS(klass), | 157 G_TYPE_FROM_CLASS(klass), |
| 103 G_CALLBACK(SelectAll)); | 158 G_CALLBACK(SelectAll)); |
| 104 | 159 |
| 105 g_signal_override_class_handler("toggle-cursor-visible", | 160 g_signal_override_class_handler("toggle-cursor-visible", |
| 106 G_TYPE_FROM_CLASS(klass), | 161 G_TYPE_FROM_CLASS(klass), |
| 107 G_CALLBACK(ToggleCursorVisible)); | 162 G_CALLBACK(ToggleCursorVisible)); |
| 108 } | 163 } |
| 109 | 164 |
| 110 GType GtkKeyBindingsHandler::HandlerGetType() { | 165 GType Gtk2KeyBindingsHandler::HandlerGetType() { |
| 111 static volatile gsize type_id_volatile = 0; | 166 static volatile gsize type_id_volatile = 0; |
| 112 if (g_once_init_enter(&type_id_volatile)) { | 167 if (g_once_init_enter(&type_id_volatile)) { |
| 113 GType type_id = g_type_register_static_simple( | 168 GType type_id = g_type_register_static_simple( |
| 114 GTK_TYPE_TEXT_VIEW, | 169 GTK_TYPE_TEXT_VIEW, |
| 115 g_intern_static_string("GtkKeyBindingsHandler"), | 170 g_intern_static_string("Gtk2KeyBindingsHandler"), |
| 116 sizeof(HandlerClass), | 171 sizeof(HandlerClass), |
| 117 reinterpret_cast<GClassInitFunc>(HandlerClassInit), | 172 reinterpret_cast<GClassInitFunc>(HandlerClassInit), |
| 118 sizeof(Handler), | 173 sizeof(Handler), |
| 119 reinterpret_cast<GInstanceInitFunc>(HandlerInit), | 174 reinterpret_cast<GInstanceInitFunc>(HandlerInit), |
| 120 static_cast<GTypeFlags>(0)); | 175 static_cast<GTypeFlags>(0)); |
| 121 g_once_init_leave(&type_id_volatile, type_id); | 176 g_once_init_leave(&type_id_volatile, type_id); |
| 122 } | 177 } |
| 123 return type_id_volatile; | 178 return type_id_volatile; |
| 124 } | 179 } |
| 125 | 180 |
| 126 GtkKeyBindingsHandler* GtkKeyBindingsHandler::GetHandlerOwner( | 181 Gtk2KeyBindingsHandler* Gtk2KeyBindingsHandler::GetHandlerOwner( |
| 127 GtkTextView* text_view) { | 182 GtkTextView* text_view) { |
| 128 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( | 183 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( |
| 129 text_view, HandlerGetType(), Handler); | 184 text_view, HandlerGetType(), Handler); |
| 130 DCHECK(handler); | 185 DCHECK(handler); |
| 131 return handler->owner; | 186 return handler->owner; |
| 132 } | 187 } |
| 133 | 188 |
| 134 void GtkKeyBindingsHandler::BackSpace(GtkTextView* text_view) { | 189 void Gtk2KeyBindingsHandler::BackSpace(GtkTextView* text_view) { |
| 135 GetHandlerOwner(text_view) | 190 GetHandlerOwner(text_view) |
| 136 ->EditCommandMatched("DeleteBackward", std::string()); | 191 ->EditCommandMatched("DeleteBackward", std::string()); |
| 137 } | 192 } |
| 138 | 193 |
| 139 void GtkKeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { | 194 void Gtk2KeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { |
| 140 GetHandlerOwner(text_view)->EditCommandMatched("Copy", std::string()); | 195 GetHandlerOwner(text_view)->EditCommandMatched("Copy", std::string()); |
| 141 } | 196 } |
| 142 | 197 |
| 143 void GtkKeyBindingsHandler::CutClipboard(GtkTextView* text_view) { | 198 void Gtk2KeyBindingsHandler::CutClipboard(GtkTextView* text_view) { |
| 144 GetHandlerOwner(text_view)->EditCommandMatched("Cut", std::string()); | 199 GetHandlerOwner(text_view)->EditCommandMatched("Cut", std::string()); |
| 145 } | 200 } |
| 146 | 201 |
| 147 void GtkKeyBindingsHandler::DeleteFromCursor( | 202 void Gtk2KeyBindingsHandler::DeleteFromCursor( |
| 148 GtkTextView* text_view, GtkDeleteType type, gint count) { | 203 GtkTextView* text_view, GtkDeleteType type, gint count) { |
| 149 if (!count) | 204 if (!count) |
| 150 return; | 205 return; |
| 151 | 206 |
| 152 const char *commands[3] = { NULL, NULL, NULL }; | 207 const char *commands[3] = { NULL, NULL, NULL }; |
| 153 switch (type) { | 208 switch (type) { |
| 154 case GTK_DELETE_CHARS: | 209 case GTK_DELETE_CHARS: |
| 155 commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); | 210 commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); |
| 156 break; | 211 break; |
| 157 case GTK_DELETE_WORD_ENDS: | 212 case GTK_DELETE_WORD_ENDS: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 180 break; | 235 break; |
| 181 case GTK_DELETE_PARAGRAPHS: | 236 case GTK_DELETE_PARAGRAPHS: |
| 182 commands[0] = "MoveToBeginningOfParagraph"; | 237 commands[0] = "MoveToBeginningOfParagraph"; |
| 183 commands[1] = "DeleteToEndOfParagraph"; | 238 commands[1] = "DeleteToEndOfParagraph"; |
| 184 break; | 239 break; |
| 185 default: | 240 default: |
| 186 // GTK_DELETE_WHITESPACE has no corresponding editor command. | 241 // GTK_DELETE_WHITESPACE has no corresponding editor command. |
| 187 return; | 242 return; |
| 188 } | 243 } |
| 189 | 244 |
| 190 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | 245 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view); |
| 191 if (count < 0) | 246 if (count < 0) |
| 192 count = -count; | 247 count = -count; |
| 193 for (; count > 0; --count) { | 248 for (; count > 0; --count) { |
| 194 for (const char* const* p = commands; *p; ++p) | 249 for (const char* const* p = commands; *p; ++p) |
| 195 owner->EditCommandMatched(*p, std::string()); | 250 owner->EditCommandMatched(*p, std::string()); |
| 196 } | 251 } |
| 197 } | 252 } |
| 198 | 253 |
| 199 void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, | 254 void Gtk2KeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, |
| 200 const gchar* str) { | 255 const gchar* str) { |
| 201 if (str && *str) | 256 if (str && *str) |
| 202 GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); | 257 GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); |
| 203 } | 258 } |
| 204 | 259 |
| 205 void GtkKeyBindingsHandler::MoveCursor( | 260 void Gtk2KeyBindingsHandler::MoveCursor( |
| 206 GtkTextView* text_view, GtkMovementStep step, gint count, | 261 GtkTextView* text_view, GtkMovementStep step, gint count, |
| 207 gboolean extend_selection) { | 262 gboolean extend_selection) { |
| 208 if (!count) | 263 if (!count) |
| 209 return; | 264 return; |
| 210 | 265 |
| 211 std::string command; | 266 std::string command; |
| 212 switch (step) { | 267 switch (step) { |
| 213 case GTK_MOVEMENT_LOGICAL_POSITIONS: | 268 case GTK_MOVEMENT_LOGICAL_POSITIONS: |
| 214 command = (count > 0 ? "MoveForward" : "MoveBackward"); | 269 command = (count > 0 ? "MoveForward" : "MoveBackward"); |
| 215 break; | 270 break; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 235 case GTK_MOVEMENT_BUFFER_ENDS: | 290 case GTK_MOVEMENT_BUFFER_ENDS: |
| 236 command = (count > 0 ? "MoveToEndOfDocument" : | 291 command = (count > 0 ? "MoveToEndOfDocument" : |
| 237 "MoveToBeginningOfDocument"); | 292 "MoveToBeginningOfDocument"); |
| 238 break; | 293 break; |
| 239 default: | 294 default: |
| 240 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have | 295 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have |
| 241 // no corresponding editor commands. | 296 // no corresponding editor commands. |
| 242 return; | 297 return; |
| 243 } | 298 } |
| 244 | 299 |
| 245 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | 300 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view); |
| 246 if (extend_selection) | 301 if (extend_selection) |
| 247 command.append("AndModifySelection"); | 302 command.append("AndModifySelection"); |
| 248 if (count < 0) | 303 if (count < 0) |
| 249 count = -count; | 304 count = -count; |
| 250 for (; count > 0; --count) | 305 for (; count > 0; --count) |
| 251 owner->EditCommandMatched(command, std::string()); | 306 owner->EditCommandMatched(command, std::string()); |
| 252 } | 307 } |
| 253 | 308 |
| 254 void GtkKeyBindingsHandler::MoveViewport( | 309 void Gtk2KeyBindingsHandler::MoveViewport( |
| 255 GtkTextView* text_view, GtkScrollStep step, gint count) { | 310 GtkTextView* text_view, GtkScrollStep step, gint count) { |
| 256 // Not supported by webkit. | 311 // Not supported by webkit. |
| 257 } | 312 } |
| 258 | 313 |
| 259 void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { | 314 void Gtk2KeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { |
| 260 GetHandlerOwner(text_view)->EditCommandMatched("Paste", std::string()); | 315 GetHandlerOwner(text_view)->EditCommandMatched("Paste", std::string()); |
| 261 } | 316 } |
| 262 | 317 |
| 263 void GtkKeyBindingsHandler::SelectAll(GtkTextView* text_view, gboolean select) { | 318 void Gtk2KeyBindingsHandler::SelectAll(GtkTextView* text_view, |
| 319 gboolean select) { |
| 264 if (select) | 320 if (select) |
| 265 GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", std::string()); | 321 GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", std::string()); |
| 266 else | 322 else |
| 267 GetHandlerOwner(text_view)->EditCommandMatched("Unselect", std::string()); | 323 GetHandlerOwner(text_view)->EditCommandMatched("Unselect", std::string()); |
| 268 } | 324 } |
| 269 | 325 |
| 270 void GtkKeyBindingsHandler::SetAnchor(GtkTextView* text_view) { | 326 void Gtk2KeyBindingsHandler::SetAnchor(GtkTextView* text_view) { |
| 271 GetHandlerOwner(text_view)->EditCommandMatched("SetMark", std::string()); | 327 GetHandlerOwner(text_view)->EditCommandMatched("SetMark", std::string()); |
| 272 } | 328 } |
| 273 | 329 |
| 274 void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { | 330 void Gtk2KeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { |
| 275 // Not supported by webkit. | 331 // Not supported by webkit. |
| 276 } | 332 } |
| 277 | 333 |
| 278 void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { | 334 void Gtk2KeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { |
| 279 // Not supported by webkit. | 335 // Not supported by webkit. |
| 280 } | 336 } |
| 281 | 337 |
| 282 gboolean GtkKeyBindingsHandler::ShowHelp(GtkWidget* widget, | 338 gboolean Gtk2KeyBindingsHandler::ShowHelp(GtkWidget* widget, |
| 283 GtkWidgetHelpType arg1) { | 339 GtkWidgetHelpType arg1) { |
| 284 // Just for disabling the default handler. | 340 // Just for disabling the default handler. |
| 285 return FALSE; | 341 return FALSE; |
| 286 } | 342 } |
| 287 | 343 |
| 288 void GtkKeyBindingsHandler::MoveFocus(GtkWidget* widget, | 344 void Gtk2KeyBindingsHandler::MoveFocus(GtkWidget* widget, |
| 289 GtkDirectionType arg1) { | 345 GtkDirectionType arg1) { |
| 290 // Just for disabling the default handler. | 346 // Just for disabling the default handler. |
| 291 } | 347 } |
| 292 | 348 |
| 293 } // namespace content | 349 } // namespace libgtk2ui |
| OLD | NEW |