/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 nsBaseWidget_h__ #define nsBaseWidget_h__ #include "mozilla/EventForwards.h" #include "mozilla/WidgetUtils.h" #include "nsRect.h" #include "nsIWidget.h" #include "nsWidgetsCID.h" #include "nsIFile.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsIRollupListener.h" #include "nsIObserver.h" #include "nsIWidgetListener.h" #include "nsPIDOMWindow.h" #include class nsIContent; class nsAutoRollup; class gfxContext; namespace mozilla { #ifdef ACCESSIBILITY namespace a11y { class Accessible; } #endif namespace layers { class BasicLayerManager; class CompositorChild; class CompositorParent; } } namespace base { class Thread; } // Windows specific constant indicating the maximum number of touch points the // inject api will allow. This also sets the maximum numerical value for touch // ids we can use when injecting touch points on Windows. #define TOUCH_INJECT_MAX_POINTS 256 class nsBaseWidget; class WidgetShutdownObserver MOZ_FINAL : public nsIObserver { ~WidgetShutdownObserver() {} public: explicit WidgetShutdownObserver(nsBaseWidget* aWidget) : mWidget(aWidget) { } NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER nsBaseWidget *mWidget; }; /** * Common widget implementation used as base class for native * or crossplatform implementations of Widgets. * All cross-platform behavior that all widgets need to implement * should be placed in this class. * (Note: widget implementations are not required to use this * class, but it gives them a head start.) */ class nsBaseWidget : public nsIWidget { friend class nsAutoRollup; protected: typedef base::Thread Thread; typedef mozilla::layers::BasicLayerManager BasicLayerManager; typedef mozilla::layers::BufferMode BufferMode; typedef mozilla::layers::CompositorChild CompositorChild; typedef mozilla::layers::CompositorParent CompositorParent; typedef mozilla::ScreenRotation ScreenRotation; virtual ~nsBaseWidget(); public: nsBaseWidget(); NS_DECL_ISUPPORTS // nsIWidget interface NS_IMETHOD CaptureMouse(bool aCapture); virtual nsIWidgetListener* GetWidgetListener(); virtual void SetWidgetListener(nsIWidgetListener* alistener); NS_IMETHOD Destroy(); NS_IMETHOD SetParent(nsIWidget* aNewParent); virtual nsIWidget* GetParent(void); virtual nsIWidget* GetTopLevelWidget(); virtual nsIWidget* GetSheetWindowParent(void); virtual float GetDPI(); virtual void AddChild(nsIWidget* aChild); virtual void RemoveChild(nsIWidget* aChild); void SetZIndex(int32_t aZIndex); NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget *aWidget, bool aActivate); NS_IMETHOD SetSizeMode(int32_t aMode); virtual int32_t SizeMode() MOZ_OVERRIDE { return mSizeMode; } virtual nsCursor GetCursor(); NS_IMETHOD SetCursor(nsCursor aCursor); NS_IMETHOD SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY); virtual void ClearCachedCursor() { mUpdateCursor = true; } virtual void SetTransparencyMode(nsTransparencyMode aMode); virtual nsTransparencyMode GetTransparencyMode(); virtual void GetWindowClipRegion(nsTArray* aRects); NS_IMETHOD SetWindowShadowStyle(int32_t aStyle); virtual void SetShowsToolbarButton(bool aShow) {} virtual void SetShowsFullScreenButton(bool aShow) {} virtual void SetWindowAnimationType(WindowAnimationType aType) {} NS_IMETHOD HideWindowChrome(bool aShouldHide); NS_IMETHOD MakeFullScreen(bool aFullScreen, nsIScreen* aScreen = nullptr); virtual nsDeviceContext* GetDeviceContext(); virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE, LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, bool* aAllowRetaining = nullptr); virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight); virtual void CreateCompositor(); virtual void CreateCompositor(int aWidth, int aHeight); virtual void PrepareWindowEffects() {} virtual void CleanupWindowEffects() {} virtual bool PreRender(LayerManagerComposite* aManager) { return true; } virtual void PostRender(LayerManagerComposite* aManager) {} virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) {} virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) {} virtual mozilla::TemporaryRef StartRemoteDrawing(); virtual void EndRemoteDrawing() { }; virtual void CleanupRemoteDrawing() { }; virtual void UpdateThemeGeometries(const nsTArray& aThemeGeometries) {} NS_IMETHOD SetModal(bool aModal); virtual uint32_t GetMaxTouchPoints() const; NS_IMETHOD SetWindowClass(const nsAString& xulWinType); virtual nsresult SetWindowClipRegion(const nsTArray& aRects, bool aIntersectWithExisting); // Return whether this widget interprets parameters to Move and Resize APIs // as "global display pixels" rather than "device pixels", and therefore // applies its GetDefaultScale() value to them before using them as mBounds // etc (which are always stored in device pixels). // Note that APIs that -get- the widget's position/size/bounds, rather than // -setting- them (i.e. moving or resizing the widget) will always return // values in the widget's device pixels. bool BoundsUseDisplayPixels() const { return mWindowType <= eWindowType_popup; } NS_IMETHOD MoveClient(double aX, double aY); NS_IMETHOD ResizeClient(double aWidth, double aHeight, bool aRepaint); NS_IMETHOD ResizeClient(double aX, double aY, double aWidth, double aHeight, bool aRepaint); NS_IMETHOD GetBounds(nsIntRect &aRect); NS_IMETHOD GetClientBounds(nsIntRect &aRect); NS_IMETHOD GetScreenBounds(nsIntRect &aRect); NS_IMETHOD GetRestoredBounds(nsIntRect &aRect) MOZ_OVERRIDE; NS_IMETHOD GetNonClientMargins(nsIntMargin &margins); NS_IMETHOD SetNonClientMargins(nsIntMargin &margins); virtual nsIntPoint GetClientOffset(); NS_IMETHOD EnableDragDrop(bool aEnable); NS_IMETHOD GetAttention(int32_t aCycleCount); virtual bool HasPendingInputEvent(); NS_IMETHOD SetIcon(const nsAString &anIconSpec); NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive); virtual void SetDrawsInTitlebar(bool aState) {} virtual bool ShowsResizeIndicator(nsIntRect* aResizerRect); virtual void FreeNativeData(void * data, uint32_t aDataType) {} NS_IMETHOD BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical); NS_IMETHOD BeginMoveDrag(mozilla::WidgetMouseEvent* aEvent); virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD_(bool) ExecuteNativeKeyBinding( NativeKeyBindingsType aType, const mozilla::WidgetKeyboardEvent& aEvent, DoCommandCallback aCallback, void* aCallbackData) MOZ_OVERRIDE { return false; } NS_IMETHOD SetLayersAcceleration(bool aEnabled); virtual bool GetLayersAcceleration() { return mUseLayersAcceleration; } virtual bool ComputeShouldAccelerate(bool aDefault); NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE { return nsIMEUpdatePreference(); } NS_IMETHOD OnDefaultButtonLoaded(const nsIntRect &aButtonRect) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD OverrideSystemMouseScrollSpeed(double aOriginalDeltaX, double aOriginalDeltaY, double& aOverriddenDeltaX, double& aOverriddenDeltaY); virtual already_AddRefed CreateChild(const nsIntRect &aRect, nsDeviceContext *aContext, nsWidgetInitData *aInitData = nullptr, bool aForceUseIWidgetParent = false); NS_IMETHOD AttachViewToTopLevel(bool aUseAttachedEvents, nsDeviceContext *aContext); virtual nsIWidgetListener* GetAttachedWidgetListener(); virtual void SetAttachedWidgetListener(nsIWidgetListener* aListener); NS_IMETHOD RegisterTouchWindow(); NS_IMETHOD UnregisterTouchWindow(); void NotifyWindowDestroyed(); void NotifySizeMoveDone(); void NotifyWindowMoved(int32_t aX, int32_t aY); // Should be called by derived implementations to notify on system color and // theme changes. void NotifySysColorChanged(); void NotifyThemeChanged(); void NotifyUIStateChanged(UIStateChangeType aShowAccelerators, UIStateChangeType aShowFocusRings); #ifdef ACCESSIBILITY // Get the accessible for the window. mozilla::a11y::Accessible* GetRootAccessible(); #endif nsPopupLevel PopupLevel() { return mPopupLevel; } virtual nsIntSize ClientToWindowSize(const nsIntSize& aClientSize) { return aClientSize; } // return true if this is a popup widget with a native titlebar bool IsPopupWithTitleBar() const { return (mWindowType == eWindowType_popup && mBorderStyle != eBorderStyle_default && mBorderStyle & eBorderStyle_title); } NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) = 0; virtual uint32_t GetGLFrameBufferFormat() MOZ_OVERRIDE; virtual const SizeConstraints& GetSizeConstraints() const; virtual void SetSizeConstraints(const SizeConstraints& aConstraints); /** * Use this when GetLayerManager() returns a BasicLayerManager * (nsBaseWidget::GetLayerManager() does). This sets up the widget's * layer manager to temporarily render into aTarget. * * |aNaturalWidgetBounds| is the un-rotated bounds of |aWidget|. * |aRotation| is the "virtual rotation" to apply when rendering to * the target. When |aRotation| is ROTATION_0, * |aNaturalWidgetBounds| is not used. */ class AutoLayerManagerSetup { public: AutoLayerManagerSetup(nsBaseWidget* aWidget, gfxContext* aTarget, BufferMode aDoubleBuffering, ScreenRotation aRotation = mozilla::ROTATION_0); ~AutoLayerManagerSetup(); private: nsBaseWidget* mWidget; nsRefPtr mLayerManager; }; friend class AutoLayerManagerSetup; class AutoUseBasicLayerManager { public: explicit AutoUseBasicLayerManager(nsBaseWidget* aWidget); ~AutoUseBasicLayerManager(); private: nsBaseWidget* mWidget; bool mPreviousTemporarilyUseBasicLayerManager; }; friend class AutoUseBasicLayerManager; virtual bool ShouldUseOffMainThreadCompositing(); static nsIRollupListener* GetActiveRollupListener(); void Shutdown(); protected: virtual void ResolveIconName(const nsAString &aIconName, const nsAString &aIconSuffix, nsIFile **aResult); virtual void OnDestroy(); virtual void BaseCreate(nsIWidget *aParent, const nsIntRect &aRect, nsDeviceContext *aContext, nsWidgetInitData *aInitData); const nsIntRegion RegionFromArray(const nsTArray& aRects); void ArrayFromRegion(const nsIntRegion& aRegion, nsTArray& aRects); virtual nsIContent* GetLastRollup() { return mLastRollup; } virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, int32_t aNativeKeyCode, uint32_t aModifierFlags, const nsAString& aCharacters, const nsAString& aUnmodifiedCharacters) { return NS_ERROR_UNEXPECTED; } virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint, uint32_t aNativeMessage, uint32_t aModifierFlags) { return NS_ERROR_UNEXPECTED; } virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint) { return NS_ERROR_UNEXPECTED; } virtual nsresult SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, uint32_t aNativeMessage, double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aModifierFlags, uint32_t aAdditionalFlags) { return NS_ERROR_UNEXPECTED; } virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId, TouchPointerState aPointerState, nsIntPoint aPointerScreenPoint, double aPointerPressure, uint32_t aPointerOrientation) { return NS_ERROR_UNEXPECTED; } protected: // Stores the clip rectangles in aRects into mClipRects. Returns true // if the new rectangles are different from the old rectangles. bool StoreWindowClipRegion(const nsTArray& aRects); virtual already_AddRefed AllocateChildPopupWidget() { static NS_DEFINE_IID(kCPopUpCID, NS_CHILD_CID); nsCOMPtr widget = do_CreateInstance(kCPopUpCID); return widget.forget(); } LayerManager* CreateBasicLayerManager(); nsPopupType PopupType() const { return mPopupType; } void NotifyRollupGeometryChange() { // XULPopupManager isn't interested in this notification, so only // send it if gRollupListener is set. if (gRollupListener) { gRollupListener->NotifyGeometryChange(); } } /** * Apply the current size constraints to the given size. * * @param aWidth width to constrain * @param aHeight height to constrain */ void ConstrainSize(int32_t* aWidth, int32_t* aHeight) const { *aWidth = std::max(mSizeConstraints.mMinSize.width, std::min(mSizeConstraints.mMaxSize.width, *aWidth)); *aHeight = std::max(mSizeConstraints.mMinSize.height, std::min(mSizeConstraints.mMaxSize.height, *aHeight)); } virtual CompositorChild* GetRemoteRenderer() MOZ_OVERRIDE; virtual void GetPreferredCompositorBackends(nsTArray& aHints); /** * Notify the widget that this window is being used with OMTC. */ virtual void WindowUsesOMTC() {} protected: /** * Starts the OMTC compositor destruction sequence. * * When this function returns, the compositor should not be * able to access the opengl context anymore. * It is safe to call it several times if platform implementations * require the compositor to be destroyed before ~nsBaseWidget is * reached (This is the case with gtk2 for instance). */ void DestroyCompositor(); nsIWidgetListener* mWidgetListener; nsIWidgetListener* mAttachedWidgetListener; nsDeviceContext* mContext; nsRefPtr mLayerManager; nsRefPtr mBasicLayerManager; nsRefPtr mCompositorChild; nsRefPtr mCompositorParent; nsRefPtr mShutdownObserver; nsCursor mCursor; bool mUpdateCursor; nsBorderStyle mBorderStyle; bool mUseLayersAcceleration; bool mForceLayersAcceleration; bool mTemporarilyUseBasicLayerManager; // Windows with out-of-process tabs always require OMTC. This flag designates // such windows. bool mRequireOffMainThreadCompositing; bool mUseAttachedEvents; bool mContextInitialized; nsIntRect mBounds; nsIntRect* mOriginalBounds; // When this pointer is null, the widget is not clipped nsAutoArrayPtr mClipRects; uint32_t mClipRectCount; nsSizeMode mSizeMode; nsPopupLevel mPopupLevel; nsPopupType mPopupType; SizeConstraints mSizeConstraints; static nsIRollupListener* gRollupListener; // the last rolled up popup. Only set this when an nsAutoRollup is in scope, // so it can be cleared automatically. static nsIContent* mLastRollup; #ifdef DEBUG protected: static nsAutoString debug_GuiEventToString(mozilla::WidgetGUIEvent* aGuiEvent); static bool debug_WantPaintFlashing(); static void debug_DumpInvalidate(FILE * aFileOut, nsIWidget * aWidget, const nsIntRect * aRect, const nsAutoCString & aWidgetName, int32_t aWindowID); static void debug_DumpEvent(FILE* aFileOut, nsIWidget* aWidget, mozilla::WidgetGUIEvent* aGuiEvent, const nsAutoCString& aWidgetName, int32_t aWindowID); static void debug_DumpPaintEvent(FILE * aFileOut, nsIWidget * aWidget, const nsIntRegion & aPaintEvent, const nsAutoCString & aWidgetName, int32_t aWindowID); static bool debug_GetCachedBoolPref(const char* aPrefName); #endif }; // A situation can occur when a mouse event occurs over a menu label while the // menu popup is already open. The expected behaviour is to close the popup. // This happens by calling nsIRollupListener::Rollup before the mouse event is // processed. However, in cases where the mouse event is not consumed, this // event will then get targeted at the menu label causing the menu to open // again. To prevent this, we store in mLastRollup a reference to the popup // that was closed during the Rollup call, and prevent this popup from // reopening while processing the mouse event. // mLastRollup should only be set while an nsAutoRollup is in scope; // when it goes out of scope mLastRollup is cleared automatically. // As mLastRollup is static, it can be retrieved by calling // nsIWidget::GetLastRollup on any widget. class nsAutoRollup { bool wasClear; public: nsAutoRollup(); ~nsAutoRollup(); }; #endif // nsBaseWidget_h__