diff options
Diffstat (limited to 'widget/cocoa')
-rw-r--r-- | widget/cocoa/MacThemeGeometryType.h | 4 | ||||
-rw-r--r-- | widget/cocoa/ScreenHelperCocoa.mm | 28 | ||||
-rw-r--r-- | widget/cocoa/TextInputHandler.mm | 68 | ||||
-rw-r--r-- | widget/cocoa/VibrancyManager.h | 1 | ||||
-rw-r--r-- | widget/cocoa/VibrancyManager.mm | 33 | ||||
-rw-r--r-- | widget/cocoa/ViewRegion.mm | 53 | ||||
-rw-r--r-- | widget/cocoa/moz.build | 6 | ||||
-rw-r--r-- | widget/cocoa/nsChildView.mm | 162 | ||||
-rw-r--r-- | widget/cocoa/nsCocoaWindow.h | 241 | ||||
-rw-r--r-- | widget/cocoa/nsCocoaWindow.mm | 809 | ||||
-rw-r--r-- | widget/cocoa/nsLookAndFeel.h | 14 | ||||
-rw-r--r-- | widget/cocoa/nsLookAndFeel.mm | 103 | ||||
-rw-r--r-- | widget/cocoa/nsNativeThemeCocoa.h | 4 | ||||
-rw-r--r-- | widget/cocoa/nsNativeThemeCocoa.mm | 70 | ||||
-rw-r--r-- | widget/cocoa/nsNativeThemeColors.h | 37 | ||||
-rw-r--r-- | widget/cocoa/nsPIWidgetCocoa.idl | 37 | ||||
-rw-r--r-- | widget/cocoa/nsWindowMap.mm | 54 |
17 files changed, 485 insertions, 1239 deletions
diff --git a/widget/cocoa/MacThemeGeometryType.h b/widget/cocoa/MacThemeGeometryType.h index 4691dbdec2..91879503e1 100644 --- a/widget/cocoa/MacThemeGeometryType.h +++ b/widget/cocoa/MacThemeGeometryType.h @@ -7,11 +7,7 @@ enum MacThemeGeometryType { eThemeGeometryTypeTitlebar = 1, - eThemeGeometryTypeToolbar, - eThemeGeometryTypeToolbox, eThemeGeometryTypeWindowButtons, - eThemeGeometryTypeMenu, - eThemeGeometryTypeTooltip, }; #endif diff --git a/widget/cocoa/ScreenHelperCocoa.mm b/widget/cocoa/ScreenHelperCocoa.mm index 57e1313320..2f1408e345 100644 --- a/widget/cocoa/ScreenHelperCocoa.mm +++ b/widget/cocoa/ScreenHelperCocoa.mm @@ -9,6 +9,7 @@ #import <Cocoa/Cocoa.h> #include "mozilla/Logging.h" +#include "nsCocoaFeatures.h" #include "nsCocoaUtils.h" #include "nsObjCExceptions.h" @@ -109,6 +110,26 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) { pixelDepth = MAX_REPORTED_PIXEL_DEPTH; } + // What's the maximum color component value this screen can display? This + // is a reasonable stand-in for measuring peak brightness. + CGFloat componentValueMax = + aScreen.maximumPotentialExtendedDynamicRangeColorComponentValue; + + // Should we treat this as HDR? Based on spec at + // https://drafts.csswg.org/mediaqueries-5/#dynamic-range, we'll consider it + // HDR if it has pixel depth greater than 24, and if has high peak brightness, + // which we measure by checking if it can represent component values greater + // than 1.0. + // + // Also, on HDR screens, users may want to force SDR by setting a different + // colorspace, for example by using the "Photography (P3 D65)" preset. In that + // case, componentValueMax will be 1.0 and we want to treat the display as + // SDR. + bool isHDR = pixelDepth > 24 && componentValueMax > 1.0; + + // Double-check HDR against the platform capabilities. + isHDR &= nsCocoaFeatures::OnBigSurOrLater(); + float dpi = 96.0f; CGDirectDisplayID displayID = [[[aScreen deviceDescription] objectForKey:@"NSScreenNumber"] intValue]; @@ -125,9 +146,10 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) { // Getting the refresh rate is a little hard on OS X. We could use // CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little // involved. Ideally we could query it from vsync. For now, we leave it out. - RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, 0, - contentsScaleFactor, defaultCssScaleFactor, - dpi, Screen::IsPseudoDisplay::No); + RefPtr<Screen> screen = + new Screen(rect, availRect, pixelDepth, pixelDepth, 0, + contentsScaleFactor, defaultCssScaleFactor, dpi, + Screen::IsPseudoDisplay::No, Screen::IsHDR(isHDR)); return screen.forget(); NS_OBJC_END_TRY_BLOCK_RETURN(nullptr); diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 1d96a3ce82..046f1c46be 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -10,6 +10,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/AutoRestore.h" +#include "mozilla/MacStringHelpers.h" #include "mozilla/MiscEvents.h" #include "mozilla/MouseEvents.h" #include "mozilla/StaticPrefs_intl.h" @@ -321,13 +322,13 @@ static const char* GetCharacters(const nsAString& aString) { } // the result will be freed automatically by cocoa. - NSString* result = nsCocoaUtils::ToNSString(escapedStr); + NSString* result = XPCOMStringToNSString(escapedStr); return [result UTF8String]; } static const char* GetCharacters(const NSString* aString) { nsAutoString str; - nsCocoaUtils::GetStringForNSString(aString, str); + CopyNSStringToXPCOMString(aString, str); return GetCharacters(str); } @@ -835,7 +836,7 @@ bool TISInputSourceWrapper::GetStringProperty(const CFStringRef aKey, nsAString& aStr) { CFStringRef str; GetStringProperty(aKey, str); - nsCocoaUtils::GetStringForNSString((const NSString*)str, aStr); + CopyNSStringToXPCOMString((const NSString*)str, aStr); return !aStr.IsEmpty(); } @@ -883,8 +884,7 @@ bool TISInputSourceWrapper::GetPrimaryLanguage(nsAString& aPrimaryLanguage) { NS_ENSURE_TRUE(mInputSource, false); CFStringRef primaryLanguage; NS_ENSURE_TRUE(GetPrimaryLanguage(primaryLanguage), false); - nsCocoaUtils::GetStringForNSString((const NSString*)primaryLanguage, - aPrimaryLanguage); + CopyNSStringToXPCOMString((const NSString*)primaryLanguage, aPrimaryLanguage); return !aPrimaryLanguage.IsEmpty(); } @@ -985,7 +985,7 @@ void TISInputSourceWrapper::ComputeInsertStringForCharCode( } else { // If the caller isn't sure what string will be input, let's use // characters of NSEvent. - nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], aResult); + CopyNSStringToXPCOMString([aNativeKeyEvent characters], aResult); } // If control key is pressed and the eventChars is a non-printable control @@ -1156,8 +1156,8 @@ void TISInputSourceWrapper::InitKeyEvent(NSEvent* aNativeKeyEvent, // non-ASCII capable layout to ASCII capable, or from Dvorak to QWERTY. // KeyboardEvent.key value should be the switched layout's character. else if (aKeyEvent.IsMeta()) { - nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], - aKeyEvent.mKeyValue); + CopyNSStringToXPCOMString([aNativeKeyEvent characters], + aKeyEvent.mKeyValue); } // If control key is pressed, some keys may produce printable character via // [aNativeKeyEvent characters]. Otherwise, translate input character of @@ -1188,8 +1188,8 @@ void TISInputSourceWrapper::InitKeyEvent(NSEvent* aNativeKeyEvent, [aNativeKeyEvent modifierFlags]); aKeyEvent.mKeyValue = TranslateToChar(nativeKeyCode, state, kbType); } else { - nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], - aKeyEvent.mKeyValue); + CopyNSStringToXPCOMString([aNativeKeyEvent characters], + aKeyEvent.mKeyValue); // If the key value is empty, the event may be a dead key event. // If TranslateToChar() returns non-zero value, that means that // the key may input a character with different dead key state. @@ -1207,8 +1207,8 @@ void TISInputSourceWrapper::InitKeyEvent(NSEvent* aNativeKeyEvent, if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING && (aKeyEvent.mKeyValue.IsEmpty() || IsControlChar(aKeyEvent.mKeyValue[0]))) { - nsCocoaUtils::GetStringForNSString( - [aNativeKeyEvent charactersIgnoringModifiers], aKeyEvent.mKeyValue); + CopyNSStringToXPCOMString([aNativeKeyEvent charactersIgnoringModifiers], + aKeyEvent.mKeyValue); // But don't expose it if it's a control character. if (!aKeyEvent.mKeyValue.IsEmpty() && IsControlChar(aKeyEvent.mKeyValue[0])) { @@ -1243,7 +1243,7 @@ void TISInputSourceWrapper::WillDispatchKeyboardEvent( if (MOZ_LOG_TEST(gKeyLog, LogLevel::Info)) { nsAutoString chars; - nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], chars); + CopyNSStringToXPCOMString([aNativeKeyEvent characters], chars); NS_ConvertUTF16toUTF8 utf8Chars(chars); char16_t uniChar = static_cast<char16_t>(aKeyEvent.mCharCode); MOZ_LOG( @@ -2428,7 +2428,7 @@ void TextInputHandler::InsertText(NSString* aString, NSRange selectedRange = SelectedRange(); nsAutoString str; - nsCocoaUtils::GetStringForNSString(aString, str); + CopyNSStringToXPCOMString(aString, str); AutoInsertStringClearer clearer(currentKeyEvent); if (currentKeyEvent) { @@ -3849,7 +3849,7 @@ bool IMEInputHandler::DispatchCompositionCommitEvent( mSelectedRange.location += aCommitString->Length(); } else if (mIMECompositionString) { nsAutoString commitString; - nsCocoaUtils::GetStringForNSString(mIMECompositionString, commitString); + CopyNSStringToXPCOMString(mIMECompositionString, commitString); mSelectedRange.location += commitString.Length(); } mSelectedRange.length = 0; @@ -4037,7 +4037,7 @@ void IMEInputHandler::InsertTextAsCommittingComposition( } nsString str; - nsCocoaUtils::GetStringForNSString(aString, str); + CopyNSStringToXPCOMString(aString, str); if (!IsIMEComposing()) { MOZ_DIAGNOSTIC_ASSERT(!str.IsEmpty()); @@ -4171,7 +4171,7 @@ void IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString, } nsString str; - nsCocoaUtils::GetStringForNSString([aAttrString string], str); + CopyNSStringToXPCOMString([aAttrString string], str); mMarkedRange.length = str.Length(); @@ -4272,7 +4272,7 @@ NSAttributedString* IMEInputHandler::GetAttributedSubstringFromRange( if (MOZ_LOG_TEST(gIMELog, LogLevel::Info)) { nsAutoString str; - nsCocoaUtils::GetStringForNSString(nsstr, str); + CopyNSStringToXPCOMString(nsstr, str); MOZ_LOG(gIMELog, LogLevel::Info, ("%p IMEInputHandler::GetAttributedSubstringFromRange, " "computed with mIMECompositionString (result string=\"%s\")", @@ -5051,18 +5051,17 @@ nsresult TextInputHandlerBase::SynthesizeNativeKeyEvent( bool sendFlagsChangedEvent = IsModifierKey(aNativeKeyCode); NSEventType eventType = sendFlagsChangedEvent ? NSEventTypeFlagsChanged : NSEventTypeKeyDown; - NSEvent* downEvent = - [NSEvent keyEventWithType:eventType - location:NSMakePoint(0, 0) - modifierFlags:modifierFlags - timestamp:0 - windowNumber:windowNumber - context:nil - characters:nsCocoaUtils::ToNSString(aCharacters) - charactersIgnoringModifiers:nsCocoaUtils::ToNSString( - aUnmodifiedCharacters) - isARepeat:NO - keyCode:aNativeKeyCode]; + NSEvent* downEvent = [NSEvent + keyEventWithType:eventType + location:NSMakePoint(0, 0) + modifierFlags:modifierFlags + timestamp:0 + windowNumber:windowNumber + context:nil + characters:XPCOMStringToNSString(aCharacters) + charactersIgnoringModifiers:XPCOMStringToNSString(aUnmodifiedCharacters) + isARepeat:NO + keyCode:aNativeKeyCode]; NSEvent* upEvent = sendFlagsChangedEvent ? nil @@ -5232,7 +5231,7 @@ bool TextInputHandlerBase::SetSelection(NSRange& aRange) { return false; } nsAutoString nativeChars; - nsCocoaUtils::GetStringForNSString([aNativeEvent characters], nativeChars); + CopyNSStringToXPCOMString([aNativeEvent characters], nativeChars); // this is not character inputting event, simply. if (nativeChars.IsEmpty() || @@ -5314,7 +5313,7 @@ void TextInputHandlerBase::KeyEventState::InitKeyEvent( if (!mInsertedString.IsEmpty()) { nsAutoString unhandledString; GetUnhandledString(unhandledString); - NSString* unhandledNSString = nsCocoaUtils::ToNSString(unhandledString); + NSString* unhandledNSString = XPCOMStringToNSString(unhandledString); // If the key event's some characters were already handled by // InsertString() calls, we need to create a dummy event which doesn't // include the handled characters. @@ -5345,7 +5344,7 @@ void TextInputHandlerBase::KeyEventState::GetUnhandledString( return; } nsAutoString characters; - nsCocoaUtils::GetStringForNSString([mKeyEvent characters], characters); + CopyNSStringToXPCOMString([mKeyEvent characters], characters); if (characters.IsEmpty()) { return; } @@ -5373,8 +5372,7 @@ TextInputHandlerBase::AutoInsertStringClearer::~AutoInsertStringClearer() { // If inserting string is a part of characters of the event, // we should record it as inserted string. nsAutoString characters; - nsCocoaUtils::GetStringForNSString([mState->mKeyEvent characters], - characters); + CopyNSStringToXPCOMString([mState->mKeyEvent characters], characters); nsAutoString insertedString(mState->mInsertedString); insertedString += *mState->mInsertString; if (StringBeginsWith(characters, insertedString)) { diff --git a/widget/cocoa/VibrancyManager.h b/widget/cocoa/VibrancyManager.h index d431540830..c70ec60a3b 100644 --- a/widget/cocoa/VibrancyManager.h +++ b/widget/cocoa/VibrancyManager.h @@ -24,6 +24,7 @@ namespace mozilla { enum class VibrancyType { TOOLTIP, MENU, + TITLEBAR, }; /** diff --git a/widget/cocoa/VibrancyManager.mm b/widget/cocoa/VibrancyManager.mm index e9cfcc3be0..6062acb931 100644 --- a/widget/cocoa/VibrancyManager.mm +++ b/widget/cocoa/VibrancyManager.mm @@ -9,6 +9,7 @@ #import <objc/message.h> #include "nsChildView.h" +#include "mozilla/StaticPrefs_widget.h" using namespace mozilla; @@ -30,18 +31,34 @@ static NSVisualEffectState VisualEffectStateForVibrancyType( // Tooltip and menu windows are never "key", so we need to tell the // vibrancy effect to look active regardless of window state. return NSVisualEffectStateActive; - default: - return NSVisualEffectStateFollowsWindowActiveState; + case VibrancyType::TITLEBAR: + break; } + return NSVisualEffectStateFollowsWindowActiveState; } static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType( - VibrancyType aType, BOOL* aOutIsEmphasized) { + VibrancyType aType) { switch (aType) { case VibrancyType::TOOLTIP: return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip; case VibrancyType::MENU: return NSVisualEffectMaterialMenu; + case VibrancyType::TITLEBAR: + return NSVisualEffectMaterialTitlebar; + } +} + +static NSVisualEffectBlendingMode VisualEffectBlendingModeForVibrancyType( + VibrancyType aType) { + switch (aType) { + case VibrancyType::TOOLTIP: + case VibrancyType::MENU: + return NSVisualEffectBlendingModeBehindWindow; + case VibrancyType::TITLEBAR: + return StaticPrefs::widget_macos_titlebar_blend_mode_behind_window() + ? NSVisualEffectBlendingModeBehindWindow + : NSVisualEffectBlendingModeWithinWindow; } } @@ -53,11 +70,9 @@ static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType( self.appearance = nil; self.state = VisualEffectStateForVibrancyType(mType); - - BOOL isEmphasized = NO; - self.material = VisualEffectMaterialForVibrancyType(mType, &isEmphasized); - self.emphasized = isEmphasized; - + self.material = VisualEffectMaterialForVibrancyType(mType); + self.blendingMode = VisualEffectBlendingModeForVibrancyType(mType); + self.emphasized = NO; return self; } @@ -89,7 +104,7 @@ bool VibrancyManager::UpdateVibrantRegion( } auto& vr = *mVibrantRegions.GetOrInsertNew(uint32_t(aType)); return vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() { - return this->CreateEffectView(aType); + return CreateEffectView(aType); }); } diff --git a/widget/cocoa/ViewRegion.mm b/widget/cocoa/ViewRegion.mm index 62e76d2df8..5b275a18a3 100644 --- a/widget/cocoa/ViewRegion.mm +++ b/widget/cocoa/ViewRegion.mm @@ -12,8 +12,8 @@ using namespace mozilla; ViewRegion::~ViewRegion() { - for (size_t i = 0; i < mViews.Length(); i++) { - [mViews[i] removeFromSuperview]; + for (NSView* view : mViews) { + [view removeFromSuperview]; } } @@ -33,34 +33,31 @@ bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion, nsTArray<NSView*> viewsToRecycle = std::move(mViews); // The mViews array is now empty. - size_t i = 0; - for (auto iter = aRegion.RectIter(); - !iter.Done() || i < viewsToRecycle.Length(); i++) { - if (!iter.Done()) { - NSView* view = nil; - NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get()); - if (i < viewsToRecycle.Length()) { - view = viewsToRecycle[i]; - } else { - view = aViewCreationCallback(); - [aContainerView addSubview:view]; - - // Now that the view is in the view hierarchy, it'll be kept alive by - // its superview, so we can drop our reference. - [view release]; - } - if (!NSEqualRects(rect, [view frame])) { - [view setFrame:rect]; - } - [view setNeedsDisplay:YES]; - mViews.AppendElement(view); - iter.Next(); + size_t viewsRecycled = 0; + for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { + NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get()); + NSView* view = nil; + if (viewsRecycled < viewsToRecycle.Length()) { + view = viewsToRecycle[viewsRecycled++]; } else { - // Our new region is made of fewer rects than the old region, so we can - // remove this view. We only have a weak reference to it, so removing it - // from the view hierarchy will release it. - [viewsToRecycle[i] removeFromSuperview]; + view = aViewCreationCallback(); + [aContainerView addSubview:view]; + + // Now that the view is in the view hierarchy, it'll be kept alive by + // its superview, so we can drop our reference. + [view release]; } + if (!NSEqualRects(rect, view.frame)) { + view.frame = rect; + } + view.needsDisplay = YES; + mViews.AppendElement(view); + } + for (NSView* view : Span(viewsToRecycle).From(viewsRecycled)) { + // Our new region is made of fewer rects than the old region, so we can + // remove this view. We only have a weak reference to it, so removing it + // from the view hierarchy will release it. + [view removeFromSuperview]; } mRegion = aRegion; diff --git a/widget/cocoa/moz.build b/widget/cocoa/moz.build index ddb402e2cc..d0939d34c7 100644 --- a/widget/cocoa/moz.build +++ b/widget/cocoa/moz.build @@ -11,12 +11,6 @@ with Files("**"): with Files("*TextInput*"): BUG_COMPONENT = ("Core", "DOM: UI Events & Focus Handling") -XPIDL_SOURCES += [ - "nsPIWidgetCocoa.idl", -] - -XPIDL_MODULE = "widget_cocoa" - EXPORTS += [ "DesktopBackgroundImage.h", "MediaHardwareKeysEventSourceMac.h", diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 79919ba69a..d3241a983f 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -473,17 +473,20 @@ void* nsChildView::GetNativeData(uint32_t aDataType) { #pragma mark - void nsChildView::SuppressAnimation(bool aSuppress) { - GetAppWindowWidget()->SuppressAnimation(aSuppress); + if (nsCocoaWindow* widget = GetAppWindowWidget()) { + widget->SuppressAnimation(aSuppress); + } } bool nsChildView::IsVisible() const { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; if (!mVisible) { - return mVisible; + return false; } - if (!GetAppWindowWidget()->IsVisible()) { + nsCocoaWindow* widget = GetAppWindowWidget(); + if (NS_WARN_IF(!widget) || !widget->IsVisible()) { return false; } @@ -739,11 +742,11 @@ void nsChildView::Resize(double aWidth, double aHeight, bool aRepaint) { mBounds.height = height; ManipulateViewWithoutNeedingDisplay(mView, ^{ - [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; + mView.frame = DevPixelsToCocoaPoints(mBounds); }); if (mVisible && aRepaint) { - [[mView pixelHostingView] setNeedsDisplay:YES]; + mView.pixelHostingView.needsDisplay = YES; } ReportSizeEvent(); @@ -779,11 +782,11 @@ void nsChildView::Resize(double aX, double aY, double aWidth, double aHeight, } ManipulateViewWithoutNeedingDisplay(mView, ^{ - [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; + mView.frame = DevPixelsToCocoaPoints(mBounds); }); if (mVisible && aRepaint) { - [[mView pixelHostingView] setNeedsDisplay:YES]; + mView.pixelHostingView.needsDisplay = YES; } if (isMoving) { @@ -1070,10 +1073,8 @@ nsresult nsChildView::SynthesizeNativeTouchpadDoubleTap( bool nsChildView::SendEventToNativeMenuSystem(NSEvent* aEvent) { bool handled = false; - nsCocoaWindow* widget = GetAppWindowWidget(); - if (widget) { - nsMenuBarX* mb = widget->GetMenuBar(); - if (mb) { + if (nsCocoaWindow* widget = GetAppWindowWidget()) { + if (nsMenuBarX* mb = widget->GetMenuBar()) { // Check if main menu wants to handle the event. handled = mb->PerformKeyEquivalent(aEvent); } @@ -1157,10 +1158,8 @@ nsresult nsChildView::ActivateNativeMenuItemAt(const nsAString& indexString) { nsresult nsChildView::ForceUpdateNativeMenuAt(const nsAString& indexString) { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; - nsCocoaWindow* widget = GetAppWindowWidget(); - if (widget) { - nsMenuBarX* mb = widget->GetMenuBar(); - if (mb) { + if (nsCocoaWindow* widget = GetAppWindowWidget()) { + if (nsMenuBarX* mb = widget->GetMenuBar()) { if (indexString.IsEmpty()) mb->ForceNativeMenuReload(); else @@ -1689,33 +1688,6 @@ RefPtr<layers::NativeLayerRoot> nsChildView::GetNativeLayerRoot() { return mNativeLayerRoot; } -static int32_t FindTitlebarBottom( - const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, - int32_t aWindowWidth) { - int32_t titlebarBottom = 0; - for (auto& g : aThemeGeometries) { - if (g.mType == eThemeGeometryTypeTitlebar && g.mRect.X() <= 0 && - g.mRect.XMost() >= aWindowWidth && g.mRect.Y() <= 0) { - titlebarBottom = std::max(titlebarBottom, g.mRect.YMost()); - } - } - return titlebarBottom; -} - -static int32_t FindUnifiedToolbarBottom( - const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, - int32_t aWindowWidth, int32_t aTitlebarBottom) { - int32_t unifiedToolbarBottom = aTitlebarBottom; - for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { - const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; - if ((g.mType == eThemeGeometryTypeToolbar) && g.mRect.X() <= 0 && - g.mRect.XMost() >= aWindowWidth && g.mRect.Y() <= aTitlebarBottom) { - unifiedToolbarBottom = std::max(unifiedToolbarBottom, g.mRect.YMost()); - } - } - return unifiedToolbarBottom; -} - static LayoutDeviceIntRect FindFirstRectOfType( const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, nsITheme::ThemeGeometryType aThemeGeometryType) { @@ -1730,32 +1702,17 @@ static LayoutDeviceIntRect FindFirstRectOfType( void nsChildView::UpdateThemeGeometries( const nsTArray<ThemeGeometry>& aThemeGeometries) { - if (![mView window]) return; + if (!mView.window) { + return; + } UpdateVibrancy(aThemeGeometries); - if (![[mView window] isKindOfClass:[ToolbarWindow class]]) return; - - // Update unified toolbar height and sheet attachment position. - int32_t windowWidth = mBounds.width; - int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth); - int32_t unifiedToolbarBottom = - FindUnifiedToolbarBottom(aThemeGeometries, windowWidth, titlebarBottom); - int32_t toolboxBottom = - FindFirstRectOfType(aThemeGeometries, eThemeGeometryTypeToolbox).YMost(); + if (![mView.window isKindOfClass:[ToolbarWindow class]]) { + return; + } ToolbarWindow* win = (ToolbarWindow*)[mView window]; - int32_t titlebarHeight = [win drawsContentsIntoWindowFrame] - ? 0 - : CocoaPointsToDevPixels([win titlebarHeight]); - int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom; - [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)]; - - int32_t sheetPositionDevPx = std::max(toolboxBottom, unifiedToolbarBottom); - NSPoint sheetPositionView = {0, DevPixelsToCocoaPoints(sheetPositionDevPx)}; - NSPoint sheetPositionWindow = [mView convertPoint:sheetPositionView - toView:nil]; - [win setSheetAttachmentPosition:sheetPositionWindow.y]; // Update titlebar control offsets. LayoutDeviceIntRect windowButtonRect = @@ -1768,10 +1725,8 @@ void nsChildView::UpdateThemeGeometries( static Maybe<VibrancyType> ThemeGeometryTypeToVibrancyType( nsITheme::ThemeGeometryType aThemeGeometryType) { switch (aThemeGeometryType) { - case eThemeGeometryTypeTooltip: - return Some(VibrancyType::TOOLTIP); - case eThemeGeometryTypeMenu: - return Some(VibrancyType::MENU); + case eThemeGeometryTypeTitlebar: + return Some(VibrancyType::TITLEBAR); default: return Nothing(); } @@ -1781,7 +1736,7 @@ static LayoutDeviceIntRegion GatherVibrantRegion( const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, VibrancyType aVibrancyType) { LayoutDeviceIntRegion region; - for (auto& geometry : aThemeGeometries) { + for (const auto& geometry : aThemeGeometries) { if (ThemeGeometryTypeToVibrancyType(geometry.mType) == Some(aVibrancyType)) { region.OrWith(geometry.mRect); @@ -1790,40 +1745,13 @@ static LayoutDeviceIntRegion GatherVibrantRegion( return region; } -template <typename Region> -static void MakeRegionsNonOverlappingImpl(Region& aOutUnion) {} - -template <typename Region, typename... Regions> -static void MakeRegionsNonOverlappingImpl(Region& aOutUnion, Region& aFirst, - Regions&... aRest) { - MakeRegionsNonOverlappingImpl(aOutUnion, aRest...); - aFirst.SubOut(aOutUnion); - aOutUnion.OrWith(aFirst); -} - -// Subtracts parts from regions in such a way that they don't have any overlap. -// Each region in the argument list will have the union of all the regions -// *following* it subtracted from itself. In other words, the arguments are -// sorted low priority to high priority. -template <typename Region, typename... Regions> -static void MakeRegionsNonOverlapping(Region& aFirst, Regions&... aRest) { - Region unionOfAll; - MakeRegionsNonOverlappingImpl(unionOfAll, aFirst, aRest...); -} - void nsChildView::UpdateVibrancy( const nsTArray<ThemeGeometry>& aThemeGeometries) { - LayoutDeviceIntRegion menuRegion = - GatherVibrantRegion(aThemeGeometries, VibrancyType::MENU); - LayoutDeviceIntRegion tooltipRegion = - GatherVibrantRegion(aThemeGeometries, VibrancyType::TOOLTIP); - - MakeRegionsNonOverlapping(menuRegion, tooltipRegion); + LayoutDeviceIntRegion titlebarRegion = + GatherVibrantRegion(aThemeGeometries, VibrancyType::TITLEBAR); auto& vm = EnsureVibrancyManager(); - bool changed = false; - changed |= vm.UpdateVibrantRegion(VibrancyType::MENU, menuRegion); - changed |= vm.UpdateVibrantRegion(VibrancyType::TOOLTIP, tooltipRegion); + bool changed = vm.UpdateVibrantRegion(VibrancyType::TITLEBAR, titlebarRegion); if (changed) { SuspendAsyncCATransactions(); @@ -1834,7 +1762,7 @@ mozilla::VibrancyManager& nsChildView::EnsureVibrancyManager() { MOZ_ASSERT(mView, "Only call this once we have a view!"); if (!mVibrancyManager) { mVibrancyManager = - MakeUnique<VibrancyManager>(*this, [mView vibrancyViewsContainer]); + MakeUnique<VibrancyManager>(*this, mView.vibrancyViewsContainer); } return *mVibrancyManager; } @@ -1897,7 +1825,7 @@ void nsChildView::UpdateWindowDraggingRegion( // Suppress calls to setNeedsDisplay during NSView geometry changes. ManipulateViewWithoutNeedingDisplay(mView, ^() { changed = mNonDraggableRegion.UpdateRegion( - nonDraggable, *this, [mView nonDraggableViewsContainer], ^() { + nonDraggable, *this, mView.nonDraggableViewsContainer, ^() { return [[NonDraggableView alloc] initWithFrame:NSZeroRect]; }); }); @@ -2198,22 +2126,22 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong] mCancelSwipeAnimation = nil; #endif + auto bounds = self.bounds; mNonDraggableViewsContainer = - [[ViewRegionContainerView alloc] initWithFrame:[self bounds]]; + [[ViewRegionContainerView alloc] initWithFrame:bounds]; mVibrancyViewsContainer = - [[ViewRegionContainerView alloc] initWithFrame:[self bounds]]; + [[ViewRegionContainerView alloc] initWithFrame:bounds]; - [mNonDraggableViewsContainer - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [mVibrancyViewsContainer - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + mNonDraggableViewsContainer.autoresizingMask = + mVibrancyViewsContainer.autoresizingMask = + NSViewWidthSizable | NSViewHeightSizable; [self addSubview:mNonDraggableViewsContainer]; [self addSubview:mVibrancyViewsContainer]; - mPixelHostingView = [[PixelHostingView alloc] initWithFrame:[self bounds]]; - [mPixelHostingView - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + mPixelHostingView = [[PixelHostingView alloc] initWithFrame:bounds]; + mPixelHostingView.autoresizingMask = + NSViewWidthSizable | NSViewHeightSizable; [self addSubview:mPixelHostingView]; @@ -2222,7 +2150,7 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong] mRootCALayer.bounds = NSZeroRect; mRootCALayer.anchorPoint = NSZeroPoint; mRootCALayer.contentsGravity = kCAGravityTopLeft; - [[mPixelHostingView layer] addSublayer:mRootCALayer]; + [mPixelHostingView.layer addSublayer:mRootCALayer]; mLastPressureStage = 0; } @@ -2398,7 +2326,7 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong] // This call will cause updateRootCALayer to be called during the upcoming // main thread CoreAnimation transaction. It will also trigger a transaction // if no transaction is currently pending. - [[mPixelHostingView layer] setNeedsDisplay]; + [mPixelHostingView.layer setNeedsDisplay]; } } @@ -5129,18 +5057,12 @@ BOOL ChildViewMouseTracker::WindowAcceptsEvent(NSWindow* aWindow, case WindowType::TopLevel: case WindowType::Dialog: - if ([aWindow attachedSheet]) return NO; + if (aWindow.attachedSheet) { + return NO; + } topLevelWindow = aWindow; break; - case WindowType::Sheet: { - nsIWidget* parentWidget = windowWidget->GetSheetWindowParent(); - if (!parentWidget) return YES; - - topLevelWindow = (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW); - break; - } - default: return YES; } diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 621c32eb44..96e117ba26 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -12,7 +12,6 @@ #include "mozilla/RefPtr.h" #include "nsBaseWidget.h" -#include "nsPIWidgetCocoa.h" #include "nsCocoaUtils.h" #include "nsTouchBar.h" #include <dlfcn.h> @@ -27,12 +26,6 @@ namespace mozilla { enum class NativeKeyBindingsType : uint8_t; } // namespace mozilla -typedef struct _nsCocoaWindowList { - _nsCocoaWindowList() : prev(nullptr), window(nullptr) {} - struct _nsCocoaWindowList* prev; - nsCocoaWindow* window; // Weak -} nsCocoaWindowList; - // NSWindow subclass that is the base class for all of our own window classes. // Among other things, this class handles the storage of those settings that // need to be persisted across window destruction and reconstruction, i.e. when @@ -169,102 +162,75 @@ typedef struct _nsCocoaWindowList { - (void)sendToplevelDeactivateEvents; @end -@interface MOZTitlebarView : NSVisualEffectView -@end - @interface FullscreenTitlebarTracker : NSTitlebarAccessoryViewController - (FullscreenTitlebarTracker*)init; @end // NSWindow subclass for handling windows with toolbars. @interface ToolbarWindow : BaseWindow { - // This window's titlebar view, if present. - // Will be nil if the window has neither a titlebar nor a unified toolbar. - // This view is a subview of the window's content view and gets created and - // destroyed by updateTitlebarView. - MOZTitlebarView* mTitlebarView; // [STRONG] // mFullscreenTitlebarTracker attaches an invisible rectangle to the system // title bar. This allows us to detect when the title bar is showing in // fullscreen. FullscreenTitlebarTracker* mFullscreenTitlebarTracker; - CGFloat mUnifiedToolbarHeight; - CGFloat mSheetAttachmentPosition; CGFloat mMenuBarHeight; - /* Store the height of the titlebar when this window is initialized. The - titlebarHeight getter returns 0 when in fullscreen, which is not useful in - some cases. */ - CGFloat mInitialTitlebarHeight; NSRect mWindowButtonsRect; } -- (void)setUnifiedToolbarHeight:(CGFloat)aHeight; -- (CGFloat)unifiedToolbarHeight; -- (CGFloat)titlebarHeight; -- (NSRect)titlebarRect; -- (void)setTitlebarNeedsDisplay; - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState; -- (void)setSheetAttachmentPosition:(CGFloat)aY; -- (CGFloat)sheetAttachmentPosition; - (void)placeWindowButtons:(NSRect)aRect; - (NSRect)windowButtonsRect; - (void)windowMainStateChanged; @end -class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { +class nsCocoaWindow final : public nsBaseWidget { private: typedef nsBaseWidget Inherited; public: nsCocoaWindow(); - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSPIWIDGETCOCOA; // semicolon for clang-format bug 1629756 - - [[nodiscard]] virtual nsresult Create(nsIWidget* aParent, - nsNativeWidget aNativeParent, - const DesktopIntRect& aRect, - InitData* = nullptr) override; - - [[nodiscard]] virtual nsresult Create(nsIWidget* aParent, - nsNativeWidget aNativeParent, - const LayoutDeviceIntRect& aRect, - InitData* = nullptr) override; - - virtual void Destroy() override; - - virtual void Show(bool aState) override; - virtual bool NeedsRecreateToReshow() override; - - virtual nsIWidget* GetSheetWindowParent(void) override; - virtual void Enable(bool aState) override; - virtual bool IsEnabled() const override; - virtual void SetModal(bool aState) override; - virtual void SetFakeModal(bool aState) override; - virtual bool IsRunningAppModal() override; - virtual bool IsVisible() const override; - virtual void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override; - virtual LayoutDeviceIntPoint WidgetToScreenOffset() override; - virtual LayoutDeviceIntPoint GetClientOffset() override; - virtual LayoutDeviceIntMargin ClientToWindowMargin() override; - - virtual void* GetNativeData(uint32_t aDataType) override; - - virtual void ConstrainPosition(DesktopIntPoint&) override; - virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override; - virtual void Move(double aX, double aY) override; - virtual nsSizeMode SizeMode() override { return mSizeMode; } - virtual void SetSizeMode(nsSizeMode aMode) override; - virtual void GetWorkspaceID(nsAString& workspaceID) override; - virtual void MoveToWorkspace(const nsAString& workspaceID) override; - virtual void SuppressAnimation(bool aSuppress) override; - virtual void HideWindowChrome(bool aShouldHide) override; - - virtual bool PrepareForFullscreenTransition(nsISupports** aData) override; - virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage, - uint16_t aDuration, - nsISupports* aData, - nsIRunnable* aCallback) override; - virtual void CleanupFullscreenTransition() override; + [[nodiscard]] nsresult Create(nsIWidget* aParent, + nsNativeWidget aNativeParent, + const DesktopIntRect& aRect, + InitData* = nullptr) override; + + [[nodiscard]] nsresult Create(nsIWidget* aParent, + nsNativeWidget aNativeParent, + const LayoutDeviceIntRect& aRect, + InitData* = nullptr) override; + + void Destroy() override; + + void Show(bool aState) override; + bool NeedsRecreateToReshow() override; + + void Enable(bool aState) override; + bool IsEnabled() const override; + void SetModal(bool aState) override; + bool IsRunningAppModal() override; + bool IsVisible() const override; + void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override; + LayoutDeviceIntPoint WidgetToScreenOffset() override; + LayoutDeviceIntPoint GetClientOffset() override; + LayoutDeviceIntMargin ClientToWindowMargin() override; + + void* GetNativeData(uint32_t aDataType) override; + + void ConstrainPosition(DesktopIntPoint&) override; + void SetSizeConstraints(const SizeConstraints& aConstraints) override; + void Move(double aX, double aY) override; + nsSizeMode SizeMode() override { return mSizeMode; } + void SetSizeMode(nsSizeMode aMode) override; + void GetWorkspaceID(nsAString& workspaceID) override; + void MoveToWorkspace(const nsAString& workspaceID) override; + void SuppressAnimation(bool aSuppress) override; + void HideWindowChrome(bool aShouldHide) override; + + bool PrepareForFullscreenTransition(nsISupports** aData) override; + void PerformFullscreenTransition(FullscreenTransitionStage aStage, + uint16_t aDuration, nsISupports* aData, + nsIRunnable* aCallback) override; + void CleanupFullscreenTransition() override; nsresult MakeFullScreen(bool aFullScreen) final; nsresult MakeFullScreenWithNativeTransition(bool aFullScreen) final; NSAnimation* FullscreenTransitionAnimation() const { @@ -277,79 +243,79 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { mFullscreenTransitionAnimation = nil; } - virtual void Resize(double aWidth, double aHeight, bool aRepaint) override; - virtual void Resize(double aX, double aY, double aWidth, double aHeight, - bool aRepaint) override; + void Resize(double aWidth, double aHeight, bool aRepaint) override; + void Resize(double aX, double aY, double aWidth, double aHeight, + bool aRepaint) override; NSRect GetClientCocoaRect(); - virtual LayoutDeviceIntRect GetClientBounds() override; - virtual LayoutDeviceIntRect GetScreenBounds() override; + LayoutDeviceIntRect GetClientBounds() override; + LayoutDeviceIntRect GetScreenBounds() override; void ReportMoveEvent(); void ReportSizeEvent(); - virtual void SetCursor(const Cursor&) override; + void SetCursor(const Cursor&) override; CGFloat BackingScaleFactor(); void BackingScaleFactorChanged(); - virtual double GetDefaultScaleInternal() override; - virtual int32_t RoundsWidgetCoordinatesTo() override; + double GetDefaultScaleInternal() override; + int32_t RoundsWidgetCoordinatesTo() override; mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final { return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor()); } - virtual nsresult SetTitle(const nsAString& aTitle) override; - - virtual void Invalidate(const LayoutDeviceIntRect& aRect) override; - virtual WindowRenderer* GetWindowRenderer() override; - virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent, - nsEventStatus& aStatus) override; - virtual void CaptureRollupEvents(bool aDoCapture) override; - [[nodiscard]] virtual nsresult GetAttention(int32_t aCycleCount) override; - virtual bool HasPendingInputEvent() override; - virtual TransparencyMode GetTransparencyMode() override; - virtual void SetTransparencyMode(TransparencyMode aMode) override; - virtual void SetWindowShadowStyle(mozilla::WindowShadow aStyle) override; - virtual void SetWindowOpacity(float aOpacity) override; - virtual void SetWindowTransform( - const mozilla::gfx::Matrix& aTransform) override; - virtual void SetInputRegion(const InputRegion&) override; - virtual void SetColorScheme( - const mozilla::Maybe<mozilla::ColorScheme>&) override; - virtual void SetShowsToolbarButton(bool aShow) override; - virtual void SetSupportsNativeFullscreen(bool aShow) override; - virtual void SetWindowAnimationType(WindowAnimationType aType) override; - virtual void SetDrawsTitle(bool aDrawTitle) override; - virtual nsresult SetNonClientMargins(const LayoutDeviceIntMargin&) override; + nsresult SetTitle(const nsAString& aTitle) override; + + void Invalidate(const LayoutDeviceIntRect& aRect) override; + WindowRenderer* GetWindowRenderer() override; + nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent, + nsEventStatus& aStatus) override; + void CaptureRollupEvents(bool aDoCapture) override; + [[nodiscard]] nsresult GetAttention(int32_t aCycleCount) override; + bool HasPendingInputEvent() override; + TransparencyMode GetTransparencyMode() override; + void SetTransparencyMode(TransparencyMode aMode) override; + void SetWindowShadowStyle(mozilla::WindowShadow aStyle) override; + void SetWindowOpacity(float aOpacity) override; + void SetWindowTransform(const mozilla::gfx::Matrix& aTransform) override; + void SetInputRegion(const InputRegion&) override; + void SetColorScheme(const mozilla::Maybe<mozilla::ColorScheme>&) override; + void SetShowsToolbarButton(bool aShow) override; + void SetSupportsNativeFullscreen(bool aShow) override; + void SetWindowAnimationType(WindowAnimationType aType) override; + void SetDrawsTitle(bool aDrawTitle) override; + nsresult SetNonClientMargins(const LayoutDeviceIntMargin&) override; void SetDrawsInTitlebar(bool aState); - virtual void UpdateThemeGeometries( + void UpdateThemeGeometries( const nsTArray<ThemeGeometry>& aThemeGeometries) override; - virtual nsresult SynthesizeNativeMouseEvent( - LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage, - mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags, - nsIObserver* aObserver) override; - virtual nsresult SynthesizeNativeMouseScrollEvent( + nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint, + NativeMouseMessage aNativeMessage, + mozilla::MouseButton aButton, + nsIWidget::Modifiers aModifierFlags, + nsIObserver* aObserver) override; + nsresult SynthesizeNativeMouseScrollEvent( LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage, double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aModifierFlags, uint32_t aAdditionalFlags, nsIObserver* aObserver) override; - virtual void LockAspectRatio(bool aShouldLock) override; + void LockAspectRatio(bool aShouldLock) override; void DispatchSizeModeEvent(); void DispatchOcclusionEvent(); // be notified that a some form of drag event needs to go into Gecko - virtual bool DragEvent(unsigned int aMessage, - mozilla::gfx::Point aMouseGlobal, - UInt16 aKeyModifiers); + bool DragEvent(unsigned int aMessage, mozilla::gfx::Point aMouseGlobal, + UInt16 aKeyModifiers); + + bool HasModalDescendants() const { return mNumModalDescendants > 0; } + bool IsModal() const { return mModal; } - bool HasModalDescendents() { return mNumModalDescendents > 0; } NSWindow* GetCocoaWindow() { return mWindow; } void SetMenuBar(RefPtr<nsMenuBarX>&& aMenuBar); nsMenuBarX* GetMenuBar(); - virtual void SetInputContext(const InputContext& aContext, - const InputContextAction& aAction) override; - virtual InputContext GetInputContext() override { return mInputContext; } - MOZ_CAN_RUN_SCRIPT virtual bool GetEditCommands( + void SetInputContext(const InputContext& aContext, + const InputContextAction& aAction) override; + InputContext GetInputContext() override { return mInputContext; } + MOZ_CAN_RUN_SCRIPT bool GetEditCommands( mozilla::NativeKeyBindingsType aType, const mozilla::WidgetKeyboardEvent& aEvent, nsTArray<mozilla::CommandInt>& aCommands) override; @@ -400,6 +366,7 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { void DestroyNativeWindow(); void UpdateBounds(); int32_t GetWorkspaceID(); + void SendSetZLevelEvent(); void DoResize(double aX, double aY, double aWidth, double aHeight, bool aRepaint, bool aConstrainToCurrentScreen); @@ -407,7 +374,7 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { void UpdateFullscreenState(bool aFullScreen, bool aNativeMode); nsresult DoMakeFullScreen(bool aFullScreen, bool aUseSystemTransition); - virtual already_AddRefed<nsIWidget> AllocateChildPopupWidget() override { + already_AddRefed<nsIWidget> AllocateChildPopupWidget() override { return nsIWidget::CreateTopLevelWindow(); } @@ -417,8 +384,6 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG] RefPtr<nsMenuBarX> mMenuBar; - NSWindow* mSheetWindowParent; // if this is a sheet, this is the NSWindow - // it's attached to nsChildView* mPopupContentView; // if this is a popup, this is its content widget // if this is a toplevel window, and there is any ongoing fullscreen @@ -432,8 +397,6 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { WindowAnimationType mAnimationType; bool mWindowMadeHere; // true if we created the window, false for embedding - bool mSheetNeedsShow; // if this is a sheet, are we waiting to be shown? - // this is used for sibling sheet contention only nsSizeMode mSizeMode; bool mInFullScreenMode; // Whether we are currently using native fullscreen. It could be false because @@ -482,19 +445,18 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { // unnecessary OcclusionStateChanged events. bool mHasStartedNativeFullscreen; - bool mModal; - bool mFakeModal; - - bool mIsAnimationSuppressed; + bool mModal = false; + bool mIsAnimationSuppressed = false; - bool mInReportMoveEvent; // true if in a call to ReportMoveEvent(). - bool mInResize; // true if in a call to DoResize(). - bool mWindowTransformIsIdentity; - bool mAlwaysOnTop; - bool mAspectRatioLocked; + bool mInReportMoveEvent = false; // true if in a call to ReportMoveEvent(). + bool mInResize = false; // true if in a call to DoResize(). + bool mWindowTransformIsIdentity = true; + bool mAlwaysOnTop = false; + bool mAspectRatioLocked = false; bool mIsAlert = false; // True if this is an non-native alert window. + bool mWasShown = false; - int32_t mNumModalDescendents; + int32_t mNumModalDescendants = 0; InputContext mInputContext; NSWindowAnimationBehavior mWindowAnimationBehavior; @@ -508,9 +470,6 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa { // to EndOurNativeTransition() when the native transition is complete. bool CanStartNativeTransition(); void EndOurNativeTransition(); - - // true if Show() has been called. - bool mWasShown; }; #endif // nsCocoaWindow_h_ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 4b135e7565..8e54d9e7fd 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -66,15 +66,6 @@ using namespace mozilla::layers; using namespace mozilla::widget; using namespace mozilla; -int32_t gXULModalLevel = 0; - -// In principle there should be only one app-modal window at any given time. -// But sometimes, despite our best efforts, another window appears above the -// current app-modal window. So we need to keep a linked list of app-modal -// windows. (A non-sheet window that appears above an app-modal window is -// also made app-modal.) See nsCocoaWindow::SetModal(). -nsCocoaWindowList* gGeckoAppModalWindowList = NULL; - BOOL sTouchBarIsInitialized = NO; // defined in nsMenuBarX.mm @@ -83,6 +74,8 @@ extern NSMenu* sApplicationMenu; // Application menu shared by all menubars // defined in nsChildView.mm extern BOOL gSomeMenuBarPainted; +static uint32_t sModalWindowCount = 0; + extern "C" { // CGSPrivate.h typedef NSInteger CGSConnection; @@ -105,13 +98,6 @@ extern CGError CGSSetWindowTransform(CGSConnection cid, CGSWindow wid, #define NS_APPSHELLSERVICE_CONTRACTID "@mozilla.org/appshell/appShellService;1" -NS_IMPL_ISUPPORTS_INHERITED(nsCocoaWindow, Inherited, nsPIWidgetCocoa) - -// A note on testing to see if your object is a sheet... -// |mWindowType == WindowType::Sheet| is true if your gecko nsIWidget is a sheet -// widget - whether or not the sheet is showing. |[mWindow isSheet]| will return -// true *only when the sheet is actually showing*. Choose your test wisely. - static void RollUpPopups(nsIRollupListener::AllowAnimations aAllowAnimations = nsIRollupListener::AllowAnimations::Yes) { if (RefPtr pm = nsXULPopupManager::GetInstance()) { @@ -139,33 +125,21 @@ nsCocoaWindow::nsCocoaWindow() mAncestorLink(nullptr), mWindow(nil), mDelegate(nil), - mSheetWindowParent(nil), mPopupContentView(nil), mFullscreenTransitionAnimation(nil), mShadowStyle(WindowShadow::None), mBackingScaleFactor(0.0), mAnimationType(nsIWidget::eGenericWindowAnimation), mWindowMadeHere(false), - mSheetNeedsShow(false), mSizeMode(nsSizeMode_Normal), mInFullScreenMode(false), mInNativeFullScreenMode(false), mIgnoreOcclusionCount(0), mHasStartedNativeFullscreen(false), - mModal(false), - mFakeModal(false), - mIsAnimationSuppressed(false), - mInReportMoveEvent(false), - mInResize(false), - mWindowTransformIsIdentity(true), - mAlwaysOnTop(false), - mAspectRatioLocked(false), - mNumModalDescendents(0), - mWindowAnimationBehavior(NSWindowAnimationBehaviorDefault), - mWasShown(false) { + mWindowAnimationBehavior(NSWindowAnimationBehaviorDefault) { // Disable automatic tabbing. We need to do this before we // orderFront any of our windows. - [NSWindow setAllowsAutomaticWindowTabbing:NO]; + NSWindow.allowsAutomaticWindowTabbing = NO; } void nsCocoaWindow::DestroyNativeWindow() { @@ -223,14 +197,6 @@ nsCocoaWindow::~nsCocoaWindow() { } NS_IF_RELEASE(mPopupContentView); - - // Deal with the possiblity that we're being destroyed while running modal. - if (mModal) { - NS_WARNING("Widget destroyed while running modal!"); - --gXULModalLevel; - NS_ASSERTION(gXULModalLevel >= 0, "Weirdness setting modality!"); - } - NS_OBJC_END_TRY_IGNORE_BLOCK; } @@ -432,15 +398,6 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect& aRect, case WindowType::Dialog: features = WindowMaskForBorderStyle(aBorderStyle); break; - case WindowType::Sheet: - if (mParent->GetWindowType() != WindowType::Invisible && - aBorderStyle & BorderStyle::ResizeH) { - features = NSWindowStyleMaskResizable; - } else { - features = NSWindowStyleMaskMiniaturizable; - } - features |= NSWindowStyleMaskTitled; - break; default: NS_ERROR("Unhandled window type!"); return NS_ERROR_FAILURE; @@ -607,14 +564,14 @@ nsresult nsCocoaWindow::CreatePopupContentView(const LayoutDeviceIntRect& aRect, } void nsCocoaWindow::Destroy() { - if (mOnDestroyCalled) return; + if (mOnDestroyCalled) { + return; + } mOnDestroyCalled = true; - // SetFakeModal(true) is called for non-modal window opened by modal window. - // On Cocoa, it needs corresponding SetFakeModal(false) on destroy to restore - // ancestor windows' state. - if (mFakeModal) { - SetFakeModal(false); + // Deal with the possiblity that we're being destroyed while running modal. + if (mModal) { + SetModal(false); } // If we don't hide here we run into problems with panels, this is not ideal. @@ -651,14 +608,6 @@ void nsCocoaWindow::Destroy() { } } -nsIWidget* nsCocoaWindow::GetSheetWindowParent(void) { - if (mWindowType != WindowType::Sheet) return nullptr; - nsCocoaWindow* parent = static_cast<nsCocoaWindow*>(mParent); - while (parent && (parent->mWindowType == WindowType::Sheet)) - parent = static_cast<nsCocoaWindow*>(parent->mParent); - return parent; -} - void* nsCocoaWindow::GetNativeData(uint32_t aDataType) { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; @@ -708,14 +657,18 @@ void* nsCocoaWindow::GetNativeData(uint32_t aDataType) { bool nsCocoaWindow::IsVisible() const { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; - return (mWindow && ([mWindow isVisibleOrBeingShown] || mSheetNeedsShow)); + return mWindow && mWindow.isVisibleOrBeingShown; NS_OBJC_END_TRY_BLOCK_RETURN(false); } -void nsCocoaWindow::SetModal(bool aState) { +void nsCocoaWindow::SetModal(bool aModal) { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; + if (mModal == aModal) { + return; + } + // Unlike many functions here, we explicitly *do not check* for the // existence of mWindow. This is to ensure that calls to SetModal have // no early exits and always update state. That way, if the calls are @@ -732,80 +685,47 @@ void nsCocoaWindow::SetModal(bool aState) { // objects leaking. nsAutoreleasePool localPool; - mModal = aState; - nsCocoaWindow* ancestor = static_cast<nsCocoaWindow*>(mAncestorLink); - if (aState) { - ++gXULModalLevel; - // When a non-sheet window gets "set modal", make the window(s) that it - // appears over behave as they should. We can't rely on native methods to - // do this, for the following reason: The OS runs modal non-sheet windows - // in an event loop (using [NSApplication runModalForWindow:] or similar - // methods) that's incompatible with the modal event loop in AppWindow:: - // ShowModal() (each of these event loops is "exclusive", and can't run at - // the same time as other (similar) event loops). - if (mWindowType != WindowType::Sheet) { - while (ancestor) { - if (ancestor->mNumModalDescendents++ == 0) { - NSWindow* aWindow = ancestor->GetCocoaWindow(); - if (ancestor->mWindowType != WindowType::Invisible) { - [[aWindow standardWindowButton:NSWindowCloseButton] setEnabled:NO]; - [[aWindow standardWindowButton:NSWindowMiniaturizeButton] - setEnabled:NO]; - [[aWindow standardWindowButton:NSWindowZoomButton] setEnabled:NO]; - } - } - ancestor = static_cast<nsCocoaWindow*>(ancestor->mParent); - } - [mWindow setLevel:NSModalPanelWindowLevel]; - nsCocoaWindowList* windowList = new nsCocoaWindowList; - if (windowList) { - windowList->window = this; // Don't ADDREF - windowList->prev = gGeckoAppModalWindowList; - gGeckoAppModalWindowList = windowList; - } - } + mModal = aModal; + + if (aModal) { + sModalWindowCount++; } else { - --gXULModalLevel; - NS_ASSERTION(gXULModalLevel >= 0, - "Mismatched call to nsCocoaWindow::SetModal(false)!"); - if (mWindowType != WindowType::Sheet) { - while (ancestor) { - if (--ancestor->mNumModalDescendents == 0) { - NSWindow* aWindow = ancestor->GetCocoaWindow(); - if (ancestor->mWindowType != WindowType::Invisible) { - [[aWindow standardWindowButton:NSWindowCloseButton] setEnabled:YES]; - [[aWindow standardWindowButton:NSWindowMiniaturizeButton] - setEnabled:YES]; - [[aWindow standardWindowButton:NSWindowZoomButton] setEnabled:YES]; - } - } - NS_ASSERTION(ancestor->mNumModalDescendents >= 0, - "Widget hierarchy changed while modal!"); - ancestor = static_cast<nsCocoaWindow*>(ancestor->mParent); - } - if (gGeckoAppModalWindowList) { - NS_ASSERTION(gGeckoAppModalWindowList->window == this, - "Widget hierarchy changed while modal!"); - nsCocoaWindowList* saved = gGeckoAppModalWindowList; - gGeckoAppModalWindowList = gGeckoAppModalWindowList->prev; - delete saved; // "window" not ADDREFed - } - if (mWindowType == WindowType::Popup) { - SetPopupWindowLevel(); - } else { - mWindow.level = NSNormalWindowLevel; - } + MOZ_ASSERT(sModalWindowCount); + sModalWindowCount--; + } + + // When a window gets "set modal", make the window(s) that it appears over + // behave as they should. We can't rely on native methods to do this, for the + // following reason: The OS runs modal non-sheet windows in an event loop + // (using [NSApplication runModalForWindow:] or similar methods) that's + // incompatible with the modal event loop in AppWindow::ShowModal() (each of + // these event loops is "exclusive", and can't run at the same time as other + // (similar) event loops). + for (auto* ancestor = static_cast<nsCocoaWindow*>(mAncestorLink); ancestor; + ancestor = static_cast<nsCocoaWindow*>(ancestor->mParent)) { + const bool changed = aModal ? ancestor->mNumModalDescendants++ == 0 + : --ancestor->mNumModalDescendants == 0; + NS_ASSERTION(ancestor->mNumModalDescendants >= 0, + "Widget hierarchy changed while modal!"); + if (!changed || ancestor->mWindowType == WindowType::Invisible) { + continue; } + NSWindow* win = ancestor->GetCocoaWindow(); + [[win standardWindowButton:NSWindowCloseButton] setEnabled:!aModal]; + [[win standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!aModal]; + [[win standardWindowButton:NSWindowZoomButton] setEnabled:!aModal]; + } + if (aModal) { + mWindow.level = NSModalPanelWindowLevel; + } else if (mWindowType == WindowType::Popup) { + SetPopupWindowLevel(); + } else { + mWindow.level = NSNormalWindowLevel; } NS_OBJC_END_TRY_IGNORE_BLOCK; } -void nsCocoaWindow::SetFakeModal(bool aState) { - mFakeModal = aState; - SetModal(aState); -} - bool nsCocoaWindow::IsRunningAppModal() { return [NSApp _isRunningAppModal]; } // Hide or show this window @@ -816,12 +736,10 @@ void nsCocoaWindow::Show(bool aState) { return; } - if (!mSheetNeedsShow) { - // Early exit if our current visibility state is already the requested - // state. - if (aState == mWindow.isVisibleOrBeingShown) { - return; - } + // Early exit if our current visibility state is already the requested + // state. + if (aState == mWindow.isVisibleOrBeingShown) { + return; } [mWindow setBeingShown:aState]; @@ -829,11 +747,8 @@ void nsCocoaWindow::Show(bool aState) { mWasShown = true; } - nsIWidget* parentWidget = mParent; - nsCOMPtr<nsPIWidgetCocoa> piParentWidget(do_QueryInterface(parentWidget)); NSWindow* nativeParentWindow = - parentWidget ? (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW) - : nil; + mParent ? (NSWindow*)mParent->GetNativeData(NS_NATIVE_WINDOW) : nil; if (aState && !mBounds.IsEmpty()) { // If we had set the activationPolicy to accessory, then right now we won't @@ -856,82 +771,7 @@ void nsCocoaWindow::Show(bool aState) { mPopupContentView->Show(true); } - if (mWindowType == WindowType::Sheet) { - // bail if no parent window (its basically what we do in Carbon) - if (!nativeParentWindow || !piParentWidget) return; - - NSWindow* topNonSheetWindow = nativeParentWindow; - - // If this sheet is the child of another sheet, hide the parent so that - // this sheet can be displayed. Leave the parent mSheetNeedsShow alone, - // that is only used to handle sibling sheet contention. The parent will - // return once there are no more child sheets. - bool parentIsSheet = false; - if (NS_SUCCEEDED(piParentWidget->GetIsSheet(&parentIsSheet)) && - parentIsSheet) { - piParentWidget->GetSheetWindowParent(&topNonSheetWindow); -#ifdef MOZ_THUNDERBIRD - [NSApp endSheet:nativeParentWindow]; -#else - [nativeParentWindow.sheetParent endSheet:nativeParentWindow]; -#endif - } - - nsCOMPtr<nsIWidget> sheetShown; - if (NS_SUCCEEDED(piParentWidget->GetChildSheet( - true, getter_AddRefs(sheetShown))) && - (!sheetShown || sheetShown == this)) { - // If this sheet is already the sheet actually being shown, don't - // tell it to show again. Otherwise the number of calls to -#ifdef MOZ_THUNDERBIRD - // [NSApp beginSheet...] won't match up with [NSApp endSheet...]. -#else - // [NSWindow beginSheet...] won't match up with [NSWindow endSheet...]. -#endif - if (![mWindow isVisible]) { - mSheetNeedsShow = false; - mSheetWindowParent = topNonSheetWindow; -#ifdef MOZ_THUNDERBIRD - // Only set contextInfo if our parent isn't a sheet. - NSWindow* contextInfo = parentIsSheet ? nil : mSheetWindowParent; - [TopLevelWindowData deactivateInWindow:mSheetWindowParent]; - [NSApp beginSheet:mWindow - modalForWindow:mSheetWindowParent - modalDelegate:mDelegate - didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) - contextInfo:contextInfo]; -#else - NSWindow* sheet = mWindow; - NSWindow* nonSheetParent = parentIsSheet ? nil : mSheetWindowParent; - [TopLevelWindowData deactivateInWindow:mSheetWindowParent]; - [mSheetWindowParent beginSheet:sheet - completionHandler:^(NSModalResponse returnCode) { - // Note: 'nonSheetParent' (if it is set) is the window - // that is the parent of the sheet. If it's set, - // 'nonSheetParent' is always the top- level window, - // not another sheet itself. But 'nonSheetParent' is - // nil if our parent window is also a sheet -- in that - // case we shouldn't send the top-level window any - // activate events (because it's our parent window that - // needs to get these events, not the top-level - // window). - [TopLevelWindowData deactivateInWindow:sheet]; - [sheet orderOut:nil]; - if (nonSheetParent) { - [TopLevelWindowData activateInWindow:nonSheetParent]; - } - }]; -#endif - [TopLevelWindowData activateInWindow:mWindow]; - SendSetZLevelEvent(); - } - } else { - // A sibling of this sheet is active, don't show this sheet yet. - // When the active sheet hides, its brothers and sisters that have - // mSheetNeedsShow set will have their opportunities to display. - mSheetNeedsShow = true; - } - } else if (mWindowType == WindowType::Popup) { + if (mWindowType == WindowType::Popup) { // For reasons that aren't yet clear, calls to [NSWindow orderFront:] or // [NSWindow makeKeyAndOrderFront:] can sometimes trigger "Error (1000) // creating CGSWindow", which in turn triggers an internal inconsistency @@ -939,7 +779,9 @@ void nsCocoaWindow::Show(bool aState) { // calls to ...orderFront: in TRY blocks. See bmo bug 470864. NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; [[mWindow contentView] setNeedsDisplay:YES]; - [mWindow orderFront:nil]; + if (!nativeParentWindow || mPopupLevel != PopupLevel::Parent) { + [mWindow orderFront:nil]; + } NS_OBJC_END_TRY_IGNORE_BLOCK; SendSetZLevelEvent(); // If our popup window is a non-native context menu, tell the OS (and @@ -955,9 +797,7 @@ void nsCocoaWindow::Show(bool aState) { // If a parent window was supplied and this is a popup at the parent // level, set its child window. This will cause the child window to - // appear above the parent and move when the parent does. Setting this - // needs to happen after the _setWindowNumber calls above, otherwise the - // window doesn't focus properly. + // appear above the parent and move when the parent does. if (nativeParentWindow && mPopupLevel == PopupLevel::Parent) { [nativeParentWindow addChildWindow:mWindow ordered:NSWindowAbove]; } @@ -1001,120 +841,22 @@ void nsCocoaWindow::Show(bool aState) { RollUpPopups(); } - // now get rid of the window/sheet - if (mWindowType == WindowType::Sheet) { - if (mSheetNeedsShow) { - // This is an attempt to hide a sheet that never had a chance to - // be shown. There's nothing to do other than make sure that it - // won't show. - mSheetNeedsShow = false; - } else { - // get sheet's parent *before* hiding the sheet (which breaks the - // linkage) - NSWindow* sheetParent = mSheetWindowParent; - - // hide the sheet -#ifdef MOZ_THUNDERBIRD - [NSApp endSheet:mWindow]; -#else - [mSheetWindowParent endSheet:mWindow]; -#endif - [TopLevelWindowData deactivateInWindow:mWindow]; - - nsCOMPtr<nsIWidget> siblingSheetToShow; - bool parentIsSheet = false; - - if (nativeParentWindow && piParentWidget && - NS_SUCCEEDED(piParentWidget->GetChildSheet( - false, getter_AddRefs(siblingSheetToShow))) && - siblingSheetToShow) { - // First, give sibling sheets an opportunity to show. - siblingSheetToShow->Show(true); - } else if (nativeParentWindow && piParentWidget && - NS_SUCCEEDED(piParentWidget->GetIsSheet(&parentIsSheet)) && - parentIsSheet) { -#ifdef MOZ_THUNDERBIRD - // Only set contextInfo if the parent of the parent sheet we're about - // to restore isn't itself a sheet. - NSWindow* contextInfo = sheetParent; -#else - // Only set nonSheetGrandparent if the parent of the parent sheet - // we're about to restore isn't itself a sheet. - NSWindow* nonSheetGrandparent = sheetParent; -#endif - nsIWidget* grandparentWidget = nil; - if (NS_SUCCEEDED(piParentWidget->GetRealParent(&grandparentWidget)) && - grandparentWidget) { - nsCOMPtr<nsPIWidgetCocoa> piGrandparentWidget( - do_QueryInterface(grandparentWidget)); - bool grandparentIsSheet = false; - if (piGrandparentWidget && - NS_SUCCEEDED( - piGrandparentWidget->GetIsSheet(&grandparentIsSheet)) && - grandparentIsSheet) { -#ifdef MOZ_THUNDERBIRD - contextInfo = nil; -#else - nonSheetGrandparent = nil; -#endif - } - } - // If there are no sibling sheets, but the parent is a sheet, restore - // it. It wasn't sent any deactivate events when it was hidden, so - // don't call through Show, just let the OS put it back up. -#ifdef MOZ_THUNDERBIRD - [NSApp beginSheet:nativeParentWindow - modalForWindow:sheetParent - modalDelegate:[nativeParentWindow delegate] - didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) - contextInfo:contextInfo]; -#else - [nativeParentWindow - beginSheet:sheetParent - completionHandler:^(NSModalResponse returnCode) { - // Note: 'nonSheetGrandparent' (if it is set) is the window that - // is the parent of sheetParent. If it's set, - // 'nonSheetGrandparent' is always the top-level window, not - // another sheet itself. But 'nonSheetGrandparent' is nil if - // our parent window is also a sheet -- in that case we - // shouldn't send the top-level window any activate events - // (because it's our parent window that needs to get these - // events, not the top-level window). - [TopLevelWindowData deactivateInWindow:sheetParent]; - [sheetParent orderOut:nil]; - if (nonSheetGrandparent) { - [TopLevelWindowData activateInWindow:nonSheetGrandparent]; - } - }]; -#endif - } else { - // Sheet, that was hard. No more siblings or parents, going back - // to a real window. - NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - [sheetParent makeKeyAndOrderFront:nil]; - NS_OBJC_END_TRY_IGNORE_BLOCK; - } - SendSetZLevelEvent(); - } - } else { - // If the window is a popup window with a parent window we need to - // unhook it here before ordering it out. When you order out the child - // of a window it hides the parent window. - if (mWindowType == WindowType::Popup && nativeParentWindow) { - [nativeParentWindow removeChildWindow:mWindow]; - } - - [mWindow orderOut:nil]; + // If the window is a popup window with a parent window we need to + // unhook it here before ordering it out. When you order out the child + // of a window it hides the parent window. + if (mWindowType == WindowType::Popup && nativeParentWindow) { + [nativeParentWindow removeChildWindow:mWindow]; + } - // If our popup window is a non-native context menu, tell the OS (and - // other programs) that a menu has closed. - if ([mWindow isKindOfClass:[PopupWindow class]] && - [(PopupWindow*)mWindow isContextMenu]) { - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName: - @"com.apple.HIToolbox.endMenuTrackingNotification" - object:@"org.mozilla.gecko.PopupWindow"]; - } + [mWindow orderOut:nil]; + // If our popup window is a non-native context menu, tell the OS (and + // other programs) that a menu has closed. + if ([mWindow isKindOfClass:[PopupWindow class]] && + [(PopupWindow*)mWindow isContextMenu]) { + [NSDistributedNotificationCenter.defaultCenter + postNotificationName: + @"com.apple.HIToolbox.endMenuTrackingNotification" + object:@"org.mozilla.gecko.PopupWindow"]; } } @@ -2287,53 +2029,13 @@ bool nsCocoaWindow::DragEvent(unsigned int aMessage, return false; } -NS_IMETHODIMP nsCocoaWindow::SendSetZLevelEvent() { - nsWindowZ placement = nsWindowZTop; - nsCOMPtr<nsIWidget> actualBelow; +void nsCocoaWindow::SendSetZLevelEvent() { if (mWidgetListener) { + nsWindowZ placement = nsWindowZTop; + nsCOMPtr<nsIWidget> actualBelow; mWidgetListener->ZLevelChanged(true, &placement, nullptr, getter_AddRefs(actualBelow)); } - return NS_OK; -} - -NS_IMETHODIMP nsCocoaWindow::GetChildSheet(bool aShown, nsIWidget** _retval) { - nsIWidget* child = GetFirstChild(); - - while (child) { - if (child->GetWindowType() == WindowType::Sheet) { - // if it's a sheet, it must be an nsCocoaWindow - nsCocoaWindow* cocoaWindow = static_cast<nsCocoaWindow*>(child); - if (cocoaWindow->mWindow && - ((aShown && [cocoaWindow->mWindow isVisible]) || - (!aShown && cocoaWindow->mSheetNeedsShow))) { - nsCOMPtr<nsIWidget> widget = cocoaWindow; - widget.forget(_retval); - return NS_OK; - } - } - child = child->GetNextSibling(); - } - - *_retval = nullptr; - - return NS_OK; -} - -NS_IMETHODIMP nsCocoaWindow::GetRealParent(nsIWidget** parent) { - *parent = mParent; - return NS_OK; -} - -NS_IMETHODIMP nsCocoaWindow::GetIsSheet(bool* isSheet) { - mWindowType == WindowType::Sheet ? * isSheet = true : * isSheet = false; - return NS_OK; -} - -NS_IMETHODIMP nsCocoaWindow::GetSheetWindowParent( - NSWindow** sheetWindowParent) { - *sheetWindowParent = mSheetWindowParent; - return NS_OK; } // Invokes callback and ProcessEvent methods on Event Listener object @@ -3184,9 +2886,7 @@ void nsCocoaWindow::CocoaWindowDidResize() { ChildViewMouseTracker::ReEvaluateMouseEnterState(); NSWindow* window = [aNotification object]; - if ([window isSheet]) [WindowDelegate paintMenubarForWindow:window]; - - nsChildView* mainChildView = + auto* mainChildView = static_cast<nsChildView*>([[(BaseWindow*)window mainChildView] widget]); if (mainChildView) { if (mainChildView->GetInputContext().IsPasswordEditor()) { @@ -3205,13 +2905,6 @@ void nsCocoaWindow::CocoaWindowDidResize() { RollUpPopups(nsIRollupListener::AllowAnimations::No); ChildViewMouseTracker::ReEvaluateMouseEnterState(); - - // If a sheet just resigned key then we should paint the menu bar - // for whatever window is now main. - NSWindow* window = [aNotification object]; - if ([window isSheet]) - [WindowDelegate paintMenubarForWindow:[NSApp mainWindow]]; - TextInputHandler::EnsureSecureEventInputDisabled(); NS_OBJC_END_TRY_IGNORE_BLOCK; @@ -3264,36 +2957,6 @@ void nsCocoaWindow::CocoaWindowDidResize() { return YES; } -- (NSRect)window:(NSWindow*)window - willPositionSheet:(NSWindow*)sheet - usingRect:(NSRect)rect { - if ([window isKindOfClass:[ToolbarWindow class]]) { - rect.origin.y = [(ToolbarWindow*)window sheetAttachmentPosition]; - } - return rect; -} - -#ifdef MOZ_THUNDERBIRD -- (void)didEndSheet:(NSWindow*)sheet - returnCode:(int)returnCode - contextInfo:(void*)contextInfo { - NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - - // Note: 'contextInfo' (if it is set) is the window that is the parent of - // the sheet. The value of contextInfo is determined in - // nsCocoaWindow::Show(). If it's set, 'contextInfo' is always the top- - // level window, not another sheet itself. But 'contextInfo' is nil if - // our parent window is also a sheet -- in that case we shouldn't send - // the top-level window any activate events (because it's our parent - // window that needs to get these events, not the top-level window). - [TopLevelWindowData deactivateInWindow:sheet]; - [sheet orderOut:self]; - if (contextInfo) [TopLevelWindowData activateInWindow:(NSWindow*)contextInfo]; - - NS_OBJC_END_TRY_ABORT_BLOCK; -} -#endif - - (void)windowDidChangeBackingProperties:(NSNotification*)aNotification { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; @@ -3354,7 +3017,7 @@ void nsCocoaWindow::CocoaWindowDidResize() { return self.FrameView__closeButtonOrigin; } auto* win = static_cast<ToolbarWindow*>(self.window); - if (win.drawsContentsIntoWindowFrame && + if (win.drawsContentsIntoWindowFrame && !win.wantsTitleDrawn && !(win.styleMask & NSWindowStyleMaskFullScreen) && (win.styleMask & NSWindowStyleMaskTitled)) { const NSRect buttonsRect = win.windowButtonsRect; @@ -3624,7 +3287,7 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn"; } - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState { - bool changed = (aState != mDrawsIntoWindowFrame); + bool changed = aState != mDrawsIntoWindowFrame; mDrawsIntoWindowFrame = aState; if (changed) { [self reflowTitlebarElements]; @@ -3826,53 +3489,6 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn"; @end -@interface NSView (NSThemeFrame) -- (void)_drawTitleStringInClip:(NSRect)aRect; -- (void)_maskCorners:(NSUInteger)aFlags clipRect:(NSRect)aRect; -@end - -@implementation MOZTitlebarView - -- (instancetype)initWithFrame:(NSRect)aFrame { - self = [super initWithFrame:aFrame]; - - self.material = NSVisualEffectMaterialTitlebar; - self.blendingMode = NSVisualEffectBlendingModeWithinWindow; - - // Add a separator line at the bottom of the titlebar. NSBoxSeparator isn't a - // perfect match for a native titlebar separator, but it's better than - // nothing. We really want the appearance that _NSTitlebarDecorationView - // creates with the help of CoreUI, but there's no public API for that. - NSBox* separatorLine = - [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, aFrame.size.width, 1)]; - separatorLine.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin; - separatorLine.boxType = NSBoxSeparator; - [self addSubview:separatorLine]; - [separatorLine release]; - - return self; -} - -- (BOOL)mouseDownCanMoveWindow { - return YES; -} - -- (void)mouseUp:(NSEvent*)event { - if (event.clickCount == 2) { - // Handle titlebar double click. We don't get the window's default behavior - // here because the window uses NSWindowStyleMaskFullSizeContentView, and - // this view (the titlebar gradient view) is technically part of the window - // "contents" (it's a subview of the content view). - if (nsCocoaUtils::ShouldZoomOnTitlebarDoubleClick()) { - [self.window performZoom:nil]; - } else if (nsCocoaUtils::ShouldMinimizeOnTitlebarDoubleClick()) { - [self.window performMiniaturize:nil]; - } - } -} - -@end - @interface MOZTitlebarAccessoryView : NSView @end @@ -3896,44 +3512,51 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn"; @implementation FullscreenTitlebarTracker - (FullscreenTitlebarTracker*)init { [super init]; - self.view = - [[[MOZTitlebarAccessoryView alloc] initWithFrame:NSZeroRect] autorelease]; self.hidden = YES; return self; } +- (void)loadView { + self.view = + [[[MOZTitlebarAccessoryView alloc] initWithFrame:NSZeroRect] autorelease]; +} @end -// This class allows us to exercise control over the window's title bar. It is -// used for all windows with titlebars. -// -// ToolbarWindow supports two modes: -// - drawsContentsIntoWindowFrame mode: In this mode, the Gecko ChildView is -// sized to cover the entire window frame and manages titlebar drawing. -// - separate titlebar mode, with support for unified toolbars: In this mode, -// the Gecko ChildView does not extend into the titlebar. However, this -// window's content view (which is the ChildView's superview) *does* extend -// into the titlebar. Moreover, in this mode, we place a MOZTitlebarView -// in the content view, as a sibling of the ChildView. -// -// The "separate titlebar mode" supports the "unified toolbar" look: -// If there's a toolbar right below the titlebar, the two can "connect" and -// form a single gradient without a separator line in between. -// -// The following mechanism communicates the height of the unified toolbar to -// the ToolbarWindow: -// -// 1) In the style sheet we set the toolbar's -moz-appearance to toolbar. -// 2) When the toolbar is visible and we paint the application chrome -// window, the array that Gecko passes nsChildView::UpdateThemeGeometries -// will contain an entry for the widget type StyleAppearance::Toolbar. -// 3) nsChildView::UpdateThemeGeometries passes the toolbar's height, plus the -// titlebar height, to -[ToolbarWindow setUnifiedToolbarHeight:]. -// -// The actual drawing of the gradient happens in two parts: The titlebar part -// (i.e. the top 22 pixels of the gradient) is drawn by the MOZTitlebarView, -// which is a subview of the window's content view and a sibling of the -// ChildView. The rest of the gradient is drawn by Gecko into the ChildView, as -// part of the -moz-appearance rendering of the toolbar. +// Drop all mouse events if a modal window has appeared above us. +// This helps make us behave as if the OS were running a "real" modal event +// loop. +static bool MaybeDropEventForModalWindow(NSEvent* aEvent, id aDelegate) { + if (!sModalWindowCount) { + return false; + } + + NSEventType type = [aEvent type]; + switch (type) { + case NSEventTypeScrollWheel: + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseDown: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseDown: + case NSEventTypeOtherMouseUp: + case NSEventTypeMouseMoved: + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDragged: + break; + default: + return false; + } + + if (aDelegate && [aDelegate isKindOfClass:[WindowDelegate class]]) { + if (nsCocoaWindow* widget = [(WindowDelegate*)aDelegate geckoWidget]) { + if (!widget->IsModal() || widget->HasModalDescendants()) { + return true; + } + } + } + return false; +} + @implementation ToolbarWindow - (id)initWithContentRect:(NSRect)aChildViewRect @@ -3972,17 +3595,12 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn"; styleMask:aStyle backing:aBufferingType defer:aFlag])) { - mTitlebarView = nil; - mUnifiedToolbarHeight = 22.0f; - mSheetAttachmentPosition = aChildViewRect.size.height; mWindowButtonsRect = NSZeroRect; - mInitialTitlebarHeight = [self titlebarHeight]; - [self setTitlebarAppearsTransparent:YES]; + self.titlebarAppearsTransparent = YES; if (@available(macOS 11.0, *)) { self.titlebarSeparatorStyle = NSTitlebarSeparatorStyleNone; } - [self updateTitlebarView]; mFullscreenTitlebarTracker = [[FullscreenTitlebarTracker alloc] init]; // revealAmount is an undocumented property of @@ -4048,8 +3666,7 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) { } - (void)updateTitlebarShownAmount:(CGFloat)aShownAmount { - NSInteger styleMask = [self styleMask]; - if (!(styleMask & NSWindowStyleMaskFullScreen)) { + if (!(self.styleMask & NSWindowStyleMaskFullScreen)) { // We are not interested in the size of the titlebar unless we are in // fullscreen. return; @@ -4071,27 +3688,24 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) { } if (nsIWidgetListener* listener = geckoWindow->GetWidgetListener()) { - // Use the titlebar height cached in our frame rather than - // [ToolbarWindow titlebarHeight]. titlebarHeight returns 0 when we're in - // fullscreen. - CGFloat shiftByPixels = mInitialTitlebarHeight * aShownAmount; + // titlebarHeight returns 0 when we're in fullscreen, return the default + // titlebar height. + CGFloat shiftByPixels = + LookAndFeel::GetInt(LookAndFeel::IntID::MacTitlebarHeight) * + aShownAmount; if (ShouldShiftByMenubarHeightInFullscreen(geckoWindow)) { shiftByPixels += mMenuBarHeight * aShownAmount; } - // Use mozilla::DesktopToLayoutDeviceScale rather than the - // DesktopToLayoutDeviceScale in nsCocoaWindow. The latter accounts for - // screen DPI. We don't want that because the revealAmount property - // already accounts for it, so we'd be compounding DPI scales > 1. - mozilla::DesktopCoord coord = LayoutDeviceCoord(shiftByPixels) / - mozilla::DesktopToLayoutDeviceScale(); - - listener->MacFullscreenMenubarOverlapChanged(coord); + // Use desktop pixels rather than the DesktopToLayoutDeviceScale in + // nsCocoaWindow. The latter accounts for screen DPI. We don't want that + // because the revealAmount property already accounts for it, so we'd be + // compounding DPI scales > 1. + listener->MacFullscreenMenubarOverlapChanged(DesktopCoord(shiftByPixels)); } } } - (void)dealloc { - [mTitlebarView release]; [mFullscreenTitlebarTracker removeObserver:self forKeyPath:@"revealAmount"]; [mFullscreenTitlebarTracker removeFromParentViewController]; [mFullscreenTitlebarTracker release]; @@ -4100,80 +3714,13 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) { } - (NSArray<NSView*>*)contentViewContents { - NSMutableArray<NSView*>* contents = [[self.contentView subviews] mutableCopy]; - if (mTitlebarView) { - // Do not include the titlebar gradient view in the returned array. - [contents removeObject:mTitlebarView]; - } - return [contents autorelease]; -} - -- (void)updateTitlebarView { - BOOL needTitlebarView = - !self.drawsContentsIntoWindowFrame || mUnifiedToolbarHeight > 0; - if (needTitlebarView && !mTitlebarView) { - mTitlebarView = - [[MOZTitlebarView alloc] initWithFrame:self.unifiedToolbarRect]; - mTitlebarView.autoresizingMask = NSViewWidthSizable | NSViewMinYMargin; - [self.contentView addSubview:mTitlebarView - positioned:NSWindowBelow - relativeTo:nil]; - } else if (needTitlebarView && mTitlebarView) { - mTitlebarView.frame = self.unifiedToolbarRect; - } else if (!needTitlebarView && mTitlebarView) { - [mTitlebarView removeFromSuperview]; - [mTitlebarView release]; - mTitlebarView = nil; - } + return [[self.contentView.subviews copy] autorelease]; } - (void)windowMainStateChanged { - [self setTitlebarNeedsDisplay]; [[self mainChildView] ensureNextCompositeIsAtomicWithMainThreadPaint]; } -- (void)setTitlebarNeedsDisplay { - [mTitlebarView setNeedsDisplay:YES]; -} - -- (NSRect)titlebarRect { - CGFloat titlebarHeight = self.titlebarHeight; - return NSMakeRect(0, self.frame.size.height - titlebarHeight, - self.frame.size.width, titlebarHeight); -} - -// In window contentView coordinates (origin bottom left) -- (NSRect)unifiedToolbarRect { - return NSMakeRect(0, self.frame.size.height - mUnifiedToolbarHeight, - self.frame.size.width, mUnifiedToolbarHeight); -} - -// Returns the unified height of titlebar + toolbar. -- (CGFloat)unifiedToolbarHeight { - return mUnifiedToolbarHeight; -} - -- (CGFloat)titlebarHeight { - // We use the original content rect here, not what we return from - // [self contentRectForFrameRect:], because that would give us a - // titlebarHeight of zero. - NSRect frameRect = self.frame; - NSUInteger styleMask = self.styleMask; - styleMask &= ~NSWindowStyleMaskFullSizeContentView; - NSRect originalContentRect = [NSWindow contentRectForFrameRect:frameRect - styleMask:styleMask]; - return NSMaxY(frameRect) - NSMaxY(originalContentRect); -} - -// Stores the complete height of titlebar + toolbar. -- (void)setUnifiedToolbarHeight:(CGFloat)aHeight { - if (aHeight == mUnifiedToolbarHeight) return; - - mUnifiedToolbarHeight = aHeight; - - [self updateTitlebarView]; -} - // Extending the content area into the title bar works by resizing the // mainChildView so that it covers the titlebar. - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState { @@ -4197,21 +3744,6 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) { // we'll send a mouse move event with the correct new position. ChildViewMouseTracker::ResendLastMouseMoveEvent(); } - - [self updateTitlebarView]; -} - -- (void)setWantsTitleDrawn:(BOOL)aDrawTitle { - [super setWantsTitleDrawn:aDrawTitle]; - [self setTitlebarNeedsDisplay]; -} - -- (void)setSheetAttachmentPosition:(CGFloat)aY { - mSheetAttachmentPosition = aY; -} - -- (CGFloat)sheetAttachmentPosition { - return mSheetAttachmentPosition; } - (void)placeWindowButtons:(NSRect)aRect { @@ -4268,42 +3800,9 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) { } - (void)sendEvent:(NSEvent*)anEvent { - NSEventType type = [anEvent type]; - - switch (type) { - case NSEventTypeScrollWheel: - case NSEventTypeLeftMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseDown: - case NSEventTypeOtherMouseUp: - case NSEventTypeMouseMoved: - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: { - // Drop all mouse events if a modal window has appeared above us. - // This helps make us behave as if the OS were running a "real" modal - // event loop. - id delegate = self.delegate; - if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) { - nsCocoaWindow* widget = [(WindowDelegate*)delegate geckoWidget]; - if (widget) { - if (gGeckoAppModalWindowList && - widget != gGeckoAppModalWindowList->window) { - return; - } - if (widget->HasModalDescendents()) { - return; - } - } - } - break; - } - default: - break; + if (MaybeDropEventForModalWindow(anEvent, self.delegate)) { + return; } - [super sendEvent:anEvent]; } @@ -4403,40 +3902,8 @@ static const NSUInteger kWindowShadowOptionsTooltip = 4; } - (void)sendEvent:(NSEvent*)anEvent { - NSEventType type = [anEvent type]; - - switch (type) { - case NSEventTypeScrollWheel: - case NSEventTypeLeftMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseDown: - case NSEventTypeOtherMouseUp: - case NSEventTypeMouseMoved: - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: { - // Drop all mouse events if a modal window has appeared above us. - // This helps make us behave as if the OS were running a "real" modal - // event loop. - id delegate = self.delegate; - if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) { - nsCocoaWindow* widget = [(WindowDelegate*)delegate geckoWidget]; - if (widget) { - if (gGeckoAppModalWindowList && - widget != gGeckoAppModalWindowList->window) { - return; - } - if (widget->HasModalDescendents()) { - return; - } - } - } - break; - } - default: - break; + if (MaybeDropEventForModalWindow(anEvent, self.delegate)) { + return; } [super sendEvent:anEvent]; diff --git a/widget/cocoa/nsLookAndFeel.h b/widget/cocoa/nsLookAndFeel.h index adce685a4e..89e4c93713 100644 --- a/widget/cocoa/nsLookAndFeel.h +++ b/widget/cocoa/nsLookAndFeel.h @@ -12,14 +12,17 @@ class nsLookAndFeel final : public nsXPLookAndFeel { nsLookAndFeel(); virtual ~nsLookAndFeel(); - void NativeInit() final; + void NativeInit() final { EnsureInit(); } + void RefreshImpl() final; + void EnsureInit(); + nsresult NativeGetColor(ColorID, ColorScheme, nscolor& aColor) override; nsresult NativeGetInt(IntID, int32_t& aResult) override; nsresult NativeGetFloat(FloatID, float& aResult) override; bool NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle& aFontStyle) override; - virtual char16_t GetPasswordCharacterImpl() override { + char16_t GetPasswordCharacterImpl() override { // unicode value for the bullet character, used for password textfields. return 0x2022; } @@ -34,10 +37,9 @@ class nsLookAndFeel final : public nsXPLookAndFeel { static void RecordAccessibilityTelemetry(); protected: - static bool SystemWantsDarkTheme(); - static bool IsSystemOrientationRTL(); - static nscolor ProcessSelectionBackground(nscolor aColor, - ColorScheme aScheme); + bool mInitialized = false; + bool mRtl = false; + int32_t mTitlebarHeight = 0; }; #endif // nsLookAndFeel_h_ diff --git a/widget/cocoa/nsLookAndFeel.mm b/widget/cocoa/nsLookAndFeel.mm index 5675198ff2..779984be0c 100644 --- a/widget/cocoa/nsLookAndFeel.mm +++ b/widget/cocoa/nsLookAndFeel.mm @@ -32,22 +32,44 @@ using namespace mozilla; + (void)startObserving; @end -nsLookAndFeel::nsLookAndFeel() = default; +nsLookAndFeel::nsLookAndFeel() { + [MOZLookAndFeelDynamicChangeObserver startObserving]; +} nsLookAndFeel::~nsLookAndFeel() = default; -void nsLookAndFeel::NativeInit() { +void nsLookAndFeel::EnsureInit() { + if (mInitialized) { + return; + } + NS_OBJC_BEGIN_TRY_ABORT_BLOCK - [MOZLookAndFeelDynamicChangeObserver startObserving]; + mInitialized = true; + NSWindow* window = + [[NSWindow alloc] initWithContentRect:NSZeroRect + styleMask:NSWindowStyleMaskTitled + backing:NSBackingStoreBuffered + defer:NO]; + auto release = MakeScopeExit([&] { [window release]; }); + + mRtl = window.windowTitlebarLayoutDirection == + NSUserInterfaceLayoutDirectionRightToLeft; + mTitlebarHeight = std::ceil(window.frame.size.height); + RecordTelemetry(); NS_OBJC_END_TRY_ABORT_BLOCK } +void nsLookAndFeel::RefreshImpl() { + mInitialized = false; + nsXPLookAndFeel::RefreshImpl(); +} + static nscolor GetColorFromNSColor(NSColor* aColor) { NSColor* deviceColor = - [aColor colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; + [aColor colorUsingColorSpace:NSColorSpace.deviceRGBColorSpace]; return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0), (unsigned int)(deviceColor.greenComponent * 255.0), (unsigned int)(deviceColor.blueComponent * 255.0), @@ -77,8 +99,7 @@ static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, // whereas white text on dark blue (which what you get if you mix // partially-transparent light blue with the black textbox background) has much // better contrast. -nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, - ColorScheme aScheme) { +static nscolor ProcessSelectionBackground(nscolor aColor, ColorScheme aScheme) { if (aScheme == ColorScheme::Dark) { // When we use a dark selection color, we do not change alpha because we do // not use dark selection in content. The dark system color is appropriate @@ -136,6 +157,14 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, case ColorID::MozMenuhover: case ColorID::Selecteditem: color = GetColorFromNSColor(NSColor.selectedContentBackgroundColor); + if (aID == ColorID::MozMenuhover && + !LookAndFeel::GetInt(IntID::PrefersReducedTransparency)) { + // Wash the color a little bit with semi-transparent white to match a + // bit closer the native NSVisualEffectSelection on menus. + color = NS_ComposeColors( + color, + NS_RGBA(255, 255, 255, aScheme == ColorScheme::Light ? 51 : 25)); + } break; case ColorID::Accentcolortext: case ColorID::MozMenuhovertext: @@ -197,6 +226,7 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, : NS_RGB(0xFF, 0xFF, 0xFF); break; case ColorID::Windowtext: + case ColorID::MozDialogtext: color = GetColorFromNSColor(NSColor.windowFrameTextColor); break; case ColorID::Appworkspace: @@ -254,13 +284,14 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, case ColorID::Windowframe: color = GetColorFromNSColor(NSColor.windowFrameColor); break; - case ColorID::Window: { - color = GetColorFromNSColor(NSColor.windowBackgroundColor); + case ColorID::MozDialog: + case ColorID::Window: + color = GetColorFromNSColor(aScheme == ColorScheme::Light + ? NSColor.windowBackgroundColor + : NSColor.underPageBackgroundColor); break; - } case ColorID::Field: case ColorID::MozCombobox: - case ColorID::MozDialog: color = GetColorFromNSColor(NSColor.controlBackgroundColor); break; case ColorID::Fieldtext: @@ -269,7 +300,6 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, case ColorID::MozButtonhovertext: case ColorID::Menutext: case ColorID::Infotext: - case ColorID::MozDialogtext: case ColorID::MozCellhighlighttext: case ColorID::MozColheadertext: case ColorID::MozColheaderhovertext: @@ -323,6 +353,7 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, case ColorID::SpellCheckerUnderline: case ColorID::Activeborder: case ColorID::Inactiveborder: + case ColorID::MozAutofillBackground: aColor = GetStandinForNativeColor(aID, aScheme); return NS_OK; default: @@ -336,6 +367,16 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, NS_OBJC_END_TRY_ABORT_BLOCK } +static bool SystemWantsDarkTheme() { + // This returns true if the macOS system appearance is set to dark mode, + // false otherwise. + NSAppearanceName aquaOrDarkAqua = + [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[ + NSAppearanceNameAqua, NSAppearanceNameDarkAqua + ]]; + return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua]; +} + nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; @@ -355,9 +396,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { case IntID::CaretWidth: aResult = 1; break; - case IntID::ShowCaretDuringSelection: - aResult = 0; - break; case IntID::SelectTextfieldsOnKeyFocus: // Select textfield content when focused by kbd // used by EventStateManager::sTextfieldSelectModel @@ -412,7 +450,12 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { aResult = nsCocoaFeatures::OnBigSurOrLater(); break; case IntID::MacRTL: - aResult = IsSystemOrientationRTL(); + EnsureInit(); + aResult = mRtl; + break; + case IntID::MacTitlebarHeight: + EnsureInit(); + aResult = mTitlebarHeight; break; case IntID::AlertNotificationOrigin: aResult = NS_ALERT_TOP; @@ -469,14 +512,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { aResult = NSWorkspace.sharedWorkspace .accessibilityDisplayShouldIncreaseContrast; break; - case IntID::VideoDynamicRange: { - // If the platform says it supports HDR, then we claim to support - // video-dynamic-range. - gfxPlatform* platform = gfxPlatform::GetPlatform(); - MOZ_ASSERT(platform); - aResult = platform->SupportsHDR(); - break; - } case IntID::PanelAnimations: aResult = 1; break; @@ -519,28 +554,6 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) { NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); } -bool nsLookAndFeel::SystemWantsDarkTheme() { - // This returns true if the macOS system appearance is set to dark mode, false - // otherwise. - NSAppearanceName aquaOrDarkAqua = - [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[ - NSAppearanceNameAqua, NSAppearanceNameDarkAqua - ]]; - return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua]; -} - -/*static*/ -bool nsLookAndFeel::IsSystemOrientationRTL() { - NSWindow* window = - [[NSWindow alloc] initWithContentRect:NSZeroRect - styleMask:NSWindowStyleMaskBorderless - backing:NSBackingStoreBuffered - defer:NO]; - auto direction = window.windowTitlebarLayoutDirection; - [window release]; - return direction == NSUserInterfaceLayoutDirectionRightToLeft; -} - bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle& aFontStyle) { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; diff --git a/widget/cocoa/nsNativeThemeCocoa.h b/widget/cocoa/nsNativeThemeCocoa.h index 9488e50e1e..ebbf782264 100644 --- a/widget/cocoa/nsNativeThemeCocoa.h +++ b/widget/cocoa/nsNativeThemeCocoa.h @@ -159,7 +159,6 @@ class nsNativeThemeCocoa : public mozilla::widget::ThemeCocoa { eSpinButtonDown, // SpinButtonParams eSegment, // SegmentParams eSeparator, - eToolbar, // bool eStatusBar, // bool eGroupBox, eTextField, // TextFieldParams @@ -204,9 +203,6 @@ class nsNativeThemeCocoa : public mozilla::widget::ThemeCocoa { static WidgetInfo Separator() { return WidgetInfo(Widget::eSeparator, false); } - static WidgetInfo Toolbar(bool aParams) { - return WidgetInfo(Widget::eToolbar, aParams); - } static WidgetInfo StatusBar(bool aParams) { return WidgetInfo(Widget::eStatusBar, aParams); } diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index ff715ac57c..18913facea 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -399,9 +399,8 @@ static BOOL FrameIsInActiveWindow(nsIFrame* aFrame) { // Toolbar controls and content controls respond to different window // activeness states. -static BOOL IsActive(nsIFrame* aFrame, BOOL aIsToolbarControl) { - if (aIsToolbarControl) return [NativeWindowForFrame(aFrame) isMainWindow]; - return FrameIsInActiveWindow(aFrame); +static BOOL IsActiveToolbarControl(nsIFrame* aFrame) { + return NativeWindowForFrame(aFrame).isMainWindow; } NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeCocoa, nsNativeTheme, nsITheme) @@ -1021,7 +1020,6 @@ static bool IsToolbarStyleContainer(nsIFrame* aFrame) { } switch (aFrame->StyleDisplay()->EffectiveAppearance()) { - case StyleAppearance::Toolbar: case StyleAppearance::Statusbar: return true; default: @@ -2078,35 +2076,6 @@ void nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, RenderWithCoreUI(drawRect, cgContext, dict); } -void nsNativeThemeCocoa::DrawToolbar(CGContextRef cgContext, - const CGRect& inBoxRect, bool aIsMain) { - CGRect drawRect = inBoxRect; - - // top border - drawRect.size.height = 1.0f; - DrawNativeGreyColorInRect(cgContext, toolbarTopBorderGrey, drawRect, aIsMain); - - // background - drawRect.origin.y += drawRect.size.height; - drawRect.size.height = inBoxRect.size.height - 2.0f; - DrawNativeGreyColorInRect(cgContext, toolbarFillGrey, drawRect, aIsMain); - - // bottom border - drawRect.origin.y += drawRect.size.height; - drawRect.size.height = 1.0f; - DrawNativeGreyColorInRect(cgContext, toolbarBottomBorderGrey, drawRect, - aIsMain); -} - -static bool ToolbarCanBeUnified(const gfx::Rect& aRect, NSWindow* aWindow) { - if (![aWindow isKindOfClass:[ToolbarWindow class]]) return false; - - ToolbarWindow* win = (ToolbarWindow*)aWindow; - float unifiedToolbarHeight = [win unifiedToolbarHeight]; - return aRect.X() == 0 && aRect.Width() >= [win frame].size.width && - aRect.YMost() <= unifiedToolbarHeight; -} - void nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect, bool aIsMain) { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; @@ -2329,25 +2298,12 @@ Maybe<nsNativeThemeCocoa::WidgetInfo> nsNativeThemeCocoa::ComputeWidgetInfo( case StyleAppearance::Separator: return Some(WidgetInfo::Separator()); - case StyleAppearance::Toolbar: { - NSWindow* win = NativeWindowForFrame(aFrame); - bool isMain = [win isMainWindow]; - if (ToolbarCanBeUnified(nativeWidgetRect, win)) { - // Unified toolbars are drawn similar to vibrancy; we communicate their - // extents via the theme geometry mechanism and then place native views - // under Gecko's rendering. So Gecko just needs to be transparent in the - // place where the toolbar should be visible. - return Nothing(); - } - return Some(WidgetInfo::Toolbar(isMain)); - } - case StyleAppearance::MozWindowTitlebar: { return Nothing(); } case StyleAppearance::Statusbar: - return Some(WidgetInfo::StatusBar(IsActive(aFrame, YES))); + return Some(WidgetInfo::StatusBar(IsActiveToolbarControl(aFrame))); case StyleAppearance::MenulistButton: case StyleAppearance::Menulist: { @@ -2594,11 +2550,6 @@ void nsNativeThemeCocoa::RenderWidget(const WidgetInfo& aWidgetInfo, HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION); break; } - case Widget::eToolbar: { - bool isMain = aWidgetInfo.Params<bool>(); - DrawToolbar(cgContext, macRect, isMain); - break; - } case Widget::eStatusBar: { bool isMain = aWidgetInfo.Params<bool>(); DrawStatusBar(cgContext, macRect, isMain); @@ -2710,7 +2661,6 @@ bool nsNativeThemeCocoa::CreateWebRenderCommandsForWidget( case StyleAppearance::SpinnerDownbutton: case StyleAppearance::Toolbarbutton: case StyleAppearance::Separator: - case StyleAppearance::Toolbar: case StyleAppearance::MozWindowTitlebar: case StyleAppearance::Statusbar: case StyleAppearance::Menulist: @@ -3091,8 +3041,6 @@ nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, // Some widget types just never change state. switch (aAppearance) { case StyleAppearance::MozWindowTitlebar: - case StyleAppearance::Toolbox: - case StyleAppearance::Toolbar: case StyleAppearance::Statusbar: case StyleAppearance::Tooltip: case StyleAppearance::Tabpanels: @@ -3178,13 +3126,11 @@ bool nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, case StyleAppearance::Spinner: case StyleAppearance::SpinnerUpbutton: case StyleAppearance::SpinnerDownbutton: - case StyleAppearance::Toolbar: case StyleAppearance::Statusbar: case StyleAppearance::NumberInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: case StyleAppearance::Searchfield: - case StyleAppearance::Toolbox: case StyleAppearance::ProgressBar: case StyleAppearance::Progresschunk: case StyleAppearance::Meter: @@ -3265,7 +3211,6 @@ bool nsNativeThemeCocoa::WidgetAppearanceDependsOnWindowFocus( case StyleAppearance::SpinnerUpbutton: case StyleAppearance::SpinnerDownbutton: case StyleAppearance::Separator: - case StyleAppearance::Toolbox: case StyleAppearance::NumberInput: case StyleAppearance::Textfield: case StyleAppearance::Treeview: @@ -3283,16 +3228,8 @@ nsITheme::ThemeGeometryType nsNativeThemeCocoa::ThemeGeometryTypeForWidget( switch (aAppearance) { case StyleAppearance::MozWindowTitlebar: return eThemeGeometryTypeTitlebar; - case StyleAppearance::Toolbar: - return eThemeGeometryTypeToolbar; - case StyleAppearance::Toolbox: - return eThemeGeometryTypeToolbox; case StyleAppearance::MozWindowButtonBox: return eThemeGeometryTypeWindowButtons; - case StyleAppearance::Tooltip: - return eThemeGeometryTypeTooltip; - case StyleAppearance::Menupopup: - return eThemeGeometryTypeMenu; default: return eThemeGeometryTypeUnknown; } @@ -3307,7 +3244,6 @@ nsITheme::Transparency nsNativeThemeCocoa::GetWidgetTransparency( switch (aAppearance) { case StyleAppearance::Menupopup: case StyleAppearance::Tooltip: - case StyleAppearance::Toolbar: return eTransparent; case StyleAppearance::MozMacUnifiedToolbarWindow: // We want these to be treated as opaque by Gecko. We ensure there's an diff --git a/widget/cocoa/nsNativeThemeColors.h b/widget/cocoa/nsNativeThemeColors.h index 02ec96f51a..051335e9bc 100644 --- a/widget/cocoa/nsNativeThemeColors.h +++ b/widget/cocoa/nsNativeThemeColors.h @@ -10,43 +10,6 @@ #include "mozilla/ColorScheme.h" -enum ColorName { - toolbarTopBorderGrey, - toolbarFillGrey, - toolbarBottomBorderGrey, -}; - -static const int sLionThemeColors[][2] = { - /* { active window, inactive window } */ - // toolbar: - {0xD0, 0xF0}, // top separator line - {0xB2, 0xE1}, // fill color - {0x59, 0x87}, // bottom separator line -}; - -static const int sYosemiteThemeColors[][2] = { - /* { active window, inactive window } */ - // toolbar: - {0xBD, 0xDF}, // top separator line - {0xD3, 0xF6}, // fill color - {0xB3, 0xD1}, // bottom separator line -}; - -inline int NativeGreyColorAsInt(ColorName name, BOOL isMain) { - return sYosemiteThemeColors[name][isMain ? 0 : 1]; -} - -inline float NativeGreyColorAsFloat(ColorName name, BOOL isMain) { - return NativeGreyColorAsInt(name, isMain) / 255.0f; -} - -inline void DrawNativeGreyColorInRect(CGContextRef context, ColorName name, - CGRect rect, BOOL isMain) { - float grey = NativeGreyColorAsFloat(name, isMain); - CGContextSetRGBFillColor(context, grey, grey, grey, 1.0f); - CGContextFillRect(context, rect); -} - inline NSAppearance* NSAppearanceForColorScheme(mozilla::ColorScheme aScheme) { NSAppearanceName appearanceName = aScheme == mozilla::ColorScheme::Light ? NSAppearanceNameAqua diff --git a/widget/cocoa/nsPIWidgetCocoa.idl b/widget/cocoa/nsPIWidgetCocoa.idl deleted file mode 100644 index 54aa0d5113..0000000000 --- a/widget/cocoa/nsPIWidgetCocoa.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- 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/. */ - -#include "nsISupports.idl" - -interface nsIWidget; - -[ptr] native NSWindowPtr(NSWindow); - -// -// nsPIWidgetCocoa -// -// A private interface (unfrozen, private to the widget implementation) that -// gives us access to some extra features on a widget/window. -// -[uuid(f75ff69e-3a51-419e-bd29-042f804bc2ed)] -interface nsPIWidgetCocoa : nsISupports -{ - void SendSetZLevelEvent(); - - // Find the displayed child sheet (if aShown) or a child sheet that - // wants to be displayed (if !aShown) - nsIWidget GetChildSheet(in boolean aShown); - - // Get the parent widget (if any) StandardCreate() was called with. - nsIWidget GetRealParent(); - - // If the object implementing this interface is a sheet, this will return the - // native NSWindow it is attached to - readonly attribute NSWindowPtr sheetWindowParent; - - // True if window is a sheet - readonly attribute boolean isSheet; - -}; // nsPIWidgetCocoa diff --git a/widget/cocoa/nsWindowMap.mm b/widget/cocoa/nsWindowMap.mm index d93f89cb58..6f92adceaf 100644 --- a/widget/cocoa/nsWindowMap.mm +++ b/widget/cocoa/nsWindowMap.mm @@ -115,31 +115,31 @@ NS_OBJC_BEGIN_TRY_BLOCK_RETURN; if ((self = [super init])) { - [[NSNotificationCenter defaultCenter] + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowBecameKey:) name:NSWindowDidBecomeKeyNotification object:inWindow]; - [[NSNotificationCenter defaultCenter] + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowResignedKey:) name:NSWindowDidResignKeyNotification object:inWindow]; - [[NSNotificationCenter defaultCenter] + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowBecameMain:) name:NSWindowDidBecomeMainNotification object:inWindow]; - [[NSNotificationCenter defaultCenter] + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowResignedMain:) name:NSWindowDidResignMainNotification object:inWindow]; - [[NSNotificationCenter defaultCenter] + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification @@ -153,7 +153,7 @@ - (void)dealloc { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - [[NSNotificationCenter defaultCenter] removeObserver:self]; + [NSNotificationCenter.defaultCenter removeObserver:self]; [super dealloc]; NS_OBJC_END_TRY_IGNORE_BLOCK; @@ -171,7 +171,7 @@ + (void)activateInWindow:(NSWindow*)aWindow { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - WindowDelegate* delegate = (WindowDelegate*)[aWindow delegate]; + WindowDelegate* delegate = (WindowDelegate*)aWindow.delegate; if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) return; if ([delegate toplevelActiveState]) return; @@ -191,7 +191,7 @@ + (void)deactivateInWindow:(NSWindow*)aWindow { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - WindowDelegate* delegate = (WindowDelegate*)[aWindow delegate]; + WindowDelegate* delegate = (WindowDelegate*)aWindow.delegate; if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) return; if (![delegate toplevelActiveState]) return; @@ -205,9 +205,10 @@ + (void)activateInWindowViews:(NSWindow*)aWindow { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - id firstResponder = [aWindow firstResponder]; - if ([firstResponder isKindOfClass:[ChildView class]]) + id firstResponder = aWindow.firstResponder; + if ([firstResponder isKindOfClass:[ChildView class]]) { [firstResponder viewsWindowDidBecomeKey]; + } NS_OBJC_END_TRY_IGNORE_BLOCK; } @@ -217,9 +218,10 @@ + (void)deactivateInWindowViews:(NSWindow*)aWindow { NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - id firstResponder = [aWindow firstResponder]; - if ([firstResponder isKindOfClass:[ChildView class]]) + id firstResponder = aWindow.firstResponder; + if ([firstResponder isKindOfClass:[ChildView class]]) { [firstResponder viewsWindowDidResignKey]; + } NS_OBJC_END_TRY_IGNORE_BLOCK; } @@ -230,23 +232,23 @@ // should be sent when a native window becomes key, and the NS_DEACTIVATE // event should be sent when it resignes key. - (void)windowBecameKey:(NSNotification*)inNotification { - NSWindow* window = (NSWindow*)[inNotification object]; + NSWindow* window = inNotification.object; - id delegate = [window delegate]; + id delegate = window.delegate; if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) { [TopLevelWindowData activateInWindowViews:window]; - } else if ([window isSheet] || [NSApp modalWindow]) { + } else if (window.isSheet || NSApp.modalWindow) { [TopLevelWindowData activateInWindow:window]; } } - (void)windowResignedKey:(NSNotification*)inNotification { - NSWindow* window = (NSWindow*)[inNotification object]; + NSWindow* window = inNotification.object; - id delegate = [window delegate]; + id delegate = window.delegate; if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) { [TopLevelWindowData deactivateInWindowViews:window]; - } else if ([window isSheet] || [NSApp modalWindow]) { + } else if (window.isSheet || NSApp.modalWindow) { [TopLevelWindowData deactivateInWindow:window]; } } @@ -255,24 +257,24 @@ // state). So (for non-embedders) we need to ensure that a top-level window // is main when an NS_ACTIVATE event is sent to Gecko for it. - (void)windowBecameMain:(NSNotification*)inNotification { - NSWindow* window = (NSWindow*)[inNotification object]; - - id delegate = [window delegate]; + NSWindow* window = inNotification.object; + id delegate = window.delegate; // Don't send events to a top-level window that has a sheet/modal-window open // above it -- as far as Gecko is concerned, it's inactive, and stays so until // the sheet/modal-window closes. if (delegate && [delegate isKindOfClass:[WindowDelegate class]] && - ![window attachedSheet] && ![NSApp modalWindow]) + !window.attachedSheet && !NSApp.modalWindow) { [TopLevelWindowData activateInWindow:window]; + } } - (void)windowResignedMain:(NSNotification*)inNotification { - NSWindow* window = (NSWindow*)[inNotification object]; - - id delegate = [window delegate]; + NSWindow* window = inNotification.object; + id delegate = window.delegate; if (delegate && [delegate isKindOfClass:[WindowDelegate class]] && - ![window attachedSheet] && ![NSApp modalWindow]) + ![window attachedSheet] && ![NSApp modalWindow]) { [TopLevelWindowData deactivateInWindow:window]; + } } - (void)windowWillClose:(NSNotification*)inNotification { |