diff options
Diffstat (limited to 'content/browser/renderer_host/gtk_im_context_wrapper.h')
-rw-r--r-- | content/browser/renderer_host/gtk_im_context_wrapper.h | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/content/browser/renderer_host/gtk_im_context_wrapper.h b/content/browser/renderer_host/gtk_im_context_wrapper.h new file mode 100644 index 0000000..a783296 --- /dev/null +++ b/content/browser/renderer_host/gtk_im_context_wrapper.h @@ -0,0 +1,197 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_ +#define CONTENT_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_ +#pragma once + +#include <gdk/gdk.h> +#include <pango/pango-attributes.h> +#include <vector> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/string16.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" +#include "ui/base/ime/composition_text.h" +#include "ui/base/ime/text_input_type.h" + +namespace gfx { +class Rect; +} + +class RenderWidgetHostViewGtk; +struct NativeWebKeyboardEvent; +typedef struct _GtkIMContext GtkIMContext; +typedef struct _GtkWidget GtkWidget; + +// This class is a convenience wrapper for GtkIMContext. +// It creates and manages two GtkIMContext instances, one is GtkIMMulticontext, +// for plain text input box, another is GtkIMContextSimple, for password input +// box. +// +// This class is in charge of dispatching key events to these two GtkIMContext +// instances and handling signals emitted by them. Key events then will be +// forwarded to renderer along with input method results via corresponding host +// view. +// +// This class is used solely by RenderWidgetHostViewGtk. +class GtkIMContextWrapper { + public: + explicit GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view); + ~GtkIMContextWrapper(); + + // Processes a gdk key event received by |host_view|. + void ProcessKeyEvent(GdkEventKey* event); + + void UpdateInputMethodState(ui::TextInputType type, + bool can_compose_inline, + const gfx::Rect& caret_rect); + void OnFocusIn(); + void OnFocusOut(); + bool is_focused() const { return is_focused_; } + +#if !defined(TOOLKIT_VIEWS) + // Not defined for views because the views context menu doesn't + // implement input methods yet. + GtkWidget* BuildInputMethodsGtkMenu(); +#endif + + void CancelComposition(); + + void ConfirmComposition(); + + private: + // Check if a text needs commit by forwarding a char event instead of + // by confirming as a composition text. + bool NeedCommitByForwardingCharEvent() const; + + // Check if the input method returned any result, eg. preedit and commit text. + bool HasInputMethodResult() const; + + void ProcessFilteredKeyPressEvent(NativeWebKeyboardEvent* wke); + void ProcessUnfilteredKeyPressEvent(NativeWebKeyboardEvent* wke); + + // Processes result returned from input method after filtering a key event. + // |filtered| indicates if the key event was filtered by the input method. + void ProcessInputMethodResult(const GdkEventKey* event, bool filtered); + + // Real code of "commit" signal handler. + void HandleCommit(const string16& text); + + // Real code of "preedit-start" signal handler. + void HandlePreeditStart(); + + // Real code of "preedit-changed" signal handler. + void HandlePreeditChanged(const gchar* text, + PangoAttrList* attrs, + int cursor_position); + + // Real code of "preedit-end" signal handler. + void HandlePreeditEnd(); + + // Real code of "realize" signal handler, used for setting im context's client + // window. + void HandleHostViewRealize(GtkWidget* widget); + + // Real code of "unrealize" signal handler, used for unsetting im context's + // client window. + void HandleHostViewUnrealize(); + + // Sends a fake composition key event with specified event type. A composition + // key event is a key event with special key code 229. + void SendFakeCompositionKeyEvent(WebKit::WebInputEvent::Type type); + + // Signal handlers of GtkIMContext object. + static void HandleCommitThunk(GtkIMContext* context, gchar* text, + GtkIMContextWrapper* self); + static void HandlePreeditStartThunk(GtkIMContext* context, + GtkIMContextWrapper* self); + static void HandlePreeditChangedThunk(GtkIMContext* context, + GtkIMContextWrapper* self); + static void HandlePreeditEndThunk(GtkIMContext* context, + GtkIMContextWrapper* self); + + // Signal handlers connecting to |host_view_|'s native view widget. + static void HandleHostViewRealizeThunk(GtkWidget* widget, + GtkIMContextWrapper* self); + static void HandleHostViewUnrealizeThunk(GtkWidget* widget, + GtkIMContextWrapper* self); + + // The parent object. + RenderWidgetHostViewGtk* host_view_; + + // The GtkIMContext object. + // In terms of the DOM event specification Appendix A + // <http://www.w3.org/TR/DOM-Level-3-Events/keyset.html>, + // GTK uses a GtkIMContext object for the following two purposes: + // 1. Composing Latin characters (A.1.2), and; + // 2. Composing CJK characters with an IME (A.1.3). + // Many JavaScript pages assume composed Latin characters are dispatched to + // their onkeypress() handlers but not dispatched CJK characters composed + // with an IME. To emulate this behavior, we should monitor the status of + // this GtkIMContext object and prevent sending Char events when a + // GtkIMContext object sends a "commit" signal with the CJK characters + // composed by an IME. + GtkIMContext* context_; + + // A GtkIMContextSimple object, for supporting dead/compose keys when input + // method is disabled, eg. in password input box. + GtkIMContext* context_simple_; + + // Whether or not this widget is focused. + bool is_focused_; + + // Whether or not the above GtkIMContext is composing a text with an IME. + // This flag is used in "commit" signal handler of the GtkIMContext object, + // which determines how to submit the result text to WebKit according to this + // flag. + // If this flag is true or there are more than one characters in the result, + // then the result text will be committed to WebKit as a confirmed + // composition. Otherwise, it'll be forwarded as a key event. + // + // The GtkIMContext object sends a "preedit_start" before it starts composing + // a text and a "preedit_end" signal after it finishes composing it. + // "preedit_start" signal is monitored to turn it on. + // We don't monitor "preedit_end" signal to turn it off, because an input + // method may fire "preedit_end" signal before "commit" signal. + // A buggy input method may not fire "preedit_start" and/or "preedit_end" + // at all, so this flag will also be set to true when "preedit_changed" signal + // is fired with non-empty preedit text. + bool is_composing_text_; + + // Whether or not the IME is enabled. + bool is_enabled_; + + // Whether or not it's currently running inside key event handler. + // If it's true, then preedit-changed and commit handler will backup the + // preedit or commit text instead of sending them down to webkit. + // key event handler will send them later. + bool is_in_key_event_handler_; + + // The most recent composition text information retrieved from context_; + ui::CompositionText composition_; + + // Whether or not the composition has been changed since last key event. + bool is_composition_changed_; + + // Stores a copy of the most recent commit text received by commit signal + // handler. + string16 commit_text_; + + // If it's true then the next "commit" signal will be suppressed. + // It's only used to workaround http://crbug.com/50485. + // TODO(suzhe): Remove it after input methods get fixed. + bool suppress_next_commit_; + + // Information of the last key event, for working around + // http://crosbug.com/6582 + int last_key_code_; + bool last_key_was_up_; + bool last_key_filtered_no_result_; + + DISALLOW_COPY_AND_ASSIGN(GtkIMContextWrapper); +}; + +#endif // CONTENT_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_ |