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.
5 #include "content/browser/renderer_host/gtk_key_bindings_handler.h"
7 #include <gdk/gdkkeysyms.h>
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "content/public/browser/native_web_keyboard_event.h"
17 GtkKeyBindingsHandler::GtkKeyBindingsHandler(GtkWidget
* parent_widget
)
18 : handler_(CreateNewHandler()) {
19 DCHECK(GTK_IS_FIXED(parent_widget
));
20 // We need add the |handler_| object into gtk widget hierarchy, so that
21 // gtk_bindings_activate_event() can find correct display and keymaps from
22 // the |handler_| object.
23 gtk_fixed_put(GTK_FIXED(parent_widget
), handler_
.get(), -1, -1);
26 GtkKeyBindingsHandler::~GtkKeyBindingsHandler() {
30 bool GtkKeyBindingsHandler::Match(const NativeWebKeyboardEvent
& wke
,
31 EditCommands
* edit_commands
) {
32 if (wke
.type
== blink::WebInputEvent::Char
|| !wke
.os_event
)
35 edit_commands_
.clear();
36 // If this key event matches a predefined key binding, corresponding signal
38 gtk_bindings_activate_event(GTK_OBJECT(handler_
.get()), &wke
.os_event
->key
);
40 bool matched
= !edit_commands_
.empty();
42 edit_commands
->swap(edit_commands_
);
46 GtkWidget
* GtkKeyBindingsHandler::CreateNewHandler() {
48 static_cast<Handler
*>(g_object_new(HandlerGetType(), NULL
));
50 handler
->owner
= this;
52 // We don't need to show the |handler| object on screen, so set its size to
54 gtk_widget_set_size_request(GTK_WIDGET(handler
), 0, 0);
56 // Prevents it from handling any events by itself.
57 gtk_widget_set_sensitive(GTK_WIDGET(handler
), FALSE
);
58 gtk_widget_set_events(GTK_WIDGET(handler
), 0);
59 gtk_widget_set_can_focus(GTK_WIDGET(handler
), TRUE
);
61 return GTK_WIDGET(handler
);
64 void GtkKeyBindingsHandler::EditCommandMatched(
65 const std::string
& name
, const std::string
& value
) {
66 edit_commands_
.push_back(EditCommand(name
, value
));
69 void GtkKeyBindingsHandler::HandlerInit(Handler
*self
) {
73 void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass
*klass
) {
74 GtkTextViewClass
* text_view_class
= GTK_TEXT_VIEW_CLASS(klass
);
75 GtkWidgetClass
* widget_class
= GTK_WIDGET_CLASS(klass
);
77 // Overrides all virtual methods related to editor key bindings.
78 text_view_class
->backspace
= BackSpace
;
79 text_view_class
->copy_clipboard
= CopyClipboard
;
80 text_view_class
->cut_clipboard
= CutClipboard
;
81 text_view_class
->delete_from_cursor
= DeleteFromCursor
;
82 text_view_class
->insert_at_cursor
= InsertAtCursor
;
83 text_view_class
->move_cursor
= MoveCursor
;
84 text_view_class
->paste_clipboard
= PasteClipboard
;
85 text_view_class
->set_anchor
= SetAnchor
;
86 text_view_class
->toggle_overwrite
= ToggleOverwrite
;
87 widget_class
->show_help
= ShowHelp
;
89 // "move-focus", "move-viewport", "select-all" and "toggle-cursor-visible"
90 // have no corresponding virtual methods. Since glib 2.18 (gtk 2.14),
91 // g_signal_override_class_handler() is introduced to override a signal
93 g_signal_override_class_handler("move-focus",
94 G_TYPE_FROM_CLASS(klass
),
95 G_CALLBACK(MoveFocus
));
97 g_signal_override_class_handler("move-viewport",
98 G_TYPE_FROM_CLASS(klass
),
99 G_CALLBACK(MoveViewport
));
101 g_signal_override_class_handler("select-all",
102 G_TYPE_FROM_CLASS(klass
),
103 G_CALLBACK(SelectAll
));
105 g_signal_override_class_handler("toggle-cursor-visible",
106 G_TYPE_FROM_CLASS(klass
),
107 G_CALLBACK(ToggleCursorVisible
));
110 GType
GtkKeyBindingsHandler::HandlerGetType() {
111 static volatile gsize type_id_volatile
= 0;
112 if (g_once_init_enter(&type_id_volatile
)) {
113 GType type_id
= g_type_register_static_simple(
115 g_intern_static_string("GtkKeyBindingsHandler"),
116 sizeof(HandlerClass
),
117 reinterpret_cast<GClassInitFunc
>(HandlerClassInit
),
119 reinterpret_cast<GInstanceInitFunc
>(HandlerInit
),
120 static_cast<GTypeFlags
>(0));
121 g_once_init_leave(&type_id_volatile
, type_id
);
123 return type_id_volatile
;
126 GtkKeyBindingsHandler
* GtkKeyBindingsHandler::GetHandlerOwner(
127 GtkTextView
* text_view
) {
128 Handler
* handler
= G_TYPE_CHECK_INSTANCE_CAST(
129 text_view
, HandlerGetType(), Handler
);
131 return handler
->owner
;
134 void GtkKeyBindingsHandler::BackSpace(GtkTextView
* text_view
) {
135 GetHandlerOwner(text_view
)
136 ->EditCommandMatched("DeleteBackward", std::string());
139 void GtkKeyBindingsHandler::CopyClipboard(GtkTextView
* text_view
) {
140 GetHandlerOwner(text_view
)->EditCommandMatched("Copy", std::string());
143 void GtkKeyBindingsHandler::CutClipboard(GtkTextView
* text_view
) {
144 GetHandlerOwner(text_view
)->EditCommandMatched("Cut", std::string());
147 void GtkKeyBindingsHandler::DeleteFromCursor(
148 GtkTextView
* text_view
, GtkDeleteType type
, gint count
) {
152 const char *commands
[3] = { NULL
, NULL
, NULL
};
154 case GTK_DELETE_CHARS
:
155 commands
[0] = (count
> 0 ? "DeleteForward" : "DeleteBackward");
157 case GTK_DELETE_WORD_ENDS
:
158 commands
[0] = (count
> 0 ? "DeleteWordForward" : "DeleteWordBackward");
160 case GTK_DELETE_WORDS
:
162 commands
[0] = "MoveWordForward";
163 commands
[1] = "DeleteWordBackward";
165 commands
[0] = "MoveWordBackward";
166 commands
[1] = "DeleteWordForward";
169 case GTK_DELETE_DISPLAY_LINES
:
170 commands
[0] = "MoveToBeginningOfLine";
171 commands
[1] = "DeleteToEndOfLine";
173 case GTK_DELETE_DISPLAY_LINE_ENDS
:
174 commands
[0] = (count
> 0 ? "DeleteToEndOfLine" :
175 "DeleteToBeginningOfLine");
177 case GTK_DELETE_PARAGRAPH_ENDS
:
178 commands
[0] = (count
> 0 ? "DeleteToEndOfParagraph" :
179 "DeleteToBeginningOfParagraph");
181 case GTK_DELETE_PARAGRAPHS
:
182 commands
[0] = "MoveToBeginningOfParagraph";
183 commands
[1] = "DeleteToEndOfParagraph";
186 // GTK_DELETE_WHITESPACE has no corresponding editor command.
190 GtkKeyBindingsHandler
* owner
= GetHandlerOwner(text_view
);
193 for (; count
> 0; --count
) {
194 for (const char* const* p
= commands
; *p
; ++p
)
195 owner
->EditCommandMatched(*p
, std::string());
199 void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView
* text_view
,
202 GetHandlerOwner(text_view
)->EditCommandMatched("InsertText", str
);
205 void GtkKeyBindingsHandler::MoveCursor(
206 GtkTextView
* text_view
, GtkMovementStep step
, gint count
,
207 gboolean extend_selection
) {
213 case GTK_MOVEMENT_LOGICAL_POSITIONS
:
214 command
= (count
> 0 ? "MoveForward" : "MoveBackward");
216 case GTK_MOVEMENT_VISUAL_POSITIONS
:
217 command
= (count
> 0 ? "MoveRight" : "MoveLeft");
219 case GTK_MOVEMENT_WORDS
:
220 command
= (count
> 0 ? "MoveWordRight" : "MoveWordLeft");
222 case GTK_MOVEMENT_DISPLAY_LINES
:
223 command
= (count
> 0 ? "MoveDown" : "MoveUp");
225 case GTK_MOVEMENT_DISPLAY_LINE_ENDS
:
226 command
= (count
> 0 ? "MoveToEndOfLine" : "MoveToBeginningOfLine");
228 case GTK_MOVEMENT_PARAGRAPH_ENDS
:
229 command
= (count
> 0 ? "MoveToEndOfParagraph" :
230 "MoveToBeginningOfParagraph");
232 case GTK_MOVEMENT_PAGES
:
233 command
= (count
> 0 ? "MovePageDown" : "MovePageUp");
235 case GTK_MOVEMENT_BUFFER_ENDS
:
236 command
= (count
> 0 ? "MoveToEndOfDocument" :
237 "MoveToBeginningOfDocument");
240 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have
241 // no corresponding editor commands.
245 GtkKeyBindingsHandler
* owner
= GetHandlerOwner(text_view
);
246 if (extend_selection
)
247 command
.append("AndModifySelection");
250 for (; count
> 0; --count
)
251 owner
->EditCommandMatched(command
, std::string());
254 void GtkKeyBindingsHandler::MoveViewport(
255 GtkTextView
* text_view
, GtkScrollStep step
, gint count
) {
256 // Not supported by webkit.
259 void GtkKeyBindingsHandler::PasteClipboard(GtkTextView
* text_view
) {
260 GetHandlerOwner(text_view
)->EditCommandMatched("Paste", std::string());
263 void GtkKeyBindingsHandler::SelectAll(GtkTextView
* text_view
, gboolean select
) {
265 GetHandlerOwner(text_view
)->EditCommandMatched("SelectAll", std::string());
267 GetHandlerOwner(text_view
)->EditCommandMatched("Unselect", std::string());
270 void GtkKeyBindingsHandler::SetAnchor(GtkTextView
* text_view
) {
271 GetHandlerOwner(text_view
)->EditCommandMatched("SetMark", std::string());
274 void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView
* text_view
) {
275 // Not supported by webkit.
278 void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView
* text_view
) {
279 // Not supported by webkit.
282 gboolean
GtkKeyBindingsHandler::ShowHelp(GtkWidget
* widget
,
283 GtkWidgetHelpType arg1
) {
284 // Just for disabling the default handler.
288 void GtkKeyBindingsHandler::MoveFocus(GtkWidget
* widget
,
289 GtkDirectionType arg1
) {
290 // Just for disabling the default handler.
293 } // namespace content