widget/gtk/nsGtkIMModule.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim:expandtab:shiftwidth=4:tabstop=4:
michael@0 3 */
michael@0 4 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #ifndef __nsGtkIMModule_h__
michael@0 9 #define __nsGtkIMModule_h__
michael@0 10
michael@0 11 #include <gdk/gdk.h>
michael@0 12 #include <gtk/gtk.h>
michael@0 13
michael@0 14 #include "nsString.h"
michael@0 15 #include "nsAutoPtr.h"
michael@0 16 #include "nsCOMPtr.h"
michael@0 17 #include "nsTArray.h"
michael@0 18 #include "nsIWidget.h"
michael@0 19 #include "mozilla/EventForwards.h"
michael@0 20
michael@0 21 class nsWindow;
michael@0 22
michael@0 23 class nsGtkIMModule
michael@0 24 {
michael@0 25 protected:
michael@0 26 typedef mozilla::widget::InputContext InputContext;
michael@0 27 typedef mozilla::widget::InputContextAction InputContextAction;
michael@0 28
michael@0 29 public:
michael@0 30 nsrefcnt AddRef()
michael@0 31 {
michael@0 32 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative");
michael@0 33 ++mRefCnt;
michael@0 34 NS_LOG_ADDREF(this, mRefCnt, "nsGtkIMModule", sizeof(*this));
michael@0 35 return mRefCnt;
michael@0 36 }
michael@0 37 nsrefcnt Release()
michael@0 38 {
michael@0 39 NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
michael@0 40 --mRefCnt;
michael@0 41 NS_LOG_RELEASE(this, mRefCnt, "nsGtkIMModule");
michael@0 42 if (mRefCnt == 0) {
michael@0 43 mRefCnt = 1; /* stabilize */
michael@0 44 delete this;
michael@0 45 return 0;
michael@0 46 }
michael@0 47 return mRefCnt;
michael@0 48 }
michael@0 49
michael@0 50 protected:
michael@0 51 nsAutoRefCnt mRefCnt;
michael@0 52
michael@0 53 public:
michael@0 54 // aOwnerWindow is a pointer of the owner window. When aOwnerWindow is
michael@0 55 // destroyed, the related IME contexts are released (i.e., IME cannot be
michael@0 56 // used with the instance after that).
michael@0 57 nsGtkIMModule(nsWindow* aOwnerWindow);
michael@0 58 ~nsGtkIMModule();
michael@0 59
michael@0 60 // "Enabled" means the users can use all IMEs.
michael@0 61 // I.e., the focus is in the normal editors.
michael@0 62 bool IsEnabled();
michael@0 63
michael@0 64 // OnFocusWindow is a notification that aWindow is going to be focused.
michael@0 65 void OnFocusWindow(nsWindow* aWindow);
michael@0 66 // OnBlurWindow is a notification that aWindow is going to be unfocused.
michael@0 67 void OnBlurWindow(nsWindow* aWindow);
michael@0 68 // OnDestroyWindow is a notification that aWindow is going to be destroyed.
michael@0 69 void OnDestroyWindow(nsWindow* aWindow);
michael@0 70 // OnFocusChangeInGecko is a notification that an editor gets focus.
michael@0 71 void OnFocusChangeInGecko(bool aFocus);
michael@0 72
michael@0 73 // OnKeyEvent is called when aWindow gets a native key press event or a
michael@0 74 // native key release event. If this returns TRUE, the key event was
michael@0 75 // filtered by IME. Otherwise, this returns FALSE.
michael@0 76 // NOTE: When the keypress event starts composition, this returns TRUE but
michael@0 77 // this dispatches keydown event before compositionstart event.
michael@0 78 bool OnKeyEvent(nsWindow* aWindow, GdkEventKey* aEvent,
michael@0 79 bool aKeyDownEventWasSent = false);
michael@0 80
michael@0 81 // IME related nsIWidget methods.
michael@0 82 nsresult CommitIMEComposition(nsWindow* aCaller);
michael@0 83 void SetInputContext(nsWindow* aCaller,
michael@0 84 const InputContext* aContext,
michael@0 85 const InputContextAction* aAction);
michael@0 86 InputContext GetInputContext();
michael@0 87 nsresult CancelIMEComposition(nsWindow* aCaller);
michael@0 88 void OnUpdateComposition();
michael@0 89
michael@0 90 // If a software keyboard has been opened, this returns TRUE.
michael@0 91 // Otherwise, FALSE.
michael@0 92 static bool IsVirtualKeyboardOpened();
michael@0 93
michael@0 94 protected:
michael@0 95 // Owner of an instance of this class. This should be top level window.
michael@0 96 // The owner window must release the contexts when it's destroyed because
michael@0 97 // the IME contexts need the native window. If OnDestroyWindow() is called
michael@0 98 // with the owner window, it'll release IME contexts. Otherwise, it'll
michael@0 99 // just clean up any existing composition if it's related to the destroying
michael@0 100 // child window.
michael@0 101 nsWindow* mOwnerWindow;
michael@0 102
michael@0 103 // A last focused window in this class's context.
michael@0 104 nsWindow* mLastFocusedWindow;
michael@0 105
michael@0 106 // Actual context. This is used for handling the user's input.
michael@0 107 GtkIMContext *mContext;
michael@0 108
michael@0 109 // mSimpleContext is used for the password field and
michael@0 110 // the |ime-mode: disabled;| editors if sUseSimpleContext is true.
michael@0 111 // These editors disable IME. But dead keys should work. Fortunately,
michael@0 112 // the simple IM context of GTK2 support only them.
michael@0 113 GtkIMContext *mSimpleContext;
michael@0 114
michael@0 115 // mDummyContext is a dummy context and will be used in Focus()
michael@0 116 // when the state of mEnabled means disabled. This context's IME state is
michael@0 117 // always "closed", so it closes IME forcedly.
michael@0 118 GtkIMContext *mDummyContext;
michael@0 119
michael@0 120 // IME enabled state and other things defined in InputContext.
michael@0 121 // Use following helper methods if you don't need the detail of the status.
michael@0 122 InputContext mInputContext;
michael@0 123
michael@0 124 // mCompositionStart is the start offset of the composition string in the
michael@0 125 // current content. When <textarea> or <input> have focus, it means offset
michael@0 126 // from the first character of them. When a HTML editor has focus, it
michael@0 127 // means offset from the first character of the root element of the editor.
michael@0 128 uint32_t mCompositionStart;
michael@0 129
michael@0 130 // mDispatchedCompositionString is the latest composition string which
michael@0 131 // was dispatched by compositionupdate event.
michael@0 132 nsString mDispatchedCompositionString;
michael@0 133
michael@0 134 // mSelectedString is the selected string which was removed by first
michael@0 135 // text event.
michael@0 136 nsString mSelectedString;
michael@0 137
michael@0 138 // OnKeyEvent() temporarily sets mProcessingKeyEvent to the given native
michael@0 139 // event.
michael@0 140 GdkEventKey* mProcessingKeyEvent;
michael@0 141
michael@0 142 // current target offset of IME composition
michael@0 143 uint32_t mCompositionTargetOffset;
michael@0 144
michael@0 145 // mCompositionState indicates current status of composition.
michael@0 146 enum eCompositionState {
michael@0 147 eCompositionState_NotComposing,
michael@0 148 eCompositionState_CompositionStartDispatched,
michael@0 149 eCompositionState_TextEventDispatched,
michael@0 150 eCompositionState_CommitTextEventDispatched
michael@0 151 };
michael@0 152 eCompositionState mCompositionState;
michael@0 153
michael@0 154 bool IsComposing()
michael@0 155 {
michael@0 156 return (mCompositionState != eCompositionState_NotComposing);
michael@0 157 }
michael@0 158
michael@0 159 bool EditorHasCompositionString()
michael@0 160 {
michael@0 161 return (mCompositionState == eCompositionState_TextEventDispatched);
michael@0 162 }
michael@0 163
michael@0 164 #ifdef PR_LOGGING
michael@0 165 const char* GetCompositionStateName()
michael@0 166 {
michael@0 167 switch (mCompositionState) {
michael@0 168 case eCompositionState_NotComposing:
michael@0 169 return "NotComposing";
michael@0 170 case eCompositionState_CompositionStartDispatched:
michael@0 171 return "CompositionStartDispatched";
michael@0 172 case eCompositionState_TextEventDispatched:
michael@0 173 return "TextEventDispatched";
michael@0 174 case eCompositionState_CommitTextEventDispatched:
michael@0 175 return "CommitTextEventDispatched";
michael@0 176 default:
michael@0 177 return "InvaildState";
michael@0 178 }
michael@0 179 }
michael@0 180 #endif // PR_LOGGING
michael@0 181
michael@0 182
michael@0 183 // mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And
michael@0 184 // it's set to FALSE when we call gtk_im_context_focus_out().
michael@0 185 bool mIsIMFocused;
michael@0 186 // mFilterKeyEvent is used by OnKeyEvent(). If the commit event should
michael@0 187 // be processed as simple key event, this is set to TRUE by the commit
michael@0 188 // handler.
michael@0 189 bool mFilterKeyEvent;
michael@0 190 // When mIgnoreNativeCompositionEvent is TRUE, all native composition
michael@0 191 // should be ignored except that the compositon should be restarted in
michael@0 192 // another content (nsIContent). Don't refer this value directly, use
michael@0 193 // ShouldIgnoreNativeCompositionEvent().
michael@0 194 bool mIgnoreNativeCompositionEvent;
michael@0 195 // mKeyDownEventWasSent is used by OnKeyEvent() and
michael@0 196 // DispatchCompositionStart(). DispatchCompositionStart() dispatches
michael@0 197 // a keydown event if the composition start is caused by a native
michael@0 198 // keypress event. If this is true, the keydown event has been dispatched.
michael@0 199 // Then, DispatchCompositionStart() doesn't dispatch keydown event.
michael@0 200 bool mKeyDownEventWasSent;
michael@0 201
michael@0 202 // sLastFocusedModule is a pointer to the last focused instance of this
michael@0 203 // class. When a instance is destroyed and sLastFocusedModule refers it,
michael@0 204 // this is cleared. So, this refers valid pointer always.
michael@0 205 static nsGtkIMModule* sLastFocusedModule;
michael@0 206
michael@0 207 // sUseSimpleContext indeicates if password editors and editors with
michael@0 208 // |ime-mode: disabled;| should use GtkIMContextSimple.
michael@0 209 // If true, they use GtkIMContextSimple. Otherwise, not.
michael@0 210 static bool sUseSimpleContext;
michael@0 211
michael@0 212 // Callback methods for native IME events. These methods should call
michael@0 213 // the related instance methods simply.
michael@0 214 static gboolean OnRetrieveSurroundingCallback(GtkIMContext *aContext,
michael@0 215 nsGtkIMModule *aModule);
michael@0 216 static gboolean OnDeleteSurroundingCallback(GtkIMContext *aContext,
michael@0 217 gint aOffset,
michael@0 218 gint aNChars,
michael@0 219 nsGtkIMModule *aModule);
michael@0 220 static void OnCommitCompositionCallback(GtkIMContext *aContext,
michael@0 221 const gchar *aString,
michael@0 222 nsGtkIMModule* aModule);
michael@0 223 static void OnChangeCompositionCallback(GtkIMContext *aContext,
michael@0 224 nsGtkIMModule* aModule);
michael@0 225 static void OnStartCompositionCallback(GtkIMContext *aContext,
michael@0 226 nsGtkIMModule* aModule);
michael@0 227 static void OnEndCompositionCallback(GtkIMContext *aContext,
michael@0 228 nsGtkIMModule* aModule);
michael@0 229
michael@0 230 // The instance methods for the native IME events.
michael@0 231 gboolean OnRetrieveSurroundingNative(GtkIMContext *aContext);
michael@0 232 gboolean OnDeleteSurroundingNative(GtkIMContext *aContext,
michael@0 233 gint aOffset,
michael@0 234 gint aNChars);
michael@0 235 void OnCommitCompositionNative(GtkIMContext *aContext,
michael@0 236 const gchar *aString);
michael@0 237 void OnChangeCompositionNative(GtkIMContext *aContext);
michael@0 238 void OnStartCompositionNative(GtkIMContext *aContext);
michael@0 239 void OnEndCompositionNative(GtkIMContext *aContext);
michael@0 240
michael@0 241
michael@0 242 // GetContext() returns current IM context which is chosen by the enabled
michael@0 243 // state. So, this means *current* IM context.
michael@0 244 GtkIMContext* GetContext();
michael@0 245
michael@0 246 // "Editable" means the users can input characters. They may be not able to
michael@0 247 // use IMEs but they can use dead keys.
michael@0 248 // I.e., the focus is in the normal editors or the password editors or
michael@0 249 // the |ime-mode: disabled;| editors.
michael@0 250 bool IsEditable();
michael@0 251
michael@0 252 // If the owner window and IM context have been destroyed, returns TRUE.
michael@0 253 bool IsDestroyed() { return !mOwnerWindow; }
michael@0 254
michael@0 255 // Sets focus to the instance of this class.
michael@0 256 void Focus();
michael@0 257
michael@0 258 // Steals focus from the instance of this class.
michael@0 259 void Blur();
michael@0 260
michael@0 261 // Initializes the instance.
michael@0 262 void Init();
michael@0 263
michael@0 264 // Reset the current composition of IME. All native composition events
michael@0 265 // during this processing are ignored.
michael@0 266 void ResetIME();
michael@0 267
michael@0 268 // Gets the current composition string by the native APIs.
michael@0 269 void GetCompositionString(nsAString &aCompositionString);
michael@0 270
michael@0 271 // Generates our text range array from current composition string.
michael@0 272 already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray();
michael@0 273
michael@0 274 // Sets the offset's cursor position to IME.
michael@0 275 void SetCursorPosition(uint32_t aTargetOffset);
michael@0 276
michael@0 277 // Queries the current selection offset of the window.
michael@0 278 uint32_t GetSelectionOffset(nsWindow* aWindow);
michael@0 279
michael@0 280 // Get current paragraph text content and cursor position
michael@0 281 nsresult GetCurrentParagraph(nsAString& aText, uint32_t& aCursorPos);
michael@0 282
michael@0 283 // Delete text portion
michael@0 284 nsresult DeleteText(const int32_t aOffset, const uint32_t aNChars);
michael@0 285
michael@0 286 // Initializes the GUI event.
michael@0 287 void InitEvent(mozilla::WidgetGUIEvent& aEvent);
michael@0 288
michael@0 289 // Called before destroying the context to work around some platform bugs.
michael@0 290 void PrepareToDestroyContext(GtkIMContext *aContext);
michael@0 291
michael@0 292 bool ShouldIgnoreNativeCompositionEvent();
michael@0 293
michael@0 294 /**
michael@0 295 * WARNING:
michael@0 296 * Following methods dispatch gecko events. Then, the focused widget
michael@0 297 * can be destroyed, and also it can be stolen focus. If they returns
michael@0 298 * FALSE, callers cannot continue the composition.
michael@0 299 * - CommitCompositionBy
michael@0 300 * - DispatchCompositionStart
michael@0 301 * - DispatchCompositionEnd
michael@0 302 * - DispatchTextEvent
michael@0 303 */
michael@0 304
michael@0 305 // Commits the current composition by the aString.
michael@0 306 bool CommitCompositionBy(const nsAString& aString);
michael@0 307
michael@0 308 // Dispatches a composition start event or a composition end event.
michael@0 309 bool DispatchCompositionStart();
michael@0 310 bool DispatchCompositionEnd();
michael@0 311
michael@0 312 // Dispatches a text event. If aIsCommit is TRUE, dispatches a committed
michael@0 313 // text event. Otherwise, dispatches a composing text event.
michael@0 314 bool DispatchTextEvent(const nsAString& aCompositionString,
michael@0 315 bool aIsCommit);
michael@0 316
michael@0 317 };
michael@0 318
michael@0 319 #endif // __nsGtkIMModule_h__

mercurial