summaryrefslogtreecommitdiffstats
path: root/widget
diff options
context:
space:
mode:
Diffstat (limited to 'widget')
-rw-r--r--widget/BasicEvents.h4
-rw-r--r--widget/EventClassList.h1
-rw-r--r--widget/EventForwards.h3
-rw-r--r--widget/EventMessageList.h8
-rw-r--r--widget/InitData.h1
-rw-r--r--widget/InputData.cpp6
-rw-r--r--widget/InputData.h3
-rw-r--r--widget/LSBUtils.cpp8
-rw-r--r--widget/LookAndFeel.h12
-rw-r--r--widget/Screen.cpp13
-rw-r--r--widget/Screen.h6
-rw-r--r--widget/ScreenManager.cpp12
-rw-r--r--widget/TextEvents.h60
-rw-r--r--widget/Theme.cpp18
-rw-r--r--widget/android/EventDispatcher.cpp10
-rw-r--r--widget/android/GfxInfo.cpp8
-rw-r--r--widget/android/ScreenHelperAndroid.cpp9
-rw-r--r--widget/android/nsLookAndFeel.cpp5
-rw-r--r--widget/android/nsWindow.cpp16
-rw-r--r--widget/cocoa/MacThemeGeometryType.h4
-rw-r--r--widget/cocoa/ScreenHelperCocoa.mm28
-rw-r--r--widget/cocoa/TextInputHandler.mm68
-rw-r--r--widget/cocoa/VibrancyManager.h1
-rw-r--r--widget/cocoa/VibrancyManager.mm33
-rw-r--r--widget/cocoa/ViewRegion.mm53
-rw-r--r--widget/cocoa/moz.build6
-rw-r--r--widget/cocoa/nsChildView.mm162
-rw-r--r--widget/cocoa/nsCocoaWindow.h241
-rw-r--r--widget/cocoa/nsCocoaWindow.mm809
-rw-r--r--widget/cocoa/nsLookAndFeel.h14
-rw-r--r--widget/cocoa/nsLookAndFeel.mm103
-rw-r--r--widget/cocoa/nsNativeThemeCocoa.h4
-rw-r--r--widget/cocoa/nsNativeThemeCocoa.mm70
-rw-r--r--widget/cocoa/nsNativeThemeColors.h37
-rw-r--r--widget/cocoa/nsPIWidgetCocoa.idl37
-rw-r--r--widget/cocoa/nsWindowMap.mm54
-rw-r--r--widget/gtk/CompositorWidgetChild.cpp10
-rw-r--r--widget/gtk/CompositorWidgetChild.h5
-rw-r--r--widget/gtk/CompositorWidgetParent.cpp8
-rw-r--r--widget/gtk/CompositorWidgetParent.h6
-rw-r--r--widget/gtk/GtkCompositorWidget.cpp50
-rw-r--r--widget/gtk/GtkCompositorWidget.h21
-rw-r--r--widget/gtk/MPRISServiceHandler.cpp6
-rw-r--r--widget/gtk/MozContainer.cpp11
-rw-r--r--widget/gtk/MozContainerWayland.cpp15
-rw-r--r--widget/gtk/PCompositorWidget.ipdl4
-rw-r--r--widget/gtk/ScreenHelperGTK.cpp2
-rw-r--r--widget/gtk/WindowSurfaceProvider.cpp30
-rw-r--r--widget/gtk/WindowSurfaceProvider.h9
-rw-r--r--widget/gtk/nsDragService.cpp55
-rw-r--r--widget/gtk/nsLookAndFeel.cpp4
-rw-r--r--widget/gtk/nsNativeThemeGTK.cpp16
-rw-r--r--widget/gtk/nsWindow.cpp493
-rw-r--r--widget/gtk/nsWindow.h29
-rw-r--r--widget/headless/HeadlessLookAndFeelGTK.cpp3
-rw-r--r--widget/headless/HeadlessScreenHelper.cpp7
-rw-r--r--widget/headless/HeadlessWidget.cpp9
-rw-r--r--widget/nsBaseClipboard.cpp30
-rw-r--r--widget/nsIDragSession.idl4
-rw-r--r--widget/nsIMacDockSupport.idl6
-rw-r--r--widget/nsIPrintSettings.idl6
-rw-r--r--widget/nsIWidget.h10
-rw-r--r--widget/nsXPLookAndFeel.cpp10
-rw-r--r--widget/tests/mochitest.toml5
-rw-r--r--widget/tests/test_assign_event_data.html46
-rw-r--r--widget/tests/window_composition_text_querycontent.xhtml176
-rw-r--r--widget/uikit/TextInputHandler.mm18
-rw-r--r--widget/uikit/nsLookAndFeel.mm3
-rw-r--r--widget/windows/GfxInfo.cpp2
-rw-r--r--widget/windows/ScreenHelperWin.cpp31
-rw-r--r--widget/windows/WindowsSMTCProvider.cpp6
-rw-r--r--widget/windows/moz.build1
-rw-r--r--widget/windows/nsFilePicker.cpp8
-rw-r--r--widget/windows/nsLookAndFeel.cpp19
-rw-r--r--widget/windows/nsLookAndFeel.h4
-rw-r--r--widget/windows/nsNativeThemeWin.cpp47
-rw-r--r--widget/windows/nsUXThemeData.cpp2
-rw-r--r--widget/windows/nsUXThemeData.h1
-rw-r--r--widget/windows/nsWindow.cpp128
-rw-r--r--widget/windows/nsWindow.h9
80 files changed, 1386 insertions, 1906 deletions
diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h
index b3707f1cf4..affc58f3be 100644
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -440,6 +440,10 @@ class WidgetEvent : public WidgetEventTime {
mFlags.mCancelable = false;
mFlags.mBubbles = mFlags.mIsTrusted;
break;
+ case eLegacyTextEventClass:
+ mFlags.mCancelable = mFlags.mIsTrusted && mMessage == eLegacyTextInput;
+ mFlags.mBubbles = mFlags.mIsTrusted && mMessage == eLegacyTextInput;
+ break;
case eMouseEventClass:
mFlags.mCancelable =
(mMessage != eMouseEnter && mMessage != eMouseLeave);
diff --git a/widget/EventClassList.h b/widget/EventClassList.h
index c8870d84e5..937047e8ba 100644
--- a/widget/EventClassList.h
+++ b/widget/EventClassList.h
@@ -26,6 +26,7 @@ NS_EVENT_CLASS(Widget, CompositionEvent)
NS_EVENT_CLASS(Widget, QueryContentEvent)
NS_EVENT_CLASS(Widget, SelectionEvent)
NS_EVENT_CLASS(Internal, EditorInputEvent)
+NS_EVENT_CLASS(Internal, LegacyTextEvent)
// MouseEvents.h
NS_EVENT_CLASS(Widget, MouseEventBase)
diff --git a/widget/EventForwards.h b/widget/EventForwards.h
index e6a1ad6274..4a6d796cd1 100644
--- a/widget/EventForwards.h
+++ b/widget/EventForwards.h
@@ -270,9 +270,6 @@ inline bool IsCancelableBeforeInputEvent(EditorInputType aInputType) {
return true;
case EditorInputType::eInsertLink:
return true;
- case EditorInputType::eDeleteByComposition:
- MOZ_ASSERT(!StaticPrefs::dom_input_events_conform_to_level_1());
- return true;
case EditorInputType::eDeleteCompositionText:
MOZ_ASSERT(!StaticPrefs::dom_input_events_conform_to_level_1());
return false;
diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h
index f42c1e3b2c..4247403770 100644
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -432,6 +432,9 @@ NS_EVENT_MESSAGE_FIRST_LAST(eGamepadEvent, eGamepadButtonDown,
NS_EVENT_MESSAGE(eEditorInput)
NS_EVENT_MESSAGE(eEditorBeforeInput)
+// textInput event which is a default action of beforeinput
+NS_EVENT_MESSAGE(eLegacyTextInput)
+
// selection events
NS_EVENT_MESSAGE(eSelectStart)
NS_EVENT_MESSAGE(eSelectionChange)
@@ -450,11 +453,6 @@ NS_EVENT_MESSAGE(eToggle)
NS_EVENT_MESSAGE(eClose)
NS_EVENT_MESSAGE(eCancel)
-// Marquee element events.
-NS_EVENT_MESSAGE(eMarqueeBounce)
-NS_EVENT_MESSAGE(eMarqueeStart)
-NS_EVENT_MESSAGE(eMarqueeFinish)
-
NS_EVENT_MESSAGE(eScrollend)
#ifdef UNDEF_NS_EVENT_MESSAGE_FIRST_LAST
diff --git a/widget/InitData.h b/widget/InitData.h
index aed5e0a551..a073362065 100644
--- a/widget/InitData.h
+++ b/widget/InitData.h
@@ -17,7 +17,6 @@ enum class WindowType : uint8_t {
TopLevel, // default top level window
Dialog, // top level window but usually handled differently
// by the OS
- Sheet, // MacOSX sheet (special dialog class)
Popup, // used for combo boxes, etc
Child, // child windows (contained inside a window on the
// desktop (has no border))
diff --git a/widget/InputData.cpp b/widget/InputData.cpp
index 3d1695dd8e..8f06a51c1c 100644
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -303,6 +303,9 @@ MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
case eMouseHitTest:
mType = MOUSE_HITTEST;
break;
+ case eContextMenu:
+ mType = MOUSE_CONTEXTMENU;
+ break;
default:
MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
break;
@@ -364,6 +367,9 @@ WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
case MOUSE_HITTEST:
msg = eMouseHitTest;
break;
+ case MOUSE_CONTEXTMENU:
+ msg = eContextMenu;
+ break;
default:
MOZ_ASSERT_UNREACHABLE(
"Did not assign a type to WidgetMouseEvent in MouseInput");
diff --git a/widget/InputData.h b/widget/InputData.h
index 855cfcd178..fa011f8451 100644
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -275,7 +275,8 @@ class MouseInput : public InputData {
MOUSE_WIDGET_ENTER,
MOUSE_WIDGET_EXIT,
MOUSE_HITTEST,
- MOUSE_EXPLORE_BY_TOUCH
+ MOUSE_EXPLORE_BY_TOUCH,
+ MOUSE_CONTEXTMENU
));
MOZ_DEFINE_ENUM_AT_CLASS_SCOPE(
diff --git a/widget/LSBUtils.cpp b/widget/LSBUtils.cpp
index 9ebffacd7e..718c43d26e 100644
--- a/widget/LSBUtils.cpp
+++ b/widget/LSBUtils.cpp
@@ -45,6 +45,7 @@ bool GetOSRelease(nsACString& aDistributor, nsACString& aDescription,
bool seen_id = false, seen_pretty_name = false, seen_version_id = false;
std::string rawline;
nsAutoCString name;
+ nsAutoCString build_id;
while (std::getline(stream, rawline)) {
std::string_view line(rawline);
size_t pos = line.find('=');
@@ -68,6 +69,8 @@ bool GetOSRelease(nsACString& aDistributor, nsACString& aDescription,
if (ExtractAndSetValue(aDescription, value)) seen_pretty_name = true;
} else if (key == "VERSION_ID") {
if (ExtractAndSetValue(aRelease, value)) seen_version_id = true;
+ } else if (key == "BUILD_ID") {
+ ExtractAndSetValue(build_id, value);
} else if (key == "VERSION_CODENAME") {
ExtractAndSetValue(aCodename, value);
}
@@ -77,6 +80,11 @@ bool GetOSRelease(nsACString& aDistributor, nsACString& aDescription,
if (seen_id && !name.IsEmpty() && name.EqualsIgnoreCase(aDistributor)) {
aDistributor = name;
}
+ // If VERSION_ID is not set but BUILD_ID is, use BUILD_ID.
+ if (!seen_version_id && !build_id.IsEmpty()) {
+ aRelease = build_id;
+ seen_version_id = true;
+ }
// Only consider our work done if we've seen at least ID, PRETTY_NAME and
// VERSION_ID.
return seen_id && seen_pretty_name && seen_version_id;
diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h
index 0cab187410..13219ff54b 100644
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -53,8 +53,6 @@ class LookAndFeel {
CaretBlinkCount,
// pixel width of caret
CaretWidth,
- // show the caret when text is selected?
- ShowCaretDuringSelection,
// select textfields when focused via tab/accesskey?
SelectTextfieldsOnKeyFocus,
// delay before submenus open
@@ -119,6 +117,9 @@ class LookAndFeel {
*/
MacRTL,
+ /* Native macOS titlebar height. */
+ MacTitlebarHeight,
+
/*
* AlertNotificationOrigin indicates from which corner of the
* screen alerts slide in, and from which direction (horizontal/vertical).
@@ -186,6 +187,7 @@ class LookAndFeel {
*/
ContextMenuOffsetVertical,
ContextMenuOffsetHorizontal,
+ TooltipOffsetVertical,
/*
* A boolean value indicating whether client-side decorations are
@@ -299,7 +301,6 @@ class LookAndFeel {
* 1: High
*/
DynamicRange,
- VideoDynamicRange,
/** Whether XUL panel animations are enabled. */
PanelAnimations,
@@ -321,6 +322,11 @@ class LookAndFeel {
return GetInt(IntID::UseOverlayScrollbars);
}
+ static constexpr int32_t kDefaultTooltipOffset = 21;
+ static int32_t TooltipOffsetVertical() {
+ return GetInt(IntID::TooltipOffsetVertical, kDefaultTooltipOffset);
+ }
+
// Returns keyCode value of a modifier key which is used for accesskey.
// Returns 0 if the platform doesn't support access key.
static uint32_t GetMenuAccessKey();
diff --git a/widget/Screen.cpp b/widget/Screen.cpp
index 71a1624624..ccc78a9413 100644
--- a/widget/Screen.cpp
+++ b/widget/Screen.cpp
@@ -30,7 +30,7 @@ Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
uint32_t aPixelDepth, uint32_t aColorDepth,
uint32_t aRefreshRate, DesktopToLayoutDeviceScale aContentsScale,
CSSToLayoutDeviceScale aDefaultCssScale, float aDPI,
- IsPseudoDisplay aIsPseudoDisplay,
+ IsPseudoDisplay aIsPseudoDisplay, IsHDR aIsHDR,
hal::ScreenOrientation aOrientation,
OrientationAngle aOrientationAngle)
: mRect(aRect),
@@ -45,7 +45,8 @@ Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
mDPI(aDPI),
mScreenOrientation(EffectiveOrientation(aOrientation, aRect)),
mOrientationAngle(aOrientationAngle),
- mIsPseudoDisplay(aIsPseudoDisplay == IsPseudoDisplay::Yes) {}
+ mIsPseudoDisplay(aIsPseudoDisplay == IsPseudoDisplay::Yes),
+ mIsHDR(aIsHDR == IsHDR::Yes) {}
Screen::Screen(const dom::ScreenDetails& aScreen)
: mRect(aScreen.rect()),
@@ -60,7 +61,8 @@ Screen::Screen(const dom::ScreenDetails& aScreen)
mDPI(aScreen.dpi()),
mScreenOrientation(aScreen.orientation()),
mOrientationAngle(aScreen.orientationAngle()),
- mIsPseudoDisplay(aScreen.isPseudoDisplay()) {}
+ mIsPseudoDisplay(aScreen.isPseudoDisplay()),
+ mIsHDR(aScreen.isHDR()) {}
Screen::Screen(const Screen& aOther)
: mRect(aOther.mRect),
@@ -75,13 +77,14 @@ Screen::Screen(const Screen& aOther)
mDPI(aOther.mDPI),
mScreenOrientation(aOther.mScreenOrientation),
mOrientationAngle(aOther.mOrientationAngle),
- mIsPseudoDisplay(aOther.mIsPseudoDisplay) {}
+ mIsPseudoDisplay(aOther.mIsPseudoDisplay),
+ mIsHDR(aOther.mIsHDR) {}
dom::ScreenDetails Screen::ToScreenDetails() const {
return dom::ScreenDetails(
mRect, mRectDisplayPix, mAvailRect, mAvailRectDisplayPix, mPixelDepth,
mColorDepth, mRefreshRate, mContentsScale, mDefaultCssScale, mDPI,
- mScreenOrientation, mOrientationAngle, mIsPseudoDisplay);
+ mScreenOrientation, mOrientationAngle, mIsPseudoDisplay, mIsHDR);
}
NS_IMETHODIMP
diff --git a/widget/Screen.h b/widget/Screen.h
index f3f8b4a628..ca2efa1f59 100644
--- a/widget/Screen.h
+++ b/widget/Screen.h
@@ -26,12 +26,13 @@ class Screen final : public nsIScreen {
using OrientationAngle = uint16_t;
enum class IsPseudoDisplay : bool { No, Yes };
+ enum class IsHDR : bool { No, Yes };
Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
uint32_t aPixelDepth, uint32_t aColorDepth, uint32_t aRefreshRate,
DesktopToLayoutDeviceScale aContentsScale,
CSSToLayoutDeviceScale aDefaultCssScale, float aDpi, IsPseudoDisplay,
- hal::ScreenOrientation = hal::ScreenOrientation::None,
+ IsHDR, hal::ScreenOrientation = hal::ScreenOrientation::None,
OrientationAngle = 0);
explicit Screen(const dom::ScreenDetails& aScreenDetails);
Screen(const Screen& aOther);
@@ -60,6 +61,8 @@ class Screen final : public nsIScreen {
enum class IncludeOSZoom : bool { No, Yes };
CSSToLayoutDeviceScale GetCSSToLayoutDeviceScale(IncludeOSZoom) const;
+ bool GetIsHDR() const { return mIsHDR; }
+
private:
virtual ~Screen() = default;
@@ -76,6 +79,7 @@ class Screen final : public nsIScreen {
const hal::ScreenOrientation mScreenOrientation;
const OrientationAngle mOrientationAngle;
const bool mIsPseudoDisplay;
+ const bool mIsHDR;
};
} // namespace widget
diff --git a/widget/ScreenManager.cpp b/widget/ScreenManager.cpp
index 58e20806eb..84d7316af7 100644
--- a/widget/ScreenManager.cpp
+++ b/widget/ScreenManager.cpp
@@ -139,7 +139,8 @@ already_AddRefed<Screen> ScreenManager::ScreenForRect(
auto screen = MakeRefPtr<Screen>(
LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0, 0,
DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */,
- Screen::IsPseudoDisplay::No, hal::ScreenOrientation::None, 0);
+ Screen::IsPseudoDisplay::No, Screen::IsHDR::No,
+ hal::ScreenOrientation::None, 0);
return screen.forget();
}
@@ -219,10 +220,11 @@ already_AddRefed<Screen> ScreenManager::GetPrimaryScreen() {
if (mScreenList.IsEmpty()) {
MOZ_LOG(sScreenLog, LogLevel::Warning,
("No screen available. This can happen in xpcshell."));
- return MakeAndAddRef<Screen>(
- LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0, 0,
- DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */,
- Screen::IsPseudoDisplay::No, hal::ScreenOrientation::None, 0);
+ return MakeAndAddRef<Screen>(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
+ 0, 0, 0, DesktopToLayoutDeviceScale(),
+ CSSToLayoutDeviceScale(), 96 /* dpi */,
+ Screen::IsPseudoDisplay::No, Screen::IsHDR::No,
+ hal::ScreenOrientation::None, 0);
}
return do_AddRef(mScreenList[0]);
diff --git a/widget/TextEvents.h b/widget/TextEvents.h
index 71d2e656e2..3f42561c75 100644
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -1442,13 +1442,8 @@ class WidgetSelectionEvent : public WidgetGUIEvent {
******************************************************************************/
class InternalEditorInputEvent : public InternalUIEvent {
- private:
- InternalEditorInputEvent()
- : mData(VoidString()),
- mInputType(EditorInputType::eUnknown),
- mIsComposing(false) {}
-
public:
+ InternalEditorInputEvent() = delete;
virtual InternalEditorInputEvent* AsEditorInputEvent() override {
return this;
}
@@ -1457,9 +1452,7 @@ class InternalEditorInputEvent : public InternalUIEvent {
nsIWidget* aWidget = nullptr,
const WidgetEventTime* aTime = nullptr)
: InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass,
- aTime),
- mData(VoidString()),
- mInputType(EditorInputType::eUnknown) {}
+ aTime) {}
virtual WidgetEvent* Duplicate() const override {
MOZ_ASSERT(mClass == eEditorInputEventClass,
@@ -1472,13 +1465,13 @@ class InternalEditorInputEvent : public InternalUIEvent {
return result;
}
- nsString mData;
+ nsString mData = VoidString();
RefPtr<dom::DataTransfer> mDataTransfer;
OwningNonNullStaticRangeArray mTargetRanges;
- EditorInputType mInputType;
+ EditorInputType mInputType = EditorInputType::eUnknown;
- bool mIsComposing;
+ bool mIsComposing = false;
void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
bool aCopyTargets) {
@@ -1502,10 +1495,51 @@ class InternalEditorInputEvent : public InternalUIEvent {
private:
static const char16_t* const kInputTypeNames[];
- typedef nsTHashMap<nsStringHashKey, EditorInputType> InputTypeHashtable;
+ using InputTypeHashtable = nsTHashMap<nsStringHashKey, EditorInputType>;
static InputTypeHashtable* sInputTypeHashtable;
};
+/******************************************************************************
+ * mozilla::InternalLegacyTextEvent
+ ******************************************************************************/
+
+class InternalLegacyTextEvent : public InternalUIEvent {
+ public:
+ InternalLegacyTextEvent() = delete;
+
+ virtual InternalLegacyTextEvent* AsLegacyTextEvent() override { return this; }
+
+ InternalLegacyTextEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget = nullptr,
+ const WidgetEventTime* aTime = nullptr)
+ : InternalUIEvent(aIsTrusted, aMessage, aWidget, eLegacyTextEventClass,
+ aTime) {}
+
+ virtual WidgetEvent* Duplicate() const override {
+ MOZ_ASSERT(mClass == eLegacyTextEventClass,
+ "Duplicate() must be overridden by sub class");
+ // Not copying widget, it is a weak reference.
+ InternalLegacyTextEvent* result =
+ new InternalLegacyTextEvent(false, mMessage, nullptr, this);
+ result->AssignLegacyTextEventData(*this, true);
+ result->mFlags = mFlags;
+ return result;
+ }
+
+ nsString mData;
+ RefPtr<dom::DataTransfer> mDataTransfer;
+ EditorInputType mInputType = EditorInputType::eUnknown;
+
+ void AssignLegacyTextEventData(const InternalLegacyTextEvent& aEvent,
+ bool aCopyTargets) {
+ AssignUIEventData(aEvent, aCopyTargets);
+
+ mData = aEvent.mData;
+ mDataTransfer = aEvent.mDataTransfer;
+ mInputType = aEvent.mInputType;
+ }
+};
+
} // namespace mozilla
#endif // mozilla_TextEvents_h__
diff --git a/widget/Theme.cpp b/widget/Theme.cpp
index 1fcd3d4bc3..15bf68ec01 100644
--- a/widget/Theme.cpp
+++ b/widget/Theme.cpp
@@ -296,6 +296,9 @@ std::pair<sRGBColor, sRGBColor> Theme::ComputeButtonColors(
bool isHovered = aState.HasState(ElementState::HOVER);
nscolor backgroundColor = [&] {
+ if (aState.HasState(ElementState::AUTOFILL)) {
+ return aColors.SystemNs(StyleSystemColor::MozAutofillBackground);
+ }
if (isDisabled) {
return aColors.SystemNs(StyleSystemColor::MozButtondisabledface);
}
@@ -308,12 +311,6 @@ std::pair<sRGBColor, sRGBColor> Theme::ComputeButtonColors(
return aColors.SystemNs(StyleSystemColor::Buttonface);
}();
- if (aState.HasState(ElementState::AUTOFILL)) {
- backgroundColor = NS_ComposeColors(
- backgroundColor,
- aColors.SystemNs(StyleSystemColor::MozAutofillBackground));
- }
-
const sRGBColor borderColor =
ComputeBorderColor(aState, aColors, OutlineCoversBorder::Yes);
return std::make_pair(sRGBColor::FromABGR(backgroundColor), borderColor);
@@ -323,18 +320,15 @@ std::pair<sRGBColor, sRGBColor> Theme::ComputeTextfieldColors(
const ElementState& aState, const Colors& aColors,
OutlineCoversBorder aOutlineCoversBorder) {
nscolor backgroundColor = [&] {
+ if (aState.HasState(ElementState::AUTOFILL)) {
+ return aColors.SystemNs(StyleSystemColor::MozAutofillBackground);
+ }
if (aState.HasState(ElementState::DISABLED)) {
return aColors.SystemNs(StyleSystemColor::MozDisabledfield);
}
return aColors.SystemNs(StyleSystemColor::Field);
}();
- if (aState.HasState(ElementState::AUTOFILL)) {
- backgroundColor = NS_ComposeColors(
- backgroundColor,
- aColors.SystemNs(StyleSystemColor::MozAutofillBackground));
- }
-
const sRGBColor borderColor =
ComputeBorderColor(aState, aColors, aOutlineCoversBorder);
return std::make_pair(sRGBColor::FromABGR(backgroundColor), borderColor);
diff --git a/widget/android/EventDispatcher.cpp b/widget/android/EventDispatcher.cpp
index 6e414c11ce..2054d822d7 100644
--- a/widget/android/EventDispatcher.cpp
+++ b/widget/android/EventDispatcher.cpp
@@ -21,12 +21,6 @@
#include "mozilla/java/EventCallbackWrappers.h"
#include "mozilla/jni/GeckoBundleUtils.h"
-// Disable the C++ 2a warning. See bug #1509926
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wc++2a-compat"
-#endif
-
namespace mozilla {
namespace widget {
@@ -770,7 +764,3 @@ nsresult EventDispatcher::UnboxBundle(JSContext* aCx, jni::Object::Param aData,
} // namespace widget
} // namespace mozilla
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp
index 6e6d3bf47b..267beaf330 100644
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -667,6 +667,14 @@ nsresult GfxInfo::GetFeatureStatusImpl(
return NS_OK;
}
+ if (aFeature == FEATURE_WEBGPU) {
+ // Ensure WebGPU is disabled by default on Android until it is better
+ // tested.
+ *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+ aFailureId = "FEATURE_FAILURE_WEBGPU_ANDROID";
+ return NS_OK;
+ }
+
return GfxInfoBase::GetFeatureStatusImpl(
aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
}
diff --git a/widget/android/ScreenHelperAndroid.cpp b/widget/android/ScreenHelperAndroid.cpp
index 33c91fe6e0..141b38e01b 100644
--- a/widget/android/ScreenHelperAndroid.cpp
+++ b/widget/android/ScreenHelperAndroid.cpp
@@ -38,14 +38,15 @@ static already_AddRefed<Screen> MakePrimaryScreen() {
uint32_t depth = java::GeckoAppShell::GetScreenDepth();
float density = java::GeckoAppShell::GetDensity();
float dpi = java::GeckoAppShell::GetDpi();
+ bool isHDR = false; // Bug 1884960: report this accurately
auto orientation =
hal::ScreenOrientation(java::GeckoAppShell::GetScreenOrientation());
uint16_t angle = java::GeckoAppShell::GetScreenAngle();
float refreshRate = java::GeckoAppShell::GetScreenRefreshRate();
- return MakeAndAddRef<Screen>(bounds, bounds, depth, depth, refreshRate,
- DesktopToLayoutDeviceScale(density),
- CSSToLayoutDeviceScale(1.0f), dpi,
- Screen::IsPseudoDisplay::No, orientation, angle);
+ return MakeAndAddRef<Screen>(
+ bounds, bounds, depth, depth, refreshRate,
+ DesktopToLayoutDeviceScale(density), CSSToLayoutDeviceScale(1.0f), dpi,
+ Screen::IsPseudoDisplay::No, Screen::IsHDR(isHDR), orientation, angle);
}
ScreenHelperAndroid::ScreenHelperAndroid() {
diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp
index 6d9f8c634f..45c556f6d1 100644
--- a/widget/android/nsLookAndFeel.cpp
+++ b/widget/android/nsLookAndFeel.cpp
@@ -253,6 +253,7 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aColorScheme,
break;
case ColorID::Marktext:
case ColorID::Mark:
+ case ColorID::MozAutofillBackground:
case ColorID::SpellCheckerUnderline:
aColor = GetStandinForNativeColor(aID, aColorScheme);
break;
@@ -298,10 +299,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = 1;
break;
- case IntID::ShowCaretDuringSelection:
- aResult = 0;
- break;
-
case IntID::SelectTextfieldsOnKeyFocus:
// Select textfield content when focused by kbd
// used by EventStateManager::sTextfieldSelectModel
diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp
index e9756c3f92..a654c8e848 100644
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -609,6 +609,22 @@ class NPZCSupport final
PostInputEvent([input = std::move(input), result](nsWindow* window) {
WidgetMouseEvent mouseEvent = input.ToWidgetEvent(window);
window->ProcessUntransformedAPZEvent(&mouseEvent, result);
+ if (MouseInput::SECONDARY_BUTTON == input.mButtonType) {
+ if ((StaticPrefs::ui_context_menus_after_mouseup() &&
+ MouseInput::MOUSE_UP == input.mType) ||
+ (!StaticPrefs::ui_context_menus_after_mouseup() &&
+ MouseInput::MOUSE_DOWN == input.mType)) {
+ MouseInput contextMenu = input;
+
+ // Actually we don't dispatch context menu event to APZ since we don't
+ // handle it on APZ yet. If handling it, we need to consider how to
+ // dispatch it on APZ thread. It may cause a race condition.
+ contextMenu.mType = MouseInput::MOUSE_CONTEXTMENU;
+
+ WidgetMouseEvent contextMenuEvent = contextMenu.ToWidgetEvent(window);
+ window->ProcessUntransformedAPZEvent(&contextMenuEvent, result);
+ }
+ }
});
switch (result.GetStatus()) {
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 {
diff --git a/widget/gtk/CompositorWidgetChild.cpp b/widget/gtk/CompositorWidgetChild.cpp
index b7908a43d4..3b6af872ed 100644
--- a/widget/gtk/CompositorWidgetChild.cpp
+++ b/widget/gtk/CompositorWidgetChild.cpp
@@ -38,13 +38,13 @@ void CompositorWidgetChild::NotifyClientSizeChanged(
Unused << SendNotifyClientSizeChanged(aClientSize);
}
-void CompositorWidgetChild::DisableRendering() {
- Unused << SendDisableRendering();
+void CompositorWidgetChild::CleanupResources() {
+ Unused << SendCleanupResources();
}
-void CompositorWidgetChild::EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) {
- Unused << SendEnableRendering(aXWindow, aShaped);
+void CompositorWidgetChild::SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) {
+ Unused << SendSetRenderingSurface(aXWindow, aShaped);
}
} // namespace widget
diff --git a/widget/gtk/CompositorWidgetChild.h b/widget/gtk/CompositorWidgetChild.h
index b1cad75da3..f46cf63bfb 100644
--- a/widget/gtk/CompositorWidgetChild.h
+++ b/widget/gtk/CompositorWidgetChild.h
@@ -27,8 +27,9 @@ class CompositorWidgetChild final : public PCompositorWidgetChild,
mozilla::ipc::IPCResult RecvUnobserveVsync() override;
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
- void DisableRendering() override;
- void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
+ void CleanupResources() override;
+ void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) override;
private:
RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
diff --git a/widget/gtk/CompositorWidgetParent.cpp b/widget/gtk/CompositorWidgetParent.cpp
index 998614622e..7f576f35e7 100644
--- a/widget/gtk/CompositorWidgetParent.cpp
+++ b/widget/gtk/CompositorWidgetParent.cpp
@@ -40,14 +40,14 @@ mozilla::ipc::IPCResult CompositorWidgetParent::RecvNotifyClientSizeChanged(
return IPC_OK();
}
-mozilla::ipc::IPCResult CompositorWidgetParent::RecvDisableRendering() {
- DisableRendering();
+mozilla::ipc::IPCResult CompositorWidgetParent::RecvCleanupResources() {
+ CleanupResources();
return IPC_OK();
}
-mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnableRendering(
+mozilla::ipc::IPCResult CompositorWidgetParent::RecvSetRenderingSurface(
const uintptr_t& aXWindow, const bool& aShaped) {
- EnableRendering(aXWindow, aShaped);
+ SetRenderingSurface(aXWindow, aShaped);
return IPC_OK();
}
diff --git a/widget/gtk/CompositorWidgetParent.h b/widget/gtk/CompositorWidgetParent.h
index 2bbc70af3e..8c0a6e8c26 100644
--- a/widget/gtk/CompositorWidgetParent.h
+++ b/widget/gtk/CompositorWidgetParent.h
@@ -28,9 +28,9 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
mozilla::ipc::IPCResult RecvNotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) override;
- mozilla::ipc::IPCResult RecvDisableRendering() override;
- mozilla::ipc::IPCResult RecvEnableRendering(const uintptr_t& aXWindow,
- const bool& aShaped) override;
+ mozilla::ipc::IPCResult RecvCleanupResources() override;
+ mozilla::ipc::IPCResult RecvSetRenderingSurface(const uintptr_t& aXWindow,
+ const bool& aShaped) override;
private:
RefPtr<VsyncObserver> mVsyncObserver;
diff --git a/widget/gtk/GtkCompositorWidget.cpp b/widget/gtk/GtkCompositorWidget.cpp
index 36559cfd54..073ad5248f 100644
--- a/widget/gtk/GtkCompositorWidget.cpp
+++ b/widget/gtk/GtkCompositorWidget.cpp
@@ -7,6 +7,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/WidgetUtilsGtk.h"
#include "mozilla/widget/InProcessCompositorWidget.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
@@ -40,25 +41,22 @@ GtkCompositorWidget::GtkCompositorWidget(
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
ConfigureX11Backend((Window)aInitData.XWindow(), aInitData.Shaped());
- LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p "
- "mIsRenderingSuspended %d\n",
- (void*)mWidget.get(), (void*)aInitData.XWindow(),
- !!mIsRenderingSuspended);
+ LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p\n",
+ (void*)mWidget.get(), (void*)aInitData.XWindow());
}
#endif
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
ConfigureWaylandBackend();
- LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p "
- "mIsRenderingSuspended %d\n",
- (void*)mWidget.get(), (void*)mWidget, !!mIsRenderingSuspended);
+ LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p\n",
+ (void*)mWidget.get(), (void*)mWidget);
}
#endif
}
GtkCompositorWidget::~GtkCompositorWidget() {
LOG("GtkCompositorWidget::~GtkCompositorWidget [%p]\n", (void*)mWidget.get());
- DisableRendering();
+ CleanupResources();
RefPtr<nsIWidget> widget = mWidget.forget();
NS_ReleaseOnMainThread("GtkCompositorWidget::mWidget", widget.forget());
}
@@ -169,57 +167,47 @@ GtkCompositorWidget::GetNativeLayerRoot() {
}
#endif
-void GtkCompositorWidget::DisableRendering() {
- LOG("GtkCompositorWidget::DisableRendering [%p]\n", (void*)mWidget.get());
- mIsRenderingSuspended = true;
+void GtkCompositorWidget::CleanupResources() {
+ LOG("GtkCompositorWidget::CleanupResources [%p]\n", (void*)mWidget.get());
mProvider.CleanupResources();
}
#if defined(MOZ_WAYLAND)
-bool GtkCompositorWidget::ConfigureWaylandBackend() {
+void GtkCompositorWidget::ConfigureWaylandBackend() {
mProvider.Initialize(this);
- return true;
}
#endif
#if defined(MOZ_X11)
-bool GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
+void GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
// We don't have X window yet.
if (!aXWindow) {
- mIsRenderingSuspended = true;
- return false;
+ mProvider.CleanupResources();
+ return;
}
// Initialize the window surface provider
- return mProvider.Initialize(aXWindow, aShaped);
+ mProvider.Initialize(aXWindow, aShaped);
}
#endif
-void GtkCompositorWidget::EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) {
- LOG("GtkCompositorWidget::EnableRendering() [%p]\n", mWidget.get());
+void GtkCompositorWidget::SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) {
+ LOG("GtkCompositorWidget::SetRenderingSurface() [%p]\n", mWidget.get());
- if (!mIsRenderingSuspended) {
- LOG(" quit, mIsRenderingSuspended = false\n");
- return;
- }
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
LOG(" configure widget %p\n", mWidget.get());
- if (!ConfigureWaylandBackend()) {
- return;
- }
+ ConfigureWaylandBackend();
}
#endif
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
LOG(" configure XWindow %p shaped %d\n", (void*)aXWindow, aShaped);
- if (!ConfigureX11Backend((Window)aXWindow, aShaped)) {
- return;
- }
+ ConfigureX11Backend((Window)aXWindow, aShaped);
}
#endif
- mIsRenderingSuspended = false;
}
+
#ifdef MOZ_LOGGING
bool GtkCompositorWidget::IsPopup() {
return mWidget ? mWidget->IsPopup() : false;
diff --git a/widget/gtk/GtkCompositorWidget.h b/widget/gtk/GtkCompositorWidget.h
index bde88bde6c..d4834247f1 100644
--- a/widget/gtk/GtkCompositorWidget.h
+++ b/widget/gtk/GtkCompositorWidget.h
@@ -28,9 +28,9 @@ class PlatformCompositorWidgetDelegate : public CompositorWidgetDelegate {
const LayoutDeviceIntSize& aClientSize) = 0;
virtual GtkCompositorWidget* AsGtkCompositorWidget() { return nullptr; };
- virtual void DisableRendering() = 0;
- virtual void EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) = 0;
+ virtual void CleanupResources() = 0;
+ virtual void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) = 0;
// CompositorWidgetDelegate Overrides
@@ -74,10 +74,11 @@ class GtkCompositorWidget : public CompositorWidget,
// Suspend rendering of this remote widget and clear all resources.
// Can be used when underlying window is hidden/unmapped.
- void DisableRendering() override;
+ void CleanupResources() override;
// Resume rendering with to given aXWindow (X11) or nsWindow (Wayland).
- void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
+ void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) override;
// If we fail to set window size (due to different screen scale or so)
// we can't paint the frame by compositor.
@@ -90,11 +91,6 @@ class GtkCompositorWidget : public CompositorWidget,
RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() override;
#endif
- bool PreRender(WidgetRenderingContext* aContext) override {
- return !mIsRenderingSuspended;
- }
- bool IsHidden() const override { return mIsRenderingSuspended; }
-
// PlatformCompositorWidgetDelegate Overrides
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
@@ -102,10 +98,10 @@ class GtkCompositorWidget : public CompositorWidget,
private:
#if defined(MOZ_WAYLAND)
- bool ConfigureWaylandBackend();
+ void ConfigureWaylandBackend();
#endif
#if defined(MOZ_X11)
- bool ConfigureX11Backend(Window aXWindow, bool aShaped);
+ void ConfigureX11Backend(Window aXWindow, bool aShaped);
#endif
#ifdef MOZ_LOGGING
bool IsPopup();
@@ -129,7 +125,6 @@ class GtkCompositorWidget : public CompositorWidget,
#ifdef MOZ_WAYLAND
RefPtr<mozilla::layers::NativeLayerRootWayland> mNativeLayerRoot;
#endif
- Atomic<bool> mIsRenderingSuspended{true};
};
} // namespace widget
diff --git a/widget/gtk/MPRISServiceHandler.cpp b/widget/gtk/MPRISServiceHandler.cpp
index ae1ef8654d..847bf3d78d 100644
--- a/widget/gtk/MPRISServiceHandler.cpp
+++ b/widget/gtk/MPRISServiceHandler.cpp
@@ -439,10 +439,10 @@ const char* MPRISServiceHandler::DesktopEntry() const {
bool MPRISServiceHandler::PressKey(dom::MediaControlKey aKey) const {
MOZ_ASSERT(mInitialized);
if (!IsMediaKeySupported(aKey)) {
- LOGMPRIS("%s is not supported", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("%s is not supported", dom::GetEnumString(aKey).get());
return false;
}
- LOGMPRIS("Press %s", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("Press %s", dom::GetEnumString(aKey).get());
EmitEvent(aKey);
return true;
}
@@ -861,7 +861,7 @@ bool MPRISServiceHandler::EmitSupportedKeyChanged(dom::MediaControlKey aKey,
bool aSupported) const {
auto it = gKeyProperty.find(aKey);
if (it == gKeyProperty.end()) {
- LOGMPRIS("No property for %s", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("No property for %s", dom::GetEnumString(aKey).get());
return false;
}
diff --git a/widget/gtk/MozContainer.cpp b/widget/gtk/MozContainer.cpp
index 775ae0488f..446dc97a66 100644
--- a/widget/gtk/MozContainer.cpp
+++ b/widget/gtk/MozContainer.cpp
@@ -87,19 +87,18 @@ void moz_container_class_init(MozContainerClass* klass) {
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->map = moz_container_map;
widget_class->realize = moz_container_realize;
widget_class->unrealize = moz_container_unrealize;
widget_class->destroy = moz_container_destroy;
#ifdef MOZ_WAYLAND
if (mozilla::widget::GdkIsWaylandDisplay()) {
- widget_class->map = moz_container_wayland_map;
widget_class->size_allocate = moz_container_wayland_size_allocate;
widget_class->map_event = moz_container_wayland_map_event;
widget_class->unmap = moz_container_wayland_unmap;
} else {
#endif
- widget_class->map = moz_container_map;
widget_class->size_allocate = moz_container_size_allocate;
widget_class->unmap = moz_container_unmap;
#ifdef MOZ_WAYLAND
@@ -130,6 +129,10 @@ void moz_container_map(GtkWidget* widget) {
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
}
+
+ // Enable rendering to nsWindow/MozContainer
+ nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
+ window->OnMap();
}
void moz_container_unmap(GtkWidget* widget) {
@@ -138,9 +141,9 @@ void moz_container_unmap(GtkWidget* widget) {
LOGCONTAINER(("moz_container_unmap() [%p]",
(void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget))));
- // Disable rendering to MozContainer before we unmap it.
+ // Disable rendering to nsWindow/MozContainer before we really unmap it.
nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
- window->DisableRendering();
+ window->OnUnmap();
gtk_widget_set_mapped(widget, FALSE);
diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp
index 8490f25599..39e8a48390 100644
--- a/widget/gtk/MozContainerWayland.cpp
+++ b/widget/gtk/MozContainerWayland.cpp
@@ -419,21 +419,6 @@ gboolean moz_container_wayland_map_event(GtkWidget* widget,
return FALSE;
}
-void moz_container_wayland_map(GtkWidget* widget) {
- LOGCONTAINER("%s [%p]\n", __FUNCTION__,
- (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
-
- g_return_if_fail(IS_MOZ_CONTAINER(widget));
-
- // We need to mark MozContainer as mapped to make sure
- // moz_container_wayland_unmap() is called on hide/withdraw.
- gtk_widget_set_mapped(widget, TRUE);
-
- if (gtk_widget_get_has_window(widget)) {
- gdk_window_show(gtk_widget_get_window(widget));
- }
-}
-
void moz_container_wayland_size_allocate(GtkWidget* widget,
GtkAllocation* allocation) {
GtkAllocation tmp_allocation;
diff --git a/widget/gtk/PCompositorWidget.ipdl b/widget/gtk/PCompositorWidget.ipdl
index d554a33144..e083e8d4ef 100644
--- a/widget/gtk/PCompositorWidget.ipdl
+++ b/widget/gtk/PCompositorWidget.ipdl
@@ -22,8 +22,8 @@ parent:
async __delete__();
async NotifyClientSizeChanged(LayoutDeviceIntSize aClientSize);
- async DisableRendering();
- async EnableRendering(uintptr_t aXWindow, bool aShaped);
+ async CleanupResources();
+ async SetRenderingSurface(uintptr_t aXWindow, bool aShaped);
child:
diff --git a/widget/gtk/ScreenHelperGTK.cpp b/widget/gtk/ScreenHelperGTK.cpp
index 60be234c60..313bf54b1e 100644
--- a/widget/gtk/ScreenHelperGTK.cpp
+++ b/widget/gtk/ScreenHelperGTK.cpp
@@ -269,7 +269,7 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen,
contentsScale.scale, defaultCssScale.scale, dpi, refreshRate);
return MakeAndAddRef<Screen>(rect, availRect, pixelDepth, pixelDepth,
refreshRate, contentsScale, defaultCssScale, dpi,
- Screen::IsPseudoDisplay::No);
+ Screen::IsPseudoDisplay::No, Screen::IsHDR::No);
}
void ScreenGetterGtk::RefreshScreens() {
diff --git a/widget/gtk/WindowSurfaceProvider.cpp b/widget/gtk/WindowSurfaceProvider.cpp
index 82f9029315..c8b2c5a7d6 100644
--- a/widget/gtk/WindowSurfaceProvider.cpp
+++ b/widget/gtk/WindowSurfaceProvider.cpp
@@ -11,6 +11,7 @@
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsWindow.h"
+#include "mozilla/ScopeExit.h"
#ifdef MOZ_WAYLAND
# include "mozilla/StaticPrefs_widget.h"
@@ -129,13 +130,13 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
// 2. XPutImage
# ifdef MOZ_HAVE_SHMIMAGE
if (!mIsShaped && nsShmImage::UseShm()) {
- LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", mXWindow));
+ LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", (Window)mXWindow));
return MakeRefPtr<WindowSurfaceX11SHM>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth);
}
# endif // MOZ_HAVE_SHMIMAGE
- LOG(("Drawing to Window 0x%lx will use XPutImage\n", mXWindow));
+ LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window)mXWindow));
return MakeRefPtr<WindowSurfaceX11Image>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth, mIsShaped);
}
@@ -143,6 +144,11 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
MOZ_RELEASE_ASSERT(false);
}
+// We need to ignore thread safety checks here. We need to hold mMutex
+// between StartRemoteDrawingInRegion()/EndRemoteDrawingInRegion() calls
+// which confuses it.
+MOZ_PUSH_IGNORE_THREAD_SAFETY
+
already_AddRefed<gfx::DrawTarget>
WindowSurfaceProvider::StartRemoteDrawingInRegion(
const LayoutDeviceIntRegion& aInvalidRegion,
@@ -151,7 +157,13 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
return nullptr;
}
- MutexAutoLock lock(mMutex);
+ // We return a reference to mWindowSurface inside draw target so we need to
+ // hold the mutex untill EndRemoteDrawingInRegion() call where draw target
+ // is returned.
+ // If we return null dt, EndRemoteDrawingInRegion() won't be called to
+ // release mutex.
+ mMutex.Lock();
+ auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
if (!mWindowSurfaceValid) {
mWindowSurface = nullptr;
@@ -178,12 +190,20 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
dt = mWindowSurface->Lock(aInvalidRegion);
}
#endif
+ if (dt) {
+ // We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
+ unlockMutex.release();
+ }
+
return dt.forget();
}
void WindowSurfaceProvider::EndRemoteDrawingInRegion(
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
- MutexAutoLock lock(mMutex);
+ // Unlock mutex from StartRemoteDrawingInRegion().
+ mMutex.AssertCurrentThreadOwns();
+ auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
+
// Commit to mWindowSurface only if we have a valid one.
if (!mWindowSurface || !mWindowSurfaceValid) {
return;
@@ -218,5 +238,7 @@ void WindowSurfaceProvider::EndRemoteDrawingInRegion(
mWindowSurface->Commit(aInvalidRegion);
}
+MOZ_POP_THREAD_SAFETY
+
} // namespace widget
} // namespace mozilla
diff --git a/widget/gtk/WindowSurfaceProvider.h b/widget/gtk/WindowSurfaceProvider.h
index 6aaf50e2da..44a0d78ec6 100644
--- a/widget/gtk/WindowSurfaceProvider.h
+++ b/widget/gtk/WindowSurfaceProvider.h
@@ -81,7 +81,7 @@ class WindowSurfaceProvider final {
*/
mozilla::Mutex mMutex MOZ_UNANNOTATED;
// WindowSurface needs to be re-created as underlying window was changed.
- mozilla::Atomic<bool> mWindowSurfaceValid;
+ bool mWindowSurfaceValid;
#ifdef MOZ_WAYLAND
RefPtr<nsWindow> mWidget;
// WindowSurfaceProvider is owned by GtkCompositorWidget so we don't need
@@ -91,7 +91,12 @@ class WindowSurfaceProvider final {
#ifdef MOZ_X11
bool mIsShaped;
int mXDepth;
- Window mXWindow;
+ // Make mXWindow atomic to allow it read from different threads
+ // and make tsan happy.
+ // We don't care much about actual mXWindow value (it may be valid XWindow or
+ // nullptr) because we invalidate mXWindow at compositor/renderer thread
+ // before it's release in unmap handler.
+ Atomic<Window, Relaxed> mXWindow;
Visual* mXVisual;
#endif
};
diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp
index 0135f97a4e..f435cdf2a0 100644
--- a/widget/gtk/nsDragService.cpp
+++ b/widget/gtk/nsDragService.cpp
@@ -607,6 +607,14 @@ nsDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
mTargetDragContextForRemote = nullptr;
mTargetWindow = nullptr;
mPendingWindow = nullptr;
+ mPendingDragContext = nullptr;
+ mPendingWindowPoint = {};
+ mScheduledTask = eDragTaskNone;
+ if (mTaskSource) {
+ g_source_remove(mTaskSource);
+ mTaskSource = 0;
+ }
+ mPendingTime = 0;
mCachedDragContext = 0;
return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
@@ -1208,19 +1216,57 @@ void nsDragService::TargetDataReceived(GtkWidget* aWidget,
GdkAtom target = gtk_selection_data_get_target(aSelectionData);
GUniquePtr<gchar> name(gdk_atom_name(target));
nsDependentCString flavor(name.get());
-
if (gtk_targets_include_uri(&target, 1)) {
- GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ // For the vnd.portal.filetransfer and vnd.portal.files we receive numeric
+ // id when it's a local file. The numeric id is then used by
+ // gtk_selection_data_get_uris implementation to get the actual file
+ // available in the flatpak environment.
+ //
+ // However due to GTK implementation also for example the uris like https
+ // are also provided by the vnd.portal.filetransfer target. In this case the
+ // call gtk_selection_data_get_uris fails. This is a bug in the gtk.
+ // To workaround it we try to create the valid uri and only if we fail
+ // we try to use the gtk_selection_data_get_uris. We ignore the valid uris
+ // for the vnd.portal.file* targets.
+ // See: https://gitlab.gnome.org/GNOME/gtk/-/issues/6563
+ if (flavor.Equals(gPortalFile) || flavor.Equals(gPortalFileTransfer)) {
+ const guchar* data = gtk_selection_data_get_data(aSelectionData);
+ if (!data || data[0] == '\0') {
+ LOGDRAGSERVICE(" Empty data!\n");
+ return;
+ }
+ nsCOMPtr<nsIURI> sourceURI;
+ nsresult rv =
+ NS_NewURI(getter_AddRefs(sourceURI), (const gchar*)data, nullptr);
+ if (NS_FAILED(rv)) {
+ // We're unable to get the URI, we'll use the
+ // gtk_selection_data_get_uris to get the actual file location
+ // accessible from the Firefox runtime.
+ GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ uris.swap(mTargetDragUris);
+ } else {
+ LOGDRAGSERVICE(
+ " got valid uri for MIME %s - this is bug in GTK - expected "
+ "numeric value for portal, got %s\n",
+ flavor.get(), data);
+ return;
+ }
+
+ } else {
+ GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ uris.swap(mTargetDragUris);
+ }
#ifdef MOZ_LOGGING
if (MOZ_LOG_TEST(gWidgetDragLog, mozilla::LogLevel::Debug)) {
- gchar** uri = uris.get();
+ gchar** uri = mTargetDragUris.get();
while (uri && *uri) {
LOGDRAGSERVICE(" got uri %s, MIME %s", *uri, flavor.get());
uri++;
}
}
+
#endif
- uris.swap(mTargetDragUris);
+
if (mTargetDragUris) {
mCachedUris.InsertOrUpdate(
flavor, GUniquePtr<gchar*>(g_strdupv(mTargetDragUris.get())));
@@ -2557,6 +2603,7 @@ gboolean nsDragService::RunScheduledTask() {
// Nothing more to do
// Returning false removes the task source from the event loop.
mTaskSource = 0;
+ mPendingDragContext = nullptr;
return FALSE;
}
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
index 040d942cdf..8702c154d6 100644
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -800,6 +800,7 @@ nsresult nsLookAndFeel::PerThemeData::GetColor(ColorID aID,
case ColorID::SpellCheckerUnderline:
case ColorID::Mark:
case ColorID::Marktext:
+ case ColorID::MozAutofillBackground:
aColor = GetStandinForNativeColor(
aID, mIsDark ? ColorScheme::Dark : ColorScheme::Light);
break;
@@ -863,9 +864,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::CaretWidth:
aResult = 1;
break;
- case IntID::ShowCaretDuringSelection:
- aResult = 0;
- break;
case IntID::SelectTextfieldsOnKeyFocus: {
GtkSettings* settings;
gboolean select_on_focus;
diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp
index 16945349bb..78d4e925fe 100644
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -167,9 +167,6 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
ElementState elementState = GetContentState(aFrame, aAppearance);
if (aState) {
memset(aState, 0, sizeof(GtkWidgetState));
-
- // For XUL checkboxes and radio buttons, the state of the parent
- // determines our state.
if (aWidgetFlags) {
if (elementState.HasState(ElementState::CHECKED)) {
*aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED;
@@ -241,7 +238,8 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
aAppearance == StyleAppearance::MozWindowButtonMinimize ||
aAppearance == StyleAppearance::MozWindowButtonMaximize ||
aAppearance == StyleAppearance::MozWindowButtonRestore) {
- aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame);
+ aState->backdrop = aFrame->PresContext()->Document()->State().HasState(
+ dom::DocumentState::WINDOW_INACTIVE);
}
}
@@ -884,11 +882,6 @@ LayoutDeviceIntMargin nsNativeThemeGTK::GetWidgetBorder(
CSSIntMargin result;
GtkTextDirection direction = GetTextDirection(aFrame);
switch (aAppearance) {
- case StyleAppearance::Toolbox:
- // gtk has no toolbox equivalent. So, although we map toolbox to
- // gtk's 'toolbar' for purposes of painting the widget background,
- // we don't use the toolbar border for toolbox.
- break;
case StyleAppearance::Dualbutton:
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
// around the entire button + dropdown, and also an inner border if you're
@@ -1169,9 +1162,7 @@ nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame,
}
// Some widget types just never change state.
- if (aAppearance == StyleAppearance::Toolbox ||
- aAppearance == StyleAppearance::Toolbar ||
- aAppearance == StyleAppearance::Progresschunk ||
+ if (aAppearance == StyleAppearance::Progresschunk ||
aAppearance == StyleAppearance::ProgressBar ||
aAppearance == StyleAppearance::Tooltip ||
aAppearance == StyleAppearance::MozWindowDecorations) {
@@ -1244,7 +1235,6 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::Button:
case StyleAppearance::Radio:
case StyleAppearance::Checkbox:
- case StyleAppearance::Toolbox: // N/A
case StyleAppearance::Toolbarbutton:
case StyleAppearance::Dualbutton: // so we can override the border with 0
case StyleAppearance::ToolbarbuttonDropdown:
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
index e84044990c..0a78d0c8ec 100644
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -187,8 +187,6 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor);
/* callbacks from widgets */
static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event);
-static void widget_map_cb(GtkWidget* widget);
-static void widget_unmap_cb(GtkWidget* widget);
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation);
static void toplevel_window_size_allocate_cb(GtkWidget* widget,
GtkAllocation* allocation);
@@ -392,11 +390,11 @@ static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) {
nsWindow::nsWindow()
: mTitlebarRectMutex("nsWindow::mTitlebarRectMutex"),
- mDestroyMutex("nsWindow::mDestroyMutex"),
+ mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"),
+ mIsMapped(false),
mIsDestroyed(false),
mIsShown(false),
mNeedsShow(false),
- mIsMapped(false),
mEnabled(true),
mCreated(false),
mHandleTouchEvent(false),
@@ -581,7 +579,6 @@ void nsWindow::Destroy() {
LOG("nsWindow::Destroy\n");
- MutexAutoLock lock(mDestroyMutex);
mIsDestroyed = true;
mCreated = false;
@@ -612,6 +609,9 @@ void nsWindow::Destroy() {
NativeShow(false);
+ MOZ_ASSERT(!gtk_widget_get_mapped(mShell));
+ MOZ_ASSERT(!gtk_widget_get_mapped(GTK_WIDGET(mContainer)));
+
ClearTransparencyBitmap();
DestroyLayerManager();
@@ -3165,23 +3165,34 @@ void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) {
LOG(" widget now has focus in SetFocus()");
}
+void nsWindow::ResetScreenBounds() {
+ mGdkWindowOrigin.reset();
+ mGdkWindowRootOrigin.reset();
+}
+
LayoutDeviceIntRect nsWindow::GetScreenBounds() {
if (!mGdkWindow) {
return mBounds;
}
const LayoutDeviceIntPoint origin = [&] {
- gint x, y;
- gdk_window_get_root_origin(mGdkWindow, &x, &y);
+ GdkPoint origin;
+
+ if (mGdkWindowRootOrigin.isSome()) {
+ origin = mGdkWindowRootOrigin.value();
+ } else {
+ gdk_window_get_root_origin(mGdkWindow, &origin.x, &origin.y);
+ mGdkWindowRootOrigin = Some(origin);
+ }
// Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820
// Bug 1775017 Gtk < 3.24.35 returns scaled values for
// override redirected window on X11.
if (gtk_check_version(3, 24, 35) != nullptr && GdkIsX11Display() &&
gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TEMP) {
- return LayoutDeviceIntPoint(x, y);
+ return LayoutDeviceIntPoint(origin.x, origin.y);
}
- return GdkPointToDevicePixels({x, y});
+ return GdkPointToDevicePixels(origin);
}();
// mBounds.Size() is the window bounds, not the window-manager frame
@@ -3237,6 +3248,7 @@ void nsWindow::RecomputeClientOffset(bool aNotify) {
gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget,
GdkEventProperty* aEvent) {
if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
+ ResetScreenBounds();
RecomputeClientOffset(/* aNotify = */ true);
return FALSE;
}
@@ -3395,40 +3407,37 @@ void* nsWindow::GetNativeData(uint32_t aDataType) {
case NS_NATIVE_OPENGL_CONTEXT:
return nullptr;
case NS_NATIVE_EGL_WINDOW: {
+ // On X11 we call it:
+ // 1) If window is mapped on OnMap() by nsWindow::ResumeCompositorImpl(),
+ // new EGLSurface/XWindow is created.
+ // 2) If window is hidden on OnUnmap(), we replace EGLSurface/XWindow
+ // by offline surface and release XWindow.
+
+ // On Wayland it:
+ // 1) If window is mapped on OnMap(), we request frame callback
+ // at MozContainer. If we get frame callback at MozContainer,
+ // nsWindow::ResumeCompositorImpl() is called from it
+ // and EGLSurface/wl_surface is created.
+ // 2) If window is hidden on OnUnmap(), we replace EGLSurface/wl_surface
+ // by offline surface and release XWindow.
+
+ // If nsWindow is already destroyed, don't try to get EGL window at all,
+ // we're going to be deleted anyway.
+ MutexAutoLock lock(mWindowVisibilityMutex);
void* eglWindow = nullptr;
-
- // We can't block on mutex here as it leads to a deadlock:
- // 1) mutex is taken at nsWindow::Destroy()
- // 2) NS_NATIVE_EGL_WINDOW is called from compositor/rendering thread,
- // blocking on mutex.
- // 3) DestroyCompositor() is called by nsWindow::Destroy(). As a sync
- // call it waits to compositor/rendering threads,
- // but they're blocked at 2).
- // It's fine if we return null EGL window during DestroyCompositor(),
- // in such case compositor painting is skipped.
- if (mDestroyMutex.TryLock()) {
- if (mGdkWindow && !mIsDestroyed) {
+ if (mIsMapped && !mIsDestroyed) {
#ifdef MOZ_X11
- if (GdkIsX11Display()) {
- eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow);
- }
+ if (GdkIsX11Display()) {
+ eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow);
+ }
#endif
#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
- bool hiddenWindow =
- mCompositorWidgetDelegate &&
- mCompositorWidgetDelegate->AsGtkCompositorWidget() &&
- mCompositorWidgetDelegate->AsGtkCompositorWidget()->IsHidden();
- if (!hiddenWindow) {
- eglWindow = moz_container_wayland_get_egl_window(
- mContainer, FractionalScaleFactor());
- }
- }
-#endif
+ if (GdkIsWaylandDisplay()) {
+ eglWindow = moz_container_wayland_get_egl_window(
+ mContainer, FractionalScaleFactor());
}
- mDestroyMutex.Unlock();
+#endif
}
-
LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p",
mGdkWindow, eglWindow);
return eglWindow;
@@ -3556,11 +3565,16 @@ LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
if (IsWaylandPopup() && !mPopupUseMoveToRect) {
return mBounds.TopLeft();
}
- nsIntPoint origin(0, 0);
- if (mGdkWindow) {
- gdk_window_get_origin(mGdkWindow, &origin.x.value, &origin.y.value);
+
+ GdkPoint origin{};
+ if (mGdkWindowOrigin.isSome()) {
+ origin = mGdkWindowOrigin.value();
+ } else if (mGdkWindow) {
+ gdk_window_get_origin(mGdkWindow, &origin.x, &origin.y);
+ mGdkWindowOrigin = Some(origin);
}
- return GdkPointToDevicePixels({origin.x, origin.y});
+
+ return GdkPointToDevicePixels(origin);
}
void nsWindow::CaptureRollupEvents(bool aDoCapture) {
@@ -3749,6 +3763,8 @@ void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
if (knowsCompositor && layerManager && mCompositorSession) {
+ LOG("nsWindow::RequestRepaint()");
+
if (!mConfiguredClearColor && !IsPopup()) {
layerManager->WrBridge()->SendSetDefaultClearColor(LookAndFeel::Color(
LookAndFeel::ColorID::Window, PreferenceSheet::ColorSchemeForChrome(),
@@ -3764,9 +3780,13 @@ void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
}
gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
+ LOG("nsWindow::OnExposeEvent GdkWindow [%p] XID [0x%lx]", mGdkWindow,
+ GetX11Window());
+
// This might destroy us.
NotifyOcclusionState(OcclusionState::VISIBLE);
if (mIsDestroyed) {
+ LOG("destroyed after NotifyOcclusionState()");
return FALSE;
}
@@ -3774,26 +3794,27 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
// May run event loop and destroy us.
MaybeDispatchResized();
if (mIsDestroyed) {
+ LOG("destroyed after MaybeDispatchResized()");
return FALSE;
}
// Windows that are not visible will be painted after they become visible.
if (!mGdkWindow || !mHasMappedToplevel) {
+ LOG("quit, !mGdkWindow || !mHasMappedToplevel");
return FALSE;
}
#ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay() && !moz_container_wayland_can_draw(mContainer)) {
+ LOG("quit, !moz_container_wayland_can_draw()");
return FALSE;
}
#endif
if (!GetListener()) {
+ LOG("quit, !GetListener()");
return FALSE;
}
- LOG("nsWindow::OnExposeEvent GdkWindow [%p] XID [0x%lx]", mGdkWindow,
- GetX11Window());
-
LayoutDeviceIntRegion exposeRegion;
if (!ExtractExposeRegion(exposeRegion, cr)) {
LOG(" no rects, quit");
@@ -3816,19 +3837,24 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
// If the window has been destroyed during the will paint notification,
// there is nothing left to do.
if (!mGdkWindow || mIsDestroyed) {
+ LOG("quit, !mGdkWindow || mIsDestroyed");
return TRUE;
}
// Re-get all rendering components since the will paint notification
// might have killed it.
nsIWidgetListener* listener = GetListener();
- if (!listener) return FALSE;
+ if (!listener) {
+ LOG("quit, !listener");
+ return FALSE;
+ }
WindowRenderer* renderer = GetWindowRenderer();
WebRenderLayerManager* layerManager = renderer->AsWebRender();
KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
+ LOG("needs composite, ScheduleComposite() call");
layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
layerManager->SetNeedsComposite(false);
}
@@ -3859,11 +3885,13 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
}
if (region.IsEmpty()) {
+ LOG("quit, region.IsEmpty()");
return TRUE;
}
// If this widget uses OMTC...
if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) {
+ LOG("redirect painting to OMTC rendering...");
listener->PaintWindow(this, region);
// Re-get the listener since the will paint notification might have
@@ -4048,6 +4076,8 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
mPendingConfigures--;
}
+ ResetScreenBounds();
+
// Don't fire configure event for scale changes, we handle that
// OnScaleChanged event. Skip that for toplevel windows only.
if (mGdkWindow && IsTopLevelWindowType()) {
@@ -4103,45 +4133,12 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
return FALSE;
}
-void nsWindow::OnMap() {
- LOG("nsWindow::OnMap");
- // Gtk mapped widget to screen. Configure underlying GdkWindow properly
- // as our rendering target.
- // This call means we have X11 (or Wayland) window we can render to by GL
- // so we need to notify compositor about it.
- mIsMapped = true;
- ConfigureGdkWindow();
-}
-
-void nsWindow::OnUnmap() {
- LOG("nsWindow::OnUnmap");
-
- mIsMapped = false;
-
- if (mSourceDragContext) {
- static auto sGtkDragCancel =
- (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
- if (sGtkDragCancel) {
- sGtkDragCancel(mSourceDragContext);
- mSourceDragContext = nullptr;
- }
- }
-
- // We don't have valid XWindow any more,
- // so clear stored ones at GtkCompositorWidget() for OMTC rendering
- // and mSurfaceProvider for legacy rendering.
- if (GdkIsX11Display()) {
- mSurfaceProvider.CleanupResources();
- if (mCompositorWidgetDelegate) {
- mCompositorWidgetDelegate->DisableRendering();
- }
- }
-}
-
void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
LOG("nsWindow::OnSizeAllocate %d,%d -> %d x %d\n", aAllocation->x,
aAllocation->y, aAllocation->width, aAllocation->height);
+ ResetScreenBounds();
+
// Client offset are updated by _NET_FRAME_EXTENTS on X11 when system titlebar
// is enabled. In either cases (Wayland or system titlebar is off on X11)
// we don't get _NET_FRAME_EXTENTS X11 property notification so we derive
@@ -4650,9 +4647,16 @@ bool nsWindow::DoTitlebarAction(LookAndFeel::TitlebarEvent aEvent,
LOG(" action menu");
TryToShowNativeWindowMenu(aButtonEvent);
break;
- // Lower is part of gtk_surface1 protocol which we can't support
- // as Gtk keeps it private. So emulate it by minimize.
case LookAndFeel::TitlebarAction::WindowLower:
+ LOG(" action lower");
+ // Lower is part of gtk_surface1 protocol which we can't support
+ // as Gtk keeps it private. So emulate it by minimize.
+ if (GdkIsWaylandDisplay()) {
+ SetSizeMode(nsSizeMode_Minimized);
+ } else {
+ gdk_window_lower(GetToplevelGdkWindow());
+ }
+ break;
case LookAndFeel::TitlebarAction::WindowMinimize:
LOG(" action minimize");
SetSizeMode(nsSizeMode_Minimized);
@@ -5425,8 +5429,8 @@ void nsWindow::OnScaleChanged(bool aNotify) {
NotifyAPZOfDPIChange();
- LOG("OnScaleChanged %d, %f -> %d, %f\n", int(mCeiledScaleFactor),
- mFractionalScaleFactor, newCeiled, newFractional);
+ LOG("OnScaleChanged %d, %f -> %d, %f Notify %d\n", int(mCeiledScaleFactor),
+ mFractionalScaleFactor, newCeiled, newFractional, aNotify);
mCeiledScaleFactor = newCeiled;
mFractionalScaleFactor = newFractional;
@@ -5822,8 +5826,8 @@ bool nsWindow::GetShapedState() {
}
void nsWindow::ConfigureCompositor() {
- MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED);
MOZ_DIAGNOSTIC_ASSERT(mIsMapped);
+ MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED);
LOG("nsWindow::ConfigureCompositor()");
auto startCompositing = [self = RefPtr{this}, this]() -> void {
@@ -5833,7 +5837,7 @@ void nsWindow::ConfigureCompositor() {
// too late
if (mIsDestroyed || !mIsMapped) {
LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed,
- mIsMapped);
+ !!mIsMapped);
return;
}
// Compositor will be resumed later by ResumeCompositorFlickering().
@@ -5860,73 +5864,6 @@ void nsWindow::ConfigureCompositor() {
}
}
-void nsWindow::ConfigureGdkWindow() {
- LOG("nsWindow::ConfigureGdkWindow()");
-
- EnsureGdkWindow();
- OnScaleChanged(/* aNotify = */ false);
-
- if (mIsAlert) {
- gdk_window_set_override_redirect(mGdkWindow, TRUE);
- }
-
-#ifdef MOZ_X11
- if (GdkIsX11Display()) {
- mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
-
- // Set window manager hint to keep fullscreen windows composited.
- //
- // If the window were to get unredirected, there could be visible
- // tearing because Gecko does not align its framebuffer updates with
- // vblank.
- SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
- }
-#endif
-#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
- mSurfaceProvider.Initialize(this);
- }
-#endif
-
- if (mIsDragPopup) {
- if (GdkIsWaylandDisplay()) {
- // Disable painting to the widget on Wayland as we paint directly to the
- // widget. Wayland compositors does not paint wl_subsurface
- // of D&D widget.
- if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
- GtkWidgetDisableUpdates(parent);
- }
- GtkWidgetDisableUpdates(mShell);
- GtkWidgetDisableUpdates(GTK_WIDGET(mContainer));
- } else {
- // Disable rendering of parent container on X11 to avoid flickering.
- if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
- gtk_widget_set_opacity(parent, 0.0);
- }
- }
- }
-
- if (mWindowType == WindowType::Popup) {
- if (mNoAutoHide) {
- gint wmd = ConvertBorderStyles(mBorderStyle);
- if (wmd != -1) {
- gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
- }
- }
- // If the popup ignores mouse events, set an empty input shape.
- SetInputRegion(mInputRegion);
- }
-
- RefreshWindowClass();
-
- // We're not mapped yet but we have already created compositor.
- if (mCompositorWidgetDelegate) {
- ConfigureCompositor();
- }
-
- LOG(" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, GetX11Window());
-}
-
nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
widget::InitData* aInitData) {
@@ -6355,8 +6292,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
G_CALLBACK(settings_xft_dpi_changed_cb), this);
// Widget signals
- g_signal_connect(mContainer, "map", G_CALLBACK(widget_map_cb), nullptr);
- g_signal_connect(mContainer, "unmap", G_CALLBACK(widget_unmap_cb), nullptr);
g_signal_connect_after(mContainer, "size_allocate",
G_CALLBACK(size_allocate_cb), nullptr);
g_signal_connect(mContainer, "hierarchy-changed",
@@ -6567,6 +6502,10 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
LOG("nsWindow::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n",
aMoved, aResized, topLeft.x, topLeft.y, size.width, size.height);
+ if (aMoved) {
+ ResetScreenBounds();
+ }
+
if (aResized && !AreBoundsSane()) {
LOG(" bounds are insane, hidding the window");
// We have been resized but to incorrect size.
@@ -6648,8 +6587,8 @@ void nsWindow::PauseCompositorFlickering() {
CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
if (remoteRenderer) {
- remoteRenderer->SendPause();
mCompositorState = COMPOSITOR_PAUSED_FLICKERING;
+ remoteRenderer->SendPause();
mCompositorPauseTimeoutID = (int)g_timeout_add(
COMPOSITOR_PAUSE_TIMEOUT,
[](void* data) -> gint {
@@ -6703,7 +6642,8 @@ void nsWindow::ResumeCompositorImpl() {
LOG("nsWindow::ResumeCompositorImpl()\n");
MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate);
- mCompositorWidgetDelegate->EnableRendering(GetX11Window(), GetShapedState());
+ mCompositorWidgetDelegate->SetRenderingSurface(GetX11Window(),
+ GetShapedState());
// As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
// time to start it.
@@ -8287,25 +8227,6 @@ static gboolean configure_event_cb(GtkWidget* widget,
return window->OnConfigureEvent(widget, event);
}
-// Some Gtk widget code may call gtk_widget_unrealize() which destroys
-// mGdkWindow. We need to listen on this signal and re-create
-// mGdkWindow when we're already mapped.
-static void widget_map_cb(GtkWidget* widget) {
- RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
- if (!window) {
- return;
- }
- window->OnMap();
-}
-
-static void widget_unmap_cb(GtkWidget* widget) {
- RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
- if (!window) {
- return;
- }
- window->OnUnmap();
-}
-
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
@@ -9124,7 +9045,7 @@ void nsWindow::DidGetNonBlankPaint() {
void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {
LOG("nsWindow::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n",
- delegate, mIsMapped, mCompositorWidgetDelegate);
+ delegate, !!mIsMapped, mCompositorWidgetDelegate);
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (delegate) {
@@ -9962,26 +9883,6 @@ void nsWindow::UnlockNativePointer() {
}
#endif
-bool nsWindow::GetTopLevelWindowActiveState(nsIFrame* aFrame) {
- // Used by window frame and button box rendering. We can end up in here in
- // the content process when rendering one of these moz styles freely in a
- // page. Fail in this case, there is no applicable window focus state.
- if (!XRE_IsParentProcess()) {
- return false;
- }
- // All headless windows are considered active so they are painted.
- if (gfxPlatform::IsHeadless()) {
- return true;
- }
- // Get the widget. nsIFrame's GetNearestWidget walks up the view chain
- // until it finds a real window.
- nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
- if (!window) {
- return false;
- }
- return !window->mTitlebarBackdropState;
-}
-
static nsIFrame* FindTitlebarFrame(nsIFrame* aFrame) {
for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
StyleAppearance appearance =
@@ -10072,41 +9973,34 @@ nsWindow* nsWindow::GetFocusedWindow() { return gFocusWindow; }
#ifdef MOZ_WAYLAND
bool nsWindow::SetEGLNativeWindowSize(
const LayoutDeviceIntSize& aEGLWindowSize) {
- if (!GdkIsWaylandDisplay()) {
+ if (!GdkIsWaylandDisplay() || !mIsMapped) {
return true;
}
- // SetEGLNativeWindowSize() is called from renderer/compositor thread,
- // make sure nsWindow is not destroyed.
- bool paint = false;
+ if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
+ LOG("nsWindow::SetEGLNativeWindowSize() return, "
+ "COMPOSITOR_PAUSED_FLICKERING is set");
+ return false;
+ }
- // See NS_NATIVE_EGL_WINDOW why we can't block here.
- if (mDestroyMutex.TryLock()) {
- if (!mIsDestroyed) {
- gint scale = GdkCeiledScaleFactor();
+ gint scale = GdkCeiledScaleFactor();
# ifdef MOZ_LOGGING
- if (LOG_ENABLED()) {
- static uintptr_t lastSizeLog = 0;
- uintptr_t sizeLog = uintptr_t(this) + aEGLWindowSize.width +
- aEGLWindowSize.height + scale +
- aEGLWindowSize.width / scale +
- aEGLWindowSize.height / scale;
- if (lastSizeLog != sizeLog) {
- lastSizeLog = sizeLog;
- LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
- "%d x "
- "%d)",
- aEGLWindowSize.width, aEGLWindowSize.height, scale,
- aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
- }
- }
-# endif
- paint = moz_container_wayland_egl_window_set_size(
- mContainer, aEGLWindowSize.ToUnknownSize(), scale);
+ if (LOG_ENABLED()) {
+ static uintptr_t lastSizeLog = 0;
+ uintptr_t sizeLog =
+ uintptr_t(this) + aEGLWindowSize.width + aEGLWindowSize.height + scale +
+ aEGLWindowSize.width / scale + aEGLWindowSize.height / scale;
+ if (lastSizeLog != sizeLog) {
+ lastSizeLog = sizeLog;
+ LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
+ "%d x %d)",
+ aEGLWindowSize.width, aEGLWindowSize.height, scale,
+ aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
}
- mDestroyMutex.Unlock();
}
- return paint;
+# endif
+ return moz_container_wayland_egl_window_set_size(
+ mContainer, aEGLWindowSize.ToUnknownSize(), scale);
}
#endif
@@ -10123,45 +10017,138 @@ void nsWindow::ClearRenderingQueue() {
DestroyLayerManager();
}
-void nsWindow::DisableRendering() {
- LOG("nsWindow::DisableRendering()");
+// nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer
+// handlers directly as we paint to mContainer.
+void nsWindow::OnMap() {
+ LOG("nsWindow::OnMap");
- if (mGdkWindow) {
- g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
- mGdkWindow = nullptr;
+ {
+ MutexAutoLock lock(mWindowVisibilityMutex);
+ mIsMapped = true;
+
+ EnsureGdkWindow();
+ OnScaleChanged(/* aNotify = */ false);
+
+ if (mIsAlert) {
+ gdk_window_set_override_redirect(mGdkWindow, TRUE);
+ }
+
+#ifdef MOZ_X11
+ if (GdkIsX11Display()) {
+ mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
+
+ // Set window manager hint to keep fullscreen windows composited.
+ //
+ // If the window were to get unredirected, there could be visible
+ // tearing because Gecko does not align its framebuffer updates with
+ // vblank.
+ SetCompositorHint(GTK_WIDGET_COMPOSITED_ENABLED);
+ }
+#endif
+#ifdef MOZ_WAYLAND
+ if (GdkIsWaylandDisplay()) {
+ mSurfaceProvider.Initialize(this);
+ }
+#endif
+ }
+
+ if (mIsDragPopup) {
+ if (GdkIsWaylandDisplay()) {
+ // Disable painting to the widget on Wayland as we paint directly to the
+ // widget. Wayland compositors does not paint wl_subsurface
+ // of D&D widget.
+ if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
+ GtkWidgetDisableUpdates(parent);
+ }
+ GtkWidgetDisableUpdates(mShell);
+ GtkWidgetDisableUpdates(GTK_WIDGET(mContainer));
+ } else {
+ // Disable rendering of parent container on X11 to avoid flickering.
+ if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
+ gtk_widget_set_opacity(parent, 0.0);
+ }
+ }
+ }
+
+ if (mWindowType == WindowType::Popup) {
+ if (mNoAutoHide) {
+ gint wmd = ConvertBorderStyles(mBorderStyle);
+ if (wmd != -1) {
+ gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
+ }
+ }
+ // If the popup ignores mouse events, set an empty input shape.
+ SetInputRegion(mInputRegion);
+ }
+
+ RefreshWindowClass();
+
+ // We're not mapped yet but we have already created compositor.
+ if (mCompositorWidgetDelegate) {
+ ConfigureCompositor();
+ }
+
+ LOG(" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, GetX11Window());
+}
+
+void nsWindow::OnUnmap() {
+ LOG("nsWindow::OnUnmap");
+
+ {
+ MutexAutoLock lock(mWindowVisibilityMutex);
+ mIsMapped = false;
+
+ if (mSourceDragContext) {
+ static auto sGtkDragCancel =
+ (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
+ if (sGtkDragCancel) {
+ sGtkDragCancel(mSourceDragContext);
+ mSourceDragContext = nullptr;
+ }
+ }
+
+ if (mGdkWindow) {
+ g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
+ mGdkWindow = nullptr;
+ }
+
+ // Clear resources (mainly XWindow) stored at GtkCompositorWidget.
+ // It makes sure we don't paint to it when nsWindow becomes hiden/deleted
+ // and XWindow is released.
+ if (mCompositorWidgetDelegate) {
+ mCompositorWidgetDelegate->CleanupResources();
+ }
+
+ // Clear nsWindow resources used for old (in-thread) rendering.
+ mSurfaceProvider.CleanupResources();
}
// Until Bug 1654938 is fixed we delete layer manager for hidden popups,
// otherwise it can easily hold 1GB+ memory for long time.
if (mWindowType == WindowType::Popup) {
DestroyLayerManager();
- mSurfaceProvider.CleanupResources();
} else {
-#ifdef MOZ_WAYLAND
- // Widget is backed by OpenGL EGLSurface created over wl_surface
- // owned by mContainer.
- // RenderCompositorEGL::Resume() deletes recent EGLSurface based on
- // wl_surface owned by mContainer and creates a new fallback EGLSurface.
- // Then we can delete wl_surface in moz_container_wayland_unmap().
+ // Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow.
+ //
+ // RenderCompositorEGL::Resume() deletes recent EGLSurface,
+ // calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor
+ // thread to get new native rendering surface.
+ //
+ // For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at
+ // nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates
+ // offscreen fallback EGLSurface to avoid compositor pause.
+ //
// We don't want to pause compositor as it may lead to whole
// browser freeze (Bug 1777664).
- ///
- // We don't need to do such operation for SW backend as
- // WindowSurfaceWaylandMB::Commit() gets wl_surface from
- // MozContainer every commit.
- if (moz_container_wayland_has_egl_window(mContainer) &&
- mCompositorWidgetDelegate) {
- if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
- // Call DisableRendering() to make GtkCompositorWidget hidden.
- // Then SendResume() will create fallback EGLSurface, see
- // GLContextEGL::CreateEGLSurfaceForCompositorWidget().
- mCompositorWidgetDelegate->DisableRendering();
- remoteRenderer->SendResume();
- mCompositorWidgetDelegate->EnableRendering(GetX11Window(),
- GetShapedState());
- }
+ //
+ // If RenderCompositorSWGL compositor is used (SW fallback)
+ // RenderCompositorSWGL::Resume() only requests full render for next paint
+ // as wl_surface/XWindow is managed by WindowSurfaceProvider owned
+ // directly by GtkCompositorWidget and that's covered by
+ // mCompositorWidgetDelegate->CleanupResources() call above.
+ if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
+ remoteRenderer->SendResume();
}
-#endif
}
}
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
index f8fe344f09..25d68129d8 100644
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -175,6 +175,7 @@ class nsWindow final : public nsBaseWidget {
void MoveToWorkspace(const nsAString& workspaceID) override;
void Enable(bool aState) override;
void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
+ void ResetScreenBounds();
LayoutDeviceIntRect GetScreenBounds() override;
LayoutDeviceIntRect GetClientBounds() override;
LayoutDeviceIntSize GetClientSize() override;
@@ -411,7 +412,6 @@ class nsWindow final : public nsBaseWidget {
*/
static GtkWindowDecoration GetSystemGtkWindowDecoration();
- static bool GetTopLevelWindowActiveState(nsIFrame* aFrame);
static bool TitlebarUseShapeMask();
bool IsRemoteContent() { return HasRemoteContent(); }
void NativeMoveResizeWaylandPopupCallback(const GdkRectangle* aFinalSize,
@@ -461,8 +461,6 @@ class nsWindow final : public nsBaseWidget {
// rendering queue blocking (see Bug 1782948).
void ClearRenderingQueue();
- void DisableRendering();
-
bool ApplyEnterLeaveMutterWorkaround();
void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;
@@ -553,6 +551,9 @@ class nsWindow final : public nsBaseWidget {
GtkWidget* mShell = nullptr;
MozContainer* mContainer = nullptr;
GdkWindow* mGdkWindow = nullptr;
+ mozilla::Maybe<GdkPoint> mGdkWindowOrigin;
+ mozilla::Maybe<GdkPoint> mGdkWindowRootOrigin;
+
PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate = nullptr;
mozilla::Atomic<WindowCompositorState, mozilla::Relaxed> mCompositorState{
COMPOSITOR_ENABLED};
@@ -633,10 +634,14 @@ class nsWindow final : public nsBaseWidget {
mozilla::Mutex mTitlebarRectMutex;
LayoutDeviceIntRect mTitlebarRect MOZ_GUARDED_BY(mTitlebarRectMutex);
- mozilla::Mutex mDestroyMutex;
+ // This mutex protect window visibility changes.
+ mozilla::Mutex mWindowVisibilityMutex;
+ // This track real window visibility from OS perspective.
+ // It's set by OnMap/OnUnmap which is based on Gtk events.
+ mozilla::Atomic<bool, mozilla::Relaxed> mIsMapped;
// Has this widget been destroyed yet?
- bool mIsDestroyed : 1;
+ mozilla::Atomic<bool, mozilla::Relaxed> mIsDestroyed;
// mIsShown tracks requested visible status from browser perspective, i.e.
// if the window should be visible or now.
bool mIsShown : 1;
@@ -646,9 +651,6 @@ class nsWindow final : public nsBaseWidget {
// that the window is not actually visible but we report to browser that
// it is visible (mIsShown == true).
bool mNeedsShow : 1;
- // This track real window visibility from OS perspective.
- // It's set by OnMap/OnUnmap which is based on Gtk events.
- bool mIsMapped : 1;
// is this widget enabled?
bool mEnabled : 1;
// has the native window for this been created yet?
@@ -802,11 +804,6 @@ class nsWindow final : public nsBaseWidget {
void DispatchMissedButtonReleases(GdkEventCrossing* aGdkEvent);
- // When window widget gets mapped/unmapped we need to configure
- // underlying GdkWindow properly. Otherwise we'll end up with
- // rendering to released window.
- void ConfigureGdkWindow();
- void ReleaseGdkWindow();
void ConfigureCompositor();
bool IsAlwaysUndecoratedWindow() const;
@@ -996,9 +993,9 @@ class nsWindow final : public nsBaseWidget {
void RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion);
#ifdef MOZ_X11
- typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
- GTK_WIDGET_COMPOSIDED_DISABLED = 1,
- GTK_WIDGET_COMPOSIDED_ENABLED = 2} WindowComposeRequest;
+ typedef enum {GTK_WIDGET_COMPOSITED_DEFAULT = 0,
+ GTK_WIDGET_COMPOSITED_DISABLED = 1,
+ GTK_WIDGET_COMPOSITED_ENABLED = 2} WindowComposeRequest;
void SetCompositorHint(WindowComposeRequest aState);
bool ConfigureX11GLVisual();
#endif
diff --git a/widget/headless/HeadlessLookAndFeelGTK.cpp b/widget/headless/HeadlessLookAndFeelGTK.cpp
index 462a877f34..aa55bcc347 100644
--- a/widget/headless/HeadlessLookAndFeelGTK.cpp
+++ b/widget/headless/HeadlessLookAndFeelGTK.cpp
@@ -32,9 +32,6 @@ nsresult HeadlessLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::CaretWidth:
aResult = 1;
break;
- case IntID::ShowCaretDuringSelection:
- aResult = 0;
- break;
case IntID::SelectTextfieldsOnKeyFocus:
aResult = 1;
break;
diff --git a/widget/headless/HeadlessScreenHelper.cpp b/widget/headless/HeadlessScreenHelper.cpp
index 4d8dbfa0d1..5a9643c572 100644
--- a/widget/headless/HeadlessScreenHelper.cpp
+++ b/widget/headless/HeadlessScreenHelper.cpp
@@ -32,9 +32,10 @@ LayoutDeviceIntRect HeadlessScreenHelper::GetScreenRect() {
HeadlessScreenHelper::HeadlessScreenHelper() {
AutoTArray<RefPtr<Screen>, 1> screenList;
LayoutDeviceIntRect rect = GetScreenRect();
- auto ret = MakeRefPtr<Screen>(
- rect, rect, 24, 24, 0, DesktopToLayoutDeviceScale(),
- CSSToLayoutDeviceScale(), 96.0f, Screen::IsPseudoDisplay::No);
+ auto ret =
+ MakeRefPtr<Screen>(rect, rect, 24, 24, 0, DesktopToLayoutDeviceScale(),
+ CSSToLayoutDeviceScale(), 96.0f,
+ Screen::IsPseudoDisplay::No, Screen::IsHDR::No);
screenList.AppendElement(ret.forget());
ScreenManager::Refresh(std::move(screenList));
}
diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp
index 083d026d3c..419b3bf940 100644
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -160,10 +160,9 @@ void HeadlessWidget::GetCompositorWidgetInitData(
nsIWidget* HeadlessWidget::GetTopLevelWidget() { return mTopLevel; }
void HeadlessWidget::RaiseWindow() {
- MOZ_ASSERT(mWindowType == WindowType::TopLevel ||
- mWindowType == WindowType::Dialog ||
- mWindowType == WindowType::Sheet,
- "Raising a non-toplevel window.");
+ MOZ_ASSERT(
+ mWindowType == WindowType::TopLevel || mWindowType == WindowType::Dialog,
+ "Raising a non-toplevel window.");
// Do nothing if this is the currently active window.
RefPtr<HeadlessWidget> activeWindow = GetActiveWindow();
@@ -204,7 +203,7 @@ void HeadlessWidget::Show(bool aState) {
// so we don't focus them by default.
if (aState && !mAlwaysOnTop &&
(mWindowType == WindowType::TopLevel ||
- mWindowType == WindowType::Dialog || mWindowType == WindowType::Sheet)) {
+ mWindowType == WindowType::Dialog)) {
RaiseWindow();
}
diff --git a/widget/nsBaseClipboard.cpp b/widget/nsBaseClipboard.cpp
index 333d154e70..9ffc53b4c2 100644
--- a/widget/nsBaseClipboard.cpp
+++ b/widget/nsBaseClipboard.cpp
@@ -340,7 +340,7 @@ class SafeContentAnalysisResultCallback final
NS_IMETHODIMP Error(nsresult aError) override {
using namespace mozilla::contentanalysis;
Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::ERROR_OTHER));
+ NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
return NS_OK;
}
@@ -379,13 +379,18 @@ CheckClipboardContentAnalysisAsText(
}
nsString text;
if (NS_FAILED(textData->GetData(text))) {
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
+ }
+ if (text.IsEmpty()) {
+ // Content Analysis doesn't expect to analyze an empty string.
+ // Just approve it.
+ return true;
}
RefPtr<mozilla::dom::WindowGlobalParent> window =
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
if (!window) {
// The window has gone away in the meantime
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
}
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest =
new ContentAnalysisRequest(
@@ -395,7 +400,7 @@ CheckClipboardContentAnalysisAsText(
nsresult rv = aContentAnalysis->AnalyzeContentRequestCallback(
contentAnalysisRequest, /* aAutoAcknowledge */ true, aResolver);
if (NS_FAILED(rv)) {
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
}
return true;
}
@@ -420,7 +425,7 @@ CheckClipboardContentAnalysisAsFile(
rv = file->GetPath(filePath);
} else {
MOZ_ASSERT_UNREACHABLE("clipboard data had kFileMime but no nsIFile!");
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
}
}
if (NS_FAILED(rv) || filePath.IsEmpty()) {
@@ -430,7 +435,7 @@ CheckClipboardContentAnalysisAsFile(
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
if (!window) {
// The window has gone away in the meantime
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
}
// Let the content analysis code calculate the digest
nsCOMPtr<nsIContentAnalysisRequest> contentAnalysisRequest =
@@ -443,7 +448,7 @@ CheckClipboardContentAnalysisAsFile(
contentAnalysisRequest,
/* aAutoAcknowledge */ true, aResolver);
if (NS_FAILED(rv)) {
- return mozilla::Err(NoContentAnalysisResult::ERROR_OTHER);
+ return mozilla::Err(NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR);
}
return true;
}
@@ -463,14 +468,15 @@ static void CheckClipboardContentAnalysis(
if (!aWindow || aWindow->GetBrowsingContext()->IsChrome() ||
aWindow->IsInProcess()) {
aResolver->Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::CONTEXT_EXEMPT_FROM_CONTENT_ANALYSIS));
+ NoContentAnalysisResult::
+ ALLOW_DUE_TO_CONTEXT_EXEMPT_FROM_CONTENT_ANALYSIS));
return;
}
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
mozilla::components::nsIContentAnalysis::Service();
if (!contentAnalysis) {
aResolver->Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::ERROR_OTHER));
+ NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
return;
}
@@ -478,7 +484,7 @@ static void CheckClipboardContentAnalysis(
nsresult rv = contentAnalysis->GetIsActive(&contentAnalysisIsActive);
if (MOZ_LIKELY(NS_FAILED(rv) || !contentAnalysisIsActive)) {
aResolver->Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::CONTENT_ANALYSIS_NOT_ACTIVE));
+ NoContentAnalysisResult::ALLOW_DUE_TO_CONTENT_ANALYSIS_NOT_ACTIVE));
return;
}
@@ -488,7 +494,7 @@ static void CheckClipboardContentAnalysis(
rv = aTransferable->FlavorsTransferableCanExport(flavors);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver->Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::ERROR_OTHER));
+ NoContentAnalysisResult::DENY_DUE_TO_OTHER_ERROR));
return;
}
bool keepChecking = true;
@@ -515,7 +521,7 @@ static void CheckClipboardContentAnalysis(
if (!textResult.unwrap()) {
// Couldn't get file or text data from this
aResolver->Callback(ContentAnalysisResult::FromNoResult(
- NoContentAnalysisResult::ERROR_COULD_NOT_GET_DATA));
+ NoContentAnalysisResult::ALLOW_DUE_TO_COULD_NOT_GET_DATA));
return;
}
}
diff --git a/widget/nsIDragSession.idl b/widget/nsIDragSession.idl
index e96e6fc1c7..8dbf93e719 100644
--- a/widget/nsIDragSession.idl
+++ b/widget/nsIDragSession.idl
@@ -135,7 +135,7 @@ interface nsIDragSession : nsISupports
/**
* Returns true if current session was started with synthesized drag start.
*/
- [notxpcom, nostdcall] bool isSynthesizedForTests();
+ [notxpcom, nostdcall] boolean isSynthesizedForTests();
/**
* Sets drag end point of synthesized session when the test does not dispatch
@@ -147,5 +147,5 @@ interface nsIDragSession : nsISupports
* Returns true if the session is for dragging text in a text in text control
* element.
*/
- [notxpcom, nostdcall] bool isDraggingTextInTextControl();
+ [notxpcom, nostdcall] boolean isDraggingTextInTextControl();
};
diff --git a/widget/nsIMacDockSupport.idl b/widget/nsIMacDockSupport.idl
index 04d6dca774..6f0f1adbae 100644
--- a/widget/nsIMacDockSupport.idl
+++ b/widget/nsIMacDockSupport.idl
@@ -41,7 +41,7 @@ interface nsIMacDockSupport : nsISupports
* True if this app is in the list of apps that are persisted to the macOS
* Dock (as if the user selected "Keep in Dock").
*/
- readonly attribute bool isAppInDock;
+ readonly attribute boolean isAppInDock;
/**
* Ensure that there is a tile for this app in the list of apps that are
@@ -66,6 +66,6 @@ interface nsIMacDockSupport : nsISupports
* @return true if the app was already in the list of persisted apps or if it
* was successfully added, else returns false.
*/
- bool ensureAppIsPinnedToDock([optional] in AString aAppPath,
- [optional] in AString aAppToReplacePath);
+ boolean ensureAppIsPinnedToDock([optional] in AString aAppPath,
+ [optional] in AString aAppToReplacePath);
};
diff --git a/widget/nsIPrintSettings.idl b/widget/nsIPrintSettings.idl
index efed9efce6..daf0e145f4 100644
--- a/widget/nsIPrintSettings.idl
+++ b/widget/nsIPrintSettings.idl
@@ -203,7 +203,7 @@ interface nsIPrintSettings : nsISupports
* to make best use of the space on the sheet. Specifically, this returns
* true IFF `numPagesPerSheet` is set to 2 or 6 pages-per-sheet.
*/
- [noscript, notxpcom, nostdcall] bool HasOrthogonalPagesPerSheet();
+ [noscript, notxpcom, nostdcall] boolean HasOrthogonalPagesPerSheet();
/**
* Makes a new copy
@@ -220,7 +220,7 @@ interface nsIPrintSettings : nsISupports
* therefore print. The printer name is ignored and it allows for a small
* delta in sizes to allow for rounding differences.
*/
- bool equivalentTo(in nsIPrintSettings aPrintSettings);
+ boolean equivalentTo(in nsIPrintSettings aPrintSettings);
/**
* The edge measurements define the positioning of the headers
@@ -335,7 +335,7 @@ interface nsIPrintSettings : nsISupports
*/
attribute AString toFileName;
- attribute nsIOutputStream outputStream; /* for kOutputDestinationPrinter */
+ attribute nsIOutputStream outputStream; /* for kOutputDestinationStream */
[infallible] attribute long printPageDelay; /* in milliseconds */
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
index 81e952a8c6..06eab558eb 100644
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -668,12 +668,6 @@ class nsIWidget : public nsISupports {
virtual void SetModal(bool aModal) = 0;
/**
- * Make the non-modal window opened by modal window fake-modal, that will
- * call SetFakeModal(false) on destroy on Cocoa.
- */
- virtual void SetFakeModal(bool aModal) { SetModal(aModal); }
-
- /**
* Are we app modal. Currently only implemented on Cocoa.
*/
virtual bool IsRunningAppModal() { return false; }
@@ -784,10 +778,6 @@ class nsIWidget : public nsISupports {
virtual void Resize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint) = 0;
- virtual mozilla::Maybe<bool> IsResizingNativeWidget() {
- return mozilla::Nothing();
- }
-
/**
* Resize the widget so that the inner client area has the given size.
*
diff --git a/widget/nsXPLookAndFeel.cpp b/widget/nsXPLookAndFeel.cpp
index 9eabbd84b6..0c5b5207f2 100644
--- a/widget/nsXPLookAndFeel.cpp
+++ b/widget/nsXPLookAndFeel.cpp
@@ -128,7 +128,6 @@ static const char sIntPrefs[][45] = {
"ui.caretBlinkTime",
"ui.caretBlinkCount",
"ui.caretWidth",
- "ui.caretVisibleWithSelection",
"ui.selectTextfieldsOnKeyFocus",
"ui.submenuDelay",
"ui.menusCanOverlapOSBar",
@@ -152,6 +151,7 @@ static const char sIntPrefs[][45] = {
"ui.windowsAccentColorInTitlebar",
"ui.macBigSurTheme",
"ui.macRTL",
+ "ui.macTitlebarHeight",
"ui.alertNotificationOrigin",
"ui.scrollToClick",
"ui.IMERawInputUnderlineStyle",
@@ -167,6 +167,7 @@ static const char sIntPrefs[][45] = {
"ui.scrollbarFadeDuration",
"ui.contextMenuOffsetVertical",
"ui.contextMenuOffsetHorizontal",
+ "ui.tooltipOffsetVertical",
"ui.GtkCSDAvailable",
"ui.GtkCSDMinimizeButton",
"ui.GtkCSDMaximizeButton",
@@ -186,7 +187,6 @@ static const char sIntPrefs[][45] = {
"ui.titlebarRadius",
"ui.titlebarButtonSpacing",
"ui.dynamicRange",
- "ui.videoDynamicRange",
"ui.panelAnimations",
"ui.hideCursorWhileTyping",
"ui.gtkThemeFamily",
@@ -711,6 +711,7 @@ nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID,
// Seems to be the default color (hardcoded because of bug 1065998)
COLOR(MozNativehyperlinktext, 0x00, 0x66, 0xCC)
COLOR(MozNativevisitedhyperlinktext, 0x55, 0x1A, 0x8B)
+ COLOR(MozAutofillBackground, 0xff, 0xfc, 0xc8)
default:
break;
}
@@ -855,6 +856,11 @@ Maybe<nscolor> nsXPLookAndFeel::GenericDarkColor(ColorID aID) {
case ColorID::Inactivecaption:
color = NS_RGB(28, 27, 34);
break;
+ case ColorID::MozAutofillBackground:
+ // This is the light version of this color, but darkened to have good
+ // contrast with our white-ish FieldText.
+ color = NS_RGB(0x72, 0x6c, 0x00);
+ break;
default:
return Nothing();
}
diff --git a/widget/tests/mochitest.toml b/widget/tests/mochitest.toml
index 4a4a9d2729..93e3adf733 100644
--- a/widget/tests/mochitest.toml
+++ b/widget/tests/mochitest.toml
@@ -36,7 +36,10 @@ skip-if = ["display == 'wayland'"] # Bug 1879835
support-files = "file_test_clipboard_getDataSnapshotSync.js"
["test_contextmenu_by_mouse_on_unix.html"]
-run-if = ["os == 'linux'"]
+run-if = [
+ "os == 'linux'",
+ "os == 'android'",
+]
skip-if = ["headless"] # headless widget doesn't dispatch contextmenu event by mouse event.
["test_keypress_event_with_alt_on_mac.html"]
diff --git a/widget/tests/test_assign_event_data.html b/widget/tests/test_assign_event_data.html
index 1da9bb535f..26d214edce 100644
--- a/widget/tests/test_assign_event_data.html
+++ b/widget/tests/test_assign_event_data.html
@@ -59,6 +59,7 @@
<body>
<div id="display">
<input id="input-text">
+ <div contenteditable id="contenteditable"><br></div>
<button id="button">button</button>
<a id="a" href="about:blank">hyper link</a>
<span id="pointer-target">span</span>
@@ -352,6 +353,44 @@ const kTests = [
},
todoMismatch: [ ],
},
+ { description: "InternalLegacyTextEvent (input at key input)",
+ targetID: "input-text", eventType: "textInput",
+ dispatchEvent() {
+ const input = document.getElementById(this.targetID);
+ input.value = "";
+ input.focus();
+ synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B,
+ { shiftKey: true }, "B", "B");
+ observeKeyUpOnContent(KeyboardEvent.DOM_VK_B, runNextTest);
+ return true;
+ },
+ canRun() {
+ return (kIsMac || kIsWin);
+ },
+ todoMismatch: [],
+ },
+ { description: "InternalLegacyTextEvent (paste)",
+ targetID: "contenteditable", eventType: "textInput",
+ async dispatchEvent() {
+ const editingHost = document.getElementById(this.targetID);
+ editingHost.innerHTML = "abc";
+ editingHost.focus();
+ getSelection().selectAllChildren(editingHost);
+ synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_C : MAC_VK_ANSI_C,
+ { accelKey: true }, "", "c");
+ const waitForInput = new Promise(resolve => {
+ editingHost.addEventListener("input", resolve, {once: true});
+ });
+ // In this case, TextEvent.data is stored with a dataTransfer.
+ synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_V : MAC_VK_ANSI_V,
+ { accelKey: true }, "", "v");
+ await waitForInput;
+ },
+ canRun() {
+ return (kIsMac || kIsWin);
+ },
+ todoMismatch: [],
+ },
{ description: "WidgetMouseScrollEvent (DOMMouseScroll, vertical)",
targetID: "input-text", eventType: "DOMMouseScroll",
dispatchEvent() {
@@ -615,7 +654,7 @@ const kTests = [
},
];
-function doTest(aTest) {
+async function doTest(aTest) {
if (!aTest.canRun()) {
SimpleTest.executeSoon(runNextTest);
return;
@@ -650,7 +689,7 @@ function doTest(aTest) {
runNextTest();
}
};
- var testWillCallRunNextTest = aTest.dispatchEvent();
+ var testWillCallRunNextTest = await aTest.dispatchEvent();
}
var gIndex = -1;
@@ -695,7 +734,8 @@ function init() {
["mousewheel.with_alt.action", 0],
["mousewheel.with_alt.action.override_x", -1],
["mousewheel.with_meta.action", 0],
- ["mousewheel.with_meta.action.override_x", -1]]}, runNextTest);
+ ["mousewheel.with_meta.action.override_x", -1],
+ ["dom.events.textevent.enabled", true]]}, runNextTest);
}
function finish() {
diff --git a/widget/tests/window_composition_text_querycontent.xhtml b/widget/tests/window_composition_text_querycontent.xhtml
index 4806d0d187..ea224a1636 100644
--- a/widget/tests/window_composition_text_querycontent.xhtml
+++ b/widget/tests/window_composition_text_querycontent.xhtml
@@ -806,6 +806,16 @@ function checkInputEvent(aEvent, aIsComposing, aInputType, aData, aTargetRanges,
}
}
+function checkTextInputEvent(aEvent, aData, aDescription) {
+ if (aEvent.type !== "textInput") {
+ throw new Error(`${aDescription}: "${aEvent.type}" is not TextEvent`);
+ }
+ ok(TextEvent.isInstance(aEvent), `"${aEvent.type}" event should be dispatched with TextEvent interface: ${aDescription}`);
+ is(aEvent.cancelable, true, `"${aEvent.type}" event should be cancelable: ${aDescription}`);
+ is(aEvent.bubbles, true, `"${aEvent.type}" event should always bubble: ${aDescription}`);
+ is(aEvent.data, aData, `data of "${aEvent.type}" event should be ${aData}: ${aDescription}`);
+}
+
function runCompositionCommitAsIsTest()
{
textarea.focus();
@@ -824,6 +834,7 @@ function runCompositionCommitAsIsTest()
textarea.addEventListener("compositionupdate", handler, true);
textarea.addEventListener("compositionend", handler, true);
textarea.addEventListener("beforeinput", handler, true);
+ textarea.addEventListener("textInput", handler, true);
textarea.addEventListener("input", handler, true);
textarea.addEventListener("text", handler, true);
@@ -842,22 +853,29 @@ function runCompositionCommitAsIsTest()
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have composition string #1");
+ is(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitAsIsTest: no textInput event should be fired before commit #1");
+
clearResult();
synthesizeComposition({ type: "compositioncommitasis", key: { key: "Enter" } });
- is(result.length, 4,
- "runCompositionCommitAsIsTest: 4 events should be fired after dispatching compositioncommitasis #1");
+ is(result.length, 5,
+ "runCompositionCommitAsIsTest: 5 events should be fired after dispatching compositioncommitasis #1");
is(result[0].type, "text",
"runCompositionCommitAsIsTest: text should be fired after dispatching compositioncommitasis because it's dispatched when there is composing string #1");
is(result[1].type, "beforeinput",
"runCompositionCommitAsIsTest: beforeinput should be fired after dispatching compositioncommitasis because it's dispatched when there is composing string #1");
checkInputEvent(result[1], true, "insertCompositionText", "\u3042", [],
"runCompositionCommitAsIsTest: after dispatching compositioncommitasis #1");
- is(result[2].type, "compositionend",
+ is(result[2].type, "textInput",
+ "runCompositionCommitAsIsText: textInput should be fired after dispatching compositioncommitasis because it's after the last beforeinput for the composition #1");
+ checkTextInputEvent(result[2], "\u3042",
+ "runCompositionCommitAsIsText: after dispatching compositioncommitasis #1");
+ is(result[3].type, "compositionend",
"runCompositionCommitAsIsTest: compositionend should be fired after dispatching compositioncommitasis #1");
- is(result[3].type, "input",
+ is(result[4].type, "input",
"runCompositionCommitAsIsTest: input should be fired after dispatching compositioncommitasis #1");
- checkInputEvent(result[3], false, "insertCompositionText", "\u3042", [],
+ checkInputEvent(result[4], false, "insertCompositionText", "\u3042", [],
"runCompositionCommitAsIsTest: after dispatching compositioncommitasis #1");
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have committed string #1");
@@ -887,6 +905,8 @@ function runCompositionCommitAsIsTest()
"key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitAsIsTest: textarea doesn't have committed string #2");
+ isnot(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitAsIsTest: a textInput event should be fired before commit #2");
clearResult();
synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Enter", type: "keyup" } });
@@ -928,6 +948,8 @@ function runCompositionCommitAsIsTest()
"key": { key: "KEY_Escape", type: "keydown" },
});
is(textarea.value, "", "runCompositionCommitAsIsTest: textarea has non-empty composition string #3");
+ todo_isnot(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitAsIsTest: a textInput event should be fired immediately before commit #3");
clearResult();
synthesizeComposition({ type: "compositioncommitasis", key: { key: "KEY_Escape", type: "keyup" } });
@@ -946,6 +968,7 @@ function runCompositionCommitAsIsTest()
textarea.removeEventListener("compositionupdate", handler, true);
textarea.removeEventListener("compositionend", handler, true);
textarea.removeEventListener("beforeinput", handler, true);
+ textarea.removeEventListener("textInput", handler, true);
textarea.removeEventListener("input", handler, true);
textarea.removeEventListener("text", handler, true);
}
@@ -968,6 +991,7 @@ function runCompositionCommitTest()
textarea.addEventListener("compositionupdate", handler, true);
textarea.addEventListener("compositionend", handler, true);
textarea.addEventListener("beforeinput", handler, true);
+ textarea.addEventListener("textInput", handler, true);
textarea.addEventListener("input", handler, true);
textarea.addEventListener("text", handler, true);
@@ -985,12 +1009,14 @@ function runCompositionCommitTest()
"key": { key: "a", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #1");
+ is(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitTest: no textInput event should be fired before commit #1");
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "a", type: "keyup" } });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #1");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired after dispatching compositioncommit #1");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit because it's dispatched when there is composing string #1");
is(result[1].type, "text",
@@ -999,16 +1025,21 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit because it's dispatched when there is composing string #1");
checkInputEvent(result[2], true, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #1");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit because the preceding beforeinput is last one for the composition #1");
+ checkTextInputEvent(result[3], "\u3043",
+ "runCompositionCommitTest: after dispatching compositioncommit #1");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #1");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #1");
- checkInputEvent(result[4], false, "insertCompositionText", "\u3043", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #1");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #1");
// compositioncommit with different committed string when there is already committed string
textarea.value = "";
+ clearResult();
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
@@ -1033,12 +1064,14 @@ function runCompositionCommitTest()
"key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have committed string #2");
+ is(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitTest: no textInput event should be fired before commit #2");
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "KEY_Enter", type: "keyup" } });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #2");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired after dispatching compositioncommit #2");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #2");
is(result[1].type, "text",
@@ -1047,16 +1080,21 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit #2");
checkInputEvent(result[2], true, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #2");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit #2");
+ checkTextInputEvent(result[3], "\u3043",
+ "runCompositionCommitTest: after dispatching compositioncommit #2");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #2");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #2");
- checkInputEvent(result[4], false, "insertCompositionText", "\u3043", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #2");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #2");
// compositioncommit with empty composition string.
textarea.value = "";
+ clearResult();
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
@@ -1081,12 +1119,14 @@ function runCompositionCommitTest()
"key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "", "runCompositionCommitTest: textarea has non-empty composition string #3");
+ is(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitTest: no textInput event should be fired before commit #3");
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3043", key: { key: "KEY_Enter", type: "keyup" } });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #3");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired after dispatching compositioncommit #3");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #3");
is(result[1].type, "text",
@@ -1095,11 +1135,15 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit #3");
checkInputEvent(result[2], true, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #3");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit #3");
+ checkTextInputEvent(result[3], "\u3043",
+ "runCompositionCommitTest: after dispatching compositioncommit #3");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #3");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #3");
- checkInputEvent(result[4], false, "insertCompositionText", "\u3043", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "\u3043", [],
"runCompositionCommitTest: after dispatching compositioncommit #3");
is(textarea.value, "\u3043", "runCompositionCommitTest: textarea doesn't have committed string #3");
@@ -1111,19 +1155,23 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "" });
- is(result.length, 4,
- "runCompositionCommitTest: 4 events should be fired when inserting empty string with composition");
+ is(result.length, 5,
+ "runCompositionCommitTest: 5 events should be fired when inserting empty string with composition");
is(result[0].type, "text",
"runCompositionCommitTest: text should be fired when inserting empty string with composition");
is(result[1].type, "beforeinput",
"runCompositionCommitTest: beforeinput should be fired when inserting empty string with composition");
checkInputEvent(result[1], true, "insertCompositionText", "", [],
"runCompositionCommitTest: when inserting empty string with composition");
- is(result[2].type, "compositionend",
+ is(result[2].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired when inserting empty string with composition");
+ checkTextInputEvent(result[2], "",
+ "runCompositionCommitTest: when inserting empty string with composition");
+ is(result[3].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired when inserting empty string with composition");
- is(result[3].type, "input",
+ is(result[4].type, "input",
"runCompositionCommitTest: input should be fired when inserting empty string with composition");
- checkInputEvent(result[3], false, "insertCompositionText", "", [],
+ checkInputEvent(result[4], false, "insertCompositionText", "", [],
"runCompositionCommitTest: when inserting empty string with composition");
is(textarea.value, "abc",
"runCompositionCommitTest: textarea should keep original value when inserting empty string with composition");
@@ -1136,19 +1184,23 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "" });
- is(result.length, 4,
- "runCompositionCommitTest: 4 events should be fired when replacing with empty string with composition");
+ is(result.length, 5,
+ "runCompositionCommitTest: 5 events should be fired when replacing with empty string with composition");
is(result[0].type, "text",
"runCompositionCommitTest: text should be fired when replacing with empty string with composition");
is(result[1].type, "beforeinput",
"runCompositionCommitTest: beforeinput should be fired when replacing with empty string with composition");
checkInputEvent(result[1], true, "insertCompositionText", "", [],
"runCompositionCommitTest: when replacing with empty string with composition");
- is(result[2].type, "compositionend",
+ is(result[2].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired when replacing with empty string with composition");
+ checkTextInputEvent(result[2], "",
+ "runCompositionCommitTest: when replacing with empty string with composition");
+ is(result[3].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired when replacing with empty string with composition");
- is(result[3].type, "input",
+ is(result[4].type, "input",
"runCompositionCommitTest: input should be fired when replacing with empty string with composition");
- checkInputEvent(result[3], false, "insertCompositionText", "", [],
+ checkInputEvent(result[4], false, "insertCompositionText", "", [],
"runCompositionCommitTest: when replacing with empty string with composition");
is(textarea.value, "",
"runCompositionCommitTest: textarea should become empty when replacing selection with empty string with composition");
@@ -1161,8 +1213,8 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "abc" });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired when replacing selection with same string with composition");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired when replacing selection with same string with composition");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired when replacing selection with same string with composition");
is(result[1].type, "text",
@@ -1171,11 +1223,15 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired when replacing selection with same string with composition");
checkInputEvent(result[2], true, "insertCompositionText", "abc", [],
"runCompositionCommitTest: when replacing selection with same string with composition");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired when replacing selection with same string with composition");
+ checkTextInputEvent(result[3], "abc",
+ "runCompositionCommitTest: when replacing selection with same string with composition");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired when replacing selection with same string with composition");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired when replacing selection with same string with composition");
- checkInputEvent(result[4], false, "insertCompositionText", "abc", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "abc", [],
"runCompositionCommitTest: when replacing selection with same string with composition");
is(textarea.value, "abc",
"runCompositionCommitTest: textarea should keep same value when replacing selection with same string with composition");
@@ -1198,8 +1254,8 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "", key: { key: "KEY_Enter" } });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #4");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired after dispatching compositioncommit #4");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #4");
is(result[1].type, "text",
@@ -1208,11 +1264,15 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit #4");
checkInputEvent(result[2], true, "insertCompositionText", "", [],
"runCompositionCommitTest: after dispatching compositioncommit #4");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit #4");
+ checkTextInputEvent(result[3], "",
+ "runCompositionCommitTest: after dispatching compositioncommit #4");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #4");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #4");
- checkInputEvent(result[4], false, "insertCompositionText", "", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "", [],
"runCompositionCommitTest: after dispatching compositioncommit #4");
is(textarea.value, "", "runCompositionCommitTest: textarea should be empty #4");
@@ -1222,8 +1282,8 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "a" } });
- is(result.length, 5,
- "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #5");
+ is(result.length, 6,
+ "runCompositionCommitTest: 6 events should be fired after dispatching compositioncommit #5");
is(result[0].type, "compositionupdate",
"runCompositionCommitTest: compositionupdate should be fired after dispatching compositioncommit #5");
is(result[1].type, "text",
@@ -1232,11 +1292,15 @@ function runCompositionCommitTest()
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit #5");
checkInputEvent(result[2], true, "insertCompositionText", "\u3042", [],
"runCompositionCommitTest: after dispatching compositioncommit #5");
- is(result[3].type, "compositionend",
+ is(result[3].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit #5");
+ checkTextInputEvent(result[3], "\u3042",
+ "runCompositionCommitTest: after dispatching compositioncommit #5");
+ is(result[4].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #5");
- is(result[4].type, "input",
+ is(result[5].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #5");
- checkInputEvent(result[4], false, "insertCompositionText", "\u3042", [],
+ checkInputEvent(result[5], false, "insertCompositionText", "\u3042", [],
"runCompositionCommitTest: after dispatching compositioncommit #5");
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea should be empty #5");
@@ -1258,24 +1322,29 @@ function runCompositionCommitTest()
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "KEY_Enter" } });
- is(result.length, 4,
- "runCompositionCommitTest: 4 events should be fired after dispatching compositioncommit #6");
+ is(result.length, 5,
+ "runCompositionCommitTest: 5 events should be fired after dispatching compositioncommit #6");
is(result[0].type, "text",
"runCompositionCommitTest: text should be fired after dispatching compositioncommit #6");
is(result[1].type, "beforeinput",
"runCompositionCommitTest: beforeinput should be fired after dispatching compositioncommit #6");
checkInputEvent(result[1], true, "insertCompositionText", "\u3042", [],
"runCompositionCommitTest: after dispatching compositioncommit #6");
- is(result[2].type, "compositionend",
+ is(result[2].type, "textInput",
+ "runCompositionCommitTest: textInput should be fired after dispatching compositioncommit #6");
+ checkTextInputEvent(result[2], "\u3042",
+ "runCompositionCommitTest: after dispatching compositioncommit #6");
+ is(result[3].type, "compositionend",
"runCompositionCommitTest: compositionend should be fired after dispatching compositioncommit #6");
- is(result[3].type, "input",
+ is(result[4].type, "input",
"runCompositionCommitTest: input should be fired after dispatching compositioncommit #6");
- checkInputEvent(result[3], false, "insertCompositionText", "\u3042", [],
+ checkInputEvent(result[4], false, "insertCompositionText", "\u3042", [],
"runCompositionCommitTest: after dispatching compositioncommit #6");
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea should have committed string #6");
// compositioncommit with same composition string when there is committed string
textarea.value = "";
+ clearResult();
synthesizeCompositionChange(
{ "composition":
{ "string": "\u3042",
@@ -1301,6 +1370,8 @@ function runCompositionCommitTest()
"key": { key: "KEY_Enter", type: "keydown" },
});
is(textarea.value, "\u3042", "runCompositionCommitTest: textarea doesn't have composition string #6");
+ todo_isnot(result.findIndex(value => value.type == "textInput"), -1,
+ "runCompositionCommitTest: a textInput event should be fired before immediately commit #6");
clearResult();
synthesizeComposition({ type: "compositioncommit", data: "\u3042", key: { key: "KEY_Enter", type: "keyup" } });
@@ -1319,6 +1390,7 @@ function runCompositionCommitTest()
textarea.removeEventListener("compositionupdate", handler, true);
textarea.removeEventListener("compositionend", handler, true);
textarea.removeEventListener("beforeinput", handler, true);
+ textarea.removeEventListener("textInput", handler, true);
textarea.removeEventListener("input", handler, true);
textarea.removeEventListener("text", handler, true);
}
@@ -10860,6 +10932,10 @@ async function runInputModeTest()
async function runTest()
{
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.events.textevent.enabled", true]],
+ });
+
window.addEventListener("unload", window.arguments[0].SimpleTest.finish, {once: true, capture: true});
contenteditable = document.getElementById("iframe4").contentDocument.getElementById("contenteditable");
diff --git a/widget/uikit/TextInputHandler.mm b/widget/uikit/TextInputHandler.mm
index 9a4a6ae226..3ee3573b83 100644
--- a/widget/uikit/TextInputHandler.mm
+++ b/widget/uikit/TextInputHandler.mm
@@ -10,6 +10,7 @@
#include "mozilla/EventForwards.h"
#include "mozilla/Logging.h"
+#include "mozilla/MacStringHelpers.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
@@ -23,21 +24,6 @@ mozilla::LazyLogModule gIMELog("TextInputHandler");
namespace mozilla::widget {
-static void GetStringForNSString(const NSString* aSrc, nsAString& aDist) {
- NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
-
- if (!aSrc) {
- aDist.Truncate();
- return;
- }
-
- aDist.SetLength([aSrc length]);
- [aSrc getCharacters:reinterpret_cast<unichar*>(aDist.BeginWriting())
- range:NSMakeRange(0, [aSrc length])];
-
- NS_OBJC_END_TRY_IGNORE_BLOCK;
-}
-
NS_IMPL_ISUPPORTS(TextInputHandler, TextEventDispatcherListener,
nsISupportsWeakReference)
@@ -63,7 +49,7 @@ void TextInputHandler::WillDispatchKeyboardEvent(
bool TextInputHandler::InsertText(NSString* aText) {
nsString str;
- GetStringForNSString(aText, str);
+ CopyNSStringToXPCOMString(aText, str);
MOZ_LOG(gIMELog, LogLevel::Info,
("%p TextInputHandler::InsertText(aText=%s)", this,
diff --git a/widget/uikit/nsLookAndFeel.mm b/widget/uikit/nsLookAndFeel.mm
index b420cc9a1d..51a9a95b52 100644
--- a/widget/uikit/nsLookAndFeel.mm
+++ b/widget/uikit/nsLookAndFeel.mm
@@ -232,9 +232,6 @@ 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 nsEventStateManager::sTextfieldSelectModel
diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp
index 0e1b4002d3..6d8429f1cc 100644
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -310,7 +310,7 @@ uint32_t ParseIDFromDeviceID(const nsAString& key, const nsAString& prefix,
return 0x5143;
}
nsresult err;
- return id.ToInteger(&err, 16);
+ return id.ToUnsignedInteger(&err, 16);
}
// OS version in 16.16 major/minor form
diff --git a/widget/windows/ScreenHelperWin.cpp b/widget/windows/ScreenHelperWin.cpp
index 8a0ec3b608..945b8d1895 100644
--- a/widget/windows/ScreenHelperWin.cpp
+++ b/widget/windows/ScreenHelperWin.cpp
@@ -7,9 +7,12 @@
#include "ScreenHelperWin.h"
#include "mozilla/Logging.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
#include "nsTArray.h"
#include "WinUtils.h"
+#include <dxgi.h>
+
static mozilla::LazyLogModule sScreenLog("WidgetScreen");
namespace mozilla {
@@ -74,8 +77,13 @@ static void GetDisplayInfo(const char16ptr_t aName,
}
}
+struct CollectMonitorsParam {
+ nsTArray<RefPtr<Screen>> screens;
+};
+
BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
- auto screens = reinterpret_cast<nsTArray<RefPtr<Screen>>*>(ioParam);
+ CollectMonitorsParam* cmParam =
+ reinterpret_cast<CollectMonitorsParam*>(ioParam);
BOOL success = FALSE;
MONITORINFOEX info;
info.cbSize = sizeof(MONITORINFOEX);
@@ -123,6 +131,9 @@ BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
GetDisplayInfo(info.szDevice, orientation, angle, isPseudoDisplay,
refreshRate);
+ auto* manager = gfx::DeviceManagerDx::Get();
+ bool isHDR = manager ? manager->MonitorHDREnabled(aMon) : false;
+
MOZ_LOG(sScreenLog, LogLevel::Debug,
("New screen [%s (%s) %d %u %f %f %f %d %d %d]",
ToString(rect).c_str(), ToString(availRect).c_str(), pixelDepth,
@@ -131,26 +142,32 @@ BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
auto screen = MakeRefPtr<Screen>(
rect, availRect, pixelDepth, pixelDepth, refreshRate, contentsScaleFactor,
defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay(isPseudoDisplay),
- orientation, angle);
+ Screen::IsHDR(isHDR), orientation, angle);
if (info.dwFlags & MONITORINFOF_PRIMARY) {
// The primary monitor must be the first element of the screen list.
- screens->InsertElementAt(0, std::move(screen));
+ cmParam->screens.InsertElementAt(0, std::move(screen));
} else {
- screens->AppendElement(std::move(screen));
+ cmParam->screens.AppendElement(std::move(screen));
}
return TRUE;
}
+/* static */
void ScreenHelperWin::RefreshScreens() {
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
- AutoTArray<RefPtr<Screen>, 4> screens;
+ auto* manager = gfx::DeviceManagerDx::Get();
+ if (XRE_IsParentProcess() && manager) {
+ manager->UpdateMonitorInfo();
+ }
+
+ CollectMonitorsParam cmParam;
BOOL result = ::EnumDisplayMonitors(
- nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&screens);
+ nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&cmParam);
if (!result) {
NS_WARNING("Unable to EnumDisplayMonitors");
}
- ScreenManager::Refresh(std::move(screens));
+ ScreenManager::Refresh(std::move(cmParam.screens));
}
} // namespace widget
diff --git a/widget/windows/WindowsSMTCProvider.cpp b/widget/windows/WindowsSMTCProvider.cpp
index 69915cafd8..3ddd26b6cc 100644
--- a/widget/windows/WindowsSMTCProvider.cpp
+++ b/widget/windows/WindowsSMTCProvider.cpp
@@ -356,7 +356,7 @@ bool WindowsSMTCProvider::RegisterEvents() {
void WindowsSMTCProvider::OnButtonPressed(
mozilla::dom::MediaControlKey aKey) const {
if (!IsKeySupported(aKey)) {
- LOG("key: %s is not supported", ToMediaControlKeyStr(aKey));
+ LOG("key: %s is not supported", dom::GetEnumString(aKey).get());
return;
}
@@ -383,7 +383,7 @@ bool WindowsSMTCProvider::UpdateButtons() {
for (const mozilla::dom::MediaControlKey& key : kKeys) {
if (!EnableKey(key, IsKeySupported(key))) {
success = false;
- LOG("Failed to set %s=%s", ToMediaControlKeyStr(key),
+ LOG("Failed to set %s=%s", dom::GetEnumString(key).get(),
IsKeySupported(key) ? "true" : "false");
}
}
@@ -414,7 +414,7 @@ bool WindowsSMTCProvider::EnableKey(mozilla::dom::MediaControlKey aKey,
// The callback for the event checks if the key is supported
return mSeekRegistrationToken.value != 0;
default:
- LOG("No button for %s", ToMediaControlKeyStr(aKey));
+ LOG("No button for %s", dom::GetEnumString(aKey).get());
return false;
}
}
diff --git a/widget/windows/moz.build b/widget/windows/moz.build
index f19a46caf1..eeda8d1257 100644
--- a/widget/windows/moz.build
+++ b/widget/windows/moz.build
@@ -39,6 +39,7 @@ EXPORTS += [
]
EXPORTS.mozilla += [
+ "ScreenHelperWin.h",
"ShellHeaderOnlyUtils.h",
"ToastNotificationHeaderOnlyUtils.h",
"UrlmonHeaderOnlyUtils.h",
diff --git a/widget/windows/nsFilePicker.cpp b/widget/windows/nsFilePicker.cpp
index fb4c6e80b5..2a45937988 100644
--- a/widget/windows/nsFilePicker.cpp
+++ b/widget/windows/nsFilePicker.cpp
@@ -735,7 +735,11 @@ nsFilePicker::CheckContentAnalysisService() {
auto contentAnalysisCallback =
mozilla::MakeRefPtr<mozilla::contentanalysis::ContentAnalysisCallback>(
[promise](nsIContentAnalysisResponse* aResponse) {
- promise->Resolve(aResponse->GetShouldAllowContent(), __func__);
+ bool shouldAllow = false;
+ mozilla::DebugOnly<nsresult> rv =
+ aResponse->GetShouldAllowContent(&shouldAllow);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ promise->Resolve(shouldAllow, __func__);
},
[promise](nsresult aError) { promise->Reject(aError, __func__); });
@@ -840,7 +844,7 @@ nsresult nsFilePicker::Open(nsIFilePickerShownCallback* aCallback) {
auto promise = mMode == modeGetFolder ? ShowFolderPicker(initialDir)
: ShowFilePicker(initialDir);
- auto p2 = promise->Then(
+ promise->Then(
mozilla::GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__,
[self = RefPtr(this),
callback = RefPtr(aCallback)](bool selectionMade) -> void {
diff --git a/widget/windows/nsLookAndFeel.cpp b/widget/windows/nsLookAndFeel.cpp
index 6122000c9e..b6b6877857 100644
--- a/widget/windows/nsLookAndFeel.cpp
+++ b/widget/windows/nsLookAndFeel.cpp
@@ -36,6 +36,17 @@ static int32_t GetSystemParam(long flag, int32_t def) {
return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
}
+static int32_t GetTooltipOffsetVertical() {
+ static constexpr DWORD kDefaultCursorSize = 32;
+ const DWORD cursorSize =
+ GetSystemParam(MOZ_SPI_CURSORSIZE, kDefaultCursorSize);
+ if (cursorSize == kDefaultCursorSize) {
+ return LookAndFeel::kDefaultTooltipOffset;
+ }
+ return std::ceilf(float(LookAndFeel::kDefaultTooltipOffset) *
+ float(cursorSize) / float(kDefaultCursorSize));
+}
+
static bool SystemWantsDarkTheme() {
if (nsUXThemeData::IsHighContrastOn()) {
return LookAndFeel::IsDarkColor(
@@ -353,6 +364,7 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme,
case ColorID::Marktext:
case ColorID::Mark:
case ColorID::SpellCheckerUnderline:
+ case ColorID::MozAutofillBackground:
aColor = GetStandinForNativeColor(aID, aScheme);
return NS_OK;
default:
@@ -392,13 +404,9 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = std::ceil(float(timeout) / (2.0f * float(blinkTime)));
break;
}
-
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
@@ -523,6 +531,9 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::ContextMenuOffsetHorizontal:
aResult = 2;
break;
+ case IntID::TooltipOffsetVertical:
+ aResult = GetTooltipOffsetVertical();
+ break;
case IntID::SystemUsesDarkTheme:
aResult = SystemWantsDarkTheme();
break;
diff --git a/widget/windows/nsLookAndFeel.h b/widget/windows/nsLookAndFeel.h
index d19aa91329..0ef38bfda5 100644
--- a/widget/windows/nsLookAndFeel.h
+++ b/widget/windows/nsLookAndFeel.h
@@ -40,6 +40,10 @@
#define SYS_COLOR_MAX 30
#define SYS_COLOR_COUNT (SYS_COLOR_MAX - SYS_COLOR_MIN + 1)
+// Undocumented SPI, see bug 1712669 comment 4.
+#define MOZ_SPI_CURSORSIZE 0x2028
+#define MOZ_SPI_SETCURSORSIZE 0x2029
+
namespace mozilla::widget::WinRegistry {
class KeyWatcher;
}
diff --git a/widget/windows/nsNativeThemeWin.cpp b/widget/windows/nsNativeThemeWin.cpp
index 04883a833f..7ef968baf6 100644
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -484,9 +484,6 @@ mozilla::Maybe<nsUXThemeClass> nsNativeThemeWin::GetThemeClass(
case StyleAppearance::Textfield:
case StyleAppearance::Textarea:
return Some(eUXEdit);
- case StyleAppearance::Toolbox:
- return Some(eUXRebar);
- case StyleAppearance::Toolbar:
case StyleAppearance::Toolbarbutton:
case StyleAppearance::Separator:
return Some(eUXToolbar);
@@ -719,27 +716,6 @@ nsresult nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame,
}
return NS_OK;
}
- case StyleAppearance::Toolbox: {
- aState = 0;
- aPart = RP_BACKGROUND;
- return NS_OK;
- }
- case StyleAppearance::Toolbar: {
- // Use -1 to indicate we don't wish to have the theme background drawn
- // for this item. We will pass any nessessary information via aState,
- // and will render the item using separate code.
- aPart = -1;
- aState = 0;
- if (aFrame) {
- nsIContent* content = aFrame->GetContent();
- nsIContent* parent = content->GetParent();
- // XXXzeniko hiding the first toolbar will result in an unwanted margin
- if (parent && parent->GetFirstChild() == content) {
- aState = 1;
- }
- }
- return NS_OK;
- }
case StyleAppearance::Treeview:
case StyleAppearance::Listbox: {
aPart = TREEVIEW_BODY;
@@ -1031,16 +1007,6 @@ RENDER_AGAIN:
::DeleteObject(hPen);
}
}
- } else if (aAppearance == StyleAppearance::Toolbar && state == 0) {
- // Draw toolbar separator lines above all toolbars except the first one.
- // The lines are part of the Rebar theme, which is loaded for
- // StyleAppearance::Toolbox.
- theme = GetTheme(StyleAppearance::Toolbox);
- if (!theme) return NS_ERROR_FAILURE;
-
- widgetRect.bottom = widgetRect.top + TB_SEPARATOR_HEIGHT;
- DrawThemeEdge(theme, hdc, RP_BAND, 0, &widgetRect, EDGE_ETCHED, BF_TOP,
- nullptr);
}
nativeDrawing.EndNativeDrawing();
@@ -1101,7 +1067,6 @@ LayoutDeviceIntMargin nsNativeThemeWin::GetWidgetBorder(
}
if (!WidgetIsContainer(aAppearance) ||
- aAppearance == StyleAppearance::Toolbox ||
aAppearance == StyleAppearance::Tabpanel)
return result; // Don't worry about it.
@@ -1109,12 +1074,6 @@ LayoutDeviceIntMargin nsNativeThemeWin::GetWidgetBorder(
nsresult rv = GetThemePartAndState(aFrame, aAppearance, part, state);
if (NS_FAILED(rv)) return result;
- if (aAppearance == StyleAppearance::Toolbar) {
- // make space for the separator line above all toolbars but the first
- if (state == 0) result.top = TB_SEPARATOR_HEIGHT;
- return result;
- }
-
result = GetCachedWidgetBorder(theme, themeClass.value(), aAppearance, part,
state);
@@ -1278,8 +1237,6 @@ LayoutDeviceIntSize nsNativeThemeWin::GetMinimumWidgetSize(
switch (aAppearance) {
case StyleAppearance::NumberInput:
case StyleAppearance::Textfield:
- case StyleAppearance::Toolbox:
- case StyleAppearance::Toolbar:
case StyleAppearance::Progresschunk:
case StyleAppearance::Tabpanels:
case StyleAppearance::Tabpanel:
@@ -1352,9 +1309,7 @@ nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame,
nsAtom* aAttribute, bool* aShouldRepaint,
const nsAttrValue* aOldValue) {
// Some widget types just never change state.
- if (aAppearance == StyleAppearance::Toolbox ||
- aAppearance == StyleAppearance::Toolbar ||
- aAppearance == StyleAppearance::Progresschunk ||
+ if (aAppearance == StyleAppearance::Progresschunk ||
aAppearance == StyleAppearance::ProgressBar ||
aAppearance == StyleAppearance::Tabpanels ||
aAppearance == StyleAppearance::Tabpanel ||
diff --git a/widget/windows/nsUXThemeData.cpp b/widget/windows/nsUXThemeData.cpp
index b3f9e6fce9..ce8b0f3479 100644
--- a/widget/windows/nsUXThemeData.cpp
+++ b/widget/windows/nsUXThemeData.cpp
@@ -62,8 +62,6 @@ const wchar_t* nsUXThemeData::GetClassName(nsUXThemeClass cls) {
return L"Button";
case eUXEdit:
return L"Edit";
- case eUXRebar:
- return L"Rebar";
case eUXToolbar:
return L"Toolbar";
case eUXProgress:
diff --git a/widget/windows/nsUXThemeData.h b/widget/windows/nsUXThemeData.h
index 38be8b4484..24fe07d128 100644
--- a/widget/windows/nsUXThemeData.h
+++ b/widget/windows/nsUXThemeData.h
@@ -19,7 +19,6 @@
enum nsUXThemeClass {
eUXButton = 0,
eUXEdit,
- eUXRebar,
eUXToolbar,
eUXProgress,
eUXTab,
diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp
index b304d2efac..22d20d099e 100644
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -78,6 +78,7 @@
#include <limits>
#include "mozilla/widget/WinMessages.h"
+#include "nsLookAndFeel.h"
#include "nsWindow.h"
#include "nsWindowTaskbarConcealer.h"
#include "nsAppRunner.h"
@@ -181,11 +182,13 @@
# endif
# include "mozilla/a11y/Compatibility.h"
# include "oleidl.h"
+# include <uiautomation.h>
# include <winuser.h>
# include "nsAccessibilityService.h"
# include "mozilla/a11y/DocAccessible.h"
# include "mozilla/a11y/LazyInstantiator.h"
# include "mozilla/a11y/Platform.h"
+# include "mozilla/StaticPrefs_accessibility.h"
# if !defined(WINABLEAPI)
# include <winable.h>
# endif // !defined(WINABLEAPI)
@@ -1335,8 +1338,6 @@ DWORD nsWindow::WindowExStyle() {
}
return extendedStyle;
}
- case WindowType::Sheet:
- MOZ_FALLTHROUGH_ASSERT("Sheets are macOS specific");
case WindowType::Dialog:
case WindowType::TopLevel:
case WindowType::Invisible:
@@ -1583,13 +1584,6 @@ void nsWindow::Show(bool bState) {
// SetWindowPos would get the correct answer.
mIsVisible = bState;
- // We may have cached an out of date visible state. This can happen
- // when session restore sets the full screen mode.
- if (mIsVisible)
- mOldStyle |= WS_VISIBLE;
- else
- mOldStyle &= ~WS_VISIBLE;
-
if (mWnd) {
if (bState) {
if (!wasVisible && mWindowType == WindowType::TopLevel) {
@@ -2043,13 +2037,6 @@ void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
if (aRepaint) Invalidate();
}
-mozilla::Maybe<bool> nsWindow::IsResizingNativeWidget() {
- if (mResizeState == RESIZING) {
- return Some(true);
- }
- return Some(false);
-}
-
/**************************************************************
*
* SECTION: Window Z-order and state.
@@ -3070,34 +3057,85 @@ void nsWindow::HideWindowChrome(bool aShouldHide) {
if (mHideChrome == aShouldHide) return;
- DWORD_PTR style, exStyle;
- mHideChrome = aShouldHide;
- if (aShouldHide) {
- DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
- DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
+ // Data manipulation: styles + ex-styles, and bitmasking operations thereupon.
+ struct Styles {
+ LONG_PTR style, ex;
+ constexpr Styles operator|(Styles const& that) const {
+ return Styles{.style = style | that.style, .ex = ex | that.ex};
+ }
+ constexpr Styles operator&(Styles const& that) const {
+ return Styles{.style = style & that.style, .ex = ex & that.ex};
+ }
+ constexpr Styles operator~() const {
+ return Styles{.style = ~style, .ex = ~ex};
+ }
- style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME);
- exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
- WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
+ // Compute a style-set which matches `zero` where the bits of `this` are 0
+ // and `one` where the bits of `this` are 1.
+ constexpr Styles merge(Styles zero, Styles one) const {
+ Styles const& mask = *this;
+ return (~mask & zero) | (mask & one);
+ }
- mOldStyle = tempStyle;
- mOldExStyle = tempExStyle;
- } else {
- if (!mOldStyle || !mOldExStyle) {
- mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE);
- mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
+ // The dual of `merge`, above: returns a pair [zero, one] satisfying
+ // `a.merge(a.split(b)...) == b`. (Or its equivalent in valid C++.)
+ constexpr std::tuple<Styles, Styles> split(Styles data) const {
+ Styles const& mask = *this;
+ return {~mask & data, mask & data};
}
+ };
- style = mOldStyle;
- exStyle = mOldExStyle;
+ // Get styles from an HWND.
+ constexpr auto const GetStyles = [](HWND hwnd) {
+ return Styles{.style = ::GetWindowLongPtrW(hwnd, GWL_STYLE),
+ .ex = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE)};
+ };
+ constexpr auto const SetStyles = [](HWND hwnd, Styles styles) {
+ VERIFY_WINDOW_STYLE(styles.style);
+ ::SetWindowLongPtrW(hwnd, GWL_STYLE, styles.style);
+ ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, styles.ex);
+ };
+
+ // Get styles from *this.
+ auto const GetCachedStyles = [&]() {
+ return mOldStyles.map([](auto const& m) {
+ return Styles{.style = m.style, .ex = m.exStyle};
+ });
+ };
+ auto const SetCachedStyles = [&](Styles styles) {
+ using WStyles = nsWindow::WindowStyles;
+ mOldStyles = Some(WStyles{.style = styles.style, .exStyle = styles.ex});
+ };
+
+ // The mask describing the "chrome" which this function is supposed to remove
+ // (or restore, as the case may be). Other style-flags will be left untouched.
+ constexpr static const Styles kChromeMask{
+ .style = WS_CAPTION | WS_THICKFRAME,
+ .ex = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE |
+ WS_EX_STATICEDGE};
+
+ // The desired style-flagset for fullscreen windows. (This happens to be all
+ // zeroes, but we don't need to rely on that.)
+ constexpr static const Styles kFullscreenChrome{.style = 0, .ex = 0};
+
+ auto const [chromeless, currentChrome] = kChromeMask.split(GetStyles(hwnd));
+ Styles newChrome{}, oldChrome{};
+
+ mHideChrome = aShouldHide;
+ if (aShouldHide) {
+ newChrome = kFullscreenChrome;
+ oldChrome = currentChrome;
+ } else {
+ // if there's nothing to "restore" it to, just use what's there now
+ oldChrome = GetCachedStyles().refOr(currentChrome);
+ newChrome = oldChrome;
if (mFutureMarginsToUse) {
SetNonClientMargins(mFutureMarginsOnceChromeShows);
}
}
- VERIFY_WINDOW_STYLE(style);
- ::SetWindowLongPtrW(hwnd, GWL_STYLE, style);
- ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle);
+ SetCachedStyles(oldChrome);
+ SetStyles(hwnd, kChromeMask.merge(chromeless, newChrome));
}
/**************************************************************
@@ -4941,10 +4979,12 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
case WM_SETTINGCHANGE: {
if (wParam == SPI_SETCLIENTAREAANIMATION ||
- wParam == SPI_SETKEYBOARDDELAY || wParam == SPI_SETMOUSEVANISH) {
+ wParam == SPI_SETKEYBOARDDELAY || wParam == SPI_SETMOUSEVANISH ||
+ wParam == MOZ_SPI_SETCURSORSIZE) {
// These need to update LookAndFeel cached values.
// They affect reduced motion settings / caret blink count / show
- // pointer while typing, so no need to invalidate style / layout.
+ // pointer while typing / tooltip offset, so no need to invalidate style
+ // / layout.
NotifyThemeChanged(widget::ThemeChangeKind::MediaQueriesOnly);
break;
}
@@ -5885,6 +5925,20 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
a11y::LazyInstantiator::EnableBlindAggregation(mWnd);
result = true;
}
+ } else if (objId == UiaRootObjectId &&
+ StaticPrefs::accessibility_uia_enable()) {
+ if (a11y::LocalAccessible* acc = GetAccessible()) {
+ RefPtr<IAccessible> ia;
+ acc->GetNativeInterface(getter_AddRefs(ia));
+ MOZ_ASSERT(ia);
+ RefPtr<IRawElementProviderSimple> uia;
+ ia->QueryInterface(IID_IRawElementProviderSimple,
+ getter_AddRefs(uia));
+ if (uia) {
+ *aRetValue = UiaReturnRawElementProvider(mWnd, wParam, lParam, uia);
+ result = true;
+ }
+ }
}
} break;
#endif
diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h
index 3a521fb978..a2b2a701bd 100644
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -175,7 +175,6 @@ class nsWindow final : public nsBaseWidget {
void Resize(double aWidth, double aHeight, bool aRepaint) override;
void Resize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint) override;
- mozilla::Maybe<bool> IsResizingNativeWidget() override;
void PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget* aWidget,
bool aActivate) override;
void SetSizeMode(nsSizeMode aMode) override;
@@ -755,8 +754,12 @@ class nsWindow final : public nsBaseWidget {
bool mIsAlert = false;
bool mIsPerformingDwmFlushHack = false;
bool mDraggingWindowWithMouse = false;
- DWORD_PTR mOldStyle = 0;
- DWORD_PTR mOldExStyle = 0;
+ // Partial cached window-styles, for when going fullscreen. (Only window-
+ // decoration-related flags are saved here.)
+ struct WindowStyles {
+ LONG_PTR style, exStyle;
+ };
+ mozilla::Maybe<WindowStyles> mOldStyles;
nsNativeDragTarget* mNativeDragTarget = nullptr;
HKL mLastKeyboardLayout = 0;
mozilla::CheckInvariantWrapper<FrameState> mFrameState;