OLD | NEW |
| (Empty) |
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 #include "content/browser/renderer_host/gtk_key_bindings_handler.h" | |
6 | |
7 #include <gdk/gdkkeysyms.h> | |
8 | |
9 #include <string> | |
10 | |
11 #include "base/logging.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "content/public/browser/native_web_keyboard_event.h" | |
14 | |
15 namespace content { | |
16 | |
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); | |
24 } | |
25 | |
26 GtkKeyBindingsHandler::~GtkKeyBindingsHandler() { | |
27 handler_.Destroy(); | |
28 } | |
29 | |
30 bool GtkKeyBindingsHandler::Match(const NativeWebKeyboardEvent& wke, | |
31 EditCommands* edit_commands) { | |
32 if (wke.type == blink::WebInputEvent::Char || !wke.os_event) | |
33 return false; | |
34 | |
35 edit_commands_.clear(); | |
36 // If this key event matches a predefined key binding, corresponding signal | |
37 // will be emitted. | |
38 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &wke.os_event->key); | |
39 | |
40 bool matched = !edit_commands_.empty(); | |
41 if (edit_commands) | |
42 edit_commands->swap(edit_commands_); | |
43 return matched; | |
44 } | |
45 | |
46 GtkWidget* GtkKeyBindingsHandler::CreateNewHandler() { | |
47 Handler* handler = | |
48 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); | |
49 | |
50 handler->owner = this; | |
51 | |
52 // We don't need to show the |handler| object on screen, so set its size to | |
53 // zero. | |
54 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); | |
55 | |
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); | |
60 | |
61 return GTK_WIDGET(handler); | |
62 } | |
63 | |
64 void GtkKeyBindingsHandler::EditCommandMatched( | |
65 const std::string& name, const std::string& value) { | |
66 edit_commands_.push_back(EditCommand(name, value)); | |
67 } | |
68 | |
69 void GtkKeyBindingsHandler::HandlerInit(Handler *self) { | |
70 self->owner = NULL; | |
71 } | |
72 | |
73 void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { | |
74 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); | |
75 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); | |
76 | |
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; | |
88 | |
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 | |
92 // handler. | |
93 g_signal_override_class_handler("move-focus", | |
94 G_TYPE_FROM_CLASS(klass), | |
95 G_CALLBACK(MoveFocus)); | |
96 | |
97 g_signal_override_class_handler("move-viewport", | |
98 G_TYPE_FROM_CLASS(klass), | |
99 G_CALLBACK(MoveViewport)); | |
100 | |
101 g_signal_override_class_handler("select-all", | |
102 G_TYPE_FROM_CLASS(klass), | |
103 G_CALLBACK(SelectAll)); | |
104 | |
105 g_signal_override_class_handler("toggle-cursor-visible", | |
106 G_TYPE_FROM_CLASS(klass), | |
107 G_CALLBACK(ToggleCursorVisible)); | |
108 } | |
109 | |
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( | |
114 GTK_TYPE_TEXT_VIEW, | |
115 g_intern_static_string("GtkKeyBindingsHandler"), | |
116 sizeof(HandlerClass), | |
117 reinterpret_cast<GClassInitFunc>(HandlerClassInit), | |
118 sizeof(Handler), | |
119 reinterpret_cast<GInstanceInitFunc>(HandlerInit), | |
120 static_cast<GTypeFlags>(0)); | |
121 g_once_init_leave(&type_id_volatile, type_id); | |
122 } | |
123 return type_id_volatile; | |
124 } | |
125 | |
126 GtkKeyBindingsHandler* GtkKeyBindingsHandler::GetHandlerOwner( | |
127 GtkTextView* text_view) { | |
128 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( | |
129 text_view, HandlerGetType(), Handler); | |
130 DCHECK(handler); | |
131 return handler->owner; | |
132 } | |
133 | |
134 void GtkKeyBindingsHandler::BackSpace(GtkTextView* text_view) { | |
135 GetHandlerOwner(text_view) | |
136 ->EditCommandMatched("DeleteBackward", std::string()); | |
137 } | |
138 | |
139 void GtkKeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { | |
140 GetHandlerOwner(text_view)->EditCommandMatched("Copy", std::string()); | |
141 } | |
142 | |
143 void GtkKeyBindingsHandler::CutClipboard(GtkTextView* text_view) { | |
144 GetHandlerOwner(text_view)->EditCommandMatched("Cut", std::string()); | |
145 } | |
146 | |
147 void GtkKeyBindingsHandler::DeleteFromCursor( | |
148 GtkTextView* text_view, GtkDeleteType type, gint count) { | |
149 if (!count) | |
150 return; | |
151 | |
152 const char *commands[3] = { NULL, NULL, NULL }; | |
153 switch (type) { | |
154 case GTK_DELETE_CHARS: | |
155 commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); | |
156 break; | |
157 case GTK_DELETE_WORD_ENDS: | |
158 commands[0] = (count > 0 ? "DeleteWordForward" : "DeleteWordBackward"); | |
159 break; | |
160 case GTK_DELETE_WORDS: | |
161 if (count > 0) { | |
162 commands[0] = "MoveWordForward"; | |
163 commands[1] = "DeleteWordBackward"; | |
164 } else { | |
165 commands[0] = "MoveWordBackward"; | |
166 commands[1] = "DeleteWordForward"; | |
167 } | |
168 break; | |
169 case GTK_DELETE_DISPLAY_LINES: | |
170 commands[0] = "MoveToBeginningOfLine"; | |
171 commands[1] = "DeleteToEndOfLine"; | |
172 break; | |
173 case GTK_DELETE_DISPLAY_LINE_ENDS: | |
174 commands[0] = (count > 0 ? "DeleteToEndOfLine" : | |
175 "DeleteToBeginningOfLine"); | |
176 break; | |
177 case GTK_DELETE_PARAGRAPH_ENDS: | |
178 commands[0] = (count > 0 ? "DeleteToEndOfParagraph" : | |
179 "DeleteToBeginningOfParagraph"); | |
180 break; | |
181 case GTK_DELETE_PARAGRAPHS: | |
182 commands[0] = "MoveToBeginningOfParagraph"; | |
183 commands[1] = "DeleteToEndOfParagraph"; | |
184 break; | |
185 default: | |
186 // GTK_DELETE_WHITESPACE has no corresponding editor command. | |
187 return; | |
188 } | |
189 | |
190 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | |
191 if (count < 0) | |
192 count = -count; | |
193 for (; count > 0; --count) { | |
194 for (const char* const* p = commands; *p; ++p) | |
195 owner->EditCommandMatched(*p, std::string()); | |
196 } | |
197 } | |
198 | |
199 void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, | |
200 const gchar* str) { | |
201 if (str && *str) | |
202 GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); | |
203 } | |
204 | |
205 void GtkKeyBindingsHandler::MoveCursor( | |
206 GtkTextView* text_view, GtkMovementStep step, gint count, | |
207 gboolean extend_selection) { | |
208 if (!count) | |
209 return; | |
210 | |
211 std::string command; | |
212 switch (step) { | |
213 case GTK_MOVEMENT_LOGICAL_POSITIONS: | |
214 command = (count > 0 ? "MoveForward" : "MoveBackward"); | |
215 break; | |
216 case GTK_MOVEMENT_VISUAL_POSITIONS: | |
217 command = (count > 0 ? "MoveRight" : "MoveLeft"); | |
218 break; | |
219 case GTK_MOVEMENT_WORDS: | |
220 command = (count > 0 ? "MoveWordRight" : "MoveWordLeft"); | |
221 break; | |
222 case GTK_MOVEMENT_DISPLAY_LINES: | |
223 command = (count > 0 ? "MoveDown" : "MoveUp"); | |
224 break; | |
225 case GTK_MOVEMENT_DISPLAY_LINE_ENDS: | |
226 command = (count > 0 ? "MoveToEndOfLine" : "MoveToBeginningOfLine"); | |
227 break; | |
228 case GTK_MOVEMENT_PARAGRAPH_ENDS: | |
229 command = (count > 0 ? "MoveToEndOfParagraph" : | |
230 "MoveToBeginningOfParagraph"); | |
231 break; | |
232 case GTK_MOVEMENT_PAGES: | |
233 command = (count > 0 ? "MovePageDown" : "MovePageUp"); | |
234 break; | |
235 case GTK_MOVEMENT_BUFFER_ENDS: | |
236 command = (count > 0 ? "MoveToEndOfDocument" : | |
237 "MoveToBeginningOfDocument"); | |
238 break; | |
239 default: | |
240 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have | |
241 // no corresponding editor commands. | |
242 return; | |
243 } | |
244 | |
245 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | |
246 if (extend_selection) | |
247 command.append("AndModifySelection"); | |
248 if (count < 0) | |
249 count = -count; | |
250 for (; count > 0; --count) | |
251 owner->EditCommandMatched(command, std::string()); | |
252 } | |
253 | |
254 void GtkKeyBindingsHandler::MoveViewport( | |
255 GtkTextView* text_view, GtkScrollStep step, gint count) { | |
256 // Not supported by webkit. | |
257 } | |
258 | |
259 void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { | |
260 GetHandlerOwner(text_view)->EditCommandMatched("Paste", std::string()); | |
261 } | |
262 | |
263 void GtkKeyBindingsHandler::SelectAll(GtkTextView* text_view, gboolean select) { | |
264 if (select) | |
265 GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", std::string()); | |
266 else | |
267 GetHandlerOwner(text_view)->EditCommandMatched("Unselect", std::string()); | |
268 } | |
269 | |
270 void GtkKeyBindingsHandler::SetAnchor(GtkTextView* text_view) { | |
271 GetHandlerOwner(text_view)->EditCommandMatched("SetMark", std::string()); | |
272 } | |
273 | |
274 void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { | |
275 // Not supported by webkit. | |
276 } | |
277 | |
278 void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { | |
279 // Not supported by webkit. | |
280 } | |
281 | |
282 gboolean GtkKeyBindingsHandler::ShowHelp(GtkWidget* widget, | |
283 GtkWidgetHelpType arg1) { | |
284 // Just for disabling the default handler. | |
285 return FALSE; | |
286 } | |
287 | |
288 void GtkKeyBindingsHandler::MoveFocus(GtkWidget* widget, | |
289 GtkDirectionType arg1) { | |
290 // Just for disabling the default handler. | |
291 } | |
292 | |
293 } // namespace content | |
OLD | NEW |