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#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_KEY_BINDINGS_HANDLER_H_
6#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_KEY_BINDINGS_HANDLER_H_
7
8#include <gtk/gtk.h>
9
10#include <string>
11#include <vector>
12
13#include "base/event_types.h"
14#include "chrome/browser/ui/libgtk2ui/owned_widget_gtk2.h"
15#include "ui/events/linux/text_edit_command_auralinux.h"
16
17namespace content {
18struct NativeWebKeyboardEvent;
19}
20
21namespace ui {
22class Event;
23}
24
25namespace libgtk2ui {
26
27// This class is a convenience class for handling editor key bindings defined
28// in gtk keyboard theme.
29// In gtk, only GtkEntry and GtkTextView support customizing editor key bindings
30// through keyboard theme. And in gtk keyboard theme definition file, each key
31// binding must be bound to a specific class or object. So existing keyboard
32// themes only define editor key bindings exactly for GtkEntry and GtkTextView.
33// Then, the only way for us to intercept editor key bindings defined in
34// keyboard theme, is to create a GtkEntry or GtkTextView object and call
35// gtk_bindings_activate_event() against it for the key events. If a key event
36// matches a predefined key binding, corresponding signal will be emitted.
37// GtkTextView is used here because it supports more key bindings than GtkEntry,
38// but in order to minimize the side effect of using a GtkTextView object, a new
39// class derived from GtkTextView is used, which overrides all signals related
40// to key bindings, to make sure GtkTextView won't receive them.
41//
42// See third_party/WebKit/Source/WebCore/editing/EditorCommand.cpp for detailed
43// definition of webkit edit commands.
44// See webkit/glue/editor_client_impl.cc for key bindings predefined in our
45// webkit glue.
46class Gtk2KeyBindingsHandler {
47 public:
48  Gtk2KeyBindingsHandler();
49  virtual ~Gtk2KeyBindingsHandler();
50
51  // Matches a key event against predefined gtk key bindings, false will be
52  // returned if the key event doesn't correspond to a predefined key binding.
53  // Edit commands matched with |event| will be stored in |edit_commands|, if
54  // non-NULL.
55  bool MatchEvent(const ui::Event& event,
56                  std::vector<ui::TextEditCommandAuraLinux>* commands);
57
58 private:
59  // Object structure of Handler class, which is derived from GtkTextView.
60  struct Handler {
61    GtkTextView parent_object;
62    Gtk2KeyBindingsHandler *owner;
63  };
64
65  // Class structure of Handler class.
66  struct HandlerClass {
67    GtkTextViewClass parent_class;
68  };
69
70  // Creates a new instance of Handler class.
71  GtkWidget* CreateNewHandler();
72
73  // Adds an edit command to the key event.
74  void EditCommandMatched(ui::TextEditCommandAuraLinux::CommandId id,
75                          const std::string& value,
76                          bool extend_selection);
77
78  // Builds a fake GdkEventKey from an XEvent.
79  void BuildGdkEventKeyFromXEvent(const base::NativeEvent& xevent,
80                                  GdkEventKey* gdk_event);
81
82  // Initializes Handler structure.
83  static void HandlerInit(Handler *self);
84
85  // Initializes HandlerClass structure.
86  static void HandlerClassInit(HandlerClass *klass);
87
88  // Registeres Handler class to GObject type system and return its type id.
89  static GType HandlerGetType();
90
91  // Gets the Gtk2KeyBindingsHandler object which owns the Handler object.
92  static Gtk2KeyBindingsHandler* GetHandlerOwner(GtkTextView* text_view);
93
94  // Handler of "backspace" signal.
95  static void BackSpace(GtkTextView* text_view);
96
97  // Handler of "copy-clipboard" signal.
98  static void CopyClipboard(GtkTextView* text_view);
99
100  // Handler of "cut-clipboard" signal.
101  static void CutClipboard(GtkTextView* text_view);
102
103  // Handler of "delete-from-cursor" signal.
104  static void DeleteFromCursor(GtkTextView* text_view, GtkDeleteType type,
105                               gint count);
106
107  // Handler of "insert-at-cursor" signal.
108  static void InsertAtCursor(GtkTextView* text_view, const gchar* str);
109
110  // Handler of "move-cursor" signal.
111  static void MoveCursor(GtkTextView* text_view, GtkMovementStep step,
112                         gint count, gboolean extend_selection);
113
114  // Handler of "move-viewport" signal.
115  static void MoveViewport(GtkTextView* text_view, GtkScrollStep step,
116                           gint count);
117
118  // Handler of "paste-clipboard" signal.
119  static void PasteClipboard(GtkTextView* text_view);
120
121  // Handler of "select-all" signal.
122  static void SelectAll(GtkTextView* text_view, gboolean select);
123
124  // Handler of "set-anchor" signal.
125  static void SetAnchor(GtkTextView* text_view);
126
127  // Handler of "toggle-cursor-visible" signal.
128  static void ToggleCursorVisible(GtkTextView* text_view);
129
130  // Handler of "toggle-overwrite" signal.
131  static void ToggleOverwrite(GtkTextView* text_view);
132
133  // Handler of "show-help" signal.
134  static gboolean ShowHelp(GtkWidget* widget, GtkWidgetHelpType arg1);
135
136  // Handler of "move-focus" signal.
137  static void MoveFocus(GtkWidget* widget, GtkDirectionType arg1);
138
139  GtkWidget* fake_window_;
140
141  libgtk2ui::OwnedWidgetGtk handler_;
142
143  // Buffer to store the match results.
144  std::vector<ui::TextEditCommandAuraLinux> edit_commands_;
145
146  // Whether the current X server has the XKeyboard extension.
147  bool has_xkb_;
148};
149
150}  // namespace libgtk2ui
151
152#endif  // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_KEY_BINDINGS_HANDLER_H_
153