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

Unified 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: Fixes for sadrul Created 6 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.h ('k') | chrome/browser/ui/libgtk2ui/gtk2_ui.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.cc
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.cc b/chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fdf5799ee42218f61b8e0d21c889a4a489987a3d
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.cc
@@ -0,0 +1,389 @@
+// Copyright (c) 2012 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/ui/libgtk2ui/gtk2_key_bindings_handler.h"
+
+#include <gdk/gdkkeysyms.h>
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/event.h"
+
+using ui::TextEditCommandX11;
+
+// TODO(erg): Rewrite the old gtk_key_bindings_handler_unittest.cc and get them
+// in a state that links. This code was adapted from the content layer GTK
+// code, which had some simple unit tests. However, the changes in the public
+// interface basically meant the tests need to be rewritten; this imposes weird
+// linking requirements regarding GTK+ as we don't have a libgtk2ui_unittests
+// yet. http://crbug.com/358297.
+
+namespace libgtk2ui {
+
+Gtk2KeyBindingsHandler::Gtk2KeyBindingsHandler()
+ : fake_window_(gtk_offscreen_window_new()),
+ handler_(CreateNewHandler()),
+ has_xkb_(false) {
+ gtk_container_add(GTK_CONTAINER(fake_window_), handler_.get());
+
+ int opcode, event, error;
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ has_xkb_ = XkbQueryExtension(gfx::GetXDisplay(), &opcode, &event, &error,
+ &major, &minor);
+}
+
+Gtk2KeyBindingsHandler::~Gtk2KeyBindingsHandler() {
+ handler_.Destroy();
+ gtk_widget_destroy(fake_window_);
+}
+
+bool Gtk2KeyBindingsHandler::MatchEvent(
+ const ui::Event& event,
+ std::vector<TextEditCommandX11>* edit_commands) {
+ CHECK(event.IsKeyEvent());
+
+ const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
+ if (key_event.is_char() || !key_event.native_event())
+ return false;
+
+ GdkEventKey gdk_event;
+ BuildGdkEventKeyFromXEvent(key_event.native_event(), &gdk_event);
+
+ 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()), &gdk_event);
+
+ bool matched = !edit_commands_.empty();
+ if (edit_commands)
+ edit_commands->swap(edit_commands_);
+ return matched;
+}
+
+GtkWidget* Gtk2KeyBindingsHandler::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_set_can_focus(GTK_WIDGET(handler), TRUE);
+
+ return GTK_WIDGET(handler);
+}
+
+void Gtk2KeyBindingsHandler::EditCommandMatched(
+ TextEditCommandX11::CommandId id,
+ const std::string& value,
+ bool extend_selection) {
+ edit_commands_.push_back(TextEditCommandX11(id, value, extend_selection));
+}
+
+void Gtk2KeyBindingsHandler::BuildGdkEventKeyFromXEvent(
+ const base::NativeEvent& xevent,
+ GdkEventKey* gdk_event) {
+ GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
+ GdkModifierType consumed, state;
+
+ gdk_event->type = xevent->xany.type == KeyPress ?
+ GDK_KEY_PRESS : GDK_KEY_RELEASE;
+ gdk_event->time = xevent->xkey.time;
+ gdk_event->state = static_cast<GdkModifierType>(xevent->xkey.state);
+ gdk_event->hardware_keycode = xevent->xkey.keycode;
+
+ if (has_xkb_) {
+ gdk_event->group = XkbGroupForCoreState(xevent->xkey.state);
+ } else {
+ // The overwhelming majority of people will be using X servers that support
+ // XKB. GDK has a fallback here that does some complicated stuff to detect
+ // whether a modifier key affects the keybinding, but that should be
+ // extremely rare.
+ NOTIMPLEMENTED();
+ gdk_event->group = 0;
+ }
+
+ gdk_event->keyval = GDK_VoidSymbol;
+ gdk_keymap_translate_keyboard_state(
+ keymap,
+ gdk_event->hardware_keycode,
+ static_cast<GdkModifierType>(gdk_event->state),
+ gdk_event->group,
+ &gdk_event->keyval,
+ NULL, NULL, &consumed);
+
+ state = static_cast<GdkModifierType>(gdk_event->state & ~consumed);
+ gdk_keymap_add_virtual_modifiers(keymap, &state);
+ gdk_event->state |= state;
+}
+
+void Gtk2KeyBindingsHandler::HandlerInit(Handler *self) {
+ self->owner = NULL;
+}
+
+void Gtk2KeyBindingsHandler::HandlerClassInit(HandlerClass *klass) {
+ GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_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;
+ widget_class->show_help = ShowHelp;
+
+ // "move-focus", "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-focus",
+ G_TYPE_FROM_CLASS(klass),
+ G_CALLBACK(MoveFocus));
+
+ 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));
+}
+
+GType Gtk2KeyBindingsHandler::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("Gtk2KeyBindingsHandler"),
+ 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;
+}
+
+Gtk2KeyBindingsHandler* Gtk2KeyBindingsHandler::GetHandlerOwner(
+ GtkTextView* text_view) {
+ Handler* handler = G_TYPE_CHECK_INSTANCE_CAST(
+ text_view, HandlerGetType(), Handler);
+ DCHECK(handler);
+ return handler->owner;
+}
+
+void Gtk2KeyBindingsHandler::BackSpace(GtkTextView* text_view) {
+ GetHandlerOwner(text_view)
+ ->EditCommandMatched(
+ TextEditCommandX11::DELETE_BACKWARD, std::string(), false);
+}
+
+void Gtk2KeyBindingsHandler::CopyClipboard(GtkTextView* text_view) {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::COPY, std::string(), false);
+}
+
+void Gtk2KeyBindingsHandler::CutClipboard(GtkTextView* text_view) {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::CUT, std::string(), false);
+}
+
+void Gtk2KeyBindingsHandler::DeleteFromCursor(
+ GtkTextView* text_view, GtkDeleteType type, gint count) {
+ if (!count)
+ return;
+
+ TextEditCommandX11::CommandId commands[2] = {
+ TextEditCommandX11::INVALID_COMMAND,
+ TextEditCommandX11::INVALID_COMMAND,
+ };
+ switch (type) {
+ case GTK_DELETE_CHARS:
+ commands[0] = (count > 0 ?
+ TextEditCommandX11::DELETE_FORWARD :
+ TextEditCommandX11::DELETE_BACKWARD);
+ break;
+ case GTK_DELETE_WORD_ENDS:
+ commands[0] = (count > 0 ?
+ TextEditCommandX11::DELETE_WORD_FORWARD :
+ TextEditCommandX11::DELETE_WORD_BACKWARD);
+ break;
+ case GTK_DELETE_WORDS:
+ if (count > 0) {
+ commands[0] = TextEditCommandX11::MOVE_WORD_FORWARD;
+ commands[1] = TextEditCommandX11::DELETE_WORD_BACKWARD;
+ } else {
+ commands[0] = TextEditCommandX11::MOVE_WORD_BACKWARD;
+ commands[1] = TextEditCommandX11::DELETE_WORD_FORWARD;
+ }
+ break;
+ case GTK_DELETE_DISPLAY_LINES:
+ commands[0] = TextEditCommandX11::MOVE_TO_BEGINING_OF_LINE;
+ commands[1] = TextEditCommandX11::DELETE_TO_END_OF_LINE;
+ break;
+ case GTK_DELETE_DISPLAY_LINE_ENDS:
+ commands[0] = (count > 0 ?
+ TextEditCommandX11::DELETE_TO_END_OF_LINE :
+ TextEditCommandX11::DELETE_TO_BEGINING_OF_LINE);
+ break;
+ case GTK_DELETE_PARAGRAPH_ENDS:
+ commands[0] = (count > 0 ?
+ TextEditCommandX11::DELETE_TO_END_OF_PARAGRAPH :
+ TextEditCommandX11::DELETE_TO_BEGINING_OF_PARAGRAPH);
+ break;
+ case GTK_DELETE_PARAGRAPHS:
+ commands[0] =
+ TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH;
+ commands[1] =
+ TextEditCommandX11::DELETE_TO_END_OF_PARAGRAPH;
+ break;
+ default:
+ // GTK_DELETE_WHITESPACE has no corresponding editor command.
+ return;
+ }
+
+ Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view);
+ if (count < 0)
+ count = -count;
+ for (; count > 0; --count) {
+ for (size_t i = 0; i < arraysize(commands); ++i)
+ if (commands[i] != TextEditCommandX11::INVALID_COMMAND)
+ owner->EditCommandMatched(commands[i], std::string(), false);
+ }
+}
+
+void Gtk2KeyBindingsHandler::InsertAtCursor(GtkTextView* text_view,
+ const gchar* str) {
+ if (str && *str)
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::INSERT_TEXT, str, false);
+}
+
+void Gtk2KeyBindingsHandler::MoveCursor(
+ GtkTextView* text_view, GtkMovementStep step, gint count,
+ gboolean extend_selection) {
+ if (!count)
+ return;
+
+ TextEditCommandX11::CommandId command;
+ switch (step) {
+ case GTK_MOVEMENT_LOGICAL_POSITIONS:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_FORWARD :
+ TextEditCommandX11::MOVE_BACKWARD);
+ break;
+ case GTK_MOVEMENT_VISUAL_POSITIONS:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_RIGHT :
+ TextEditCommandX11::MOVE_LEFT);
+ break;
+ case GTK_MOVEMENT_WORDS:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_WORD_RIGHT :
+ TextEditCommandX11::MOVE_WORD_LEFT);
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINES:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_DOWN : TextEditCommandX11::MOVE_UP);
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_TO_END_OF_LINE :
+ TextEditCommandX11::MOVE_TO_BEGINING_OF_LINE);
+ break;
+ case GTK_MOVEMENT_PARAGRAPH_ENDS:
+ command = (count > 0 ?
+ TextEditCommandX11::MOVE_TO_END_OF_PARAGRAPH :
+ TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH);
+ break;
+ case GTK_MOVEMENT_PAGES:
+ command = (count > 0 ? TextEditCommandX11::MOVE_PAGE_DOWN :
+ TextEditCommandX11::MOVE_PAGE_UP);
+ break;
+ case GTK_MOVEMENT_BUFFER_ENDS:
+ command = (count > 0 ? TextEditCommandX11::MOVE_TO_END_OF_DOCUMENT :
+ TextEditCommandX11::MOVE_TO_BEGINING_OF_PARAGRAPH);
+ break;
+ default:
+ // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have
+ // no corresponding editor commands.
+ return;
+ }
+
+ Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view);
+ if (count < 0)
+ count = -count;
+ for (; count > 0; --count)
+ owner->EditCommandMatched(command, std::string(), extend_selection);
+}
+
+void Gtk2KeyBindingsHandler::MoveViewport(
+ GtkTextView* text_view, GtkScrollStep step, gint count) {
+ // Not supported by webkit.
+}
+
+void Gtk2KeyBindingsHandler::PasteClipboard(GtkTextView* text_view) {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::PASTE, std::string(), false);
+}
+
+void Gtk2KeyBindingsHandler::SelectAll(GtkTextView* text_view,
+ gboolean select) {
+ if (select) {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::SELECT_ALL, std::string(), false);
+ } else {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::UNSELECT, std::string(), false);
+ }
+}
+
+void Gtk2KeyBindingsHandler::SetAnchor(GtkTextView* text_view) {
+ GetHandlerOwner(text_view)->EditCommandMatched(
+ TextEditCommandX11::SET_MARK, std::string(), false);
+}
+
+void Gtk2KeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) {
+ // Not supported by webkit.
+}
+
+void Gtk2KeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) {
+ // Not supported by webkit.
+}
+
+gboolean Gtk2KeyBindingsHandler::ShowHelp(GtkWidget* widget,
+ GtkWidgetHelpType arg1) {
+ // Just for disabling the default handler.
+ return FALSE;
+}
+
+void Gtk2KeyBindingsHandler::MoveFocus(GtkWidget* widget,
+ GtkDirectionType arg1) {
+ // Just for disabling the default handler.
+}
+
+} // namespace libgtk2ui
« no previous file with comments | « chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.h ('k') | chrome/browser/ui/libgtk2ui/gtk2_ui.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698