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/. */
5 
6 #ifndef nsCocoaWindow_h_
7 #define nsCocoaWindow_h_
8 
9 #undef DARWIN
10 
11 #import <Cocoa/Cocoa.h>
12 
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 
20 class nsCocoaWindow;
21 class nsChildView;
22 class nsMenuBarX;
23 @class ChildView;
24 
25 typedef struct _nsCocoaWindowList {
_nsCocoaWindowList_nsCocoaWindowList26   _nsCocoaWindowList() : prev(nullptr), window(nullptr) {}
27   struct _nsCocoaWindowList* prev;
28   nsCocoaWindow* window;  // Weak
29 } nsCocoaWindowList;
30 
31 // NSWindow subclass that is the base class for all of our own window classes.
32 // Among other things, this class handles the storage of those settings that
33 // need to be persisted across window destruction and reconstruction, i.e. when
34 // switching to and from fullscreen mode.
35 // We don't save shadow, transparency mode or background color because it's not
36 // worth the hassle - Gecko will reset them anyway as soon as the window is
37 // resized.
38 @interface BaseWindow : NSWindow {
39   // Data Storage
40   NSMutableDictionary* mState;
41   BOOL mDrawsIntoWindowFrame;
42 
43   // Invalidation disabling
44   BOOL mDisabledNeedsDisplay;
45 
46   NSTrackingArea* mTrackingArea;
47 
48   NSRect mDirtyRect;
49 
50   BOOL mBeingShown;
51   BOOL mDrawTitle;
52   BOOL mUseMenuStyle;
53   BOOL mIsAnimationSuppressed;
54 
55   nsTouchBar* mTouchBar;
56 }
57 
58 - (void)importState:(NSDictionary*)aState;
59 - (NSMutableDictionary*)exportState;
60 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
61 - (BOOL)drawsContentsIntoWindowFrame;
62 
63 // These two methods are like contentRectForFrameRect and frameRectForContentRect,
64 // but they deal with the rect of the window's "main ChildView" instead of the
65 // rect of the window's content view. The two are sometimes sized differently: The
66 // window's content view always covers the entire window, whereas the ChildView
67 // only covers the full window when drawsContentsIntoWindowFrame is YES. When
68 // drawsContentsIntoWindowFrame is NO, there's a titlebar-sized gap above the
69 // ChildView within the content view.
70 - (NSRect)childViewRectForFrameRect:(NSRect)aFrameRect;
71 - (NSRect)frameRectForChildViewRect:(NSRect)aChildViewRect;
72 
73 - (void)mouseEntered:(NSEvent*)aEvent;
74 - (void)mouseExited:(NSEvent*)aEvent;
75 - (void)mouseMoved:(NSEvent*)aEvent;
76 - (void)updateTrackingArea;
77 - (NSView*)trackingAreaView;
78 
79 - (void)setBeingShown:(BOOL)aValue;
80 - (BOOL)isBeingShown;
81 - (BOOL)isVisibleOrBeingShown;
82 
83 - (void)setIsAnimationSuppressed:(BOOL)aValue;
84 - (BOOL)isAnimationSuppressed;
85 
86 // Returns an autoreleased NSArray containing the NSViews that we consider the
87 // "contents" of this window. All views in the returned array are subviews of
88 // this window's content view. However, the array may not include all of the
89 // content view's subviews; concretely, the ToolbarWindow implementation will
90 // exclude its MOZTitlebarView from the array that is returned here.
91 // In the vast majority of cases, the array will only have a single element:
92 // this window's mainChildView.
93 - (NSArray<NSView*>*)contentViewContents;
94 
95 - (ChildView*)mainChildView;
96 
97 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle;
98 - (BOOL)wantsTitleDrawn;
99 
100 - (void)disableSetNeedsDisplay;
101 - (void)enableSetNeedsDisplay;
102 
103 - (NSRect)getAndResetNativeDirtyRect;
104 
105 - (void)setUseMenuStyle:(BOOL)aValue;
106 @property(nonatomic) mozilla::StyleWindowShadow shadowStyle;
107 
108 - (void)releaseJSObjects;
109 
110 @end
111 
112 @interface NSWindow (Undocumented)
113 
114 // If a window has been explicitly removed from the "window cache" (to
115 // deactivate it), it's sometimes necessary to "reset" it to reactivate it
116 // (and put it back in the "window cache").  One way to do this, which Apple
117 // often uses, is to set the "window number" to '-1' and then back to its
118 // original value.
119 - (void)_setWindowNumber:(NSInteger)aNumber;
120 
121 - (BOOL)bottomCornerRounded;
122 
123 // Present in the same form on OS X since at least OS X 10.5.
124 - (NSRect)contentRectForFrameRect:(NSRect)windowFrame styleMask:(NSUInteger)windowStyle;
125 - (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle;
126 
127 // Present since at least OS X 10.5.  The OS calls this method on NSWindow
128 // (and its subclasses) to find out which NSFrameView subclass to instantiate
129 // to create its "frame view".
130 + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
131 
132 @end
133 
134 @interface PopupWindow : BaseWindow {
135  @private
136   BOOL mIsContextMenu;
137 }
138 
139 - (id)initWithContentRect:(NSRect)contentRect
140                 styleMask:(NSUInteger)styleMask
141                   backing:(NSBackingStoreType)bufferingType
142                     defer:(BOOL)deferCreation;
143 - (BOOL)isContextMenu;
144 - (void)setIsContextMenu:(BOOL)flag;
145 - (BOOL)canBecomeMainWindow;
146 
147 @end
148 
149 @interface BorderlessWindow : BaseWindow {
150 }
151 
152 - (BOOL)canBecomeKeyWindow;
153 - (BOOL)canBecomeMainWindow;
154 
155 @end
156 
157 @interface WindowDelegate : NSObject <NSWindowDelegate> {
158   nsCocoaWindow* mGeckoWindow;  // [WEAK] (we are owned by the window)
159   // Used to avoid duplication when we send NS_ACTIVATE and
160   // NS_DEACTIVATE to Gecko for toplevel widgets.  Starts out
161   // false.
162   bool mToplevelActiveState;
163   BOOL mHasEverBeenZoomed;
164 }
165 + (void)paintMenubarForWindow:(NSWindow*)aWindow;
166 - (id)initWithGeckoWindow:(nsCocoaWindow*)geckoWind;
167 - (void)windowDidResize:(NSNotification*)aNotification;
168 - (nsCocoaWindow*)geckoWidget;
169 - (bool)toplevelActiveState;
170 - (void)sendToplevelActivateEvents;
171 - (void)sendToplevelDeactivateEvents;
172 @end
173 
174 @interface MOZTitlebarView : NSVisualEffectView
175 @end
176 
177 @interface FullscreenTitlebarTracker : NSTitlebarAccessoryViewController
178 - (FullscreenTitlebarTracker*)init;
179 @end
180 
181 // NSWindow subclass for handling windows with toolbars.
182 @interface ToolbarWindow : BaseWindow {
183   // This window's titlebar view, if present.
184   // Will be nil if the window has neither a titlebar nor a unified toolbar.
185   // This view is a subview of the window's content view and gets created and
186   // destroyed by updateTitlebarView.
187   MOZTitlebarView* mTitlebarView;  // [STRONG]
188   // mFullscreenTitlebarTracker attaches an invisible rectangle to the system
189   // title bar. This allows us to detect when the title bar is showing in
190   // fullscreen.
191   FullscreenTitlebarTracker* mFullscreenTitlebarTracker;
192 
193   CGFloat mUnifiedToolbarHeight;
194   CGFloat mSheetAttachmentPosition;
195   CGFloat mMenuBarHeight;
196   /* Store the height of the titlebar when this window is initialized. The
197      titlebarHeight getter returns 0 when in fullscreen, which is not useful in
198      some cases. */
199   CGFloat mInitialTitlebarHeight;
200   NSRect mWindowButtonsRect;
201 }
202 - (void)setUnifiedToolbarHeight:(CGFloat)aHeight;
203 - (CGFloat)unifiedToolbarHeight;
204 - (CGFloat)titlebarHeight;
205 - (NSRect)titlebarRect;
206 - (void)setTitlebarNeedsDisplay;
207 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
208 - (void)setSheetAttachmentPosition:(CGFloat)aY;
209 - (CGFloat)sheetAttachmentPosition;
210 - (void)placeWindowButtons:(NSRect)aRect;
211 - (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
212 - (void)windowMainStateChanged;
213 @end
214 
215 class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
216  private:
217   typedef nsBaseWidget Inherited;
218 
219  public:
220   nsCocoaWindow();
221 
222   NS_DECL_ISUPPORTS_INHERITED
223   NS_DECL_NSPIWIDGETCOCOA;  // semicolon for clang-format bug 1629756
224 
225   [[nodiscard]] virtual nsresult Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
226                                         const DesktopIntRect& aRect,
227                                         nsWidgetInitData* aInitData = nullptr) override;
228 
229   [[nodiscard]] virtual nsresult Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
230                                         const LayoutDeviceIntRect& aRect,
231                                         nsWidgetInitData* aInitData = nullptr) override;
232 
233   virtual void Destroy() override;
234 
235   virtual void Show(bool aState) override;
236   virtual bool NeedsRecreateToReshow() override;
237 
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 LayoutDeviceIntSize ClientToWindowSize(const LayoutDeviceIntSize& aClientSize) override;
249 
250   virtual void* GetNativeData(uint32_t aDataType) override;
251 
252   virtual void ConstrainPosition(bool aAllowSlop, int32_t* aX, int32_t* aY) override;
253   virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override;
254   virtual void Move(double aX, double aY) override;
255   virtual void SetSizeMode(nsSizeMode aMode) override;
256   virtual void GetWorkspaceID(nsAString& workspaceID) override;
257   virtual void MoveToWorkspace(const nsAString& workspaceID) override;
258   virtual void SuppressAnimation(bool aSuppress) override;
259   virtual void HideWindowChrome(bool aShouldHide) override;
260 
261   void WillEnterFullScreen(bool aFullScreen);
262   void EnteredFullScreen(bool aFullScreen, bool aNativeMode = true);
263   virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
264   virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage, uint16_t aDuration,
265                                            nsISupports* aData, nsIRunnable* aCallback) override;
266   virtual void CleanupFullscreenTransition() override;
267   nsresult MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen = nullptr) final;
268   nsresult MakeFullScreenWithNativeTransition(bool aFullScreen,
269                                               nsIScreen* aTargetScreen = nullptr) final;
FullscreenTransitionAnimation()270   NSAnimation* FullscreenTransitionAnimation() const { return mFullscreenTransitionAnimation; }
ReleaseFullscreenTransitionAnimation()271   void ReleaseFullscreenTransitionAnimation() {
272     MOZ_ASSERT(mFullscreenTransitionAnimation, "Should only be called when there is animation");
273     [mFullscreenTransitionAnimation release];
274     mFullscreenTransitionAnimation = nil;
275   }
276 
277   virtual void Resize(double aWidth, double aHeight, bool aRepaint) override;
278   virtual void Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
279   NSRect GetClientCocoaRect();
280   virtual LayoutDeviceIntRect GetClientBounds() override;
281   virtual LayoutDeviceIntRect GetScreenBounds() override;
282   void ReportMoveEvent();
283   void ReportSizeEvent();
284   virtual void SetCursor(const Cursor&) override;
285 
286   CGFloat BackingScaleFactor();
287   void BackingScaleFactorChanged();
288   virtual double GetDefaultScaleInternal() override;
289   virtual int32_t RoundsWidgetCoordinatesTo() override;
290 
GetDesktopToDeviceScale()291   mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
292     return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
293   }
294 
295   virtual nsresult SetTitle(const nsAString& aTitle) override;
296 
297   virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
298   virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
299   virtual LayerManager* GetLayerManager(
300       PLayerTransactionChild* aShadowManager = nullptr,
301       LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
302       LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
303   virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
304   virtual void CaptureRollupEvents(nsIRollupListener* aListener, bool aDoCapture) override;
305   [[nodiscard]] virtual nsresult GetAttention(int32_t aCycleCount) override;
306   virtual bool HasPendingInputEvent() override;
307   virtual nsTransparencyMode GetTransparencyMode() override;
308   virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
309   virtual void SetWindowShadowStyle(mozilla::StyleWindowShadow aStyle) override;
310   virtual void SetWindowOpacity(float aOpacity) override;
311   virtual void SetWindowTransform(const mozilla::gfx::Matrix& aTransform) override;
312   virtual void SetWindowMouseTransparent(bool aIsTransparent) override;
313   virtual void SetShowsToolbarButton(bool aShow) override;
314   virtual void SetSupportsNativeFullscreen(bool aShow) override;
315   virtual void SetWindowAnimationType(WindowAnimationType aType) override;
316   virtual void SetDrawsTitle(bool aDrawTitle) override;
317   virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
318   virtual void SetDrawsInTitlebar(bool aState) override;
319   virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
320   virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
321                                               NativeMouseMessage aNativeMessage,
322                                               mozilla::MouseButton aButton,
323                                               nsIWidget::Modifiers aModifierFlags,
324                                               nsIObserver* aObserver) override;
325   virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,
326                                                     uint32_t aNativeMessage, double aDeltaX,
327                                                     double aDeltaY, double aDeltaZ,
328                                                     uint32_t aModifierFlags,
329                                                     uint32_t aAdditionalFlags,
330                                                     nsIObserver* aObserver) override;
331   virtual void LockAspectRatio(bool aShouldLock) override;
332 
333   void DispatchSizeModeEvent();
334   void DispatchOcclusionEvent();
335 
336   // be notified that a some form of drag event needs to go into Gecko
337   virtual bool DragEvent(unsigned int aMessage, mozilla::gfx::Point aMouseGlobal,
338                          UInt16 aKeyModifiers);
339 
HasModalDescendents()340   bool HasModalDescendents() { return mNumModalDescendents > 0; }
GetCocoaWindow()341   NSWindow* GetCocoaWindow() { return mWindow; }
342 
343   void SetMenuBar(RefPtr<nsMenuBarX>&& aMenuBar);
344   nsMenuBarX* GetMenuBar();
345 
346   virtual void SetInputContext(const InputContext& aContext,
347                                const InputContextAction& aAction) override;
GetInputContext()348   virtual InputContext GetInputContext() override { return mInputContext; }
349   MOZ_CAN_RUN_SCRIPT virtual bool GetEditCommands(
350       NativeKeyBindingsType aType, const mozilla::WidgetKeyboardEvent& aEvent,
351       nsTArray<mozilla::CommandInt>& aCommands) override;
352 
353   void SetPopupWindowLevel();
354 
InFullScreenMode()355   bool InFullScreenMode() const { return mInFullScreenMode; }
356 
357   void PauseCompositor();
358   void ResumeCompositor();
359 
360   bool AsyncPanZoomEnabled() const override;
361 
362   bool StartAsyncAutoscroll(const ScreenPoint& aAnchorLocation,
363                             const ScrollableLayerGuid& aGuid) override;
364   void StopAsyncAutoscroll(const ScrollableLayerGuid& aGuid) override;
365 
366  protected:
367   virtual ~nsCocoaWindow();
368 
369   nsresult CreateNativeWindow(const NSRect& aRect, nsBorderStyle aBorderStyle,
370                               bool aRectIsFrameRect);
371   nsresult CreatePopupContentView(const LayoutDeviceIntRect& aRect, nsWidgetInitData* aInitData);
372   void DestroyNativeWindow();
373   void UpdateBounds();
374   int32_t GetWorkspaceID();
375 
376   void DoResize(double aX, double aY, double aWidth, double aHeight, bool aRepaint,
377                 bool aConstrainToCurrentScreen);
378 
379   inline bool ShouldToggleNativeFullscreen(bool aFullScreen, bool aUseSystemTransition);
380   void UpdateFullscreenState(bool aFullScreen, bool aNativeMode);
381   nsresult DoMakeFullScreen(bool aFullScreen, bool aUseSystemTransition);
382 
AllocateChildPopupWidget()383   virtual already_AddRefed<nsIWidget> AllocateChildPopupWidget() override {
384     return nsIWidget::CreateTopLevelWindow();
385   }
386 
387   nsIWidget* mParent;         // if we're a popup, this is our parent [WEAK]
388   nsIWidget* mAncestorLink;   // link to traverse ancestors [WEAK]
389   BaseWindow* mWindow;        // our cocoa window [STRONG]
390   WindowDelegate* mDelegate;  // our delegate for processing window msgs [STRONG]
391   RefPtr<nsMenuBarX> mMenuBar;
392   NSWindow* mSheetWindowParent;    // if this is a sheet, this is the NSWindow it's attached to
393   nsChildView* mPopupContentView;  // if this is a popup, this is its content widget
394   // if this is a toplevel window, and there is any ongoing fullscreen
395   // transition, it is the animation object.
396   NSAnimation* mFullscreenTransitionAnimation;
397   mozilla::StyleWindowShadow mShadowStyle;
398 
399   CGFloat mBackingScaleFactor;
400   CGFloat mAspectRatio;
401 
402   WindowAnimationType mAnimationType;
403 
404   bool mWindowMadeHere;  // true if we created the window, false for embedding
405   bool mSheetNeedsShow;  // if this is a sheet, are we waiting to be shown?
406                          // this is used for sibling sheet contention only
407   bool mInFullScreenMode;
408   bool mInFullScreenTransition;  // true from the request to enter/exit fullscreen
409                                  // (MakeFullScreen() call) to EnteredFullScreen()
410 
411   // Ignore occlusion events caused by displaying the temporary fullscreen
412   // window during the fullscreen transition animation because only focused
413   // contexts are permitted to enter DOM fullscreen.
414   int mIgnoreOcclusionCount;
415 
416   bool mModal;
417   bool mFakeModal;
418 
419   // Whether we are currently using native fullscreen. It could be false because
420   // we are in the DOM fullscreen where we do not use the native fullscreen.
421   bool mInNativeFullScreenMode;
422 
423   bool mIsAnimationSuppressed;
424 
425   bool mInReportMoveEvent;  // true if in a call to ReportMoveEvent().
426   bool mInResize;           // true if in a call to DoResize().
427   bool mWindowTransformIsIdentity;
428   bool mAlwaysOnTop;
429   bool mAspectRatioLocked;
430 
431   int32_t mNumModalDescendents;
432   InputContext mInputContext;
433   NSWindowAnimationBehavior mWindowAnimationBehavior;
434 
435  private:
436   // true if Show() has been called.
437   bool mWasShown;
438 };
439 
440 #endif  // nsCocoaWindow_h_
441