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

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: Removes unexpected 229 keydown for non-IME users. 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,
29 bool is_simple)
29 : delegate_(delegate), 30 : delegate_(delegate),
30 gtk_context_simple_(NULL),
31 gtk_multicontext_(NULL),
32 gtk_context_(NULL), 31 gtk_context_(NULL),
33 gdk_last_set_client_window_(NULL) { 32 gdk_last_set_client_window_(NULL) {
34 CHECK(delegate_); 33 CHECK(delegate_);
35 34
36 ResetXModifierKeycodesCache(); 35 ResetXModifierKeycodesCache();
37 36
38 gtk_context_simple_ = gtk_im_context_simple_new(); 37 if (is_simple)
39 gtk_multicontext_ = gtk_im_multicontext_new(); 38 gtk_context_ = gtk_im_context_simple_new();
39 else
40 gtk_context_ = gtk_im_multicontext_new();
James Su 2015/04/09 08:40:02 nit: gtk_context_ = is_simple ? gtk_im_context_sim
Shu Chen 2015/04/10 05:26:52 Done.
40 41
41 GtkIMContext* contexts[] = {gtk_context_simple_, gtk_multicontext_}; 42 g_signal_connect(gtk_context_, "commit", G_CALLBACK(OnCommitThunk), this);
42 for (size_t i = 0; i < arraysize(contexts); ++i) { 43 g_signal_connect(gtk_context_, "preedit-changed",
43 g_signal_connect(contexts[i], "commit", 44 G_CALLBACK(OnPreeditChangedThunk), this);
44 G_CALLBACK(OnCommitThunk), this); 45 g_signal_connect(gtk_context_, "preedit-end", G_CALLBACK(OnPreeditEndThunk),
45 g_signal_connect(contexts[i], "preedit-changed", 46 this);
46 G_CALLBACK(OnPreeditChangedThunk), this); 47 g_signal_connect(gtk_context_, "preedit-start",
47 g_signal_connect(contexts[i], "preedit-end", 48 G_CALLBACK(OnPreeditStartThunk), this);
48 G_CALLBACK(OnPreeditEndThunk), this); 49 // TODO(yukishiino): Handle operations on surrounding text.
James Su 2015/04/09 08:40:02 change this to TODO(shuchen) ?
Shu Chen 2015/04/10 05:26:52 Done.
49 g_signal_connect(contexts[i], "preedit-start", 50 // "delete-surrounding" and "retrieve-surrounding" signals should be
50 G_CALLBACK(OnPreeditStartThunk), this); 51 // handled.
51 // TODO(yukishiino): Handle operations on surrounding text. 52 }
52 // "delete-surrounding" and "retrieve-surrounding" signals should be 53
53 // handled. 54 X11InputMethodContextImplGtk2::~X11InputMethodContextImplGtk2() {
55 if (gtk_context_) {
56 g_object_unref(gtk_context_);
57 gtk_context_ = NULL;
54 } 58 }
55 } 59 }
56 60
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 61 // Overriden from ui::LinuxInputMethodContext
70 62
71 bool X11InputMethodContextImplGtk2::DispatchKeyEvent( 63 bool X11InputMethodContextImplGtk2::DispatchKeyEvent(
72 const ui::KeyEvent& key_event) { 64 const ui::KeyEvent& key_event) {
73 if (!key_event.HasNativeEvent()) 65 if (!key_event.HasNativeEvent() || !gtk_context_)
74 return false;
75
76 // The caller must call Focus() first.
77 if (!gtk_context_)
78 return false; 66 return false;
79 67
80 // Translate a XKeyEvent to a GdkEventKey. 68 // Translate a XKeyEvent to a GdkEventKey.
81 GdkEvent* event = GdkEventFromNativeEvent(key_event.native_event()); 69 GdkEvent* event = GdkEventFromNativeEvent(key_event.native_event());
82 if (!event) { 70 if (!event) {
83 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent."; 71 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent.";
84 return false; 72 return false;
85 } 73 }
86 74
87 // Set the client window and cursor location.
88 if (event->key.window != gdk_last_set_client_window_) { 75 if (event->key.window != gdk_last_set_client_window_) {
89 gtk_im_context_set_client_window(gtk_context_, event->key.window); 76 gtk_im_context_set_client_window(gtk_context_, event->key.window);
90 gdk_last_set_client_window_ = event->key.window; 77 gdk_last_set_client_window_ = event->key.window;
91 } 78 }
79
92 // Convert the last known caret bounds relative to the screen coordinates 80 // Convert the last known caret bounds relative to the screen coordinates
93 // to a GdkRectangle relative to the client window. 81 // to a GdkRectangle relative to the client window.
94 gint x = 0; 82 gint x = 0;
95 gint y = 0; 83 gint y = 0;
96 gdk_window_get_origin(event->key.window, &x, &y); 84 gdk_window_get_origin(event->key.window, &x, &y);
97 GdkRectangle rect = {last_caret_bounds_.x() - x, 85 GdkRectangle rect = {last_caret_bounds_.x() - x,
98 last_caret_bounds_.y() - y, 86 last_caret_bounds_.y() - y,
99 last_caret_bounds_.width(), 87 last_caret_bounds_.width(),
100 last_caret_bounds_.height()}; 88 last_caret_bounds_.height()};
101 gtk_im_context_set_cursor_location(gtk_context_, &rect); 89 gtk_im_context_set_cursor_location(gtk_context_, &rect);
102 90
103 // Let an IME handle the key event. 91 const bool handled =
104 commit_signal_trap_.StartTrap(event->key.keyval); 92 gtk_im_context_filter_keypress(gtk_context_, &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); 93 gdk_event_free(event);
109 94 return handled;
110 return handled && !commit_signal_trap_.IsSignalCaught();
111 } 95 }
112 96
113 void X11InputMethodContextImplGtk2::Reset() { 97 void X11InputMethodContextImplGtk2::Reset() {
114 // Reset all the states of the context, not only preedit, caret but also 98 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 } 99 }
123 100
124 void X11InputMethodContextImplGtk2::OnTextInputTypeChanged( 101 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_); 102 gtk_im_context_focus_in(gtk_context_);
135 } 103 }
136 104
137 void X11InputMethodContextImplGtk2::OnCaretBoundsChanged( 105 void X11InputMethodContextImplGtk2::Blur() {
138 const gfx::Rect& caret_bounds) { 106 gtk_im_context_focus_out(gtk_context_);
107 }
108
109 void X11InputMethodContextImplGtk2::SetCursorLocation(const gfx::Rect& rect) {
139 // Remember the caret bounds so that we can set the cursor location later. 110 // 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 111 // 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 112 // client window, which is unknown at this point. So we'll call
142 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where 113 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where
143 // (and only where) we know the client window. 114 // (and only where) we know the client window.
144 last_caret_bounds_ = caret_bounds; 115 last_caret_bounds_ = rect;
145 } 116 }
146 117
147 // private: 118 // private:
148 119
149 void X11InputMethodContextImplGtk2::ResetXModifierKeycodesCache() { 120 void X11InputMethodContextImplGtk2::ResetXModifierKeycodesCache() {
150 modifier_keycodes_.clear(); 121 modifier_keycodes_.clear();
151 meta_keycodes_.clear(); 122 meta_keycodes_.clear();
152 super_keycodes_.clear(); 123 super_keycodes_.clear();
153 hyper_keycodes_.clear(); 124 hyper_keycodes_.clear();
154 125
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 return false; 273 return false;
303 } 274 }
304 275
305 // GtkIMContext event handlers. 276 // GtkIMContext event handlers.
306 277
307 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context, 278 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context,
308 gchar* text) { 279 gchar* text) {
309 if (context != gtk_context_) 280 if (context != gtk_context_)
310 return; 281 return;
311 282
312 const base::string16& text_in_utf16 = base::UTF8ToUTF16(text); 283 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 } 284 }
323 285
324 void X11InputMethodContextImplGtk2::OnPreeditChanged(GtkIMContext* context) { 286 void X11InputMethodContextImplGtk2::OnPreeditChanged(GtkIMContext* context) {
325 if (context != gtk_context_) 287 if (context != gtk_context_)
326 return; 288 return;
327 289
328 gchar* str = NULL; 290 gchar* str = NULL;
329 PangoAttrList* attrs = NULL; 291 PangoAttrList* attrs = NULL;
330 gint cursor_pos = 0; 292 gint cursor_pos = 0;
331 gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos); 293 gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos);
(...skipping 13 matching lines...) Expand all
345 delegate_->OnPreeditEnd(); 307 delegate_->OnPreeditEnd();
346 } 308 }
347 309
348 void X11InputMethodContextImplGtk2::OnPreeditStart(GtkIMContext* context) { 310 void X11InputMethodContextImplGtk2::OnPreeditStart(GtkIMContext* context) {
349 if (context != gtk_context_) 311 if (context != gtk_context_)
350 return; 312 return;
351 313
352 delegate_->OnPreeditStart(); 314 delegate_->OnPreeditStart();
353 } 315 }
354 316
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 317 } // namespace libgtk2ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698