/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_IMEStateManager_h_ #define mozilla_IMEStateManager_h_ #include "mozilla/EventForwards.h" #include "mozilla/StaticPtr.h" #include "mozilla/dom/TabParent.h" #include "nsIWidget.h" class nsIContent; class nsINode; class nsPresContext; namespace mozilla { class EditorBase; class EventDispatchingCallback; class IMEContentObserver; class TextCompositionArray; class TextComposition; namespace dom { class Selection; } // namespace dom /** * IMEStateManager manages InputContext (e.g., active editor type, IME enabled * state and IME open state) of nsIWidget instances, manages IMEContentObserver * and provides useful API for IME. */ class IMEStateManager { typedef dom::TabParent TabParent; typedef widget::IMEMessage IMEMessage; typedef widget::IMENotification IMENotification; typedef widget::IMEState IMEState; typedef widget::InputContext InputContext; typedef widget::InputContextAction InputContextAction; public: static void Init(); static void Shutdown(); /** * GetActiveTabParent() returns a pointer to a TabParent instance which is * managed by the focused content (sContent). If the focused content isn't * managing another process, this returns nullptr. */ static TabParent* GetActiveTabParent() { // If menu has pseudo focus, we should ignore active child process. if (sInstalledMenuKeyboardListener) { return nullptr; } return sActiveTabParent.get(); } /** * DoesTabParentHaveIMEFocus() returns true when aTabParent has IME focus, * i.e., the TabParent sent "focus" notification but not yet sends "blur". * Note that this doesn't check if the remote processes are same because * if another TabParent has focus, committing composition causes firing * composition events in different TabParent. (Anyway, such case shouldn't * occur.) */ static bool DoesTabParentHaveIMEFocus(const TabParent* aTabParent) { MOZ_ASSERT(aTabParent); return sFocusedIMETabParent == aTabParent; } /** * OnTabParentDestroying() is called when aTabParent is being destroyed. */ static void OnTabParentDestroying(TabParent* aTabParent); /** * Called when aWidget is being deleted. */ static void WidgetDestroyed(nsIWidget* aWidget); /** * GetWidgetForActiveInputContext() returns a widget which IMEStateManager * is managing input context with. If a widget instance needs to cache * the last input context for nsIWidget::GetInputContext() or something, * it should check if its cache is valid with this method before using it * because if this method returns another instance, it means that * IMEStateManager may have already changed shared input context via the * widget. */ static nsIWidget* GetWidgetForActiveInputContext() { return sActiveInputContextWidget; } /** * SetIMEContextForChildProcess() is called when aTabParent receives * SetInputContext() from the remote process. */ static void SetInputContextForChildProcess(TabParent* aTabParent, const InputContext& aInputContext, const InputContextAction& aAction); /** * StopIMEStateManagement() is called when the process should stop managing * IME state. */ static void StopIMEStateManagement(); /** * MaybeStartOffsetUpdatedInChild() is called when composition start offset * is maybe updated in the child process. I.e., even if it's not updated, * this is called and never called if the composition is in this process. * @param aWidget The widget whose native IME context has the * composition. * @param aStartOffset New composition start offset with native * linebreaks. */ static void MaybeStartOffsetUpdatedInChild(nsIWidget* aWidget, uint32_t aStartOffset); static nsresult OnDestroyPresContext(nsPresContext* aPresContext); static nsresult OnRemoveContent(nsPresContext* aPresContext, nsIContent* aContent); /** * OnChangeFocus() should be called when focused content is changed or * IME enabled state is changed. If nobody has focus, set both aPresContext * and aContent nullptr. E.g., all windows are deactivated. */ static nsresult OnChangeFocus(nsPresContext* aPresContext, nsIContent* aContent, InputContextAction::Cause aCause); /** * OnInstalledMenuKeyboardListener() is called when menu keyboard listener * is installed or uninstalled in the process. So, even if menu keyboard * listener was installed in chrome process, this won't be called in content * processes. * * @param aInstalling true if menu keyboard listener is installed. * Otherwise, i.e., menu keyboard listener is * uninstalled, false. */ static void OnInstalledMenuKeyboardListener(bool aInstalling); // These two methods manage focus and selection/text observers. // They are separate from OnChangeFocus above because this offers finer // control compared to having the two methods incorporated into OnChangeFocus // Get the focused editor's selection and root static nsresult GetFocusSelectionAndRoot(dom::Selection** aSel, nsIContent** aRoot); // This method updates the current IME state. However, if the enabled state // isn't changed by the new state, this method does nothing. // Note that this method changes the IME state of the active element in the // widget. So, the caller must have focus. static void UpdateIMEState(const IMEState& aNewIMEState, nsIContent* aContent, EditorBase* aEditorBase); // This method is called when user operates mouse button in focused editor // and before the editor handles it. // Returns true if IME consumes the event. Otherwise, false. static bool OnMouseButtonEventInEditor(nsPresContext* aPresContext, nsIContent* aContent, WidgetMouseEvent* aMouseEvent); // This method is called when user clicked in an editor. // aContent must be: // If the editor is for or