Bug 1865372: Call nsCocoaWindow::DestroyNativeWindow more often in Destroy. r=mac...
[gecko.git] / widget / cocoa / nsCocoaWindow.h
blobe072e51ab7b4821319109f2aaf6ac1467c55aee9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsCocoaWindow_h_
7 #define nsCocoaWindow_h_
9 #undef DARWIN
11 #import <Cocoa/Cocoa.h>
13 #include "mozilla/RefPtr.h"
14 #include "nsBaseWidget.h"
15 #include "nsPIWidgetCocoa.h"
16 #include "nsCocoaUtils.h"
17 #include "nsTouchBar.h"
18 #include <dlfcn.h>
19 #include <queue>
21 class nsCocoaWindow;
22 class nsChildView;
23 class nsMenuBarX;
24 @class ChildView;
26 namespace mozilla {
27 enum class NativeKeyBindingsType : uint8_t;
28 } // namespace mozilla
30 typedef struct _nsCocoaWindowList {
31 _nsCocoaWindowList() : prev(nullptr), window(nullptr) {}
32 struct _nsCocoaWindowList* prev;
33 nsCocoaWindow* window; // Weak
34 } nsCocoaWindowList;
36 // NSWindow subclass that is the base class for all of our own window classes.
37 // Among other things, this class handles the storage of those settings that
38 // need to be persisted across window destruction and reconstruction, i.e. when
39 // switching to and from fullscreen mode.
40 // We don't save shadow, transparency mode or background color because it's not
41 // worth the hassle - Gecko will reset them anyway as soon as the window is
42 // resized.
43 @interface BaseWindow : NSWindow {
44 // Data Storage
45 NSMutableDictionary* mState;
46 BOOL mDrawsIntoWindowFrame;
48 // Invalidation disabling
49 BOOL mDisabledNeedsDisplay;
51 NSTrackingArea* mTrackingArea;
53 NSRect mDirtyRect;
55 BOOL mBeingShown;
56 BOOL mDrawTitle;
57 BOOL mIsAnimationSuppressed;
59 nsTouchBar* mTouchBar;
62 - (void)importState:(NSDictionary*)aState;
63 - (NSMutableDictionary*)exportState;
64 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
65 - (BOOL)drawsContentsIntoWindowFrame;
67 // These two methods are like contentRectForFrameRect and
68 // frameRectForContentRect, but they deal with the rect of the window's "main
69 // ChildView" instead of the rect of the window's content view. The two are
70 // sometimes sized differently: The window's content view always covers the
71 // entire window, whereas the ChildView only covers the full window when
72 // drawsContentsIntoWindowFrame is YES. When drawsContentsIntoWindowFrame is NO,
73 // there's a titlebar-sized gap above the ChildView within the content view.
74 - (NSRect)childViewRectForFrameRect:(NSRect)aFrameRect;
75 - (NSRect)frameRectForChildViewRect:(NSRect)aChildViewRect;
77 - (void)mouseEntered:(NSEvent*)aEvent;
78 - (void)mouseExited:(NSEvent*)aEvent;
79 - (void)mouseMoved:(NSEvent*)aEvent;
80 - (void)updateTrackingArea;
81 - (NSView*)trackingAreaView;
83 - (void)setBeingShown:(BOOL)aValue;
84 - (BOOL)isBeingShown;
85 - (BOOL)isVisibleOrBeingShown;
87 - (void)setIsAnimationSuppressed:(BOOL)aValue;
88 - (BOOL)isAnimationSuppressed;
90 // Returns an autoreleased NSArray containing the NSViews that we consider the
91 // "contents" of this window. All views in the returned array are subviews of
92 // this window's content view. However, the array may not include all of the
93 // content view's subviews; concretely, the ToolbarWindow implementation will
94 // exclude its MOZTitlebarView from the array that is returned here.
95 // In the vast majority of cases, the array will only have a single element:
96 // this window's mainChildView.
97 - (NSArray<NSView*>*)contentViewContents;
99 - (ChildView*)mainChildView;
101 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle;
102 - (BOOL)wantsTitleDrawn;
104 - (void)disableSetNeedsDisplay;
105 - (void)enableSetNeedsDisplay;
107 - (NSRect)getAndResetNativeDirtyRect;
109 - (void)setEffectViewWrapperForStyle:(mozilla::WindowShadow)aStyle;
110 @property(nonatomic) mozilla::WindowShadow shadowStyle;
112 - (void)releaseJSObjects;
114 @end
116 @interface NSWindow (Undocumented)
117 - (NSDictionary*)shadowParameters;
119 // Present in the same form on OS X since at least OS X 10.5.
120 - (NSRect)contentRectForFrameRect:(NSRect)windowFrame
121 styleMask:(NSUInteger)windowStyle;
122 - (NSRect)frameRectForContentRect:(NSRect)windowContentRect
123 styleMask:(NSUInteger)windowStyle;
125 // Present since at least OS X 10.5. The OS calls this method on NSWindow
126 // (and its subclasses) to find out which NSFrameView subclass to instantiate
127 // to create its "frame view".
128 + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
130 @end
132 @interface PopupWindow : BaseWindow {
133 @private
134 BOOL mIsContextMenu;
137 - (id)initWithContentRect:(NSRect)contentRect
138 styleMask:(NSUInteger)styleMask
139 backing:(NSBackingStoreType)bufferingType
140 defer:(BOOL)deferCreation;
141 - (BOOL)isContextMenu;
142 - (void)setIsContextMenu:(BOOL)flag;
143 - (BOOL)canBecomeMainWindow;
145 @end
147 @interface BorderlessWindow : BaseWindow {
150 - (BOOL)canBecomeKeyWindow;
151 - (BOOL)canBecomeMainWindow;
153 @end
155 @interface WindowDelegate : NSObject <NSWindowDelegate> {
156 nsCocoaWindow* mGeckoWindow; // [WEAK] (we are owned by the window)
157 // Used to avoid duplication when we send NS_ACTIVATE and
158 // NS_DEACTIVATE to Gecko for toplevel widgets. Starts out
159 // false.
160 bool mToplevelActiveState;
161 BOOL mHasEverBeenZoomed;
163 + (void)paintMenubarForWindow:(NSWindow*)aWindow;
164 - (id)initWithGeckoWindow:(nsCocoaWindow*)geckoWind;
165 - (void)windowDidResize:(NSNotification*)aNotification;
166 - (nsCocoaWindow*)geckoWidget;
167 - (bool)toplevelActiveState;
168 - (void)sendToplevelActivateEvents;
169 - (void)sendToplevelDeactivateEvents;
170 @end
172 @interface MOZTitlebarView : NSVisualEffectView
173 @end
175 @interface FullscreenTitlebarTracker : NSTitlebarAccessoryViewController
176 - (FullscreenTitlebarTracker*)init;
177 @end
179 // NSWindow subclass for handling windows with toolbars.
180 @interface ToolbarWindow : BaseWindow {
181 // This window's titlebar view, if present.
182 // Will be nil if the window has neither a titlebar nor a unified toolbar.
183 // This view is a subview of the window's content view and gets created and
184 // destroyed by updateTitlebarView.
185 MOZTitlebarView* mTitlebarView; // [STRONG]
186 // mFullscreenTitlebarTracker attaches an invisible rectangle to the system
187 // title bar. This allows us to detect when the title bar is showing in
188 // fullscreen.
189 FullscreenTitlebarTracker* mFullscreenTitlebarTracker;
191 CGFloat mUnifiedToolbarHeight;
192 CGFloat mSheetAttachmentPosition;
193 CGFloat mMenuBarHeight;
194 /* Store the height of the titlebar when this window is initialized. The
195 titlebarHeight getter returns 0 when in fullscreen, which is not useful in
196 some cases. */
197 CGFloat mInitialTitlebarHeight;
198 NSRect mWindowButtonsRect;
200 - (void)setUnifiedToolbarHeight:(CGFloat)aHeight;
201 - (CGFloat)unifiedToolbarHeight;
202 - (CGFloat)titlebarHeight;
203 - (NSRect)titlebarRect;
204 - (void)setTitlebarNeedsDisplay;
205 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
206 - (void)setSheetAttachmentPosition:(CGFloat)aY;
207 - (CGFloat)sheetAttachmentPosition;
208 - (void)placeWindowButtons:(NSRect)aRect;
209 - (NSRect)windowButtonsRect;
210 - (void)windowMainStateChanged;
211 @end
213 class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
214 private:
215 typedef nsBaseWidget Inherited;
217 public:
218 nsCocoaWindow();
220 NS_DECL_ISUPPORTS_INHERITED
221 NS_DECL_NSPIWIDGETCOCOA; // semicolon for clang-format bug 1629756
223 [[nodiscard]] virtual nsresult Create(nsIWidget* aParent,
224 nsNativeWidget aNativeParent,
225 const DesktopIntRect& aRect,
226 InitData* = nullptr) override;
228 [[nodiscard]] virtual nsresult Create(nsIWidget* aParent,
229 nsNativeWidget aNativeParent,
230 const LayoutDeviceIntRect& aRect,
231 InitData* = nullptr) override;
233 virtual void Destroy() override;
235 virtual void Show(bool aState) override;
236 virtual bool NeedsRecreateToReshow() override;
238 virtual nsIWidget* GetSheetWindowParent(void) override;
239 virtual void Enable(bool aState) override;
240 virtual bool IsEnabled() const override;
241 virtual void SetModal(bool aState) override;
242 virtual void SetFakeModal(bool aState) override;
243 virtual bool IsRunningAppModal() override;
244 virtual bool IsVisible() const override;
245 virtual void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
246 virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
247 virtual LayoutDeviceIntPoint GetClientOffset() override;
248 virtual LayoutDeviceIntMargin ClientToWindowMargin() override;
250 virtual void* GetNativeData(uint32_t aDataType) override;
252 virtual void ConstrainPosition(DesktopIntPoint&) override;
253 virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override;
254 virtual void Move(double aX, double aY) override;
255 virtual nsSizeMode SizeMode() override { return mSizeMode; }
256 virtual void SetSizeMode(nsSizeMode aMode) override;
257 virtual void GetWorkspaceID(nsAString& workspaceID) override;
258 virtual void MoveToWorkspace(const nsAString& workspaceID) override;
259 virtual void SuppressAnimation(bool aSuppress) override;
260 virtual void HideWindowChrome(bool aShouldHide) override;
262 virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
263 virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
264 uint16_t aDuration,
265 nsISupports* aData,
266 nsIRunnable* aCallback) override;
267 virtual void CleanupFullscreenTransition() override;
268 nsresult MakeFullScreen(bool aFullScreen) final;
269 nsresult MakeFullScreenWithNativeTransition(bool aFullScreen) final;
270 NSAnimation* FullscreenTransitionAnimation() const {
271 return mFullscreenTransitionAnimation;
273 void ReleaseFullscreenTransitionAnimation() {
274 MOZ_ASSERT(mFullscreenTransitionAnimation,
275 "Should only be called when there is animation");
276 [mFullscreenTransitionAnimation release];
277 mFullscreenTransitionAnimation = nil;
280 virtual void Resize(double aWidth, double aHeight, bool aRepaint) override;
281 virtual void Resize(double aX, double aY, double aWidth, double aHeight,
282 bool aRepaint) override;
283 NSRect GetClientCocoaRect();
284 virtual LayoutDeviceIntRect GetClientBounds() override;
285 virtual LayoutDeviceIntRect GetScreenBounds() override;
286 void ReportMoveEvent();
287 void ReportSizeEvent();
288 virtual void SetCursor(const Cursor&) override;
290 CGFloat BackingScaleFactor();
291 void BackingScaleFactorChanged();
292 virtual double GetDefaultScaleInternal() override;
293 virtual int32_t RoundsWidgetCoordinatesTo() override;
295 mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
296 return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
299 virtual nsresult SetTitle(const nsAString& aTitle) override;
301 virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
302 virtual WindowRenderer* GetWindowRenderer() override;
303 virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
304 nsEventStatus& aStatus) override;
305 virtual void CaptureRollupEvents(bool aDoCapture) override;
306 [[nodiscard]] virtual nsresult GetAttention(int32_t aCycleCount) override;
307 virtual bool HasPendingInputEvent() override;
308 virtual TransparencyMode GetTransparencyMode() override;
309 virtual void SetTransparencyMode(TransparencyMode aMode) override;
310 virtual void SetWindowShadowStyle(mozilla::WindowShadow aStyle) override;
311 virtual void SetWindowOpacity(float aOpacity) override;
312 virtual void SetWindowTransform(
313 const mozilla::gfx::Matrix& aTransform) override;
314 virtual void SetInputRegion(const InputRegion&) override;
315 virtual void SetColorScheme(
316 const mozilla::Maybe<mozilla::ColorScheme>&) override;
317 virtual void SetShowsToolbarButton(bool aShow) override;
318 virtual void SetSupportsNativeFullscreen(bool aShow) override;
319 virtual void SetWindowAnimationType(WindowAnimationType aType) override;
320 virtual void SetDrawsTitle(bool aDrawTitle) override;
321 virtual nsresult SetNonClientMargins(const LayoutDeviceIntMargin&) override;
322 void SetDrawsInTitlebar(bool aState);
323 virtual void UpdateThemeGeometries(
324 const nsTArray<ThemeGeometry>& aThemeGeometries) override;
325 virtual nsresult SynthesizeNativeMouseEvent(
326 LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
327 mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
328 nsIObserver* aObserver) override;
329 virtual nsresult SynthesizeNativeMouseScrollEvent(
330 LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage, double aDeltaX,
331 double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
332 uint32_t aAdditionalFlags, nsIObserver* aObserver) override;
333 virtual void LockAspectRatio(bool aShouldLock) override;
335 void DispatchSizeModeEvent();
336 void DispatchOcclusionEvent();
338 // be notified that a some form of drag event needs to go into Gecko
339 virtual bool DragEvent(unsigned int aMessage,
340 mozilla::gfx::Point aMouseGlobal,
341 UInt16 aKeyModifiers);
343 bool HasModalDescendents() { return mNumModalDescendents > 0; }
344 NSWindow* GetCocoaWindow() { return mWindow; }
346 void SetMenuBar(RefPtr<nsMenuBarX>&& aMenuBar);
347 nsMenuBarX* GetMenuBar();
349 virtual void SetInputContext(const InputContext& aContext,
350 const InputContextAction& aAction) override;
351 virtual InputContext GetInputContext() override { return mInputContext; }
352 MOZ_CAN_RUN_SCRIPT virtual bool GetEditCommands(
353 mozilla::NativeKeyBindingsType aType,
354 const mozilla::WidgetKeyboardEvent& aEvent,
355 nsTArray<mozilla::CommandInt>& aCommands) override;
357 void SetPopupWindowLevel();
359 bool InFullScreenMode() const { return mInFullScreenMode; }
361 void PauseOrResumeCompositor(bool aPause) override;
363 bool AsyncPanZoomEnabled() const override;
365 bool StartAsyncAutoscroll(const ScreenPoint& aAnchorLocation,
366 const ScrollableLayerGuid& aGuid) override;
367 void StopAsyncAutoscroll(const ScrollableLayerGuid& aGuid) override;
369 // Class method versions of NSWindow/Delegate callbacks which need to
370 // access object state.
371 void CocoaWindowWillEnterFullscreen(bool aFullscreen);
372 void CocoaWindowDidEnterFullscreen(bool aFullscreen);
373 void CocoaWindowDidResize();
374 void CocoaSendToplevelActivateEvents();
375 void CocoaSendToplevelDeactivateEvents();
377 enum class TransitionType {
378 Windowed,
379 Fullscreen,
380 EmulatedFullscreen,
381 Miniaturize,
382 Deminiaturize,
383 Zoom,
385 void FinishCurrentTransitionIfMatching(const TransitionType& aTransition);
387 // Called when something has happened that might cause us to update our
388 // fullscreen state. Returns true if we updated state. We'll call this
389 // on window resize, and we'll call it when we enter or exit fullscreen,
390 // since fullscreen to-and-from zoomed windows won't necessarily trigger
391 // a resize.
392 bool HandleUpdateFullscreenOnResize();
394 protected:
395 virtual ~nsCocoaWindow();
397 nsresult CreateNativeWindow(const NSRect& aRect, BorderStyle aBorderStyle,
398 bool aRectIsFrameRect, bool aIsPrivateBrowsing);
399 nsresult CreatePopupContentView(const LayoutDeviceIntRect& aRect, InitData*);
400 void DestroyNativeWindow();
401 void UpdateBounds();
402 int32_t GetWorkspaceID();
404 void DoResize(double aX, double aY, double aWidth, double aHeight,
405 bool aRepaint, bool aConstrainToCurrentScreen);
407 void UpdateFullscreenState(bool aFullScreen, bool aNativeMode);
408 nsresult DoMakeFullScreen(bool aFullScreen, bool aUseSystemTransition);
410 virtual already_AddRefed<nsIWidget> AllocateChildPopupWidget() override {
411 return nsIWidget::CreateTopLevelWindow();
414 nsIWidget* mParent; // if we're a popup, this is our parent [WEAK]
415 nsIWidget* mAncestorLink; // link to traverse ancestors [WEAK]
416 BaseWindow* mWindow; // our cocoa window [STRONG]
417 WindowDelegate*
418 mDelegate; // our delegate for processing window msgs [STRONG]
419 RefPtr<nsMenuBarX> mMenuBar;
420 NSWindow* mSheetWindowParent; // if this is a sheet, this is the NSWindow
421 // it's attached to
422 nsChildView*
423 mPopupContentView; // if this is a popup, this is its content widget
424 // if this is a toplevel window, and there is any ongoing fullscreen
425 // transition, it is the animation object.
426 NSAnimation* mFullscreenTransitionAnimation;
427 mozilla::WindowShadow mShadowStyle;
429 CGFloat mBackingScaleFactor;
430 CGFloat mAspectRatio;
432 WindowAnimationType mAnimationType;
434 bool mWindowMadeHere; // true if we created the window, false for embedding
435 bool mSheetNeedsShow; // if this is a sheet, are we waiting to be shown?
436 // this is used for sibling sheet contention only
437 nsSizeMode mSizeMode;
438 bool mInFullScreenMode;
439 // Whether we are currently using native fullscreen. It could be false because
440 // we are in the emulated fullscreen where we do not use the native
441 // fullscreen.
442 bool mInNativeFullScreenMode;
444 mozilla::Maybe<TransitionType> mTransitionCurrent;
445 std::queue<TransitionType> mTransitionsPending;
447 // Sometimes we add a transition that wasn't requested by a caller. We do this
448 // to manage transitions between states that otherwise would be rejected by
449 // Cocoa. When we do this, it's useful to know when we are handling an added
450 // transition because we don't want to send size mode events when they
451 // execute.
452 bool mIsTransitionCurrentAdded = false;
454 // Whether we are treating the next resize as the start of a fullscreen
455 // transition. If we are, which direction are we going: Fullscreen or
456 // Windowed.
457 mozilla::Maybe<TransitionType> mUpdateFullscreenOnResize;
459 bool IsInTransition() { return mTransitionCurrent.isSome(); }
460 void QueueTransition(const TransitionType& aTransition);
461 void ProcessTransitions();
463 bool mInProcessTransitions = false;
465 // While running an emulated fullscreen transition, we want to suppress
466 // sending size mode events due to window resizing. We fix it up at the end
467 // when the transition is complete.
468 bool mSuppressSizeModeEvents = false;
470 // Ignore occlusion events caused by displaying the temporary fullscreen
471 // window during the fullscreen transition animation because only focused
472 // contexts are permitted to enter DOM fullscreen.
473 int mIgnoreOcclusionCount;
475 // Set to true when a native fullscreen transition is initiated -- either to
476 // or from fullscreen -- and set to false when it is complete. During this
477 // period, we presume the window is visible, which prevents us from sending
478 // unnecessary OcclusionStateChanged events.
479 bool mHasStartedNativeFullscreen;
481 bool mModal;
482 bool mFakeModal;
484 bool mIsAnimationSuppressed;
486 bool mInReportMoveEvent; // true if in a call to ReportMoveEvent().
487 bool mInResize; // true if in a call to DoResize().
488 bool mWindowTransformIsIdentity;
489 bool mAlwaysOnTop;
490 bool mAspectRatioLocked;
492 int32_t mNumModalDescendents;
493 InputContext mInputContext;
494 NSWindowAnimationBehavior mWindowAnimationBehavior;
496 private:
497 // This is class state for tracking which nsCocoaWindow, if any, is in the
498 // middle of a native fullscreen transition.
499 static nsCocoaWindow* sWindowInNativeTransition;
501 // This function returns true if the caller has been able to claim the sole
502 // permission to start a native transition. It must be followed by a call
503 // to EndOurNativeTransition() when the native transition is complete.
504 bool CanStartNativeTransition();
505 void EndOurNativeTransition();
507 // true if Show() has been called.
508 bool mWasShown;
511 #endif // nsCocoaWindow_h_