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