1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gtk/nsGtkIMModule.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,319 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4: 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#ifndef __nsGtkIMModule_h__ 1.12 +#define __nsGtkIMModule_h__ 1.13 + 1.14 +#include <gdk/gdk.h> 1.15 +#include <gtk/gtk.h> 1.16 + 1.17 +#include "nsString.h" 1.18 +#include "nsAutoPtr.h" 1.19 +#include "nsCOMPtr.h" 1.20 +#include "nsTArray.h" 1.21 +#include "nsIWidget.h" 1.22 +#include "mozilla/EventForwards.h" 1.23 + 1.24 +class nsWindow; 1.25 + 1.26 +class nsGtkIMModule 1.27 +{ 1.28 +protected: 1.29 + typedef mozilla::widget::InputContext InputContext; 1.30 + typedef mozilla::widget::InputContextAction InputContextAction; 1.31 + 1.32 +public: 1.33 + nsrefcnt AddRef() 1.34 + { 1.35 + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative"); 1.36 + ++mRefCnt; 1.37 + NS_LOG_ADDREF(this, mRefCnt, "nsGtkIMModule", sizeof(*this)); 1.38 + return mRefCnt; 1.39 + } 1.40 + nsrefcnt Release() 1.41 + { 1.42 + NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero"); 1.43 + --mRefCnt; 1.44 + NS_LOG_RELEASE(this, mRefCnt, "nsGtkIMModule"); 1.45 + if (mRefCnt == 0) { 1.46 + mRefCnt = 1; /* stabilize */ 1.47 + delete this; 1.48 + return 0; 1.49 + } 1.50 + return mRefCnt; 1.51 + } 1.52 + 1.53 +protected: 1.54 + nsAutoRefCnt mRefCnt; 1.55 + 1.56 +public: 1.57 + // aOwnerWindow is a pointer of the owner window. When aOwnerWindow is 1.58 + // destroyed, the related IME contexts are released (i.e., IME cannot be 1.59 + // used with the instance after that). 1.60 + nsGtkIMModule(nsWindow* aOwnerWindow); 1.61 + ~nsGtkIMModule(); 1.62 + 1.63 + // "Enabled" means the users can use all IMEs. 1.64 + // I.e., the focus is in the normal editors. 1.65 + bool IsEnabled(); 1.66 + 1.67 + // OnFocusWindow is a notification that aWindow is going to be focused. 1.68 + void OnFocusWindow(nsWindow* aWindow); 1.69 + // OnBlurWindow is a notification that aWindow is going to be unfocused. 1.70 + void OnBlurWindow(nsWindow* aWindow); 1.71 + // OnDestroyWindow is a notification that aWindow is going to be destroyed. 1.72 + void OnDestroyWindow(nsWindow* aWindow); 1.73 + // OnFocusChangeInGecko is a notification that an editor gets focus. 1.74 + void OnFocusChangeInGecko(bool aFocus); 1.75 + 1.76 + // OnKeyEvent is called when aWindow gets a native key press event or a 1.77 + // native key release event. If this returns TRUE, the key event was 1.78 + // filtered by IME. Otherwise, this returns FALSE. 1.79 + // NOTE: When the keypress event starts composition, this returns TRUE but 1.80 + // this dispatches keydown event before compositionstart event. 1.81 + bool OnKeyEvent(nsWindow* aWindow, GdkEventKey* aEvent, 1.82 + bool aKeyDownEventWasSent = false); 1.83 + 1.84 + // IME related nsIWidget methods. 1.85 + nsresult CommitIMEComposition(nsWindow* aCaller); 1.86 + void SetInputContext(nsWindow* aCaller, 1.87 + const InputContext* aContext, 1.88 + const InputContextAction* aAction); 1.89 + InputContext GetInputContext(); 1.90 + nsresult CancelIMEComposition(nsWindow* aCaller); 1.91 + void OnUpdateComposition(); 1.92 + 1.93 + // If a software keyboard has been opened, this returns TRUE. 1.94 + // Otherwise, FALSE. 1.95 + static bool IsVirtualKeyboardOpened(); 1.96 + 1.97 +protected: 1.98 + // Owner of an instance of this class. This should be top level window. 1.99 + // The owner window must release the contexts when it's destroyed because 1.100 + // the IME contexts need the native window. If OnDestroyWindow() is called 1.101 + // with the owner window, it'll release IME contexts. Otherwise, it'll 1.102 + // just clean up any existing composition if it's related to the destroying 1.103 + // child window. 1.104 + nsWindow* mOwnerWindow; 1.105 + 1.106 + // A last focused window in this class's context. 1.107 + nsWindow* mLastFocusedWindow; 1.108 + 1.109 + // Actual context. This is used for handling the user's input. 1.110 + GtkIMContext *mContext; 1.111 + 1.112 + // mSimpleContext is used for the password field and 1.113 + // the |ime-mode: disabled;| editors if sUseSimpleContext is true. 1.114 + // These editors disable IME. But dead keys should work. Fortunately, 1.115 + // the simple IM context of GTK2 support only them. 1.116 + GtkIMContext *mSimpleContext; 1.117 + 1.118 + // mDummyContext is a dummy context and will be used in Focus() 1.119 + // when the state of mEnabled means disabled. This context's IME state is 1.120 + // always "closed", so it closes IME forcedly. 1.121 + GtkIMContext *mDummyContext; 1.122 + 1.123 + // IME enabled state and other things defined in InputContext. 1.124 + // Use following helper methods if you don't need the detail of the status. 1.125 + InputContext mInputContext; 1.126 + 1.127 + // mCompositionStart is the start offset of the composition string in the 1.128 + // current content. When <textarea> or <input> have focus, it means offset 1.129 + // from the first character of them. When a HTML editor has focus, it 1.130 + // means offset from the first character of the root element of the editor. 1.131 + uint32_t mCompositionStart; 1.132 + 1.133 + // mDispatchedCompositionString is the latest composition string which 1.134 + // was dispatched by compositionupdate event. 1.135 + nsString mDispatchedCompositionString; 1.136 + 1.137 + // mSelectedString is the selected string which was removed by first 1.138 + // text event. 1.139 + nsString mSelectedString; 1.140 + 1.141 + // OnKeyEvent() temporarily sets mProcessingKeyEvent to the given native 1.142 + // event. 1.143 + GdkEventKey* mProcessingKeyEvent; 1.144 + 1.145 + // current target offset of IME composition 1.146 + uint32_t mCompositionTargetOffset; 1.147 + 1.148 + // mCompositionState indicates current status of composition. 1.149 + enum eCompositionState { 1.150 + eCompositionState_NotComposing, 1.151 + eCompositionState_CompositionStartDispatched, 1.152 + eCompositionState_TextEventDispatched, 1.153 + eCompositionState_CommitTextEventDispatched 1.154 + }; 1.155 + eCompositionState mCompositionState; 1.156 + 1.157 + bool IsComposing() 1.158 + { 1.159 + return (mCompositionState != eCompositionState_NotComposing); 1.160 + } 1.161 + 1.162 + bool EditorHasCompositionString() 1.163 + { 1.164 + return (mCompositionState == eCompositionState_TextEventDispatched); 1.165 + } 1.166 + 1.167 +#ifdef PR_LOGGING 1.168 + const char* GetCompositionStateName() 1.169 + { 1.170 + switch (mCompositionState) { 1.171 + case eCompositionState_NotComposing: 1.172 + return "NotComposing"; 1.173 + case eCompositionState_CompositionStartDispatched: 1.174 + return "CompositionStartDispatched"; 1.175 + case eCompositionState_TextEventDispatched: 1.176 + return "TextEventDispatched"; 1.177 + case eCompositionState_CommitTextEventDispatched: 1.178 + return "CommitTextEventDispatched"; 1.179 + default: 1.180 + return "InvaildState"; 1.181 + } 1.182 + } 1.183 +#endif // PR_LOGGING 1.184 + 1.185 + 1.186 + // mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And 1.187 + // it's set to FALSE when we call gtk_im_context_focus_out(). 1.188 + bool mIsIMFocused; 1.189 + // mFilterKeyEvent is used by OnKeyEvent(). If the commit event should 1.190 + // be processed as simple key event, this is set to TRUE by the commit 1.191 + // handler. 1.192 + bool mFilterKeyEvent; 1.193 + // When mIgnoreNativeCompositionEvent is TRUE, all native composition 1.194 + // should be ignored except that the compositon should be restarted in 1.195 + // another content (nsIContent). Don't refer this value directly, use 1.196 + // ShouldIgnoreNativeCompositionEvent(). 1.197 + bool mIgnoreNativeCompositionEvent; 1.198 + // mKeyDownEventWasSent is used by OnKeyEvent() and 1.199 + // DispatchCompositionStart(). DispatchCompositionStart() dispatches 1.200 + // a keydown event if the composition start is caused by a native 1.201 + // keypress event. If this is true, the keydown event has been dispatched. 1.202 + // Then, DispatchCompositionStart() doesn't dispatch keydown event. 1.203 + bool mKeyDownEventWasSent; 1.204 + 1.205 + // sLastFocusedModule is a pointer to the last focused instance of this 1.206 + // class. When a instance is destroyed and sLastFocusedModule refers it, 1.207 + // this is cleared. So, this refers valid pointer always. 1.208 + static nsGtkIMModule* sLastFocusedModule; 1.209 + 1.210 + // sUseSimpleContext indeicates if password editors and editors with 1.211 + // |ime-mode: disabled;| should use GtkIMContextSimple. 1.212 + // If true, they use GtkIMContextSimple. Otherwise, not. 1.213 + static bool sUseSimpleContext; 1.214 + 1.215 + // Callback methods for native IME events. These methods should call 1.216 + // the related instance methods simply. 1.217 + static gboolean OnRetrieveSurroundingCallback(GtkIMContext *aContext, 1.218 + nsGtkIMModule *aModule); 1.219 + static gboolean OnDeleteSurroundingCallback(GtkIMContext *aContext, 1.220 + gint aOffset, 1.221 + gint aNChars, 1.222 + nsGtkIMModule *aModule); 1.223 + static void OnCommitCompositionCallback(GtkIMContext *aContext, 1.224 + const gchar *aString, 1.225 + nsGtkIMModule* aModule); 1.226 + static void OnChangeCompositionCallback(GtkIMContext *aContext, 1.227 + nsGtkIMModule* aModule); 1.228 + static void OnStartCompositionCallback(GtkIMContext *aContext, 1.229 + nsGtkIMModule* aModule); 1.230 + static void OnEndCompositionCallback(GtkIMContext *aContext, 1.231 + nsGtkIMModule* aModule); 1.232 + 1.233 + // The instance methods for the native IME events. 1.234 + gboolean OnRetrieveSurroundingNative(GtkIMContext *aContext); 1.235 + gboolean OnDeleteSurroundingNative(GtkIMContext *aContext, 1.236 + gint aOffset, 1.237 + gint aNChars); 1.238 + void OnCommitCompositionNative(GtkIMContext *aContext, 1.239 + const gchar *aString); 1.240 + void OnChangeCompositionNative(GtkIMContext *aContext); 1.241 + void OnStartCompositionNative(GtkIMContext *aContext); 1.242 + void OnEndCompositionNative(GtkIMContext *aContext); 1.243 + 1.244 + 1.245 + // GetContext() returns current IM context which is chosen by the enabled 1.246 + // state. So, this means *current* IM context. 1.247 + GtkIMContext* GetContext(); 1.248 + 1.249 + // "Editable" means the users can input characters. They may be not able to 1.250 + // use IMEs but they can use dead keys. 1.251 + // I.e., the focus is in the normal editors or the password editors or 1.252 + // the |ime-mode: disabled;| editors. 1.253 + bool IsEditable(); 1.254 + 1.255 + // If the owner window and IM context have been destroyed, returns TRUE. 1.256 + bool IsDestroyed() { return !mOwnerWindow; } 1.257 + 1.258 + // Sets focus to the instance of this class. 1.259 + void Focus(); 1.260 + 1.261 + // Steals focus from the instance of this class. 1.262 + void Blur(); 1.263 + 1.264 + // Initializes the instance. 1.265 + void Init(); 1.266 + 1.267 + // Reset the current composition of IME. All native composition events 1.268 + // during this processing are ignored. 1.269 + void ResetIME(); 1.270 + 1.271 + // Gets the current composition string by the native APIs. 1.272 + void GetCompositionString(nsAString &aCompositionString); 1.273 + 1.274 + // Generates our text range array from current composition string. 1.275 + already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray(); 1.276 + 1.277 + // Sets the offset's cursor position to IME. 1.278 + void SetCursorPosition(uint32_t aTargetOffset); 1.279 + 1.280 + // Queries the current selection offset of the window. 1.281 + uint32_t GetSelectionOffset(nsWindow* aWindow); 1.282 + 1.283 + // Get current paragraph text content and cursor position 1.284 + nsresult GetCurrentParagraph(nsAString& aText, uint32_t& aCursorPos); 1.285 + 1.286 + // Delete text portion 1.287 + nsresult DeleteText(const int32_t aOffset, const uint32_t aNChars); 1.288 + 1.289 + // Initializes the GUI event. 1.290 + void InitEvent(mozilla::WidgetGUIEvent& aEvent); 1.291 + 1.292 + // Called before destroying the context to work around some platform bugs. 1.293 + void PrepareToDestroyContext(GtkIMContext *aContext); 1.294 + 1.295 + bool ShouldIgnoreNativeCompositionEvent(); 1.296 + 1.297 + /** 1.298 + * WARNING: 1.299 + * Following methods dispatch gecko events. Then, the focused widget 1.300 + * can be destroyed, and also it can be stolen focus. If they returns 1.301 + * FALSE, callers cannot continue the composition. 1.302 + * - CommitCompositionBy 1.303 + * - DispatchCompositionStart 1.304 + * - DispatchCompositionEnd 1.305 + * - DispatchTextEvent 1.306 + */ 1.307 + 1.308 + // Commits the current composition by the aString. 1.309 + bool CommitCompositionBy(const nsAString& aString); 1.310 + 1.311 + // Dispatches a composition start event or a composition end event. 1.312 + bool DispatchCompositionStart(); 1.313 + bool DispatchCompositionEnd(); 1.314 + 1.315 + // Dispatches a text event. If aIsCommit is TRUE, dispatches a committed 1.316 + // text event. Otherwise, dispatches a composing text event. 1.317 + bool DispatchTextEvent(const nsAString& aCompositionString, 1.318 + bool aIsCommit); 1.319 + 1.320 +}; 1.321 + 1.322 +#endif // __nsGtkIMModule_h__