Index: chrome/browser/renderer_host/gtk_key_bindings_handler.cc |
=================================================================== |
--- chrome/browser/renderer_host/gtk_key_bindings_handler.cc (revision 0) |
+++ chrome/browser/renderer_host/gtk_key_bindings_handler.cc (revision 0) |
@@ -0,0 +1,304 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/renderer_host/gtk_key_bindings_handler.h" |
+ |
+#include <gdk/gdkkeysyms.h> |
+ |
+#include <string> |
+ |
+#include "base/logging.h" |
+#include "base/string_util.h" |
+#include "chrome/common/native_web_keyboard_event.h" |
+ |
+GtkKeyBindingsHandler::GtkKeyBindingsHandler(GtkWidget* parent_widget) |
+ : handler_(CreateNewHandler()), |
+ edit_commands_(NULL), |
+ enabled_(false) { |
+ DCHECK(GTK_IS_FIXED(parent_widget)); |
+ // We need add the |handler_| object into gtk widget hierarchy, so that |
+ // gtk_bindings_activate_event() can find correct display and keymaps from |
+ // the |handler_| object. |
+ gtk_fixed_put(GTK_FIXED(parent_widget), handler_.get(), -1, -1); |
+} |
+ |
+GtkKeyBindingsHandler::~GtkKeyBindingsHandler() { |
+ handler_.Destroy(); |
+} |
+ |
+bool GtkKeyBindingsHandler::Match(const NativeWebKeyboardEvent& wke, |
+ EditCommands* edit_commands) { |
+ if (!enabled_ || wke.type == WebKit::WebInputEvent::Char || |
+ !wke.os_event || wke.os_event->keyval == GDK_VoidSymbol) |
+ return false; |
+ |
+ edit_commands_.clear(); |
+ // If this key event matches a predefined key binding, corresponding signal |
+ // will be emitted. |
+ gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), wke.os_event); |
+ |
+ bool matched = !edit_commands_.empty(); |
+ if (edit_commands) |
+ edit_commands->swap(edit_commands_); |
+ return matched; |
+} |
+ |
+GtkWidget* GtkKeyBindingsHandler::CreateNewHandler() { |
+ Handler* handler = |
+ static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); |
+ |
+ handler->owner = this; |
+ |
+ // We don't need to show the |handler| object on screen, so set its size to |
+ // zero. |
+ gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); |
+ |
+ // Prevents it from handling any events by itself. |
+ gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE); |
+ gtk_widget_set_events(GTK_WIDGET(handler), 0); |
+ GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(handler), GTK_CAN_FOCUS); |
+ |
+#if !GTK_CHECK_VERSION(2, 14, 0) |
+ // "move-viewport", "select-all" and "toggle-cursor-visible" have no |
+ // corresponding virtual methods. Prior to glib 2.18 (gtk 2.14), there is no |
+ // way to override the default class handler of a signal. So we need hook |
+ // these signal explicitly. |
+ g_signal_connect(handler, "move-viewport", G_CALLBACK(MoveViewport), NULL); |
+ g_signal_connect(handler, "select-all", G_CALLBACK(SelectAll), NULL); |
+ g_signal_connect(handler, "toggle-cursor-visible", |
+ G_CALLBACK(ToggleCursorVisible), NULL); |
+#endif |
+ return GTK_WIDGET(handler); |
+} |
+ |
+void GtkKeyBindingsHandler::EditCommandMatched( |
+ const std::string& name, const std::string& value) { |
+ edit_commands_.push_back(EditCommand(name, value)); |
+} |
+ |
+void GtkKeyBindingsHandler::HandlerInit(Handler *self) { |
+ self->owner = NULL; |
+} |
+ |
+void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { |
+ GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); |
+ |
+ // Overrides all virtual methods related to editor key bindings. |
+ text_view_class->backspace = BackSpace; |
+ text_view_class->copy_clipboard = CopyClipboard; |
+ text_view_class->cut_clipboard = CutClipboard; |
+ text_view_class->delete_from_cursor = DeleteFromCursor; |
+ text_view_class->insert_at_cursor = InsertAtCursor; |
+ text_view_class->move_cursor = MoveCursor; |
+ text_view_class->paste_clipboard = PasteClipboard; |
+ text_view_class->set_anchor = SetAnchor; |
+ text_view_class->toggle_overwrite = ToggleOverwrite; |
+ |
+#if GTK_CHECK_VERSION(2, 14, 0) |
+ // "move-viewport", "select-all" and "toggle-cursor-visible" have no |
+ // corresponding virtual methods. Since glib 2.18 (gtk 2.14), |
+ // g_signal_override_class_handler() is introduced to override a signal |
+ // handler. |
+ g_signal_override_class_handler("move-viewport", |
+ G_TYPE_FROM_CLASS(klass), |
+ G_CALLBACK(MoveViewport)); |
+ |
+ g_signal_override_class_handler("select-all", |
+ G_TYPE_FROM_CLASS(klass), |
+ G_CALLBACK(SelectAll)); |
+ |
+ g_signal_override_class_handler("toggle-cursor-visible", |
+ G_TYPE_FROM_CLASS(klass), |
+ G_CALLBACK(ToggleCursorVisible)); |
+#endif |
+} |
+ |
+GType GtkKeyBindingsHandler::HandlerGetType() { |
+ static volatile gsize type_id_volatile = 0; |
+ if (g_once_init_enter(&type_id_volatile)) { |
+ GType type_id = g_type_register_static_simple( |
+ GTK_TYPE_TEXT_VIEW, |
+ g_intern_static_string("GtkKeyBindingsHandler"), |
+ sizeof(HandlerClass), |
+ reinterpret_cast<GClassInitFunc>(HandlerClassInit), |
+ sizeof(Handler), |
+ reinterpret_cast<GInstanceInitFunc>(HandlerInit), |
+ static_cast<GTypeFlags>(0)); |
+ g_once_init_leave(&type_id_volatile, type_id); |
+ } |
+ return type_id_volatile; |
+} |
+ |
+GtkKeyBindingsHandler* GtkKeyBindingsHandler::GetHandlerOwner( |
+ GtkTextView* text_view) { |
+ Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( |
+ text_view, HandlerGetType(), Handler); |
+ DCHECK(handler); |
+ return handler->owner; |
+} |
+ |
+void GtkKeyBindingsHandler::BackSpace(GtkTextView* text_view) { |
+ GetHandlerOwner(text_view)->EditCommandMatched("DeleteBackward", ""); |
+} |
+ |
+void GtkKeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { |
+ GetHandlerOwner(text_view)->EditCommandMatched("Copy", ""); |
+} |
+ |
+void GtkKeyBindingsHandler::CutClipboard(GtkTextView* text_view) { |
+ GetHandlerOwner(text_view)->EditCommandMatched("Cut", ""); |
+} |
+ |
+void GtkKeyBindingsHandler::DeleteFromCursor( |
+ GtkTextView* text_view, GtkDeleteType type, gint count) { |
+ if (!count) |
+ return; |
+ |
+ const char *commands[3] = { NULL, NULL, NULL }; |
+ switch (type) { |
+ case GTK_DELETE_CHARS: |
+ commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); |
+ break; |
+ case GTK_DELETE_WORD_ENDS: |
+ commands[0] = (count > 0 ? "DeleteWordForward" : "DeleteWordBackward"); |
+ break; |
+ case GTK_DELETE_WORDS: |
+ if (count > 0) { |
+ commands[0] = "MoveWordForward"; |
+ commands[1] = "DeleteWordBackward"; |
+ } else { |
+ commands[0] = "MoveWordBackward"; |
+ commands[1] = "DeleteWordForward"; |
+ } |
+ break; |
+ case GTK_DELETE_DISPLAY_LINES: |
+ commands[0] = "MoveToBeginningOfLine"; |
+ commands[1] = "DeleteToEndOfLine"; |
+ break; |
+ case GTK_DELETE_DISPLAY_LINE_ENDS: |
+ commands[0] = (count > 0 ? "DeleteToEndOfLine" : |
+ "DeleteToBeginningOfLine"); |
+ break; |
+ case GTK_DELETE_PARAGRAPH_ENDS: |
+ commands[0] = (count > 0 ? "DeleteToEndOfParagraph" : |
+ "DeleteToBeginningOfParagraph"); |
+ break; |
+ case GTK_DELETE_PARAGRAPHS: |
+ commands[0] = "MoveToBeginningOfParagraph"; |
+ commands[1] = "DeleteToEndOfParagraph"; |
+ break; |
+ default: |
+ // GTK_DELETE_WHITESPACE has no corresponding editor command. |
+ return; |
+ } |
+ |
+ GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); |
+ if (count < 0) |
+ count = -count; |
+ for (; count > 0; --count) { |
+ for (const char* const* p = commands; *p; ++p) |
+ owner->EditCommandMatched(*p, ""); |
+ } |
+} |
+ |
+void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, |
+ const gchar* str) { |
+ if (str && *str) |
+ GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); |
+} |
+ |
+void GtkKeyBindingsHandler::MoveCursor( |
+ GtkTextView* text_view, GtkMovementStep step, gint count, |
+ gboolean extend_selection) { |
+ if (!count) |
+ return; |
+ |
+ std::string command; |
+ switch (step) { |
+ case GTK_MOVEMENT_LOGICAL_POSITIONS: |
+ command = (count > 0 ? "MoveForward" : "MoveBackward"); |
+ break; |
+ case GTK_MOVEMENT_VISUAL_POSITIONS: |
+ command = (count > 0 ? "MoveRight" : "MoveLeft"); |
+ break; |
+ case GTK_MOVEMENT_WORDS: |
+ command = (count > 0 ? "MoveWordForward" : "MoveWordBackward"); |
+ break; |
+ case GTK_MOVEMENT_DISPLAY_LINES: |
+ command = (count > 0 ? "MoveDown" : "MoveUp"); |
+ break; |
+ case GTK_MOVEMENT_DISPLAY_LINE_ENDS: |
+ command = (count > 0 ? "MoveToEndOfLine" : "MoveToBeginningOfLine"); |
+ break; |
+ case GTK_MOVEMENT_PARAGRAPH_ENDS: |
+ command = (count > 0 ? "MoveToEndOfParagraph" : |
+ "MoveToBeginningOfParagraph"); |
+ break; |
+ case GTK_MOVEMENT_PAGES: |
+ command = (count > 0 ? "MovePageDown" : "MovePageUp"); |
+ break; |
+ case GTK_MOVEMENT_BUFFER_ENDS: |
+ command = (count > 0 ? "MoveToEndOfDocument" : |
+ "MoveToBeginningOfDocument"); |
+ break; |
+ default: |
+ // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have |
+ // no corresponding editor commands. |
+ return; |
+ } |
+ |
+ GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); |
+ if (extend_selection) |
+ command.append("AndModifySelection"); |
+ if (count < 0) |
+ count = -count; |
+ for (; count > 0; --count) |
+ owner->EditCommandMatched(command, ""); |
+} |
+ |
+void GtkKeyBindingsHandler::MoveViewport( |
+ GtkTextView* text_view, GtkScrollStep step, gint count) { |
+ // Not supported by webkit. |
+#if !GTK_CHECK_VERSION(2, 14, 0) |
+ // Before gtk 2.14.0, there is no way to override a non-virtual default signal |
+ // handler, so we need stop the signal emission explicitly to prevent the |
+ // default handler from being executed. |
+ g_signal_stop_emission_by_name(text_view, "move-viewport"); |
+#endif |
+} |
+ |
+void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { |
+ GetHandlerOwner(text_view)->EditCommandMatched("Paste", ""); |
+} |
+ |
+void GtkKeyBindingsHandler::SelectAll(GtkTextView* text_view, gboolean select) { |
+ if (select) |
+ GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", ""); |
+ else |
+ GetHandlerOwner(text_view)->EditCommandMatched("Unselect", ""); |
+#if !GTK_CHECK_VERSION(2, 14, 0) |
+ // Before gtk 2.14.0, there is no way to override a non-virtual default signal |
+ // handler, so we need stop the signal emission explicitly to prevent the |
+ // default handler from being executed. |
+ g_signal_stop_emission_by_name(text_view, "select-all"); |
+#endif |
+} |
+ |
+void GtkKeyBindingsHandler::SetAnchor(GtkTextView* text_view) { |
+ GetHandlerOwner(text_view)->EditCommandMatched("SetMark", ""); |
+} |
+ |
+void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { |
+ // Not supported by webkit. |
+#if !GTK_CHECK_VERSION(2, 14, 0) |
+ // Before gtk 2.14.0, there is no way to override a non-virtual default signal |
+ // handler, so we need stop the signal emission explicitly to prevent the |
+ // default handler from being executed. |
+ g_signal_stop_emission_by_name(text_view, "toggle-cursor-visible"); |
+#endif |
+} |
+ |
+void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { |
+ // Not supported by webkit. |
+} |
Property changes on: chrome/browser/renderer_host/gtk_key_bindings_handler.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |