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

Side by Side Diff: chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.cc

Issue 1068093002: Refactoring for InputMethodAuraLinux. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: addressed nona's comments. Created 5 years, 8 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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h" 5 #include "chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h"
6 6
7 #include <gdk/gdk.h> 7 #include <gdk/gdk.h>
8 #include <gdk/gdkkeysyms.h> 8 #include <gdk/gdkkeysyms.h>
9 #include <gdk/gdkx.h> 9 #include <gdk/gdkx.h>
10 10
11 #include <gtk/gtk.h> 11 #include <gtk/gtk.h>
12 12
13 #include <X11/X.h> 13 #include <X11/X.h>
14 #include <X11/Xlib.h> 14 #include <X11/Xlib.h>
15 15
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "ui/base/ime/composition_text.h" 18 #include "ui/base/ime/composition_text.h"
19 #include "ui/base/ime/composition_text_util_pango.h" 19 #include "ui/base/ime/composition_text_util_pango.h"
20 #include "ui/base/ime/text_input_client.h" 20 #include "ui/base/ime/text_input_client.h"
21 #include "ui/events/event.h" 21 #include "ui/events/event.h"
22 #include "ui/events/keycodes/keyboard_code_conversion_x.h" 22 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
23 #include "ui/gfx/x/x11_types.h" 23 #include "ui/gfx/x/x11_types.h"
24 24
25 namespace libgtk2ui { 25 namespace libgtk2ui {
26 26
27 X11InputMethodContextImplGtk2::X11InputMethodContextImplGtk2( 27 X11InputMethodContextImplGtk2::X11InputMethodContextImplGtk2(
28 ui::LinuxInputMethodContextDelegate* delegate) 28 ui::LinuxInputMethodContextDelegate* delegate, bool is_simple)
29 : delegate_(delegate), 29 : delegate_(delegate), gtk_context_(NULL),
30 gtk_context_simple_(NULL),
31 gtk_multicontext_(NULL),
32 gtk_context_(NULL),
33 gdk_last_set_client_window_(NULL) { 30 gdk_last_set_client_window_(NULL) {
34 CHECK(delegate_); 31 CHECK(delegate_);
35 32
36 ResetXModifierKeycodesCache(); 33 ResetXModifierKeycodesCache();
37 34
38 gtk_context_simple_ = gtk_im_context_simple_new(); 35 if (is_simple)
39 gtk_multicontext_ = gtk_im_multicontext_new(); 36 gtk_context_ = gtk_im_context_simple_new();
37 else
38 gtk_context_ = gtk_im_multicontext_new();
40 39
41 GtkIMContext* contexts[] = {gtk_context_simple_, gtk_multicontext_}; 40 g_signal_connect(gtk_context_, "commit",
42 for (size_t i = 0; i < arraysize(contexts); ++i) { 41 G_CALLBACK(OnCommitThunk), this);
43 g_signal_connect(contexts[i], "commit", 42 g_signal_connect(gtk_context_, "preedit-changed",
44 G_CALLBACK(OnCommitThunk), this); 43 G_CALLBACK(OnPreeditChangedThunk), this);
45 g_signal_connect(contexts[i], "preedit-changed", 44 g_signal_connect(gtk_context_, "preedit-end",
46 G_CALLBACK(OnPreeditChangedThunk), this); 45 G_CALLBACK(OnPreeditEndThunk), this);
47 g_signal_connect(contexts[i], "preedit-end", 46 g_signal_connect(gtk_context_, "preedit-start",
48 G_CALLBACK(OnPreeditEndThunk), this); 47 G_CALLBACK(OnPreeditStartThunk), this);
49 g_signal_connect(contexts[i], "preedit-start", 48 // TODO(yukishiino): Handle operations on surrounding text.
50 G_CALLBACK(OnPreeditStartThunk), this); 49 // "delete-surrounding" and "retrieve-surrounding" signals should be
51 // TODO(yukishiino): Handle operations on surrounding text. 50 // handled.
52 // "delete-surrounding" and "retrieve-surrounding" signals should be 51 }
53 // handled. 52
53 X11InputMethodContextImplGtk2::~X11InputMethodContextImplGtk2() {
54 if (gtk_context_) {
55 g_object_unref(gtk_context_);
56 gtk_context_ = NULL;
54 } 57 }
55 } 58 }
56 59
57 X11InputMethodContextImplGtk2::~X11InputMethodContextImplGtk2() {
58 gtk_context_ = NULL;
59 if (gtk_context_simple_) {
60 g_object_unref(gtk_context_simple_);
61 gtk_context_simple_ = NULL;
62 }
63 if (gtk_multicontext_) {
64 g_object_unref(gtk_multicontext_);
65 gtk_multicontext_ = NULL;
66 }
67 }
68
69 // Overriden from ui::LinuxInputMethodContext 60 // Overriden from ui::LinuxInputMethodContext
70 61
71 bool X11InputMethodContextImplGtk2::DispatchKeyEvent( 62 bool X11InputMethodContextImplGtk2::DispatchKeyEvent(
72 const ui::KeyEvent& key_event) { 63 const ui::KeyEvent& key_event) {
73 if (!key_event.HasNativeEvent()) 64 if (!key_event.HasNativeEvent() || !gtk_context_)
74 return false;
75
76 // The caller must call Focus() first.
77 if (!gtk_context_)
78 return false; 65 return false;
79 66
80 // Translate a XKeyEvent to a GdkEventKey. 67 // Translate a XKeyEvent to a GdkEventKey.
81 GdkEvent* event = GdkEventFromNativeEvent(key_event.native_event()); 68 GdkEvent* event = GdkEventFromNativeEvent(key_event.native_event());
82 if (!event) { 69 if (!event) {
83 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent."; 70 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent.";
84 return false; 71 return false;
85 } 72 }
86 73
87 // Set the client window and cursor location.
88 if (event->key.window != gdk_last_set_client_window_) { 74 if (event->key.window != gdk_last_set_client_window_) {
89 gtk_im_context_set_client_window(gtk_context_, event->key.window); 75 gtk_im_context_set_client_window(gtk_context_, event->key.window);
90 gdk_last_set_client_window_ = event->key.window; 76 gdk_last_set_client_window_ = event->key.window;
91 } 77 }
78
92 // Convert the last known caret bounds relative to the screen coordinates 79 // Convert the last known caret bounds relative to the screen coordinates
93 // to a GdkRectangle relative to the client window. 80 // to a GdkRectangle relative to the client window.
94 gint x = 0; 81 gint x = 0;
95 gint y = 0; 82 gint y = 0;
96 gdk_window_get_origin(event->key.window, &x, &y); 83 gdk_window_get_origin(event->key.window, &x, &y);
97 GdkRectangle rect = {last_caret_bounds_.x() - x, 84 GdkRectangle rect = {last_caret_bounds_.x() - x,
98 last_caret_bounds_.y() - y, 85 last_caret_bounds_.y() - y,
99 last_caret_bounds_.width(), 86 last_caret_bounds_.width(),
100 last_caret_bounds_.height()}; 87 last_caret_bounds_.height()};
101 gtk_im_context_set_cursor_location(gtk_context_, &rect); 88 gtk_im_context_set_cursor_location(gtk_context_, &rect);
102 89
103 // Let an IME handle the key event. 90 const bool handled = gtk_im_context_filter_keypress(gtk_context_,
104 commit_signal_trap_.StartTrap(event->key.keyval); 91 &event->key);
105 const gboolean handled = gtk_im_context_filter_keypress(gtk_context_,
106 &event->key);
107 commit_signal_trap_.StopTrap();
108 gdk_event_free(event); 92 gdk_event_free(event);
109 93 return handled;
110 return handled && !commit_signal_trap_.IsSignalCaught();
111 } 94 }
112 95
113 void X11InputMethodContextImplGtk2::Reset() { 96 void X11InputMethodContextImplGtk2::Reset() {
114 // Reset all the states of the context, not only preedit, caret but also 97 gtk_im_context_reset(gtk_context_);
115 // focus.
116 gtk_context_ = NULL;
117 gtk_im_context_reset(gtk_context_simple_);
118 gtk_im_context_reset(gtk_multicontext_);
119 gtk_im_context_focus_out(gtk_context_simple_);
120 gtk_im_context_focus_out(gtk_multicontext_);
121 gdk_last_set_client_window_ = NULL;
122 } 98 }
123 99
124 void X11InputMethodContextImplGtk2::OnTextInputTypeChanged( 100 void X11InputMethodContextImplGtk2::Focus() {
125 ui::TextInputType text_input_type) {
126 switch (text_input_type) {
127 case ui::TEXT_INPUT_TYPE_NONE:
128 case ui::TEXT_INPUT_TYPE_PASSWORD:
129 gtk_context_ = gtk_context_simple_;
130 break;
131 default:
132 gtk_context_ = gtk_multicontext_;
133 }
134 gtk_im_context_focus_in(gtk_context_); 101 gtk_im_context_focus_in(gtk_context_);
135 } 102 }
136 103
137 void X11InputMethodContextImplGtk2::OnCaretBoundsChanged( 104 void X11InputMethodContextImplGtk2::Blur() {
138 const gfx::Rect& caret_bounds) { 105 gtk_im_context_focus_out(gtk_context_);
106 }
107
108 void X11InputMethodContextImplGtk2::SetCursorLocation(const gfx::Rect& rect) {
139 // Remember the caret bounds so that we can set the cursor location later. 109 // Remember the caret bounds so that we can set the cursor location later.
140 // gtk_im_context_set_cursor_location() takes the location relative to the 110 // gtk_im_context_set_cursor_location() takes the location relative to the
141 // client window, which is unknown at this point. So we'll call 111 // client window, which is unknown at this point. So we'll call
142 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where 112 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where
143 // (and only where) we know the client window. 113 // (and only where) we know the client window.
144 last_caret_bounds_ = caret_bounds; 114 last_caret_bounds_ = rect;
145 } 115 }
146 116
147 // private: 117 // private:
148 118
149 void X11InputMethodContextImplGtk2::ResetXModifierKeycodesCache() { 119 void X11InputMethodContextImplGtk2::ResetXModifierKeycodesCache() {
150 modifier_keycodes_.clear(); 120 modifier_keycodes_.clear();
151 meta_keycodes_.clear(); 121 meta_keycodes_.clear();
152 super_keycodes_.clear(); 122 super_keycodes_.clear();
153 hyper_keycodes_.clear(); 123 hyper_keycodes_.clear();
154 124
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 return false; 272 return false;
303 } 273 }
304 274
305 // GtkIMContext event handlers. 275 // GtkIMContext event handlers.
306 276
307 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context, 277 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context,
308 gchar* text) { 278 gchar* text) {
309 if (context != gtk_context_) 279 if (context != gtk_context_)
310 return; 280 return;
311 281
312 const base::string16& text_in_utf16 = base::UTF8ToUTF16(text); 282 delegate_->OnCommit(base::UTF8ToUTF16(text));
313 // If an underlying IME is emitting the "commit" signal to insert a character
314 // for a direct input key event, ignores the insertion of the character at
315 // this point, because we have to call DispatchKeyEventPostIME() for direct
316 // input key events. DispatchKeyEvent() takes care of the trapped character
317 // and calls DispatchKeyEventPostIME().
318 if (commit_signal_trap_.Trap(text_in_utf16))
319 return;
320
321 delegate_->OnCommit(text_in_utf16);
322 } 283 }
323 284
324 void X11InputMethodContextImplGtk2::OnPreeditChanged(GtkIMContext* context) { 285 void X11InputMethodContextImplGtk2::OnPreeditChanged(GtkIMContext* context) {
325 if (context != gtk_context_) 286 if (context != gtk_context_)
326 return; 287 return;
327 288
328 gchar* str = NULL; 289 gchar* str = NULL;
329 PangoAttrList* attrs = NULL; 290 PangoAttrList* attrs = NULL;
330 gint cursor_pos = 0; 291 gint cursor_pos = 0;
331 gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos); 292 gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos);
(...skipping 13 matching lines...) Expand all
345 delegate_->OnPreeditEnd(); 306 delegate_->OnPreeditEnd();
346 } 307 }
347 308
348 void X11InputMethodContextImplGtk2::OnPreeditStart(GtkIMContext* context) { 309 void X11InputMethodContextImplGtk2::OnPreeditStart(GtkIMContext* context) {
349 if (context != gtk_context_) 310 if (context != gtk_context_)
350 return; 311 return;
351 312
352 delegate_->OnPreeditStart(); 313 delegate_->OnPreeditStart();
353 } 314 }
354 315
355 // GtkCommitSignalTrap
356
357 X11InputMethodContextImplGtk2::GtkCommitSignalTrap::GtkCommitSignalTrap()
358 : is_trap_enabled_(false),
359 #if GTK_CHECK_VERSION (2,22,0)
360 gdk_event_key_keyval_(GDK_KEY_VoidSymbol),
361 #else
362 gdk_event_key_keyval_(GDK_VoidSymbol),
363 #endif
364 is_signal_caught_(false) {}
365
366 void X11InputMethodContextImplGtk2::GtkCommitSignalTrap::StartTrap(
367 guint keyval) {
368 is_signal_caught_ = false;
369 gdk_event_key_keyval_ = keyval;
370 is_trap_enabled_ = true;
371 }
372
373 void X11InputMethodContextImplGtk2::GtkCommitSignalTrap::StopTrap() {
374 is_trap_enabled_ = false;
375 }
376
377 bool X11InputMethodContextImplGtk2::GtkCommitSignalTrap::Trap(
378 const base::string16& text) {
379 DCHECK(!is_signal_caught_);
380 if (is_trap_enabled_ &&
381 text.length() == 1 &&
382 text[0] == gdk_keyval_to_unicode(gdk_event_key_keyval_)) {
383 is_signal_caught_ = true;
384 return true;
385 } else {
386 return false;
387 }
388 }
389
390 } // namespace libgtk2ui 316 } // namespace libgtk2ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698