summaryrefslogtreecommitdiffstats
path: root/widget
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /widget
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget')
-rw-r--r--widget/EventMessageList.h4
-rw-r--r--widget/GfxInfoBase.cpp29
-rw-r--r--widget/GfxInfoBase.h2
-rw-r--r--widget/IMEData.h14
-rw-r--r--widget/IconLoader.cpp6
-rw-r--r--widget/InitData.h5
-rw-r--r--widget/LookAndFeel.h7
-rw-r--r--widget/Theme.cpp2
-rw-r--r--widget/ThemeCocoa.cpp15
-rw-r--r--widget/ThemeCocoa.h6
-rw-r--r--widget/android/EventDispatcher.cpp6
-rw-r--r--widget/android/GfxInfo.cpp10
-rw-r--r--widget/android/jni/Utils.cpp2
-rw-r--r--widget/android/nsLookAndFeel.cpp4
-rw-r--r--widget/cocoa/CFTypeRefPtr.h194
-rw-r--r--widget/cocoa/GfxInfo.mm18
-rw-r--r--widget/cocoa/MOZIconHelper.mm8
-rw-r--r--widget/cocoa/OSXNotificationCenter.mm6
-rw-r--r--widget/cocoa/TextRecognition.mm4
-rw-r--r--widget/cocoa/moz.build1
-rw-r--r--widget/cocoa/nsCocoaUtils.h21
-rw-r--r--widget/cocoa/nsCocoaUtils.mm84
-rw-r--r--widget/cocoa/nsCocoaWindow.h1
-rw-r--r--widget/cocoa/nsCocoaWindow.mm410
-rw-r--r--widget/cocoa/nsCursorManager.mm10
-rw-r--r--widget/cocoa/nsLookAndFeel.mm3
-rw-r--r--widget/cocoa/nsMacSharingService.mm2
-rw-r--r--widget/gtk/DBusMenu.cpp67
-rw-r--r--widget/gtk/DBusMenu.h137
-rw-r--r--widget/gtk/GRefPtr.h5
-rw-r--r--widget/gtk/GfxInfo.cpp18
-rw-r--r--widget/gtk/GtkCompositorWidget.cpp31
-rw-r--r--widget/gtk/GtkCompositorWidget.h6
-rw-r--r--widget/gtk/IMContextWrapper.cpp38
-rw-r--r--widget/gtk/IMContextWrapper.h4
-rw-r--r--widget/gtk/MozContainer.cpp167
-rw-r--r--widget/gtk/MozContainer.h28
-rw-r--r--widget/gtk/MozContainerWayland.cpp6
-rw-r--r--widget/gtk/NativeMenuGtk.cpp451
-rw-r--r--widget/gtk/NativeMenuGtk.h34
-rw-r--r--widget/gtk/NativeMenuSupport.cpp12
-rw-r--r--widget/gtk/WakeLockListener.cpp26
-rw-r--r--widget/gtk/WidgetStyleCache.cpp5
-rw-r--r--widget/gtk/WindowSurfaceProvider.cpp22
-rw-r--r--widget/gtk/WindowSurfaceProvider.h7
-rw-r--r--widget/gtk/gtk3drawing.cpp103
-rw-r--r--widget/gtk/gtkdrawing.h8
-rw-r--r--widget/gtk/moz.build1
-rw-r--r--widget/gtk/nsGtkKeyUtils.cpp206
-rw-r--r--widget/gtk/nsGtkKeyUtils.h2
-rw-r--r--widget/gtk/nsLookAndFeel.cpp13
-rw-r--r--widget/gtk/nsLookAndFeel.h1
-rw-r--r--widget/gtk/nsNativeThemeGTK.cpp34
-rw-r--r--widget/gtk/nsNativeThemeGTK.h1
-rw-r--r--widget/gtk/nsWaylandDisplay.cpp10
-rw-r--r--widget/gtk/nsWaylandDisplay.h7
-rw-r--r--widget/gtk/nsWindow.cpp528
-rw-r--r--widget/gtk/nsWindow.h10
-rw-r--r--widget/gtk/wayland/moz.build2
-rw-r--r--widget/gtk/wayland/xdg-dbus-annotation-v1-client-protocol.h284
-rw-r--r--widget/gtk/wayland/xdg-dbus-annotation-v1-protocol.c75
-rw-r--r--widget/headless/HeadlessLookAndFeelGTK.cpp3
-rw-r--r--widget/headless/tests/test_headless.js4
-rw-r--r--widget/moz.build2
-rw-r--r--widget/nsBaseClipboard.cpp142
-rw-r--r--widget/nsBaseClipboard.h9
-rw-r--r--widget/nsBaseFilePicker.cpp35
-rw-r--r--widget/nsBaseFilePicker.h8
-rw-r--r--widget/nsBaseWidget.cpp6
-rw-r--r--widget/nsBaseWidget.h9
-rw-r--r--widget/nsClipboardProxy.cpp72
-rw-r--r--widget/nsFilePickerProxy.cpp19
-rw-r--r--widget/nsFilePickerProxy.h5
-rw-r--r--widget/nsIClipboard.idl25
-rw-r--r--widget/nsIFilePicker.idl20
-rw-r--r--widget/nsIGfxInfo.idl8
-rw-r--r--widget/nsIPrintDialogService.idl8
-rw-r--r--widget/nsIPrintSettingsService.idl6
-rw-r--r--widget/nsISound.idl4
-rw-r--r--widget/nsNativeTheme.cpp6
-rw-r--r--widget/nsPrinterBase.cpp24
-rw-r--r--widget/nsPrinterBase.h4
-rw-r--r--widget/nsXPLookAndFeel.cpp4
-rw-r--r--widget/tests/browser/browser_test_clipboard_contextmenu.js2
-rw-r--r--widget/tests/browser/browser_test_clipboardcache.js4
-rw-r--r--widget/tests/browser/browser_test_swipe_gesture.js20
-rw-r--r--widget/tests/chrome.toml16
-rw-r--r--widget/tests/clipboard_helper.js14
-rw-r--r--widget/tests/file_test_clipboard_asyncGetData.js4
-rw-r--r--widget/tests/file_test_clipboard_getDataSnapshotSync.js153
-rw-r--r--widget/tests/mochitest.toml6
-rw-r--r--widget/tests/standalone_native_menu_window.xhtml4
-rw-r--r--widget/tests/test_bug343416.xhtml2
-rw-r--r--widget/tests/test_clipboard_cache_chrome.html55
-rw-r--r--widget/tests/test_clipboard_getDataSnapshotSync.html19
-rw-r--r--widget/tests/test_clipboard_getDataSnapshotSync_chrome.html19
-rw-r--r--widget/tests/test_clipboard_owner_chrome.html2
-rw-r--r--widget/tests/test_contextmenu_by_mouse_on_unix.html2
-rw-r--r--widget/tests/test_ime_focus_with_multiple_contenteditable.html104
-rw-r--r--widget/tests/test_ime_state_others_in_parent.html2
-rw-r--r--widget/tests/test_key_event_counts.xhtml2
-rw-r--r--widget/tests/test_keycodes.xhtml38
-rw-r--r--widget/tests/test_native_key_bindings_mac.html2
-rw-r--r--widget/tests/test_sizemode_events.xhtml2
-rw-r--r--widget/tests/window_bug478536.xhtml6
-rw-r--r--widget/tests/window_composition_text_querycontent.xhtml2
-rw-r--r--widget/tests/window_imestate_iframes.html100
-rw-r--r--widget/tests/window_mouse_scroll_win.html10
-rw-r--r--widget/uikit/GfxInfo.cpp45
-rw-r--r--widget/uikit/GfxInfo.h21
-rw-r--r--widget/uikit/MediaKeysEventSourceFactory.cpp17
-rw-r--r--widget/uikit/TextInputHandler.h67
-rw-r--r--widget/uikit/TextInputHandler.mm254
-rw-r--r--widget/uikit/UIKitUtils.h23
-rw-r--r--widget/uikit/UIKitUtils.mm89
-rw-r--r--widget/uikit/components.conf28
-rw-r--r--widget/uikit/moz.build17
-rw-r--r--widget/uikit/nsAppShell.h4
-rw-r--r--widget/uikit/nsBidiKeyboard.h23
-rw-r--r--widget/uikit/nsBidiKeyboard.mm35
-rw-r--r--widget/uikit/nsLookAndFeel.h7
-rw-r--r--widget/uikit/nsLookAndFeel.mm46
-rw-r--r--widget/uikit/nsNativeThemeUIKit.h21
-rw-r--r--widget/uikit/nsNativeThemeUIKit.mm19
-rw-r--r--widget/uikit/nsScreenManager.h61
-rw-r--r--widget/uikit/nsScreenManager.mm104
-rw-r--r--widget/uikit/nsWidgetFactory.h21
-rw-r--r--widget/uikit/nsWidgetFactory.mm45
-rw-r--r--widget/uikit/nsWindow.h77
-rw-r--r--widget/uikit/nsWindow.mm420
-rw-r--r--widget/windows/GfxInfo.cpp69
-rw-r--r--widget/windows/JumpListBuilder.cpp12
-rw-r--r--widget/windows/JumpListBuilder.h2
-rw-r--r--widget/windows/WinTaskbar.cpp5
-rw-r--r--widget/windows/WindowsSMTCProvider.cpp179
-rw-r--r--widget/windows/WindowsSMTCProvider.h12
-rw-r--r--widget/windows/filedialog/WinFileDialogChild.cpp7
-rw-r--r--widget/windows/filedialog/WinFileDialogCommands.cpp2
-rw-r--r--widget/windows/nsFilePicker.cpp14
-rw-r--r--widget/windows/nsFilePicker.h6
-rw-r--r--widget/windows/nsLookAndFeel.cpp3
-rw-r--r--widget/windows/nsWindow.cpp136
-rw-r--r--widget/windows/nsWindow.h4
143 files changed, 4329 insertions, 1802 deletions
diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h
index ae02d04676..f42c1e3b2c 100644
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -209,6 +209,10 @@ NS_EVENT_MESSAGE(eLegacyDOMFocusOut)
NS_EVENT_MESSAGE(ePageShow)
NS_EVENT_MESSAGE(ePageHide)
+// Canvas events
+NS_EVENT_MESSAGE(eContextLost)
+NS_EVENT_MESSAGE(eContextRestored)
+
// SVG events
NS_EVENT_MESSAGE(eSVGLoad)
NS_EVENT_MESSAGE(eSVGScroll)
diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp
index 3e32ffbe15..251b46ce66 100644
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -279,6 +279,12 @@ static const char* GetPrefNameForFeature(int32_t aFeature) {
case nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE:
name = BLOCKLIST_PREF_BRANCH "webgl-use-hardware";
break;
+ case nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR:
+ name = BLOCKLIST_PREF_BRANCH "overlay-vp-auto-hdr";
+ break;
+ case nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION:
+ name = BLOCKLIST_PREF_BRANCH "overlay-vp-super-resolution";
+ break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
break;
@@ -555,6 +561,12 @@ static int32_t BlocklistFeatureToGfxFeature(const nsAString& aFeature) {
if (aFeature.EqualsLiteral("ACCELERATED_CANVAS2D")) {
return nsIGfxInfo::FEATURE_ACCELERATED_CANVAS2D;
}
+ if (aFeature.EqualsLiteral("FEATURE_OVERLAY_VP_AUTO_HDR")) {
+ return nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR;
+ }
+ if (aFeature.EqualsLiteral("FEATURE_OVERLAY_VP_SUPER_RESOLUTION")) {
+ return nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION;
+ }
if (aFeature.EqualsLiteral("ALL")) {
return GfxDriverInfo::allFeatures;
}
@@ -1276,8 +1288,7 @@ bool GfxInfoBase::DoesDriverVendorMatch(const nsAString& aBlocklistVendor,
}
bool GfxInfoBase::IsFeatureAllowlisted(int32_t aFeature) const {
- return aFeature == nsIGfxInfo::FEATURE_VIDEO_OVERLAY ||
- aFeature == nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY;
+ return aFeature == nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY;
}
nsresult GfxInfoBase::GetFeatureStatusImpl(
@@ -1925,7 +1936,7 @@ using Device = nsIGfxInfo::FontVisibilityDeviceDetermination;
static StaticAutoPtr<std::pair<Device, nsString>> ret;
std::pair<Device, nsString>* GfxInfoBase::GetFontVisibilityDeterminationPair() {
- if(!ret) {
+ if (!ret) {
ret = new std::pair<Device, nsString>();
ret->first = Device::Unassigned;
ret->second = u""_ns;
@@ -2150,6 +2161,18 @@ GfxInfoBase::GetUsingGPUProcess(bool* aOutValue) {
return NS_OK;
}
+NS_IMETHODIMP
+GfxInfoBase::GetUsingRemoteCanvas(bool* aOutValue) {
+ *aOutValue = gfx::gfxVars::RemoteCanvasEnabled();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GfxInfoBase::GetUsingAcceleratedCanvas(bool* aOutValue) {
+ *aOutValue = gfx::gfxVars::UseAcceleratedCanvas2D();
+ return NS_OK;
+}
+
NS_IMETHODIMP_(int32_t)
GfxInfoBase::GetMaxRefreshRate(bool* aMixed) {
if (aMixed) {
diff --git a/widget/GfxInfoBase.h b/widget/GfxInfoBase.h
index 4d4b1a2def..c2bab66400 100644
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -73,6 +73,8 @@ class GfxInfoBase : public nsIGfxInfo,
NS_IMETHOD GetAzureCanvasBackend(nsAString& aBackend) override;
NS_IMETHOD GetAzureContentBackend(nsAString& aBackend) override;
NS_IMETHOD GetUsingGPUProcess(bool* aOutValue) override;
+ NS_IMETHOD GetUsingRemoteCanvas(bool* aOutValue) override;
+ NS_IMETHOD GetUsingAcceleratedCanvas(bool* aOutValue) override;
NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override;
NS_IMETHOD GetTargetFrameRate(uint32_t* aTargetFrameRate) override;
NS_IMETHOD GetCodecSupportInfo(nsACString& aCodecSupportInfo) override;
diff --git a/widget/IMEData.h b/widget/IMEData.h
index 7fb1241333..1ea33e18b9 100644
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -451,18 +451,20 @@ struct InputContext final {
bool IsInputAttributeChanged(const InputContext& aOldContext) const {
return mIMEState.mEnabled != aOldContext.mIMEState.mEnabled ||
-#if defined(ANDROID) || defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
+#if defined(ANDROID) || defined(MOZ_WIDGET_GTK) || defined(XP_WIN) || \
+ defined(XP_IOS)
// input type and inputmode are supported by Windows IME API, GTK
- // IME API and Android IME API
+ // IME API, Android IME API and iOS API.
mHTMLInputType != aOldContext.mHTMLInputType ||
mHTMLInputMode != aOldContext.mHTMLInputMode ||
#endif
-#if defined(ANDROID) || defined(MOZ_WIDGET_GTK)
- // autocapitalize is supported by Android IME API and GTK IME API
+#if defined(ANDROID) || defined(MOZ_WIDGET_GTK) || defined(XP_IOS)
+ // autocapitalize is supported by Android IME API, GTK IME API, and
+ // iOS API
mAutocapitalize != aOldContext.mAutocapitalize ||
#endif
-#if defined(ANDROID)
- // enterkeyhint is only supported by Android IME API.
+#if defined(ANDROID) || defined(XP_IOS)
+ // enterkeyhint is only supported by Android IME API and iOS API.
mActionHint != aOldContext.mActionHint ||
#endif
false;
diff --git a/widget/IconLoader.cpp b/widget/IconLoader.cpp
index 5c0488e3e2..41d2a29bc7 100644
--- a/widget/IconLoader.cpp
+++ b/widget/IconLoader.cpp
@@ -9,6 +9,7 @@
#include "imgLoader.h"
#include "imgRequestProxy.h"
#include "mozilla/dom/Document.h"
+#include "mozilla/dom/FetchPriority.h"
#include "nsContentUtils.h"
#include "nsIContent.h"
#include "nsIContentPolicy.h"
@@ -63,7 +64,7 @@ nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode,
nullptr, nsIRequest::LOAD_NORMAL, nullptr,
nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
/* aUseUrgentStartForChannel */ false, /* aLinkPreload */ false, 0,
- getter_AddRefs(mIconRequest));
+ dom::FetchPriority::Auto, getter_AddRefs(mIconRequest));
} else {
// TODO: nsIContentPolicy::TYPE_INTERNAL_IMAGE may not be the correct
// policy. See bug 1691868 for more details.
@@ -72,7 +73,8 @@ nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode,
aNode, document, nsIRequest::LOAD_NORMAL, nullptr,
nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
/* aUseUrgentStartForChannel */ false,
- /* aLinkPreload */ false, 0, getter_AddRefs(mIconRequest));
+ /* aLinkPreload */ false, 0, dom::FetchPriority::Auto,
+ getter_AddRefs(mIconRequest));
}
if (NS_FAILED(rv)) {
return rv;
diff --git a/widget/InitData.h b/widget/InitData.h
index 1498feed9a..aed5e0a551 100644
--- a/widget/InitData.h
+++ b/widget/InitData.h
@@ -37,11 +37,6 @@ enum class PopupLevel : uint8_t {
// The popup appears just above its parent and maintains its position
// relative to the parent.
Parent,
- // The popup is a floating popup used for tool palettes. A parent window must
- // be specified, but a platform implementation need not use this. On Windows,
- // floating is generally equivalent to parent. On Mac, floating puts the
- // popup at toplevel, but it will hide when the application is deactivated.
- Floating,
// The popup appears on top of other windows, including those of other
// applications.
Top,
diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h
index 2ab61df304..0cab187410 100644
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -163,10 +163,6 @@ class LookAndFeel {
* 1: scrollbar button repeats to scroll even if cursor is outside of it.
*/
ScrollbarButtonAutoRepeatBehavior,
- /**
- * Delay before showing a tooltip.
- */
- TooltipDelay,
/*
* A Boolean value to determine whether swipe animations should be used.
*/
@@ -293,6 +289,9 @@ class LookAndFeel {
/** GTK titlebar radius */
TitlebarRadius,
+ /** GTK button-to-button spacing in the inline axis */
+ TitlebarButtonSpacing,
+
/**
* Corresponding to dynamic-range.
* https://drafts.csswg.org/mediaqueries-5/#dynamic-range
diff --git a/widget/Theme.cpp b/widget/Theme.cpp
index 35c53240e5..1fcd3d4bc3 100644
--- a/widget/Theme.cpp
+++ b/widget/Theme.cpp
@@ -1562,7 +1562,7 @@ UniquePtr<ScrollbarDrawing> Theme::ScrollbarStyle() {
return MakeUnique<ScrollbarDrawingWin11>();
}
return MakeUnique<ScrollbarDrawingWin>();
-#elif MOZ_WIDGET_COCOA
+#elif defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
return MakeUnique<ScrollbarDrawingCocoa>();
#elif MOZ_WIDGET_GTK
return MakeUnique<ScrollbarDrawingGTK>();
diff --git a/widget/ThemeCocoa.cpp b/widget/ThemeCocoa.cpp
index 733c215991..a41d41409b 100644
--- a/widget/ThemeCocoa.cpp
+++ b/widget/ThemeCocoa.cpp
@@ -4,27 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ThemeCocoa.h"
-
-#include "cocoa/MacThemeGeometryType.h"
#include "gfxPlatform.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "mozilla/gfx/Helpers.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/ServoStyleConsts.h"
namespace mozilla::widget {
-LayoutDeviceIntSize ThemeCocoa::GetMinimumWidgetSize(
- nsPresContext* aPresContext, nsIFrame* aFrame,
- StyleAppearance aAppearance) {
- if (aAppearance == StyleAppearance::MozMenulistArrowButton) {
- auto size =
- GetScrollbarSize(aPresContext, StyleScrollbarWidth::Auto, Overlay::No);
- return {size, size};
- }
- return Theme::GetMinimumWidgetSize(aPresContext, aFrame, aAppearance);
-}
-
NS_IMETHODIMP
ThemeCocoa::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
diff --git a/widget/ThemeCocoa.h b/widget/ThemeCocoa.h
index f846766f37..d5d84ee5f0 100644
--- a/widget/ThemeCocoa.h
+++ b/widget/ThemeCocoa.h
@@ -9,8 +9,6 @@
#include "Theme.h"
-#include "ScrollbarDrawingCocoa.h"
-
namespace mozilla::widget {
class ThemeCocoa : public Theme {
@@ -18,10 +16,6 @@ class ThemeCocoa : public Theme {
explicit ThemeCocoa(UniquePtr<ScrollbarDrawing>&& aScrollbarDrawing)
: Theme(std::move(aScrollbarDrawing)) {}
- LayoutDeviceIntSize GetMinimumWidgetSize(
- nsPresContext* aPresContext, nsIFrame* aFrame,
- StyleAppearance aAppearance) override;
-
NS_IMETHOD DrawWidgetBackground(gfxContext* aContext, nsIFrame*,
StyleAppearance, const nsRect& aRect,
const nsRect& aDirtyRect,
diff --git a/widget/android/EventDispatcher.cpp b/widget/android/EventDispatcher.cpp
index ab876de136..6e414c11ce 100644
--- a/widget/android/EventDispatcher.cpp
+++ b/widget/android/EventDispatcher.cpp
@@ -129,9 +129,9 @@ nsresult UnboxBundle(JSContext* aCx, const jni::Object::LocalRef& aData,
nsresult rv = UnboxValue(aCx, values->GetElement(i), &value);
if (rv == NS_ERROR_INVALID_ARG && !JS_IsExceptionPending(aCx)) {
JS_ReportErrorUTF8(
- aCx, u8"Invalid event data property %s",
- NS_ConvertUTF16toUTF8(
- nsString(reinterpret_cast<const char16_t*>(keyChars), keyLen))
+ aCx, "Invalid event data property %s",
+ NS_ConvertUTF16toUTF8(reinterpret_cast<const char16_t*>(keyChars),
+ keyLen)
.get());
}
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp
index 0e78b187bf..6e6d3bf47b 100644
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -350,11 +350,11 @@ GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
}
void GfxInfo::AddCrashReportAnnotations() {
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
- mGLStrings->Vendor());
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
- mGLStrings->Renderer());
- CrashReporter::AnnotateCrashReport(
+ CrashReporter::RecordAnnotationNSCString(
+ CrashReporter::Annotation::AdapterVendorID, mGLStrings->Vendor());
+ CrashReporter::RecordAnnotationNSCString(
+ CrashReporter::Annotation::AdapterDeviceID, mGLStrings->Renderer());
+ CrashReporter::RecordAnnotationNSCString(
CrashReporter::Annotation::AdapterDriverVersion, mGLStrings->Version());
}
diff --git a/widget/android/jni/Utils.cpp b/widget/android/jni/Utils.cpp
index 08164e4950..8d3800fd03 100644
--- a/widget/android/jni/Utils.cpp
+++ b/widget/android/jni/Utils.cpp
@@ -221,7 +221,7 @@ bool HandleUncaughtException(JNIEnv* aEnv) {
bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack) {
bool result = true;
- result &= NS_SUCCEEDED(CrashReporter::AnnotateCrashReport(
+ result &= NS_SUCCEEDED(CrashReporter::RecordAnnotationNSCString(
CrashReporter::Annotation::JavaStackTrace,
String::Ref::From(aStack)->ToCString()));
diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp
index 02919e0dbf..6d9f8c634f 100644
--- a/widget/android/nsLookAndFeel.cpp
+++ b/widget/android/nsLookAndFeel.cpp
@@ -312,10 +312,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = 200;
break;
- case IntID::TooltipDelay:
- aResult = 500;
- break;
-
case IntID::MenusCanOverlapOSBar:
// we want XUL popups to be able to overlap the task bar.
aResult = 1;
diff --git a/widget/cocoa/CFTypeRefPtr.h b/widget/cocoa/CFTypeRefPtr.h
deleted file mode 100644
index 185355777e..0000000000
--- a/widget/cocoa/CFTypeRefPtr.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#ifndef CFTypeRefPtr_h
-#define CFTypeRefPtr_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/DbgMacro.h"
-#include "mozilla/HashFunctions.h"
-
-// A smart pointer for CoreFoundation classes which does reference counting.
-//
-// Manual reference counting:
-//
-// UInt32 someNumber = 10;
-// CFNumberRef numberObject =
-// CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber);
-// // do something with numberObject
-// CFRelease(numberObject);
-//
-// Automatic reference counting using CFTypeRefPtr:
-//
-// UInt32 someNumber = 10;
-// auto numberObject =
-// CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
-// CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber));
-// // do something with numberObject
-// // no CFRelease
-
-template <class PtrT>
-class CFTypeRefPtr {
- private:
- void assign_with_CFRetain(PtrT aRawPtr) {
- CFRetain(aRawPtr);
- assign_assuming_CFRetain(aRawPtr);
- }
-
- void assign_assuming_CFRetain(PtrT aNewPtr) {
- PtrT oldPtr = mRawPtr;
- mRawPtr = aNewPtr;
- if (oldPtr) {
- CFRelease(oldPtr);
- }
- }
-
- private:
- PtrT mRawPtr;
-
- public:
- ~CFTypeRefPtr() {
- if (mRawPtr) {
- CFRelease(mRawPtr);
- }
- }
-
- // Constructors
-
- CFTypeRefPtr() : mRawPtr(nullptr) {}
-
- CFTypeRefPtr(const CFTypeRefPtr<PtrT>& aSmartPtr)
- : mRawPtr(aSmartPtr.mRawPtr) {
- if (mRawPtr) {
- CFRetain(mRawPtr);
- }
- }
-
- CFTypeRefPtr(CFTypeRefPtr<PtrT>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
- aRefPtr.mRawPtr = nullptr;
- }
-
- MOZ_IMPLICIT CFTypeRefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
-
- // There is no constructor from a raw pointer value.
- // Use one of the static WrapUnder*Rule methods below instead.
-
- static CFTypeRefPtr<PtrT> WrapUnderCreateRule(PtrT aRawPtr) {
- CFTypeRefPtr<PtrT> ptr;
- ptr.AssignUnderCreateRule(aRawPtr);
- return ptr;
- }
-
- static CFTypeRefPtr<PtrT> WrapUnderGetRule(PtrT aRawPtr) {
- CFTypeRefPtr<PtrT> ptr;
- ptr.AssignUnderGetRule(aRawPtr);
- return ptr;
- }
-
- // Assignment operators
-
- CFTypeRefPtr<PtrT>& operator=(decltype(nullptr)) {
- assign_assuming_CFRetain(nullptr);
- return *this;
- }
-
- CFTypeRefPtr<PtrT>& operator=(const CFTypeRefPtr<PtrT>& aRhs) {
- assign_with_CFRetain(aRhs.mRawPtr);
- return *this;
- }
-
- CFTypeRefPtr<PtrT>& operator=(CFTypeRefPtr<PtrT>&& aRefPtr) {
- assign_assuming_CFRetain(aRefPtr.mRawPtr);
- aRefPtr.mRawPtr = nullptr;
- return *this;
- }
-
- // There is no operator= for a raw pointer value.
- // Use one of the AssignUnder*Rule methods below instead.
-
- CFTypeRefPtr<PtrT>& AssignUnderCreateRule(PtrT aRawPtr) {
- // Freshly-created objects come with a retain count of 1.
- assign_assuming_CFRetain(aRawPtr);
- return *this;
- }
-
- CFTypeRefPtr<PtrT>& AssignUnderGetRule(PtrT aRawPtr) {
- assign_with_CFRetain(aRawPtr);
- return *this;
- }
-
- // Other pointer operators
-
- // This is the only way to get the raw pointer out of the smart pointer.
- // There is no implicit conversion to a raw pointer.
- PtrT get() const { return mRawPtr; }
-
- // Don't allow implicit conversion of temporary CFTypeRefPtr to raw pointer,
- // because the refcount might be one and the pointer will immediately become
- // invalid.
- operator PtrT() const&& = delete;
- // Also don't allow implicit conversion of non-temporary CFTypeRefPtr.
- operator PtrT() const& = delete;
-
- // These let you null-check a pointer without calling get().
- explicit operator bool() const { return !!mRawPtr; }
-};
-
-template <class PtrT>
-inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs,
- const CFTypeRefPtr<PtrT>& aRhs) {
- return aLhs.get() == aRhs.get();
-}
-
-template <class PtrT>
-inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs,
- const CFTypeRefPtr<PtrT>& aRhs) {
- return !(aLhs == aRhs);
-}
-
-// Comparing an |CFTypeRefPtr| to |nullptr|
-
-template <class PtrT>
-inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) {
- return aLhs.get() == nullptr;
-}
-
-template <class PtrT>
-inline bool operator==(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) {
- return nullptr == aRhs.get();
-}
-
-template <class PtrT>
-inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) {
- return aLhs.get() != nullptr;
-}
-
-template <class PtrT>
-inline bool operator!=(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) {
- return nullptr != aRhs.get();
-}
-
-// MOZ_DBG support
-
-template <class PtrT>
-std::ostream& operator<<(std::ostream& aOut, const CFTypeRefPtr<PtrT>& aObj) {
- return mozilla::DebugValue(aOut, aObj.get());
-}
-
-// std::hash support (e.g. for unordered_map)
-namespace std {
-template <class PtrT>
-struct hash<CFTypeRefPtr<PtrT>> {
- typedef CFTypeRefPtr<PtrT> argument_type;
- typedef std::size_t result_type;
- result_type operator()(argument_type const& aPtr) const {
- return mozilla::HashGeneric(reinterpret_cast<uintptr_t>(aPtr.get()));
- }
-};
-} // namespace std
-
-#endif /* CFTypeRefPtr_h */
diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm
index 1476cc27db..f4477cef4a 100644
--- a/widget/cocoa/GfxInfo.mm
+++ b/widget/cocoa/GfxInfo.mm
@@ -419,21 +419,17 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
void GfxInfo::AddCrashReportAnnotations() {
nsString deviceID, vendorID, driverVersion;
- nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion;
GetAdapterDeviceID(deviceID);
- CopyUTF16toUTF8(deviceID, narrowDeviceID);
GetAdapterVendorID(vendorID);
- CopyUTF16toUTF8(vendorID, narrowVendorID);
GetAdapterDriverVersion(driverVersion);
- CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
-
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
- narrowVendorID);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
- narrowDeviceID);
- CrashReporter::AnnotateCrashReport(
- CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
+
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterVendorID, vendorID);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterDeviceID, deviceID);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterDriverVersion, driverVersion);
}
// We don't support checking driver versions on Mac.
diff --git a/widget/cocoa/MOZIconHelper.mm b/widget/cocoa/MOZIconHelper.mm
index e15407b797..f9c8f02406 100644
--- a/widget/cocoa/MOZIconHelper.mm
+++ b/widget/cocoa/MOZIconHelper.mm
@@ -32,11 +32,11 @@
if (aScaleFactor != 0.0f) {
rv = nsCocoaUtils::CreateNSImageFromImageContainer(
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
- &retainedImage, aScaleFactor, &isEntirelyBlack);
+ aSize, &retainedImage, aScaleFactor, &isEntirelyBlack);
} else {
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
- &retainedImage, &isEntirelyBlack);
+ aSize, &retainedImage, &isEntirelyBlack);
}
NSImage* image = [retainedImage autorelease];
@@ -45,10 +45,6 @@
return nil;
}
- int32_t origWidth = 0, origHeight = 0;
- aImage->GetWidth(&origWidth);
- aImage->GetHeight(&origHeight);
-
// If all the color channels in the image are black, treat the image as a
// template. This will cause macOS to use the image's alpha channel as a mask
// and it will fill it with a color that looks good in the context that it's
diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm
index 07cb026f1f..f7d507a947 100644
--- a/widget/cocoa/OSXNotificationCenter.mm
+++ b/widget/cocoa/OSXNotificationCenter.mm
@@ -544,9 +544,11 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData,
NSImage* cocoaImage = nil;
// TODO: Pass pres context / ComputedStyle here to support context paint
- // properties
+ // properties.
+ // TODO: Do we have a reasonable size to pass around here?
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
- image, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cocoaImage);
+ image, imgIContainer::FRAME_FIRST, nullptr, nullptr, NSMakeSize(0, 0),
+ &cocoaImage);
(osxni->mPendingNotification).contentImage = cocoaImage;
[cocoaImage release];
ShowPendingNotification(osxni);
diff --git a/widget/cocoa/TextRecognition.mm b/widget/cocoa/TextRecognition.mm
index c365f51982..31a170466a 100644
--- a/widget/cocoa/TextRecognition.mm
+++ b/widget/cocoa/TextRecognition.mm
@@ -70,8 +70,8 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
auto& quad = *pResult->quads().AppendElement();
- CopyCocoaStringToXPCOMString(recognizedText.string,
- quad.string());
+ CopyNSStringToXPCOMString(recognizedText.string,
+ quad.string());
quad.confidence() = recognizedText.confidence;
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
diff --git a/widget/cocoa/moz.build b/widget/cocoa/moz.build
index ebee9439e0..ddb402e2cc 100644
--- a/widget/cocoa/moz.build
+++ b/widget/cocoa/moz.build
@@ -18,7 +18,6 @@ XPIDL_SOURCES += [
XPIDL_MODULE = "widget_cocoa"
EXPORTS += [
- "CFTypeRefPtr.h",
"DesktopBackgroundImage.h",
"MediaHardwareKeysEventSourceMac.h",
"MediaHardwareKeysEventSourceMacMediaCenter.h",
diff --git a/widget/cocoa/nsCocoaUtils.h b/widget/cocoa/nsCocoaUtils.h
index 9e3b76a920..9b36c1192d 100644
--- a/widget/cocoa/nsCocoaUtils.h
+++ b/widget/cocoa/nsCocoaUtils.h
@@ -18,6 +18,7 @@
#include "nsObjCExceptions.h"
#include "mozilla/EventForwards.h"
+#include "mozilla/MacStringHelpers.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "nsIWidget.h"
@@ -298,8 +299,9 @@ class nsCocoaUtils {
static nsresult CreateNSImageFromImageContainer(
imgIContainer* aImage, uint32_t aWhichFrame,
const nsPresContext* aPresContext,
- const mozilla::ComputedStyle* aComputedStyle, NSImage** aResult,
- CGFloat scaleFactor, bool* aIsEntirelyBlack = nullptr);
+ const mozilla::ComputedStyle* aComputedStyle,
+ const NSSize& aPreferredSize, NSImage** aResult, CGFloat scaleFactor,
+ bool* aIsEntirelyBlack = nullptr);
/** Creates a Cocoa <code>NSImage</code> from a frame of an
<code>imgIContainer</code>. The new <code>NSImage</code> will have both a
@@ -317,18 +319,23 @@ class nsCocoaUtils {
static nsresult CreateDualRepresentationNSImageFromImageContainer(
imgIContainer* aImage, uint32_t aWhichFrame,
const nsPresContext* aPresContext,
- const mozilla::ComputedStyle* aComputedStyle, NSImage** aResult,
+ const mozilla::ComputedStyle* aComputedStyle,
+ const NSSize& aPreferredSize, NSImage** aResult,
bool* aIsEntirelyBlack = nullptr);
/**
* Returns nsAString for aSrc.
*/
- static void GetStringForNSString(const NSString* aSrc, nsAString& aDist);
+ static void GetStringForNSString(const NSString* aSrc, nsAString& aDist) {
+ mozilla::CopyNSStringToXPCOMString(aSrc, aDist);
+ }
/**
* Makes NSString instance for aString.
*/
- static NSString* ToNSString(const nsAString& aString);
+ static NSString* ToNSString(const nsAString& aString) {
+ return mozilla::XPCOMStringToNSString(aString);
+ }
/**
* Returns an NSURL instance for the provided string.
@@ -338,7 +345,9 @@ class nsCocoaUtils {
/**
* Makes NSString instance for aCString.
*/
- static NSString* ToNSString(const nsACString& aCString);
+ static NSString* ToNSString(const nsACString& aCString) {
+ return mozilla::XPCOMStringToNSString(aCString);
+ }
/**
* Returns NSRect for aGeckoRect.
diff --git a/widget/cocoa/nsCocoaUtils.mm b/widget/cocoa/nsCocoaUtils.mm
index f3a7604762..769eb05a85 100644
--- a/widget/cocoa/nsCocoaUtils.mm
+++ b/widget/cocoa/nsCocoaUtils.mm
@@ -515,11 +515,27 @@ nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage,
nsresult nsCocoaUtils::CreateNSImageFromImageContainer(
imgIContainer* aImage, uint32_t aWhichFrame,
const nsPresContext* aPresContext, const ComputedStyle* aComputedStyle,
- NSImage** aResult, CGFloat scaleFactor, bool* aIsEntirelyBlack) {
+ const NSSize& aPreferredSize, NSImage** aResult, CGFloat scaleFactor,
+ bool* aIsEntirelyBlack) {
RefPtr<SourceSurface> surface;
- int32_t width = 0, height = 0;
- aImage->GetWidth(&width);
- aImage->GetHeight(&height);
+ int32_t width = 0;
+ int32_t height = 0;
+ {
+ const bool gotWidth = NS_SUCCEEDED(aImage->GetWidth(&width));
+ const bool gotHeight = NS_SUCCEEDED(aImage->GetHeight(&height));
+ if (auto ratio = aImage->GetIntrinsicRatio()) {
+ if (gotWidth != gotHeight) {
+ if (gotWidth) {
+ height = ratio->Inverted().ApplyTo(width);
+ } else {
+ width = ratio->ApplyTo(height);
+ }
+ } else if (!gotWidth) {
+ height = std::ceil(aPreferredSize.height);
+ width = ratio->ApplyTo(height);
+ }
+ }
+ }
// Render a vector image at the correct resolution on a retina display
if (aImage->GetType() == imgIContainer::TYPE_VECTOR) {
@@ -582,31 +598,28 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(
nsresult nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
imgIContainer* aImage, uint32_t aWhichFrame,
const nsPresContext* aPresContext, const ComputedStyle* aComputedStyle,
- NSImage** aResult, bool* aIsEntirelyBlack) {
- int32_t width = 0, height = 0;
- aImage->GetWidth(&width);
- aImage->GetHeight(&height);
- NSSize size = NSMakeSize(width, height);
- *aResult = [[NSImage alloc] init];
- [*aResult setSize:size];
-
+ const NSSize& aPreferredSize, NSImage** aResult, bool* aIsEntirelyBlack) {
NSImage* newRepresentation = nil;
nsresult rv = CreateNSImageFromImageContainer(
- aImage, aWhichFrame, aPresContext, aComputedStyle, &newRepresentation,
- 1.0f, aIsEntirelyBlack);
+ aImage, aWhichFrame, aPresContext, aComputedStyle, aPreferredSize,
+ &newRepresentation, 1.0f, aIsEntirelyBlack);
if (NS_FAILED(rv) || !newRepresentation) {
return NS_ERROR_FAILURE;
}
+ NSSize size = newRepresentation.size;
+ *aResult = [[NSImage alloc] init];
+ [*aResult setSize:size];
+
[[[newRepresentation representations] objectAtIndex:0] setSize:size];
[*aResult
addRepresentation:[[newRepresentation representations] objectAtIndex:0]];
[newRepresentation release];
newRepresentation = nil;
- rv = CreateNSImageFromImageContainer(aImage, aWhichFrame, aPresContext,
- aComputedStyle, &newRepresentation, 2.0f,
- aIsEntirelyBlack);
+ rv = CreateNSImageFromImageContainer(
+ aImage, aWhichFrame, aPresContext, aComputedStyle, aPreferredSize,
+ &newRepresentation, 2.0f, aIsEntirelyBlack);
if (NS_FAILED(rv) || !newRepresentation) {
return NS_ERROR_FAILURE;
}
@@ -619,43 +632,6 @@ nsresult nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
}
// static
-void nsCocoaUtils::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;
-}
-
-// static
-NSString* nsCocoaUtils::ToNSString(const nsAString& aString) {
- if (aString.IsEmpty()) {
- return [NSString string];
- }
- return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
- aString.BeginReading())
- length:aString.Length()];
-}
-
-// static
-NSString* nsCocoaUtils::ToNSString(const nsACString& aCString) {
- if (aCString.IsEmpty()) {
- return [NSString string];
- }
- return [[[NSString alloc] initWithBytes:aCString.BeginReading()
- length:aCString.Length()
- encoding:NSUTF8StringEncoding] autorelease];
-}
-
-// static
NSURL* nsCocoaUtils::ToNSURL(const nsAString& aURLString) {
nsAutoCString encodedURLString;
nsresult rv = NS_GetSpecWithNSURLEncoding(encodedURLString,
diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
index c2e595677f..621c32eb44 100644
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -492,6 +492,7 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
bool mWindowTransformIsIdentity;
bool mAlwaysOnTop;
bool mAspectRatioLocked;
+ bool mIsAlert = false; // True if this is an non-native alert window.
int32_t mNumModalDescendents;
InputContext mInputContext;
diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
index e5abaa5a87..4b135e7565 100644
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -187,7 +187,7 @@ void nsCocoaWindow::DestroyNativeWindow() {
[mWindow releaseJSObjects];
// We want to unhook the delegate here because we don't want events
// sent to it after this object has been destroyed.
- [mWindow setDelegate:nil];
+ mWindow.delegate = nil;
[mWindow close];
mWindow = nil;
[mDelegate autorelease];
@@ -260,7 +260,7 @@ DesktopToLayoutDeviceScale ParentBackingScaleFactor(nsIWidget* aParent,
}
NSWindow* parentWindow = [aParentView window];
if (parentWindow) {
- return DesktopToLayoutDeviceScale([parentWindow backingScaleFactor]);
+ return DesktopToLayoutDeviceScale(parentWindow.backingScaleFactor);
}
return DesktopToLayoutDeviceScale(1.0);
}
@@ -322,6 +322,7 @@ nsresult nsCocoaWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
mParent = aParent;
mAncestorLink = aParent;
mAlwaysOnTop = aInitData->mAlwaysOnTop;
+ mIsAlert = aInitData->mIsAlert;
// If we have a parent widget, the new widget will be offset from the
// parent widget by aRect.{x,y}. Otherwise, we'll use aRect for the
@@ -477,29 +478,31 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect& aRect,
contentRect = aRect;
contentRect.origin.y -= (newWindowFrame.size.height - aRect.size.height);
- if (mWindowType != WindowType::Popup)
- contentRect.origin.y -= [[NSApp mainMenu] menuBarHeight];
+ if (mWindowType != WindowType::Popup) {
+ contentRect.origin.y -= NSApp.mainMenu.menuBarHeight;
+ }
}
// NSLog(@"Top-level window being created at Cocoa rect: %f, %f, %f, %f\n",
// rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
Class windowClass = [BaseWindow class];
- // If we have a titlebar on a top-level window, we want to be able to control
- // the titlebar color (for unified windows), so use the special ToolbarWindow
- // class. Note that we need to check the window type because we mark sheets as
- // having titlebars.
if ((mWindowType == WindowType::TopLevel ||
mWindowType == WindowType::Dialog) &&
- (features & NSWindowStyleMaskTitled))
+ (features & NSWindowStyleMaskTitled)) {
+ // If we have a titlebar on a top-level window, we want to be able to
+ // control the titlebar color (for unified windows), so use the special
+ // ToolbarWindow class. Note that we need to check the window type because
+ // we mark sheets as having titlebars.
windowClass = [ToolbarWindow class];
- // If we're a popup window we need to use the PopupWindow class.
- else if (mWindowType == WindowType::Popup)
+ } else if (mWindowType == WindowType::Popup) {
windowClass = [PopupWindow class];
- // If we're a non-popup borderless window we need to use the
- // BorderlessWindow class.
- else if (features == NSWindowStyleMaskBorderless)
+ // If we're a popup window we need to use the PopupWindow class.
+ } else if (features == NSWindowStyleMaskBorderless) {
+ // If we're a non-popup borderless window we need to use the
+ // BorderlessWindow class.
windowClass = [BorderlessWindow class];
+ }
// Create the window
mWindow = [[windowClass alloc] initWithContentRect:contentRect
@@ -509,65 +512,60 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect& aRect,
// Make sure that window titles don't leak to disk in private browsing mode
// due to macOS' resume feature.
- [mWindow setRestorable:!aIsPrivateBrowsing];
+ mWindow.restorable = !aIsPrivateBrowsing;
if (aIsPrivateBrowsing) {
[mWindow disableSnapshotRestoration];
}
// setup our notification delegate. Note that setDelegate: does NOT retain.
mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
- [mWindow setDelegate:mDelegate];
+ mWindow.delegate = mDelegate;
// Make sure that the content rect we gave has been honored.
NSRect wantedFrame = [mWindow frameRectForChildViewRect:contentRect];
- if (!NSEqualRects([mWindow frame], wantedFrame)) {
+ if (!NSEqualRects(mWindow.frame, wantedFrame)) {
// This can happen when the window is not on the primary screen.
[mWindow setFrame:wantedFrame display:NO];
}
UpdateBounds();
if (mWindowType == WindowType::Invisible) {
- [mWindow setLevel:kCGDesktopWindowLevelKey];
+ mWindow.level = kCGDesktopWindowLevelKey;
}
if (mWindowType == WindowType::Popup) {
SetPopupWindowLevel();
- [mWindow setBackgroundColor:NSColor.clearColor];
- [mWindow setOpaque:NO];
+ mWindow.backgroundColor = NSColor.clearColor;
+ mWindow.opaque = NO;
// When multiple spaces are in use and the browser is assigned to a
// particular space, override the "Assign To" space and display popups on
// the active space. Does not work with multiple displays. See
// NeedsRecreateToReshow() for multi-display with multi-space workaround.
- if (!mAlwaysOnTop) {
- NSWindowCollectionBehavior behavior = [mWindow collectionBehavior];
- behavior |= NSWindowCollectionBehaviorMoveToActiveSpace;
- [mWindow setCollectionBehavior:behavior];
- }
+ mWindow.collectionBehavior = mWindow.collectionBehavior |
+ NSWindowCollectionBehaviorMoveToActiveSpace;
} else {
// Non-popup windows are always opaque.
- [mWindow setOpaque:YES];
+ mWindow.opaque = YES;
}
- NSWindowCollectionBehavior newBehavior = [mWindow collectionBehavior];
- if (mAlwaysOnTop) {
- [mWindow setLevel:NSFloatingWindowLevel];
- newBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces;
+ if (mAlwaysOnTop || mIsAlert) {
+ mWindow.level = NSFloatingWindowLevel;
+ mWindow.collectionBehavior =
+ mWindow.collectionBehavior | NSWindowCollectionBehaviorCanJoinAllSpaces;
}
- [mWindow setCollectionBehavior:newBehavior];
-
- [mWindow setContentMinSize:NSMakeSize(60, 60)];
+ mWindow.contentMinSize = NSMakeSize(60, 60);
[mWindow disableCursorRects];
// Make the window use CoreAnimation from the start, so that we don't
// switch from a non-CA window to a CA-window in the middle.
- [[mWindow contentView] setWantsLayer:YES];
+ mWindow.contentView.wantsLayer = YES;
// Make sure the window starts out not draggable by the background.
// We will turn it on as necessary.
- [mWindow setMovableByWindowBackground:NO];
+ mWindow.movableByWindowBackground = NO;
- [[WindowDataMap sharedWindowDataMap] ensureDataForWindow:mWindow];
+ [WindowDataMap.sharedWindowDataMap ensureDataForWindow:mWindow];
mWindowMadeHere = true;
// Make the window respect the global appearance, which follows the
@@ -596,11 +594,11 @@ nsresult nsCocoaWindow::CreatePopupContentView(const LayoutDeviceIntRect& aRect,
return rv;
}
- NSView* contentView = [mWindow contentView];
- ChildView* childView =
- (ChildView*)mPopupContentView->GetNativeData(NS_NATIVE_WIDGET);
- [childView setFrame:[contentView bounds]];
- [childView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ NSView* contentView = mWindow.contentView;
+ auto* childView = static_cast<ChildView*>(
+ mPopupContentView->GetNativeData(NS_NATIVE_WIDGET));
+ childView.frame = contentView.bounds;
+ childView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[contentView addSubview:childView];
return NS_OK;
@@ -670,7 +668,7 @@ void* nsCocoaWindow::GetNativeData(uint32_t aDataType) {
// to emulate how windows works, we always have to return a NSView
// for NS_NATIVE_WIDGET
case NS_NATIVE_WIDGET:
- retVal = [mWindow contentView];
+ retVal = mWindow.contentView;
break;
case NS_NATIVE_WINDOW:
@@ -687,9 +685,9 @@ void* nsCocoaWindow::GetNativeData(uint32_t aDataType) {
if (retVal) {
break;
}
- NSView* view = mWindow ? [mWindow contentView] : nil;
+ NSView* view = mWindow ? mWindow.contentView : nil;
if (view) {
- retVal = [view inputContext];
+ retVal = view.inputContext;
}
// If inputContext isn't available on this window, return this window's
// pointer instead of nullptr since if this returns nullptr,
@@ -792,10 +790,11 @@ void nsCocoaWindow::SetModal(bool aState) {
gGeckoAppModalWindowList = gGeckoAppModalWindowList->prev;
delete saved; // "window" not ADDREFed
}
- if (mWindowType == WindowType::Popup)
+ if (mWindowType == WindowType::Popup) {
SetPopupWindowLevel();
- else
- [mWindow setLevel:NSNormalWindowLevel];
+ } else {
+ mWindow.level = NSNormalWindowLevel;
+ }
}
}
@@ -810,43 +809,44 @@ void nsCocoaWindow::SetFakeModal(bool aState) {
bool nsCocoaWindow::IsRunningAppModal() { return [NSApp _isRunningAppModal]; }
// Hide or show this window
-void nsCocoaWindow::Show(bool bState) {
+void nsCocoaWindow::Show(bool aState) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
- if (!mWindow) return;
+ if (!mWindow) {
+ return;
+ }
if (!mSheetNeedsShow) {
// Early exit if our current visibility state is already the requested
// state.
- if (bState == ([mWindow isVisible] || [mWindow isBeingShown])) {
+ if (aState == mWindow.isVisibleOrBeingShown) {
return;
}
}
- [mWindow setBeingShown:bState];
- if (bState && !mWasShown) {
+ [mWindow setBeingShown:aState];
+ if (aState && !mWasShown) {
mWasShown = true;
}
nsIWidget* parentWidget = mParent;
nsCOMPtr<nsPIWidgetCocoa> piParentWidget(do_QueryInterface(parentWidget));
NSWindow* nativeParentWindow =
- (parentWidget) ? (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW)
- : nil;
+ parentWidget ? (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW)
+ : nil;
- if (bState && !mBounds.IsEmpty()) {
+ if (aState && !mBounds.IsEmpty()) {
// If we had set the activationPolicy to accessory, then right now we won't
// have a dock icon. Make sure that we undo that and show a dock icon now
// that we're going to show a window.
- if ([NSApp activationPolicy] != NSApplicationActivationPolicyRegular) {
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+ if (NSApp.activationPolicy != NSApplicationActivationPolicyRegular) {
+ NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
PR_SetEnv("MOZ_APP_NO_DOCK=");
}
// Don't try to show a popup when the parent isn't visible or is minimized.
if (mWindowType == WindowType::Popup && nativeParentWindow) {
- if (![nativeParentWindow isVisible] ||
- [nativeParentWindow isMiniaturized]) {
+ if (!nativeParentWindow.isVisible || nativeParentWindow.isMiniaturized) {
return;
}
}
@@ -947,7 +947,7 @@ void nsCocoaWindow::Show(bool bState) {
// close other programs' context menus when ours open.
if ([mWindow isKindOfClass:[PopupWindow class]] &&
[(PopupWindow*)mWindow isContextMenu]) {
- [[NSDistributedNotificationCenter defaultCenter]
+ [NSDistributedNotificationCenter.defaultCenter
postNotificationName:
@"com.apple.HIToolbox.beginMenuTrackingNotification"
object:@"org.mozilla.gecko.PopupWindow"];
@@ -958,8 +958,9 @@ void nsCocoaWindow::Show(bool bState) {
// 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.
- if (nativeParentWindow && mPopupLevel == PopupLevel::Parent)
+ if (nativeParentWindow && mPopupLevel == PopupLevel::Parent) {
[nativeParentWindow addChildWindow:mWindow ordered:NSWindowAbove];
+ }
} else {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (mWindowType == WindowType::TopLevel &&
@@ -983,9 +984,9 @@ void nsCocoaWindow::Show(bool bState) {
mWindowAnimationBehavior = behavior;
}
- // We don't want alwaysontop windows to pull focus when they're opened,
- // as these tend to be for peripheral indicators and displays.
- if (mAlwaysOnTop) {
+ // We don't want alwaysontop / alert windows to pull focus when they're
+ // opened, as these tend to be for peripheral indicators and displays.
+ if (mAlwaysOnTop || mIsAlert) {
[mWindow orderFront:nil];
} else {
[mWindow makeKeyAndOrderFront:nil];
@@ -1099,8 +1100,9 @@ void nsCocoaWindow::Show(bool bState) {
// 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)
+ if (mWindowType == WindowType::Popup && nativeParentWindow) {
[nativeParentWindow removeChildWindow:mWindow];
+ }
[mWindow orderOut:nil];
@@ -1129,8 +1131,8 @@ void nsCocoaWindow::Show(bool bState) {
bool nsCocoaWindow::NeedsRecreateToReshow() {
// Limit the workaround to popup windows because only they need to override
// the "Assign To" setting. i.e., to display where the parent window is.
- return (mWindowType == WindowType::Popup) && mWasShown &&
- ([[NSScreen screens] count] > 1);
+ return mWindowType == WindowType::Popup && mWasShown &&
+ NSScreen.screens.count > 1;
}
WindowRenderer* nsCocoaWindow::GetWindowRenderer() {
@@ -1143,8 +1145,8 @@ WindowRenderer* nsCocoaWindow::GetWindowRenderer() {
TransparencyMode nsCocoaWindow::GetTransparencyMode() {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
- return (!mWindow || [mWindow isOpaque]) ? TransparencyMode::Opaque
- : TransparencyMode::Transparent;
+ return !mWindow || mWindow.isOpaque ? TransparencyMode::Opaque
+ : TransparencyMode::Transparent;
NS_OBJC_END_TRY_BLOCK_RETURN(TransparencyMode::Opaque);
}
@@ -1162,9 +1164,9 @@ void nsCocoaWindow::SetTransparencyMode(TransparencyMode aMode) {
if (isTransparent == currentTransparency) {
return;
}
- [mWindow setOpaque:!isTransparent];
- [mWindow setBackgroundColor:(isTransparent ? NSColor.clearColor
- : NSColor.whiteColor)];
+ mWindow.opaque = !isTransparent;
+ mWindow.backgroundColor =
+ isTransparent ? NSColor.clearColor : NSColor.whiteColor;
NS_OBJC_END_TRY_IGNORE_BLOCK;
}
@@ -1184,7 +1186,7 @@ void nsCocoaWindow::ConstrainPosition(DesktopIntPoint& aPoint) {
int32_t width, height;
- NSRect frame = [mWindow frame];
+ NSRect frame = mWindow.frame;
// zero size rects confuse the screen manager
width = std::max<int32_t>(frame.size.width, 1);
@@ -1243,7 +1245,7 @@ void nsCocoaWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
NSSize minSize = {
nsCocoaUtils::DevPixelsToCocoaPoints(c.mMinSize.width, c.mScale.scale),
nsCocoaUtils::DevPixelsToCocoaPoints(c.mMinSize.height, c.mScale.scale)};
- [mWindow setMinSize:minSize];
+ mWindow.minSize = minSize;
c.mMaxSize.width = std::max(
nsCocoaUtils::CocoaPointsToDevPixels(c.mMaxSize.width, c.mScale.scale),
@@ -1259,8 +1261,7 @@ void nsCocoaWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
c.mMaxSize.height == NS_MAXSIZE ? FLT_MAX
: nsCocoaUtils::DevPixelsToCocoaPoints(
c.mMaxSize.height, c.mScale.scale)};
- [mWindow setMaxSize:maxSize];
-
+ mWindow.maxSize = maxSize;
nsBaseWidget::SetSizeConstraints(c);
NS_OBJC_END_TRY_IGNORE_BLOCK;
@@ -1280,7 +1281,7 @@ void nsCocoaWindow::Move(double aX, double aY) {
static_cast<float>(aX),
static_cast<float>(nsCocoaUtils::FlippedScreenY(NSToIntRound(aY)))};
- NSRect frame = [mWindow frame];
+ NSRect frame = mWindow.frame;
if (frame.origin.x != coord.x ||
frame.origin.y + frame.size.height != coord.y) {
[mWindow setFrameTopLeftPoint:coord];
@@ -1488,13 +1489,9 @@ void nsCocoaWindow::MoveToWorkspace(const nsAString& workspaceIDStr) {
void nsCocoaWindow::SuppressAnimation(bool aSuppress) {
if ([mWindow respondsToSelector:@selector(setAnimationBehavior:)]) {
- if (aSuppress) {
- [mWindow setIsAnimationSuppressed:YES];
- [mWindow setAnimationBehavior:NSWindowAnimationBehaviorNone];
- } else {
- [mWindow setIsAnimationSuppressed:NO];
- [mWindow setAnimationBehavior:mWindowAnimationBehavior];
- }
+ mWindow.isAnimationSuppressed = aSuppress;
+ mWindow.animationBehavior =
+ aSuppress ? NSWindowAnimationBehaviorNone : mWindowAnimationBehavior;
}
}
@@ -1506,10 +1503,11 @@ void nsCocoaWindow::HideWindowChrome(bool aShouldHide) {
if (!mWindow || !mWindowMadeHere ||
(mWindowType != WindowType::TopLevel &&
- mWindowType != WindowType::Dialog))
+ mWindowType != WindowType::Dialog)) {
return;
+ }
- BOOL isVisible = [mWindow isVisible];
+ const BOOL isVisible = mWindow.isVisible;
// Remove child windows.
NSArray* childWindows = [mWindow childWindows];
@@ -1530,7 +1528,7 @@ void nsCocoaWindow::HideWindowChrome(bool aShouldHide) {
NSMutableDictionary* state = [mWindow exportState];
// Recreate the window with the right border style.
- NSRect frameRect = [mWindow frame];
+ NSRect frameRect = mWindow.frame;
DestroyNativeWindow();
nsresult rv = CreateNativeWindow(
frameRect, aShouldHide ? BorderStyle::None : mBorderStyle, true,
@@ -1629,7 +1627,7 @@ static bool AlwaysUsesNativeFullScreen() {
NSScreen* cocoaScreen = ScreenHelperCocoa::CocoaScreenForScreen(widgetScreen);
NSWindow* win =
- [[NSWindow alloc] initWithContentRect:[cocoaScreen frame]
+ [[NSWindow alloc] initWithContentRect:cocoaScreen.frame
styleMask:NSWindowStyleMaskBorderless
backing:NSBackingStoreBuffered
defer:YES];
@@ -2075,7 +2073,7 @@ void nsCocoaWindow::DoResize(double aX, double aY, double aWidth,
// convert requested bounds into Cocoa coordinate system
NSRect newFrame = nsCocoaUtils::GeckoRectToCocoaRect(newBounds);
- NSRect frame = [mWindow frame];
+ NSRect frame = mWindow.frame;
BOOL isMoving = newFrame.origin.x != frame.origin.x ||
newFrame.origin.y != frame.origin.y;
BOOL isResizing = newFrame.size.width != frame.size.width ||
@@ -2114,7 +2112,7 @@ NSRect nsCocoaWindow::GetClientCocoaRect() {
return NSZeroRect;
}
- return [mWindow childViewRectForFrameRect:[mWindow frame]];
+ return [mWindow childViewRectForFrameRect:mWindow.frame];
}
LayoutDeviceIntRect nsCocoaWindow::GetClientBounds() {
@@ -2130,7 +2128,7 @@ LayoutDeviceIntRect nsCocoaWindow::GetClientBounds() {
void nsCocoaWindow::UpdateBounds() {
NSRect frame = NSZeroRect;
if (mWindow) {
- frame = [mWindow frame];
+ frame = mWindow.frame;
}
mBounds =
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor());
@@ -2145,7 +2143,7 @@ LayoutDeviceIntRect nsCocoaWindow::GetScreenBounds() {
#ifdef DEBUG
LayoutDeviceIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
- [mWindow frame], BackingScaleFactor());
+ mWindow.frame, BackingScaleFactor());
NS_ASSERTION(mWindow && mBounds == r, "mBounds out of sync!");
#endif
@@ -2157,7 +2155,7 @@ LayoutDeviceIntRect nsCocoaWindow::GetScreenBounds() {
double nsCocoaWindow::GetDefaultScaleInternal() { return BackingScaleFactor(); }
static CGFloat GetBackingScaleFactor(NSWindow* aWindow) {
- NSRect frame = [aWindow frame];
+ NSRect frame = aWindow.frame;
if (frame.size.width > 0 && frame.size.height > 0) {
return nsCocoaUtils::GetBackingScaleFactor(aWindow);
}
@@ -2220,6 +2218,7 @@ void nsCocoaWindow::BackingScaleFactorChanged() {
}
mBackingScaleFactor = newScale;
+ NotifyAPZOfDPIChange();
if (!mWidgetListener || mWidgetListener->GetAppWindow()) {
return;
@@ -2255,7 +2254,7 @@ nsresult nsCocoaWindow::SetTitle(const nsAString& aTitle) {
const unichar* uniTitle = reinterpret_cast<const unichar*>(strTitle.get());
NSString* title = [NSString stringWithCharacters:uniTitle
length:strTitle.Length()];
- if ([mWindow drawsContentsIntoWindowFrame] && ![mWindow wantsTitleDrawn]) {
+ if (mWindow.drawsContentsIntoWindowFrame && !mWindow.wantsTitleDrawn) {
// Don't cause invalidations when the title isn't displayed.
[mWindow disableSetNeedsDisplay];
[mWindow setTitle:title];
@@ -2291,9 +2290,10 @@ bool nsCocoaWindow::DragEvent(unsigned int aMessage,
NS_IMETHODIMP nsCocoaWindow::SendSetZLevelEvent() {
nsWindowZ placement = nsWindowZTop;
nsCOMPtr<nsIWidget> actualBelow;
- if (mWidgetListener)
+ if (mWidgetListener) {
mWidgetListener->ZLevelChanged(true, &placement, nullptr,
getter_AddRefs(actualBelow));
+ }
return NS_OK;
}
@@ -2344,8 +2344,9 @@ nsresult nsCocoaWindow::DispatchEvent(WidgetGUIEvent* event,
nsCOMPtr<nsIWidget> kungFuDeathGrip(event->mWidget);
mozilla::Unused << kungFuDeathGrip; // Not used within this function
- if (mWidgetListener)
+ if (mWidgetListener) {
aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents);
+ }
return NS_OK;
}
@@ -2355,10 +2356,15 @@ nsresult nsCocoaWindow::DispatchEvent(WidgetGUIEvent* event,
// canonical indicator that a window is currently full screen and it makes sense
// to keep all sizemode logic here.
static nsSizeMode GetWindowSizeMode(NSWindow* aWindow, bool aFullScreen) {
- if (aFullScreen) return nsSizeMode_Fullscreen;
- if ([aWindow isMiniaturized]) return nsSizeMode_Minimized;
- if (([aWindow styleMask] & NSWindowStyleMaskResizable) && [aWindow isZoomed])
+ if (aFullScreen) {
+ return nsSizeMode_Fullscreen;
+ }
+ if (aWindow.isMiniaturized) {
+ return nsSizeMode_Minimized;
+ }
+ if ((aWindow.styleMask & NSWindowStyleMaskResizable) && aWindow.isZoomed) {
return nsSizeMode_Maximized;
+ }
return nsSizeMode_Normal;
}
@@ -2379,7 +2385,7 @@ void nsCocoaWindow::ReportMoveEvent() {
// The zoomed state can change when we're moving, in which case we need to
// update our internal mSizeMode. This can happen either if we're maximized
// and then moved, or if we're not maximized and moved back to zoomed state.
- if (mWindow && ((mSizeMode == nsSizeMode_Maximized) ^ [mWindow isZoomed])) {
+ if (mWindow && (mSizeMode == nsSizeMode_Maximized) ^ mWindow.isZoomed) {
DispatchSizeModeEvent();
}
@@ -2462,8 +2468,9 @@ void nsCocoaWindow::SetMenuBar(RefPtr<nsMenuBarX>&& aMenuBar) {
// displayed when the app starts up.
if (mMenuBar && ((!gSomeMenuBarPainted &&
nsMenuUtilsX::GetHiddenWindowMenuBar() == mMenuBar) ||
- [mWindow isMainWindow]))
+ mWindow.isMainWindow)) {
mMenuBar->Paint();
+ }
}
void nsCocoaWindow::SetFocus(Raise aRaise,
@@ -2474,12 +2481,10 @@ void nsCocoaWindow::SetFocus(Raise aRaise,
return mPopupContentView->SetFocus(aRaise, aCallerType);
}
- if (aRaise == Raise::Yes &&
- ([mWindow isVisible] || [mWindow isMiniaturized])) {
- if ([mWindow isMiniaturized]) {
+ if (aRaise == Raise::Yes && (mWindow.isVisible || mWindow.isMiniaturized)) {
+ if (mWindow.isMiniaturized) {
[mWindow deminiaturize:nil];
}
-
[mWindow makeKeyAndOrderFront:nil];
SendSetZLevelEvent();
}
@@ -2533,7 +2538,7 @@ void nsCocoaWindow::CaptureRollupEvents(bool aDoCapture) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (aDoCapture) {
- if (![NSApp isActive]) {
+ if (!NSApp.isActive) {
// We need to capture mouse event if we aren't
// the active application. We only set this up when needed
// because they cause spurious mouse event after crash
@@ -2553,14 +2558,17 @@ void nsCocoaWindow::CaptureRollupEvents(bool aDoCapture) {
// So here we fiddle with a non-native popup window's level to make sure the
// "active" one is always above any other non-native popup windows that
// may be visible.
- if (mWindow && (mWindowType == WindowType::Popup)) SetPopupWindowLevel();
+ if (mWindowType == WindowType::Popup) {
+ SetPopupWindowLevel();
+ }
} else {
nsToolkit::GetToolkit()->StopMonitoringAllProcessMouseEvents();
// XXXndeakin this doesn't make sense.
// Why is the new window assumed to be a modal panel?
- if (mWindow && (mWindowType == WindowType::Popup))
- [mWindow setLevel:NSModalPanelWindowLevel];
+ if (mWindow && mWindowType == WindowType::Popup) {
+ mWindow.level = NSModalPanelWindowLevel;
+ }
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
@@ -2644,7 +2652,7 @@ void nsCocoaWindow::SetWindowTransform(const gfx::Matrix& aTransform) {
// Calling CGSSetWindowTransform when the window is not visible results in
// misplacing the window into doubled x,y coordinates (see bug 1448132).
- if (![mWindow isVisible] || NSIsEmptyRect([mWindow frame])) {
+ if (!mWindow.isVisible || NSIsEmptyRect(mWindow.frame)) {
return;
}
@@ -2753,13 +2761,9 @@ void nsCocoaWindow::SetWindowAnimationType(
void nsCocoaWindow::SetDrawsTitle(bool aDrawTitle) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
- if (![mWindow drawsContentsIntoWindowFrame]) {
- // If we don't draw into the window frame, we always want to display window
- // titles.
- [mWindow setWantsTitleDrawn:YES];
- } else {
- [mWindow setWantsTitleDrawn:aDrawTitle];
- }
+ // If we don't draw into the window frame, we always want to display window
+ // titles.
+ mWindow.wantsTitleDrawn = aDrawTitle || !mWindow.drawsContentsIntoWindowFrame;
NS_OBJC_END_TRY_IGNORE_BLOCK;
}
@@ -2853,19 +2857,13 @@ void nsCocoaWindow::UpdateThemeGeometries(
}
void nsCocoaWindow::SetPopupWindowLevel() {
- if (!mWindow) return;
-
- // Floating popups are at the floating level and hide when the window is
- // deactivated.
- if (mPopupLevel == PopupLevel::Floating) {
- [mWindow setLevel:NSFloatingWindowLevel];
- [mWindow setHidesOnDeactivate:YES];
- } else {
- // Otherwise, this is a top-level or parent popup. Parent popups always
- // appear just above their parent and essentially ignore the level.
- [mWindow setLevel:NSPopUpMenuWindowLevel];
- [mWindow setHidesOnDeactivate:NO];
+ if (!mWindow) {
+ return;
}
+ // Otherwise, this is a top-level or parent popup. Parent popups always
+ // appear just above their parent and essentially ignore the level.
+ mWindow.level = NSPopUpMenuWindowLevel;
+ mWindow.hidesOnDeactivate = NO;
}
void nsCocoaWindow::SetInputContext(const InputContext& aContext,
@@ -2897,7 +2895,7 @@ bool nsCocoaWindow::GetEditCommands(NativeKeyBindingsType aType,
void nsCocoaWindow::PauseOrResumeCompositor(bool aPause) {
if (auto* mainChildView =
- static_cast<nsIWidget*>([[mWindow mainChildView] widget])) {
+ static_cast<nsIWidget*>(mWindow.mainChildView.widget)) {
mainChildView->PauseOrResumeCompositor(aPause);
}
}
@@ -2951,16 +2949,17 @@ already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
nsCocoaWindow* geckoWidget = [windowDelegate geckoWidget];
NS_ASSERTION(geckoWidget, "Window delegate not returning a gecko widget!");
- nsMenuBarX* geckoMenuBar = geckoWidget->GetMenuBar();
- if (geckoMenuBar) {
+ if (nsMenuBarX* geckoMenuBar = geckoWidget->GetMenuBar()) {
geckoMenuBar->Paint();
} else {
// sometimes we don't have a native application menu early in launching
- if (!sApplicationMenu) return;
+ if (!sApplicationMenu) {
+ return;
+ }
- NSMenu* mainMenu = [NSApp mainMenu];
+ NSMenu* mainMenu = NSApp.mainMenu;
NS_ASSERTION(
- [mainMenu numberOfItems] > 0,
+ mainMenu.numberOfItems > 0,
"Main menu does not have any items, something is terribly wrong!");
// Create a new menu bar.
@@ -2976,7 +2975,7 @@ already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
[firstMenuItem release];
// set our new menu bar as the main menu
- [NSApp setMainMenu:newMenuBar];
+ NSApp.mainMenu = newMenuBar;
[newMenuBar release];
}
@@ -3097,8 +3096,8 @@ void nsCocoaWindow::CocoaWindowDidResize() {
// in fullscreen mode. In Safari they're not transparent. But in Firefox
// for some reason they are, which causes bug 1069658. The following code
// works around this Apple bug or design flaw.
- NSWindow* window = (NSWindow*)[notification object];
- NSView* frameView = [[window contentView] superview];
+ NSWindow* window = notification.object;
+ NSView* frameView = window.contentView.superview;
NSView* titlebarView = nil;
NSView* titlebarContainerView = nil;
if ([frameView respondsToSelector:@selector(titlebarView)]) {
@@ -3142,9 +3141,13 @@ void nsCocoaWindow::CocoaWindowDidResize() {
// [NSApp _isRunningAppModal] will return true if we're running an OS dialog
// app modally. If one of those is up then we want it to retain its menu bar.
- if ([NSApp _isRunningAppModal]) return;
- NSWindow* window = [aNotification object];
- if (window) [WindowDelegate paintMenubarForWindow:window];
+ if (NSApp._isRunningAppModal) {
+ return;
+ }
+ NSWindow* window = aNotification.object;
+ if (window) {
+ [WindowDelegate paintMenubarForWindow:window];
+ }
if ([window isKindOfClass:[ToolbarWindow class]]) {
[(ToolbarWindow*)window windowMainStateChanged];
@@ -3254,8 +3257,9 @@ void nsCocoaWindow::CocoaWindowDidResize() {
}
- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)proposedFrame {
- if (!mHasEverBeenZoomed && [window isZoomed]) return NO; // See bug 429954.
-
+ if (!mHasEverBeenZoomed && window.isZoomed) {
+ return NO; // See bug 429954.
+ }
mHasEverBeenZoomed = YES;
return YES;
}
@@ -3298,7 +3302,7 @@ void nsCocoaWindow::CocoaWindowDidResize() {
if ([window respondsToSelector:@selector(backingScaleFactor)]) {
CGFloat oldFactor = [[[aNotification userInfo]
objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
- if ([window backingScaleFactor] != oldFactor) {
+ if (window.backingScaleFactor != oldFactor) {
mGeckoWindow->BackingScaleFactorChanged();
}
}
@@ -3349,7 +3353,7 @@ void nsCocoaWindow::CocoaWindowDidResize() {
if (![self.window isKindOfClass:[ToolbarWindow class]]) {
return self.FrameView__closeButtonOrigin;
}
- ToolbarWindow* win = (ToolbarWindow*)[self window];
+ auto* win = static_cast<ToolbarWindow*>(self.window);
if (win.drawsContentsIntoWindowFrame &&
!(win.styleMask & NSWindowStyleMaskFullScreen) &&
(win.styleMask & NSWindowStyleMaskTitled)) {
@@ -3360,8 +3364,9 @@ void nsCocoaWindow::CocoaWindowDidResize() {
// for the vertical coordinate will move the buttons above the window,
// making them invisible.
return NSMakePoint(buttonsRect.origin.x, win.frame.size.height);
- } else if (win.windowTitlebarLayoutDirection ==
- NSUserInterfaceLayoutDirectionRightToLeft) {
+ }
+ if (win.windowTitlebarLayoutDirection ==
+ NSUserInterfaceLayoutDirectionRightToLeft) {
// We're in RTL mode, which means that the close button is the rightmost
// button of the three window buttons. and buttonsRect.origin is the
// bottom left corner of the green (zoom) button. The close button is 40px
@@ -3375,13 +3380,14 @@ void nsCocoaWindow::CocoaWindowDidResize() {
}
- (CGFloat)FrameView__titlebarHeight {
+ // XXX: Shouldn't this be [super FrameView__titlebarHeight]?
CGFloat height = [self FrameView__titlebarHeight];
- if ([[self window] isKindOfClass:[ToolbarWindow class]]) {
+ if ([self.window isKindOfClass:[ToolbarWindow class]]) {
// Make sure that the titlebar height includes our shifted buttons.
// The following coordinates are in window space, with the origin being at
// the bottom left corner of the window.
- ToolbarWindow* win = (ToolbarWindow*)[self window];
- CGFloat frameHeight = [self frame].size.height;
+ auto* win = static_cast<ToolbarWindow*>(self.window);
+ CGFloat frameHeight = self.frame.size.height;
CGFloat windowButtonY = frameHeight;
if (!NSIsEmptyRect(win.windowButtonsRect) &&
win.drawsContentsIntoWindowFrame &&
@@ -3506,8 +3512,8 @@ static NSImage* GetMenuMaskImage() {
}
- (void)swapOutChildViewWrapper:(NSView*)aNewWrapper {
- [aNewWrapper setFrame:[[self contentView] frame]];
- NSView* childView = [[self mainChildView] retain];
+ aNewWrapper.frame = self.contentView.frame;
+ NSView* childView = [self.mainChildView retain];
[childView removeFromSuperview];
[aNewWrapper addSubview:childView];
[childView release];
@@ -3603,16 +3609,16 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
- (NSMutableDictionary*)exportState {
NSMutableDictionary* state = [NSMutableDictionary dictionaryWithCapacity:10];
- if (NSString* title = [self title]) {
+ if (NSString* title = self.title) {
[state setObject:title forKey:kStateTitleKey];
}
- [state setObject:[NSNumber numberWithBool:[self drawsContentsIntoWindowFrame]]
+ [state setObject:[NSNumber numberWithBool:self.drawsContentsIntoWindowFrame]
forKey:kStateDrawsContentsIntoWindowFrameKey];
- [state setObject:[NSNumber numberWithBool:[self showsToolbarButton]]
+ [state setObject:[NSNumber numberWithBool:self.showsToolbarButton]
forKey:kStateShowsToolbarButton];
- [state setObject:[NSNumber numberWithUnsignedInt:[self collectionBehavior]]
+ [state setObject:[NSNumber numberWithUnsignedInt:self.collectionBehavior]
forKey:kStateCollectionBehavior];
- [state setObject:[NSNumber numberWithBool:[self wantsTitleDrawn]]
+ [state setObject:[NSNumber numberWithBool:self.wantsTitleDrawn]
forKey:kStateWantsTitleDrawn];
return state;
}
@@ -3667,17 +3673,17 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
}
- (NSView*)trackingAreaView {
- NSView* contentView = [self contentView];
- return [contentView superview] ? [contentView superview] : contentView;
+ NSView* contentView = self.contentView;
+ return contentView.superview ? contentView.superview : contentView;
}
- (NSArray<NSView*>*)contentViewContents {
- return [[[[self contentView] subviews] copy] autorelease];
+ return [[self.contentView.subviews copy] autorelease];
}
- (ChildView*)mainChildView {
- NSView* contentView = [self contentView];
- NSView* lastView = [[contentView subviews] lastObject];
+ NSView* contentView = self.contentView;
+ NSView* lastView = contentView.subviews.lastObject;
if ([lastView isKindOfClass:[ChildView class]]) {
return (ChildView*)lastView;
}
@@ -3686,7 +3692,7 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
- (void)removeTrackingArea {
if (mTrackingArea) {
- [[self trackingAreaView] removeTrackingArea:mTrackingArea];
+ [self.trackingAreaView removeTrackingArea:mTrackingArea];
[mTrackingArea release];
mTrackingArea = nil;
}
@@ -3695,7 +3701,7 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
- (void)updateTrackingArea {
[self removeTrackingArea];
- NSView* view = [self trackingAreaView];
+ NSView* view = self.trackingAreaView;
const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingActiveAlways;
@@ -3741,7 +3747,7 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
// Possibly move the titlebar buttons.
- (void)reflowTitlebarElements {
- NSView* frameView = [[self contentView] superview];
+ NSView* frameView = self.contentView.superview;
if ([frameView respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) {
[frameView _tileTitlebarAndRedisplay:NO];
}
@@ -3852,15 +3858,15 @@ static const NSString* kStateWantsTitleDrawn = @"wantsTitleDrawn";
}
- (void)mouseUp:(NSEvent*)event {
- if ([event clickCount] == 2) {
+ 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];
+ [self.window performZoom:nil];
} else if (nsCocoaUtils::ShouldMinimizeOnTitlebarDoubleClick()) {
- [[self window] performMiniaturize:nil];
+ [self.window performMiniaturize:nil];
}
}
}
@@ -4094,8 +4100,7 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
}
- (NSArray<NSView*>*)contentViewContents {
- NSMutableArray<NSView*>* contents =
- [[[self contentView] subviews] mutableCopy];
+ NSMutableArray<NSView*>* contents = [[self.contentView subviews] mutableCopy];
if (mTitlebarView) {
// Do not include the titlebar gradient view in the returned array.
[contents removeObject:mTitlebarView];
@@ -4105,16 +4110,16 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
- (void)updateTitlebarView {
BOOL needTitlebarView =
- ![self drawsContentsIntoWindowFrame] || mUnifiedToolbarHeight > 0;
+ !self.drawsContentsIntoWindowFrame || mUnifiedToolbarHeight > 0;
if (needTitlebarView && !mTitlebarView) {
mTitlebarView =
- [[MOZTitlebarView alloc] initWithFrame:[self unifiedToolbarRect]];
+ [[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];
+ mTitlebarView.frame = self.unifiedToolbarRect;
} else if (!needTitlebarView && mTitlebarView) {
[mTitlebarView removeFromSuperview];
[mTitlebarView release];
@@ -4132,15 +4137,15 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
}
- (NSRect)titlebarRect {
- CGFloat titlebarHeight = [self titlebarHeight];
- return NSMakeRect(0, [self frame].size.height - titlebarHeight,
- [self frame].size.width, titlebarHeight);
+ 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);
+ return NSMakeRect(0, self.frame.size.height - mUnifiedToolbarHeight,
+ self.frame.size.width, mUnifiedToolbarHeight);
}
// Returns the unified height of titlebar + toolbar.
@@ -4152,8 +4157,8 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
// 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];
+ NSRect frameRect = self.frame;
+ NSUInteger styleMask = self.styleMask;
styleMask &= ~NSWindowStyleMaskFullSizeContentView;
NSRect originalContentRect = [NSWindow contentRectForFrameRect:frameRect
styleMask:styleMask];
@@ -4172,16 +4177,15 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
// Extending the content area into the title bar works by resizing the
// mainChildView so that it covers the titlebar.
- (void)setDrawsContentsIntoWindowFrame:(BOOL)aState {
- BOOL stateChanged = ([self drawsContentsIntoWindowFrame] != aState);
+ BOOL stateChanged = self.drawsContentsIntoWindowFrame != aState;
[super setDrawsContentsIntoWindowFrame:aState];
- if (stateChanged && [[self delegate] isKindOfClass:[WindowDelegate class]]) {
+ if (stateChanged && [self.delegate isKindOfClass:[WindowDelegate class]]) {
// Here we extend / shrink our mainChildView. We do that by firing a resize
// event which will cause the ChildView to be resized to the rect returned
// by nsCocoaWindow::GetClientBounds. GetClientBounds bases its return
// value on what we return from drawsContentsIntoWindowFrame.
- WindowDelegate* windowDelegate = (WindowDelegate*)[self delegate];
- nsCocoaWindow* geckoWindow = [windowDelegate geckoWidget];
- if (geckoWindow) {
+ auto* windowDelegate = static_cast<WindowDelegate*>(self.delegate);
+ if (nsCocoaWindow* geckoWindow = windowDelegate.geckoWidget) {
// Re-layout our contents.
geckoWindow->ReportSizeEvent();
}
@@ -4233,13 +4237,16 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
RollUpPopups();
- if ([[self delegate] isKindOfClass:[WindowDelegate class]]) {
- WindowDelegate* windowDelegate = (WindowDelegate*)[self delegate];
- nsCocoaWindow* geckoWindow = [windowDelegate geckoWidget];
- if (!geckoWindow) return;
+ if ([self.delegate isKindOfClass:[WindowDelegate class]]) {
+ auto* windowDelegate = static_cast<WindowDelegate*>(self.delegate);
+ nsCocoaWindow* geckoWindow = windowDelegate.geckoWidget;
+ if (!geckoWindow) {
+ return;
+ }
- nsIWidgetListener* listener = geckoWindow->GetWidgetListener();
- if (listener) listener->OSToolbarButtonPressed();
+ if (nsIWidgetListener* listener = geckoWindow->GetWidgetListener()) {
+ listener->OSToolbarButtonPressed();
+ }
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
@@ -4278,14 +4285,17 @@ static bool ShouldShiftByMenubarHeightInFullscreen(nsCocoaWindow* aWindow) {
// 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];
+ id delegate = self.delegate;
if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) {
nsCocoaWindow* widget = [(WindowDelegate*)delegate geckoWidget];
if (widget) {
if (gGeckoAppModalWindowList &&
- (widget != gGeckoAppModalWindowList->window))
+ widget != gGeckoAppModalWindowList->window) {
+ return;
+ }
+ if (widget->HasModalDescendents()) {
return;
- if (widget->HasModalDescendents()) return;
+ }
}
}
break;
@@ -4410,14 +4420,17 @@ static const NSUInteger kWindowShadowOptionsTooltip = 4;
// 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];
+ id delegate = self.delegate;
if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) {
nsCocoaWindow* widget = [(WindowDelegate*)delegate geckoWidget];
if (widget) {
if (gGeckoAppModalWindowList &&
- (widget != gGeckoAppModalWindowList->window))
+ widget != gGeckoAppModalWindowList->window) {
return;
- if (widget->HasModalDescendents()) return;
+ }
+ if (widget->HasModalDescendents()) {
+ return;
+ }
}
}
break;
@@ -4436,8 +4449,7 @@ static const NSUInteger kWindowShadowOptionsTooltip = 4;
- (BOOL)canBecomeMainWindow {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
- if (![self isVisible]) return NO;
- return YES;
+ return self.isVisible;
NS_OBJC_END_TRY_BLOCK_RETURN(NO);
}
diff --git a/widget/cocoa/nsCursorManager.mm b/widget/cocoa/nsCursorManager.mm
index 2db20681ad..11a37f59b7 100644
--- a/widget/cocoa/nsCursorManager.mm
+++ b/widget/cocoa/nsCursorManager.mm
@@ -304,19 +304,17 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
return NS_ERROR_FAILURE;
}
+ const NSSize cocoaSize = NSMakeSize(size.width, size.height);
NSImage* cursorImage;
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(
aCursor.mContainer, imgIContainer::FRAME_FIRST, nullptr, nullptr,
- &cursorImage, scaleFactor);
+ cocoaSize, &cursorImage, scaleFactor);
if (NS_FAILED(rv) || !cursorImage) {
return NS_ERROR_FAILURE;
}
- {
- NSSize cocoaSize = NSMakeSize(size.width, size.height);
- [cursorImage setSize:cocoaSize];
- [[[cursorImage representations] objectAtIndex:0] setSize:cocoaSize];
- }
+ [cursorImage setSize:cocoaSize];
+ [[[cursorImage representations] objectAtIndex:0] setSize:cocoaSize];
// if the hotspot is nonsensical, make it 0,0
uint32_t hotspotX =
diff --git a/widget/cocoa/nsLookAndFeel.mm b/widget/cocoa/nsLookAndFeel.mm
index 73fd6b689c..5675198ff2 100644
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -366,9 +366,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::SubmenuDelay:
aResult = 200;
break;
- case IntID::TooltipDelay:
- aResult = 500;
- break;
case IntID::MenusCanOverlapOSBar:
// xul popups are not allowed to overlap the menubar.
aResult = 0;
diff --git a/widget/cocoa/nsMacSharingService.mm b/widget/cocoa/nsMacSharingService.mm
index 694617ba65..c8509af00f 100644
--- a/widget/cocoa/nsMacSharingService.mm
+++ b/widget/cocoa/nsMacSharingService.mm
@@ -98,7 +98,7 @@ static NSString* NSImageToBase64(const NSImage* aImage) {
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj,
const char* aKey, NSString* aVal) {
nsAutoString strVal;
- mozilla::CopyCocoaStringToXPCOMString(aVal, strVal);
+ mozilla::CopyNSStringToXPCOMString(aVal, strVal);
JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get()));
JS::Rooted<JS::Value> attVal(aCx, JS::StringValue(title));
JS_SetProperty(aCx, aObj, aKey, attVal);
diff --git a/widget/gtk/DBusMenu.cpp b/widget/gtk/DBusMenu.cpp
new file mode 100644
index 0000000000..8672de40ef
--- /dev/null
+++ b/widget/gtk/DBusMenu.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
+/* 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 "DBusMenu.h"
+#include "prlink.h"
+#include "nsThreadUtils.h"
+#include "mozilla/ArrayUtils.h"
+
+namespace mozilla::widget {
+
+#define FUNC(name, type, params) \
+ DBusMenuFunctions::_##name##_fn DBusMenuFunctions::s_##name;
+DBUSMENU_GLIB_FUNCTIONS
+DBUSMENU_GTK_FUNCTIONS
+#undef FUNC
+
+static PRLibrary* gDbusmenuGlib = nullptr;
+static PRLibrary* gDbusmenuGtk = nullptr;
+
+using DBusMenuFunc = void (*)();
+struct DBusMenuDynamicFunction {
+ const char* functionName;
+ DBusMenuFunc* function;
+};
+
+static bool sInitialized;
+static bool sLibPresent;
+
+/* static */ bool DBusMenuFunctions::Init() {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (sInitialized) {
+ return sLibPresent;
+ }
+ sInitialized = true;
+#define FUNC(name, type, params) \
+ {#name, (DBusMenuFunc*)&DBusMenuFunctions::s_##name},
+ static const DBusMenuDynamicFunction kDbusmenuGlibSymbols[] = {
+ DBUSMENU_GLIB_FUNCTIONS};
+ static const DBusMenuDynamicFunction kDbusmenuGtkSymbols[] = {
+ DBUSMENU_GTK_FUNCTIONS};
+
+#define LOAD_LIBRARY(symbol, name) \
+ if (!g##symbol) { \
+ g##symbol = PR_LoadLibrary(name); \
+ if (!g##symbol) { \
+ return false; \
+ } \
+ } \
+ for (uint32_t i = 0; i < mozilla::ArrayLength(k##symbol##Symbols); ++i) { \
+ *k##symbol##Symbols[i].function = \
+ PR_FindFunctionSymbol(g##symbol, k##symbol##Symbols[i].functionName); \
+ if (!*k##symbol##Symbols[i].function) { \
+ return false; \
+ } \
+ }
+
+ LOAD_LIBRARY(DbusmenuGlib, "libdbusmenu-glib.so.4")
+ LOAD_LIBRARY(DbusmenuGtk, "libdbusmenu-gtk3.so.4")
+#undef LOAD_LIBRARY
+
+ sLibPresent = true;
+ return true;
+}
+
+} // namespace mozilla::widget
diff --git a/widget/gtk/DBusMenu.h b/widget/gtk/DBusMenu.h
new file mode 100644
index 0000000000..d288d02322
--- /dev/null
+++ b/widget/gtk/DBusMenu.h
@@ -0,0 +1,137 @@
+/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
+/* 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/. */
+
+#ifndef mozilla_widget_DBusMenu_h
+#define mozilla_widget_DBusMenu_h
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+namespace mozilla {
+
+namespace dom {
+class Element;
+}
+
+namespace widget {
+
+#define DBUSMENU_GLIB_FUNCTIONS \
+ FUNC(dbusmenu_menuitem_child_add_position, gboolean, \
+ (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position)) \
+ FUNC(dbusmenu_menuitem_set_root, void, \
+ (DbusmenuMenuitem * mi, gboolean root)) \
+ FUNC(dbusmenu_menuitem_child_append, gboolean, \
+ (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)) \
+ FUNC(dbusmenu_menuitem_child_delete, gboolean, \
+ (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)) \
+ FUNC(dbusmenu_menuitem_get_children, GList*, (DbusmenuMenuitem * mi)) \
+ FUNC(dbusmenu_menuitem_new, DbusmenuMenuitem*, (void)) \
+ FUNC(dbusmenu_menuitem_property_get, const gchar*, \
+ (DbusmenuMenuitem * mi, const gchar* property)) \
+ FUNC(dbusmenu_menuitem_property_get_bool, gboolean, \
+ (DbusmenuMenuitem * mi, const gchar* property)) \
+ FUNC(dbusmenu_menuitem_property_remove, void, \
+ (DbusmenuMenuitem * mi, const gchar* property)) \
+ FUNC(dbusmenu_menuitem_property_set, gboolean, \
+ (DbusmenuMenuitem * mi, const gchar* property, const gchar* value)) \
+ FUNC(dbusmenu_menuitem_property_set_bool, gboolean, \
+ (DbusmenuMenuitem * mi, const gchar* property, const gboolean value)) \
+ FUNC(dbusmenu_menuitem_property_set_int, gboolean, \
+ (DbusmenuMenuitem * mi, const gchar* property, const gint value)) \
+ FUNC(dbusmenu_menuitem_show_to_user, void, \
+ (DbusmenuMenuitem * mi, guint timestamp)) \
+ FUNC(dbusmenu_menuitem_take_children, GList*, (DbusmenuMenuitem * mi)) \
+ FUNC(dbusmenu_server_new, DbusmenuServer*, (const gchar* object)) \
+ FUNC(dbusmenu_server_set_root, void, \
+ (DbusmenuServer * server, DbusmenuMenuitem * root)) \
+ FUNC(dbusmenu_server_set_status, void, \
+ (DbusmenuServer * server, DbusmenuStatus status))
+
+#define DBUSMENU_GTK_FUNCTIONS \
+ FUNC(dbusmenu_menuitem_property_set_image, gboolean, \
+ (DbusmenuMenuitem * menuitem, const gchar* property, \
+ const GdkPixbuf* data)) \
+ FUNC(dbusmenu_menuitem_property_set_shortcut, gboolean, \
+ (DbusmenuMenuitem * menuitem, guint key, GdkModifierType modifier))
+
+typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
+typedef struct _DbusmenuServer DbusmenuServer;
+
+enum DbusmenuStatus { DBUSMENU_STATUS_NORMAL, DBUSMENU_STATUS_NOTICE };
+
+#define DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU "submenu"
+#define DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY "children-display"
+#define DBUSMENU_MENUITEM_PROP_ENABLED "enabled"
+#define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
+#define DBUSMENU_MENUITEM_PROP_LABEL "label"
+#define DBUSMENU_MENUITEM_PROP_SHORTCUT "shortcut"
+#define DBUSMENU_MENUITEM_PROP_TYPE "type"
+#define DBUSMENU_MENUITEM_PROP_TOGGLE_STATE "toggle-state"
+#define DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE "toggle-type"
+#define DBUSMENU_MENUITEM_PROP_VISIBLE "visible"
+#define DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW "about-to-show"
+#define DBUSMENU_MENUITEM_SIGNAL_EVENT "event"
+#define DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED "item-activated"
+#define DBUSMENU_MENUITEM_TOGGLE_CHECK "checkmark"
+#define DBUSMENU_MENUITEM_TOGGLE_RADIO "radio"
+#define DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED 1
+#define DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED 0
+#define DBUSMENU_SERVER_PROP_DBUS_OBJECT "dbus-object"
+
+class DBusMenuFunctions {
+ public:
+ DBusMenuFunctions() = delete;
+
+ static bool Init();
+
+#define FUNC(name, type, params) \
+ typedef type(*_##name##_fn) params; \
+ static _##name##_fn s_##name;
+ DBUSMENU_GLIB_FUNCTIONS
+ DBUSMENU_GTK_FUNCTIONS
+#undef FUNC
+};
+
+#define dbusmenu_menuitem_set_root \
+ DBusMenuFunctions::s_dbusmenu_menuitem_set_root
+#define dbusmenu_menuitem_child_add_position \
+ DBusMenuFunctions::s_dbusmenu_menuitem_child_add_position
+#define dbusmenu_menuitem_child_append \
+ DBusMenuFunctions::s_dbusmenu_menuitem_child_append
+#define dbusmenu_menuitem_child_delete \
+ DBusMenuFunctions::s_dbusmenu_menuitem_child_delete
+#define dbusmenu_menuitem_get_children \
+ DBusMenuFunctions::s_dbusmenu_menuitem_get_children
+#define dbusmenu_menuitem_new DBusMenuFunctions::s_dbusmenu_menuitem_new
+#define dbusmenu_menuitem_property_get \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_get
+#define dbusmenu_menuitem_property_get_bool \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_get_bool
+#define dbusmenu_menuitem_property_remove \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_remove
+#define dbusmenu_menuitem_property_set \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_set
+#define dbusmenu_menuitem_property_set_bool \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_set_bool
+#define dbusmenu_menuitem_property_set_int \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_set_int
+#define dbusmenu_menuitem_show_to_user \
+ DBusMenuFunctions::s_dbusmenu_menuitem_show_to_user
+#define dbusmenu_menuitem_take_children \
+ DBusMenuFunctions::s_dbusmenu_menuitem_take_children
+#define dbusmenu_server_new DBusMenuFunctions::s_dbusmenu_server_new
+#define dbusmenu_server_set_root DBusMenuFunctions::s_dbusmenu_server_set_root
+#define dbusmenu_server_set_status \
+ DBusMenuFunctions::s_dbusmenu_server_set_status
+
+#define dbusmenu_menuitem_property_set_image \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_set_image
+#define dbusmenu_menuitem_property_set_shortcut \
+ DBusMenuFunctions::s_dbusmenu_menuitem_property_set_shortcut
+
+} // namespace widget
+} // namespace mozilla
+
+#endif
diff --git a/widget/gtk/GRefPtr.h b/widget/gtk/GRefPtr.h
index 1970008811..071164c06f 100644
--- a/widget/gtk/GRefPtr.h
+++ b/widget/gtk/GRefPtr.h
@@ -13,6 +13,9 @@
#include <gtk/gtk.h>
#include "mozilla/RefPtr.h"
+typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
+typedef struct _DbusmenuServer DbusmenuServer;
+
namespace mozilla {
template <typename T>
@@ -25,6 +28,8 @@ struct GObjectRefPtrTraits {
template <> \
struct RefPtrTraits<type_> : public GObjectRefPtrTraits<type_> {};
+GOBJECT_TRAITS(DbusmenuMenuitem)
+GOBJECT_TRAITS(DbusmenuServer)
GOBJECT_TRAITS(GtkWidget)
GOBJECT_TRAITS(GFile)
GOBJECT_TRAITS(GFileMonitor)
diff --git a/widget/gtk/GfxInfo.cpp b/widget/gtk/GfxInfo.cpp
index 4dadbc81b5..457b2c72ce 100644
--- a/widget/gtk/GfxInfo.cpp
+++ b/widget/gtk/GfxInfo.cpp
@@ -75,17 +75,17 @@ nsresult GfxInfo::Init() {
}
void GfxInfo::AddCrashReportAnnotations() {
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
- mVendorId);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
- mDeviceId);
- CrashReporter::AnnotateCrashReport(
+ CrashReporter::RecordAnnotationNSCString(
+ CrashReporter::Annotation::AdapterVendorID, mVendorId);
+ CrashReporter::RecordAnnotationNSCString(
+ CrashReporter::Annotation::AdapterDeviceID, mDeviceId);
+ CrashReporter::RecordAnnotationNSCString(
CrashReporter::Annotation::AdapterDriverVendor, mDriverVendor);
- CrashReporter::AnnotateCrashReport(
+ CrashReporter::RecordAnnotationNSCString(
CrashReporter::Annotation::AdapterDriverVersion, mDriverVersion);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IsWayland,
- mIsWayland);
- CrashReporter::AnnotateCrashReport(
+ CrashReporter::RecordAnnotationBool(CrashReporter::Annotation::IsWayland,
+ mIsWayland);
+ CrashReporter::RecordAnnotationNSCString(
CrashReporter::Annotation::DesktopEnvironment,
GetDesktopEnvironmentIdentifier());
diff --git a/widget/gtk/GtkCompositorWidget.cpp b/widget/gtk/GtkCompositorWidget.cpp
index a3443b9828..36559cfd54 100644
--- a/widget/gtk/GtkCompositorWidget.cpp
+++ b/widget/gtk/GtkCompositorWidget.cpp
@@ -39,11 +39,11 @@ GtkCompositorWidget::GtkCompositorWidget(
"GtkCompositorWidget::mClientSize") {
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
- mXWindow = (Window)aInitData.XWindow();
- ConfigureX11Backend(mXWindow, aInitData.Shaped());
+ ConfigureX11Backend((Window)aInitData.XWindow(), aInitData.Shaped());
LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p "
"mIsRenderingSuspended %d\n",
- (void*)mWidget.get(), (void*)mXWindow, !!mIsRenderingSuspended);
+ (void*)mWidget.get(), (void*)aInitData.XWindow(),
+ !!mIsRenderingSuspended);
}
#endif
#if defined(MOZ_WAYLAND)
@@ -123,8 +123,8 @@ EGLNativeWindowType GtkCompositorWidget::GetEGLNativeWindow() {
window = (EGLNativeWindowType)mWidget->GetNativeData(NS_NATIVE_EGL_WINDOW);
}
#if defined(MOZ_X11)
- if (mXWindow) {
- window = (EGLNativeWindowType)mXWindow;
+ else {
+ window = (EGLNativeWindowType)mProvider.GetXWindow();
}
#endif
LOG("GtkCompositorWidget::GetEGLNativeWindow [%p] window %p\n", mWidget.get(),
@@ -173,9 +173,6 @@ void GtkCompositorWidget::DisableRendering() {
LOG("GtkCompositorWidget::DisableRendering [%p]\n", (void*)mWidget.get());
mIsRenderingSuspended = true;
mProvider.CleanupResources();
-#if defined(MOZ_X11)
- mXWindow = {};
-#endif
}
#if defined(MOZ_WAYLAND)
@@ -187,27 +184,13 @@ bool GtkCompositorWidget::ConfigureWaylandBackend() {
#if defined(MOZ_X11)
bool GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
- mXWindow = aXWindow;
-
// We don't have X window yet.
- if (!mXWindow) {
+ if (!aXWindow) {
mIsRenderingSuspended = true;
return false;
}
-
- // Grab the window's visual and depth
- XWindowAttributes windowAttrs;
- if (!XGetWindowAttributes(DefaultXDisplay(), mXWindow, &windowAttrs)) {
- NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
- return false;
- }
-
- Visual* visual = windowAttrs.visual;
- int depth = windowAttrs.depth;
-
// Initialize the window surface provider
- mProvider.Initialize(mXWindow, visual, depth, aShaped);
- return true;
+ return mProvider.Initialize(aXWindow, aShaped);
}
#endif
diff --git a/widget/gtk/GtkCompositorWidget.h b/widget/gtk/GtkCompositorWidget.h
index 5bf89835d7..bde88bde6c 100644
--- a/widget/gtk/GtkCompositorWidget.h
+++ b/widget/gtk/GtkCompositorWidget.h
@@ -84,7 +84,7 @@ class GtkCompositorWidget : public CompositorWidget,
bool SetEGLNativeWindowSize(const LayoutDeviceIntSize& aEGLWindowSize);
#if defined(MOZ_X11)
- Window XWindow() const { return mXWindow; }
+ Window XWindow() const { return mProvider.GetXWindow(); }
#endif
#if defined(MOZ_WAYLAND)
RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() override;
@@ -123,11 +123,9 @@ class GtkCompositorWidget : public CompositorWidget,
// of the two.
DataMutex<LayoutDeviceIntSize> mClientSize;
+ // Holds rendering resources
WindowSurfaceProvider mProvider;
-#if defined(MOZ_X11)
- Window mXWindow = {};
-#endif
#ifdef MOZ_WAYLAND
RefPtr<mozilla::layers::NativeLayerRootWayland> mNativeLayerRoot;
#endif
diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp
index fc87acbf86..2e438bbc5c 100644
--- a/widget/gtk/IMContextWrapper.cpp
+++ b/widget/gtk/IMContextWrapper.cpp
@@ -232,11 +232,18 @@ class SelectionStyleProvider final {
sHasShutDown = true;
}
- // mContainer associated with an IM context.
- void AttachTo(MozContainer* aContainer) {
- gtk_style_context_add_provider(
- gtk_widget_get_style_context(GTK_WIDGET(aContainer)),
- GTK_STYLE_PROVIDER(mProvider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ // aGDKWindow is a GTK window which will be associated with an IM context.
+ void AttachTo(GdkWindow* aGDKWindow) {
+ GtkWidget* widget = nullptr;
+ // gdk_window_get_user_data() typically returns pointer to widget that
+ // window belongs to. If it's widget, fcitx retrieves selection colors
+ // of them. So, we need to overwrite its style.
+ gdk_window_get_user_data(aGDKWindow, (gpointer*)&widget);
+ if (GTK_IS_WIDGET(widget)) {
+ gtk_style_context_add_provider(gtk_widget_get_style_context(widget),
+ GTK_STYLE_PROVIDER(mProvider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
}
void OnThemeChanged() {
@@ -410,17 +417,21 @@ nsDependentCSubstring IMContextWrapper::GetIMName() const {
}
void IMContextWrapper::Init() {
+ MozContainer* container = mOwnerWindow->GetMozContainer();
+ MOZ_ASSERT(container, "container is null");
+ GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(container));
+
// Overwrite selection colors of the window before associating the window
// with IM context since IME may look up selection colors via IM context
// to support any colored widgets.
- SelectionStyleProvider::GetInstance()->AttachTo(
- mOwnerWindow->GetMozContainer());
+ SelectionStyleProvider::GetInstance()->AttachTo(gdkWindow);
// NOTE: gtk_im_*_new() abort (kill) the whole process when it fails.
// So, we don't need to check the result.
// Normal context.
mContext = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(mContext, gdkWindow);
g_signal_connect(mContext, "preedit_changed",
G_CALLBACK(IMContextWrapper::OnChangeCompositionCallback),
this);
@@ -492,6 +503,7 @@ void IMContextWrapper::Init() {
// Simple context
if (sUseSimpleContext) {
mSimpleContext = gtk_im_context_simple_new();
+ gtk_im_context_set_client_window(mSimpleContext, gdkWindow);
g_signal_connect(mSimpleContext, "preedit_changed",
G_CALLBACK(&IMContextWrapper::OnChangeCompositionCallback),
this);
@@ -514,6 +526,7 @@ void IMContextWrapper::Init() {
// Dummy context
mDummyContext = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(mDummyContext, gdkWindow);
MOZ_LOG(gIMELog, LogLevel::Info,
("0x%p Init(), mOwnerWindow=%p, mContext=%p (im=\"%s\"), "
@@ -540,17 +553,6 @@ IMContextWrapper::~IMContextWrapper() {
MOZ_LOG(gIMELog, LogLevel::Info, ("0x%p ~IMContextWrapper()", this));
}
-void IMContextWrapper::SetGdkWindow(GdkWindow* aGdkWindow) {
- MOZ_LOG(gIMELog, LogLevel::Info,
- ("0x%p GdkWindowChanged(%p)", this, aGdkWindow));
- MOZ_ASSERT(!aGdkWindow || mOwnerWindow->GetGdkWindow() == aGdkWindow);
- gtk_im_context_set_client_window(mContext, aGdkWindow);
- if (mSimpleContext) {
- gtk_im_context_set_client_window(mSimpleContext, aGdkWindow);
- }
- gtk_im_context_set_client_window(mDummyContext, aGdkWindow);
-}
-
NS_IMETHODIMP
IMContextWrapper::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) {
diff --git a/widget/gtk/IMContextWrapper.h b/widget/gtk/IMContextWrapper.h
index 213c5ce8d3..cf1d2638e0 100644
--- a/widget/gtk/IMContextWrapper.h
+++ b/widget/gtk/IMContextWrapper.h
@@ -117,10 +117,6 @@ class IMContextWrapper final : public TextEventDispatcherListener {
void OnUpdateComposition();
void OnLayoutChange();
- // Set GdkWindow associated with IM context.
- // It can be null which disables context operations.
- void SetGdkWindow(GdkWindow* aGdkWindow);
-
TextEventDispatcher* GetTextEventDispatcher();
// TODO: Typically, new IM comes every several years. And now, our code
diff --git a/widget/gtk/MozContainer.cpp b/widget/gtk/MozContainer.cpp
index 95d32b57b4..775ae0488f 100644
--- a/widget/gtk/MozContainer.cpp
+++ b/widget/gtk/MozContainer.cpp
@@ -35,27 +35,6 @@ static void moz_container_size_allocate(GtkWidget* widget,
static void moz_container_realize(GtkWidget* widget);
static void moz_container_unrealize(GtkWidget* widget);
-/* container class methods */
-static void moz_container_remove(GtkContainer* container,
- GtkWidget* child_widget);
-static void moz_container_forall(GtkContainer* container,
- gboolean include_internals,
- GtkCallback callback, gpointer callback_data);
-static void moz_container_add(GtkContainer* container, GtkWidget* widget);
-
-typedef struct _MozContainerChild MozContainerChild;
-
-struct _MozContainerChild {
- GtkWidget* widget;
- gint x;
- gint y;
-};
-
-static void moz_container_allocate_child(MozContainer* container,
- MozContainerChild* child);
-static MozContainerChild* moz_container_get_child(MozContainer* container,
- GtkWidget* child);
-
/* public methods */
GType moz_container_get_type(void) {
@@ -92,26 +71,6 @@ GtkWidget* moz_container_new(void) {
return GTK_WIDGET(container);
}
-void moz_container_put(MozContainer* container, GtkWidget* child_widget, gint x,
- gint y) {
- MozContainerChild* child;
-
- child = g_new(MozContainerChild, 1);
-
- child->widget = child_widget;
- child->x = x;
- child->y = y;
-
- /* printf("moz_container_put %p %p %d %d\n", (void *)container,
- (void *)child_widget, x, y); */
-
- container->data.children = g_list_append(container->data.children, child);
-
- /* we assume that the caller of this function will have already set
- the parent GdkWindow because we can have many anonymous children. */
- gtk_widget_set_parent(child_widget, GTK_WIDGET(container));
-}
-
static void moz_container_destroy(GtkWidget* widget) {
auto* container = MOZ_CONTAINER(widget);
if (container->destroyed) {
@@ -126,7 +85,6 @@ static void moz_container_destroy(GtkWidget* widget) {
void moz_container_class_init(MozContainerClass* klass) {
/*GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
- GtkContainerClass* container_class = GTK_CONTAINER_CLASS(klass);
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->realize = moz_container_realize;
@@ -147,10 +105,6 @@ void moz_container_class_init(MozContainerClass* klass) {
#ifdef MOZ_WAYLAND
}
#endif
-
- container_class->remove = moz_container_remove;
- container_class->forall = moz_container_forall;
- container_class->add = moz_container_add;
}
void moz_container_init(MozContainer* container) {
@@ -164,8 +118,6 @@ void moz_container_init(MozContainer* container) {
void moz_container_map(GtkWidget* widget) {
MozContainer* container;
- GList* tmp_list;
- GtkWidget* tmp_child;
g_return_if_fail(IS_MOZ_CONTAINER(widget));
container = MOZ_CONTAINER(widget);
@@ -175,16 +127,6 @@ void moz_container_map(GtkWidget* widget) {
gtk_widget_set_mapped(widget, TRUE);
- tmp_list = container->data.children;
- while (tmp_list) {
- tmp_child = ((MozContainerChild*)tmp_list->data)->widget;
-
- if (gtk_widget_get_visible(tmp_child)) {
- if (!gtk_widget_get_mapped(tmp_child)) gtk_widget_map(tmp_child);
- }
- tmp_list = tmp_list->next;
- }
-
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
}
@@ -257,8 +199,6 @@ void moz_container_unrealize(GtkWidget* widget) {
}
void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) {
- MozContainer* container;
- GList* tmp_list;
GtkAllocation tmp_allocation;
g_return_if_fail(IS_MOZ_CONTAINER(widget));
@@ -269,10 +209,8 @@ void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) {
allocation->height));
/* short circuit if you can */
- container = MOZ_CONTAINER(widget);
gtk_widget_get_allocation(widget, &tmp_allocation);
- if (!container->data.children && tmp_allocation.x == allocation->x &&
- tmp_allocation.y == allocation->y &&
+ if (tmp_allocation.x == allocation->x && tmp_allocation.y == allocation->y &&
tmp_allocation.width == allocation->width &&
tmp_allocation.height == allocation->height) {
return;
@@ -280,16 +218,6 @@ void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) {
gtk_widget_set_allocation(widget, allocation);
- tmp_list = container->data.children;
-
- while (tmp_list) {
- MozContainerChild* child = static_cast<MozContainerChild*>(tmp_list->data);
-
- moz_container_allocate_child(container, child);
-
- tmp_list = tmp_list->next;
- }
-
if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
allocation->y, allocation->width,
@@ -297,99 +225,6 @@ void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) {
}
}
-void moz_container_remove(GtkContainer* container, GtkWidget* child_widget) {
- MozContainerChild* child;
- MozContainer* moz_container;
- GdkWindow* parent_window;
-
- g_return_if_fail(IS_MOZ_CONTAINER(container));
- g_return_if_fail(GTK_IS_WIDGET(child_widget));
-
- moz_container = MOZ_CONTAINER(container);
-
- child = moz_container_get_child(moz_container, child_widget);
- g_return_if_fail(child);
-
- /* gtk_widget_unparent will remove the parent window (as well as the
- * parent widget), but, in Mozilla's window hierarchy, the parent window
- * may need to be kept because it may be part of a GdkWindow sub-hierarchy
- * that is being moved to another MozContainer.
- *
- * (In a conventional GtkWidget hierarchy, GdkWindows being reparented
- * would have their own GtkWidget and that widget would be the one being
- * reparented. In Mozilla's hierarchy, the parent_window needs to be
- * retained so that the GdkWindow sub-hierarchy is maintained.)
- */
- parent_window = gtk_widget_get_parent_window(child_widget);
- if (parent_window) g_object_ref(parent_window);
-
- gtk_widget_unparent(child_widget);
-
- if (parent_window) {
- /* The child_widget will always still exist because g_signal_emit,
- * which invokes this function, holds a reference.
- *
- * If parent_window is the container's root window then it will not be
- * the parent_window if the child_widget is placed in another
- * container.
- */
- if (parent_window != gtk_widget_get_window(GTK_WIDGET(container))) {
- gtk_widget_set_parent_window(child_widget, parent_window);
- }
-
- g_object_unref(parent_window);
- }
-
- moz_container->data.children =
- g_list_remove(moz_container->data.children, child);
- g_free(child);
-}
-
-void moz_container_forall(GtkContainer* container, gboolean include_internals,
- GtkCallback callback, gpointer callback_data) {
- g_return_if_fail(IS_MOZ_CONTAINER(container));
- g_return_if_fail(callback);
-
- MozContainer* moz_container = MOZ_CONTAINER(container);
-
- GList* tmp_list = moz_container->data.children;
- while (tmp_list) {
- MozContainerChild* child;
- child = static_cast<MozContainerChild*>(tmp_list->data);
- tmp_list = tmp_list->next;
- (*callback)(child->widget, callback_data);
- }
-}
-
-static void moz_container_allocate_child(MozContainer* container,
- MozContainerChild* child) {
- GtkAllocation allocation;
-
- gtk_widget_get_allocation(child->widget, &allocation);
- allocation.x = child->x;
- allocation.y = child->y;
-
- gtk_widget_size_allocate(child->widget, &allocation);
-}
-
-MozContainerChild* moz_container_get_child(MozContainer* container,
- GtkWidget* child_widget) {
- GList* tmp_list = container->data.children;
- while (tmp_list) {
- MozContainerChild* child;
-
- child = static_cast<MozContainerChild*>(tmp_list->data);
- tmp_list = tmp_list->next;
-
- if (child->widget == child_widget) return child;
- }
- return nullptr;
-}
-
-static void moz_container_add(GtkContainer* container, GtkWidget* widget) {
- moz_container_put(MOZ_CONTAINER(container), widget, 0, 0);
-}
-
void moz_container_force_default_visual(MozContainer* container) {
container->data.force_default_visual = true;
}
diff --git a/widget/gtk/MozContainer.h b/widget/gtk/MozContainer.h
index 27fa2a701f..e6f9b4e992 100644
--- a/widget/gtk/MozContainer.h
+++ b/widget/gtk/MozContainer.h
@@ -18,35 +18,12 @@
/*
* MozContainer
*
- * This class serves three purposes in the nsIWidget implementation.
+ * This class serves two purposes in the nsIWidget implementation.
*
* - It provides objects to receive signals from GTK for events on native
* windows.
*
- * - It provides GdkWindow to draw content on Wayland or when Gtk+ renders
- * client side decorations to mShell.
- *
- * - It provides a container parent for GtkWidgets. The only GtkWidgets
- * that need this in Mozilla are the GtkSockets for windowed plugins (Xt
- * and XEmbed).
- *
- * Note that the window hierarchy in Mozilla differs from conventional
- * GtkWidget hierarchies.
- *
- * Mozilla's hierarchy exists through the GdkWindow hierarchy, and all child
- * GdkWindows (within a child nsIWidget hierarchy) belong to one MozContainer
- * GtkWidget. If the MozContainer is unrealized or its GdkWindows are
- * destroyed for some other reason, then the hierarchy no longer exists. (In
- * conventional GTK clients, the hierarchy is recorded by the GtkWidgets, and
- * so can be re-established after destruction of the GdkWindows.)
- *
- * One consequence of this is that the MozContainer does not know which of its
- * GdkWindows should parent child GtkWidgets. (Conventional GtkContainers
- * determine which GdkWindow to assign child GtkWidgets.)
- *
- * Therefore, when adding a child GtkWidget to a MozContainer,
- * gtk_widget_set_parent_window should be called on the child GtkWidget before
- * it is realized.
+ * - It provides GdkWindow to draw content.
*/
#define MOZ_CONTAINER_TYPE (moz_container_get_type())
@@ -71,7 +48,6 @@ struct _MozContainer {
GtkContainer container;
gboolean destroyed;
struct Data {
- GList* children = nullptr;
gboolean force_default_visual = false;
#ifdef MOZ_WAYLAND
MozContainerWayland wl_container;
diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp
index 0e50a3f27c..8490f25599 100644
--- a/widget/gtk/MozContainerWayland.cpp
+++ b/widget/gtk/MozContainerWayland.cpp
@@ -436,7 +436,6 @@ void moz_container_wayland_map(GtkWidget* widget) {
void moz_container_wayland_size_allocate(GtkWidget* widget,
GtkAllocation* allocation) {
- MozContainer* container;
GtkAllocation tmp_allocation;
g_return_if_fail(IS_MOZ_CONTAINER(widget));
@@ -447,10 +446,8 @@ void moz_container_wayland_size_allocate(GtkWidget* widget,
allocation->height);
/* short circuit if you can */
- container = MOZ_CONTAINER(widget);
gtk_widget_get_allocation(widget, &tmp_allocation);
- if (!container->data.children && tmp_allocation.x == allocation->x &&
- tmp_allocation.y == allocation->y &&
+ if (tmp_allocation.x == allocation->x && tmp_allocation.y == allocation->y &&
tmp_allocation.width == allocation->width &&
tmp_allocation.height == allocation->height) {
return;
@@ -464,6 +461,7 @@ void moz_container_wayland_size_allocate(GtkWidget* widget,
// We need to position our subsurface according to GdkWindow
// when offset changes (GdkWindow is maximized for instance).
// see gtk-clutter-embed.c for reference.
+ MozContainer* container = MOZ_CONTAINER(widget);
MutexAutoLock lock(container->data.wl_container.container_lock);
if (!container->data.wl_container.surface) {
if (!moz_container_wayland_surface_create_locked(lock, container)) {
diff --git a/widget/gtk/NativeMenuGtk.cpp b/widget/gtk/NativeMenuGtk.cpp
index 9d413d475e..3f8aeb1940 100644
--- a/widget/gtk/NativeMenuGtk.cpp
+++ b/widget/gtk/NativeMenuGtk.cpp
@@ -4,6 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NativeMenuGtk.h"
+#include "AsyncDBus.h"
+#include "gdk/gdkkeysyms-compat.h"
+#include "mozilla/BasicEvents.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/XULCommandEvent.h"
@@ -15,6 +18,10 @@
#include "nsStubMutationObserver.h"
#include "mozilla/dom/Element.h"
#include "mozilla/StaticPrefs_widget.h"
+#include "DBusMenu.h"
+#include "nsLayoutUtils.h"
+#include "nsGtkUtils.h"
+#include "nsGtkKeyUtils.h"
#include <dlfcn.h>
#include <gtk/gtk.h>
@@ -35,7 +42,8 @@ static bool IsDisabled(const dom::Element& aElement) {
}
static bool NodeIsRelevant(const nsINode& aNode) {
return aNode.IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menuseparator,
- nsGkAtoms::menuitem, nsGkAtoms::menugroup);
+ nsGkAtoms::menuitem, nsGkAtoms::menugroup,
+ nsGkAtoms::menubar);
}
// If this is a radio / checkbox menuitem, get the current value.
@@ -155,7 +163,7 @@ void Actions::Clear() {
mNextActionIndex = 0;
}
-class MenuModel final : public nsStubMutationObserver {
+class MenuModel : public nsStubMutationObserver {
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
@@ -166,41 +174,60 @@ class MenuModel final : public nsStubMutationObserver {
public:
explicit MenuModel(dom::Element* aElement) : mElement(aElement) {
mElement->AddMutationObserver(this);
- mGMenu = dont_AddRef(g_menu_new());
- mActions.mGroup = dont_AddRef(g_simple_action_group_new());
- }
-
- GMenuModel* GetModel() { return G_MENU_MODEL(mGMenu.get()); }
- GActionGroup* GetActionGroup() {
- return G_ACTION_GROUP(mActions.mGroup.get());
}
dom::Element* Element() { return mElement; }
- void RecomputeModelIfNeeded();
+ void RecomputeModelIfNeeded() {
+ if (!mDirty) {
+ return;
+ }
+ RecomputeModel();
+ mDirty = false;
+ }
- bool IsShowing() { return mPoppedUp; }
+ bool IsShowing() { return mShowing; }
void WillShow() {
- mPoppedUp = true;
+ mShowing = true;
RecomputeModelIfNeeded();
}
- void DidHide() { mPoppedUp = false; }
+ void DidHide() { mShowing = false; }
- private:
+ protected:
+ virtual void RecomputeModel() = 0;
virtual ~MenuModel() { mElement->RemoveMutationObserver(this); }
void DirtyModel() {
mDirty = true;
- if (mPoppedUp) {
+ if (mShowing) {
RecomputeModelIfNeeded();
}
}
RefPtr<dom::Element> mElement;
+ bool mDirty = true;
+ bool mShowing = false;
+};
+
+class MenuModelGMenu final : public MenuModel {
+ public:
+ explicit MenuModelGMenu(dom::Element* aElement) : MenuModel(aElement) {
+ mGMenu = dont_AddRef(g_menu_new());
+ mActions.mGroup = dont_AddRef(g_simple_action_group_new());
+ }
+
+ GMenuModel* GetModel() { return G_MENU_MODEL(mGMenu.get()); }
+ GActionGroup* GetActionGroup() {
+ return G_ACTION_GROUP(mActions.mGroup.get());
+ }
+
+ protected:
+ void RecomputeModel() override;
+ static void RecomputeModelFor(GMenu* aMenu, Actions& aActions,
+ const dom::Element& aElement);
+
RefPtr<GMenu> mGMenu;
Actions mActions;
- bool mDirty = true;
- bool mPoppedUp = false;
};
NS_IMPL_ISUPPORTS(MenuModel, nsIMutationObserver)
@@ -243,8 +270,8 @@ static const dom::Element* GetMenuPopupChild(const dom::Element& aElement) {
return nullptr;
}
-static void RecomputeModelFor(GMenu* aMenu, Actions& aActions,
- const dom::Element& aElement) {
+void MenuModelGMenu::RecomputeModelFor(GMenu* aMenu, Actions& aActions,
+ const dom::Element& aElement) {
RefPtr<GMenu> sectionMenu;
auto FlushSectionMenu = [&] {
if (sectionMenu) {
@@ -305,10 +332,7 @@ static void RecomputeModelFor(GMenu* aMenu, Actions& aActions,
FlushSectionMenu();
}
-void MenuModel::RecomputeModelIfNeeded() {
- if (!mDirty) {
- return;
- }
+void MenuModelGMenu::RecomputeModel() {
mActions.Clear();
g_menu_remove_all(mGMenu.get());
RecomputeModelFor(mGMenu.get(), mActions, *mElement);
@@ -341,7 +365,7 @@ METHOD_SIGNAL(Unmap);
#undef METHOD_SIGNAL
NativeMenuGtk::NativeMenuGtk(dom::Element* aElement)
- : mMenuModel(MakeRefPtr<MenuModel>(aElement)) {
+ : mMenuModel(MakeRefPtr<MenuModelGMenu>(aElement)) {
// Floating, so no need to dont_AddRef.
mNativeMenu = gtk_menu_new_from_model(mMenuModel->GetModel());
gtk_widget_insert_action_group(mNativeMenu.get(), "menu",
@@ -421,4 +445,383 @@ void NativeMenuGtk::CloseSubmenu(dom::Element*) {
// TODO: For testing mostly.
}
+#ifdef MOZ_ENABLE_DBUS
+
+class MenubarModelDBus final : public MenuModel {
+ public:
+ explicit MenubarModelDBus(dom::Element* aElement) : MenuModel(aElement) {
+ mRoot = dont_AddRef(dbusmenu_menuitem_new());
+ dbusmenu_menuitem_set_root(mRoot.get(), true);
+ mShowing = true;
+ }
+
+ DbusmenuMenuitem* Root() const { return mRoot.get(); }
+
+ protected:
+ void RecomputeModel() override;
+ static void AppendMenuItem(DbusmenuMenuitem* aParent,
+ const dom::Element* aElement);
+ static void AppendSeparator(DbusmenuMenuitem* aParent);
+ static void AppendSubmenu(DbusmenuMenuitem* aParent,
+ const dom::Element* aMenu,
+ const dom::Element* aPopup);
+ static uint RecomputeModelFor(DbusmenuMenuitem* aParent,
+ const dom::Element& aElement);
+
+ RefPtr<DbusmenuMenuitem> mRoot;
+};
+
+void MenubarModelDBus::RecomputeModel() {
+ while (GList* children = dbusmenu_menuitem_get_children(mRoot.get())) {
+ auto* first = static_cast<DbusmenuMenuitem*>(children->data);
+ if (!first) {
+ break;
+ }
+ dbusmenu_menuitem_child_delete(mRoot.get(), first);
+ }
+ RecomputeModelFor(mRoot, *Element());
+}
+
+static const dom::Element* RelevantElementForKeys(
+ const dom::Element* aElement) {
+ nsAutoString key;
+ aElement->GetAttr(nsGkAtoms::key, key);
+ if (!key.IsEmpty()) {
+ dom::Document* document = aElement->OwnerDoc();
+ dom::Element* element = document->GetElementById(key);
+ if (element) {
+ return element;
+ }
+ }
+ return aElement;
+}
+
+static uint32_t ParseKey(const nsAString& aKey, const nsAString& aKeyCode) {
+ guint key = 0;
+ if (!aKey.IsEmpty()) {
+ key = gdk_unicode_to_keyval(*aKey.BeginReading());
+ }
+
+ if (key == 0 && !aKeyCode.IsEmpty()) {
+ key = KeymapWrapper::ConvertGeckoKeyCodeToGDKKeyval(aKeyCode);
+ }
+
+ return key;
+}
+
+static uint32_t KeyFrom(const dom::Element* aElement) {
+ const auto* element = RelevantElementForKeys(aElement);
+
+ nsAutoString key;
+ nsAutoString keycode;
+ element->GetAttr(nsGkAtoms::key, key);
+ element->GetAttr(nsGkAtoms::keycode, keycode);
+
+ return ParseKey(key, keycode);
+}
+
+// TODO(emilio): Unify with nsMenuUtilsX::GeckoModifiersForNodeAttribute (or
+// at least switch to strtok_r).
+static uint32_t ParseModifiers(const nsAString& aModifiers) {
+ if (aModifiers.IsEmpty()) {
+ return 0;
+ }
+
+ uint32_t modifier = 0;
+ char* str = ToNewUTF8String(aModifiers);
+ char* token = strtok(str, ", \t");
+ while (token) {
+ if (nsCRT::strcmp(token, "shift") == 0) {
+ modifier |= GDK_SHIFT_MASK;
+ } else if (nsCRT::strcmp(token, "alt") == 0) {
+ modifier |= GDK_MOD1_MASK;
+ } else if (nsCRT::strcmp(token, "meta") == 0) {
+ modifier |= GDK_META_MASK;
+ } else if (nsCRT::strcmp(token, "control") == 0) {
+ modifier |= GDK_CONTROL_MASK;
+ } else if (nsCRT::strcmp(token, "accel") == 0) {
+ auto accel = WidgetInputEvent::AccelModifier();
+ if (accel == MODIFIER_META) {
+ modifier |= GDK_META_MASK;
+ } else if (accel == MODIFIER_ALT) {
+ modifier |= GDK_MOD1_MASK;
+ } else if (accel == MODIFIER_CONTROL) {
+ modifier |= GDK_CONTROL_MASK;
+ }
+ }
+
+ token = strtok(nullptr, ", \t");
+ }
+
+ free(str);
+
+ return modifier;
+}
+
+static uint32_t ModifiersFrom(const dom::Element* aContent) {
+ const auto* element = RelevantElementForKeys(aContent);
+
+ nsAutoString modifiers;
+ element->GetAttr(nsGkAtoms::modifiers, modifiers);
+
+ return ParseModifiers(modifiers);
+}
+
+static void UpdateAccel(DbusmenuMenuitem* aItem, const nsIContent* aContent) {
+ uint32_t key = KeyFrom(aContent->AsElement());
+ if (key != 0) {
+ dbusmenu_menuitem_property_set_shortcut(
+ aItem, key,
+ static_cast<GdkModifierType>(ModifiersFrom(aContent->AsElement())));
+ }
+}
+
+static void UpdateRadioOrCheck(DbusmenuMenuitem* aItem,
+ const dom::Element* aContent) {
+ static mozilla::dom::Element::AttrValuesArray attrs[] = {
+ nsGkAtoms::checkbox, nsGkAtoms::radio, nullptr};
+ int32_t type = aContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
+ attrs, eCaseMatters);
+
+ if (type < 0 || type >= 2) {
+ return;
+ }
+
+ if (type == 0) {
+ dbusmenu_menuitem_property_set(aItem, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ DBUSMENU_MENUITEM_TOGGLE_CHECK);
+ } else {
+ dbusmenu_menuitem_property_set(aItem, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
+ DBUSMENU_MENUITEM_TOGGLE_RADIO);
+ }
+
+ bool isChecked = aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
+ nsGkAtoms::_true, eCaseMatters);
+ dbusmenu_menuitem_property_set_int(
+ aItem, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ isChecked ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED
+ : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+}
+
+static void UpdateEnabled(DbusmenuMenuitem* aItem, const nsIContent* aContent) {
+ bool disabled = aContent->AsElement()->AttrValueIs(
+ kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
+
+ dbusmenu_menuitem_property_set_bool(aItem, DBUSMENU_MENUITEM_PROP_ENABLED,
+ !disabled);
+}
+
+// we rebuild the dbus model when elements are removed from the DOM,
+// so this isn't going to trigger for asynchronous
+static MOZ_CAN_RUN_SCRIPT void DBusActivationCallback(
+ DbusmenuMenuitem* aMenuitem, guint aTimestamp, gpointer aUserData) {
+ RefPtr element = static_cast<dom::Element*>(aUserData);
+ ActivateItem(*element);
+}
+
+static void ConnectActivated(DbusmenuMenuitem* aItem,
+ const dom::Element* aContent) {
+ g_signal_connect(G_OBJECT(aItem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK(DBusActivationCallback),
+ const_cast<dom::Element*>(aContent));
+}
+
+static MOZ_CAN_RUN_SCRIPT void DBusAboutToShowCallback(
+ DbusmenuMenuitem* aMenuitem, gpointer aUserData) {
+ RefPtr element = static_cast<dom::Element*>(aUserData);
+ FireEvent(element, eXULPopupShowing);
+ FireEvent(element, eXULPopupShown);
+}
+
+static void ConnectAboutToShow(DbusmenuMenuitem* aItem,
+ const dom::Element* aContent) {
+ g_signal_connect(G_OBJECT(aItem), DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
+ G_CALLBACK(DBusAboutToShowCallback),
+ const_cast<dom::Element*>(aContent));
+}
+
+void MenubarModelDBus::AppendMenuItem(DbusmenuMenuitem* aParent,
+ const dom::Element* aChild) {
+ nsAutoString label;
+ aChild->GetAttr(nsGkAtoms::label, label);
+ if (label.IsEmpty()) {
+ aChild->GetAttr(nsGkAtoms::aria_label, label);
+ }
+ RefPtr<DbusmenuMenuitem> child = dont_AddRef(dbusmenu_menuitem_new());
+ dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL,
+ NS_ConvertUTF16toUTF8(label).get());
+ dbusmenu_menuitem_child_append(aParent, child);
+ UpdateAccel(child, aChild);
+ UpdateRadioOrCheck(child, aChild);
+ UpdateEnabled(child, aChild);
+ ConnectActivated(child, aChild);
+ // TODO: icons
+}
+
+void MenubarModelDBus::AppendSeparator(DbusmenuMenuitem* aParent) {
+ RefPtr<DbusmenuMenuitem> child = dont_AddRef(dbusmenu_menuitem_new());
+ dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE,
+ "separator");
+ dbusmenu_menuitem_child_append(aParent, child);
+}
+
+void MenubarModelDBus::AppendSubmenu(DbusmenuMenuitem* aParent,
+ const dom::Element* aMenu,
+ const dom::Element* aPopup) {
+ RefPtr<DbusmenuMenuitem> submenu = dont_AddRef(dbusmenu_menuitem_new());
+ if (RecomputeModelFor(submenu, *aPopup) == 0) {
+ RefPtr<DbusmenuMenuitem> placeholder = dont_AddRef(dbusmenu_menuitem_new());
+ dbusmenu_menuitem_child_append(submenu, placeholder);
+ }
+ nsAutoString label;
+ aMenu->GetAttr(nsGkAtoms::label, label);
+ ConnectAboutToShow(submenu, aPopup);
+ dbusmenu_menuitem_property_set(submenu, DBUSMENU_MENUITEM_PROP_LABEL,
+ NS_ConvertUTF16toUTF8(label).get());
+ dbusmenu_menuitem_child_append(aParent, submenu);
+}
+
+uint MenubarModelDBus::RecomputeModelFor(DbusmenuMenuitem* aParent,
+ const dom::Element& aElement) {
+ uint childCount = 0;
+ for (const nsIContent* child = aElement.GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ if (child->IsXULElement(nsGkAtoms::menuitem) &&
+ !IsDisabled(*child->AsElement())) {
+ AppendMenuItem(aParent, child->AsElement());
+ childCount++;
+ continue;
+ }
+ if (child->IsXULElement(nsGkAtoms::menuseparator)) {
+ AppendSeparator(aParent);
+ childCount++;
+ continue;
+ }
+ if (child->IsXULElement(nsGkAtoms::menu) &&
+ !IsDisabled(*child->AsElement())) {
+ if (const auto* popup = GetMenuPopupChild(*child->AsElement())) {
+ childCount++;
+ AppendSubmenu(aParent, child->AsElement(), popup);
+ }
+ }
+ }
+ return childCount;
+}
+
+void DBusMenuBar::NameOwnerChangedCallback(GObject*, GParamSpec*,
+ gpointer user_data) {
+ static_cast<DBusMenuBar*>(user_data)->OnNameOwnerChanged();
+}
+
+void DBusMenuBar::OnNameOwnerChanged() {
+ GUniquePtr<gchar> nameOwner(g_dbus_proxy_get_name_owner(mProxy));
+ if (!nameOwner) {
+ return;
+ }
+
+ RefPtr win = mMenuModel->Element()->OwnerDoc()->GetInnerWindow();
+ if (NS_WARN_IF(!win)) {
+ return;
+ }
+ nsIWidget* widget = nsGlobalWindowInner::Cast(win.get())->GetNearestWidget();
+ if (NS_WARN_IF(!widget)) {
+ return;
+ }
+ auto* gdkWin =
+ static_cast<GdkWindow*>(widget->GetNativeData(NS_NATIVE_WINDOW));
+ if (NS_WARN_IF(!gdkWin)) {
+ return;
+ }
+
+# ifdef MOZ_WAYLAND
+ if (auto* display = widget::WaylandDisplayGet()) {
+ if (!StaticPrefs::widget_gtk_global_menu_wayland_enabled()) {
+ return;
+ }
+ xdg_dbus_annotation_manager_v1* annotationManager =
+ display->GetXdgDbusAnnotationManager();
+ if (NS_WARN_IF(!annotationManager)) {
+ return;
+ }
+
+ wl_surface* surface = gdk_wayland_window_get_wl_surface(gdkWin);
+ if (NS_WARN_IF(!surface)) {
+ return;
+ }
+
+ GDBusConnection* connection = g_dbus_proxy_get_connection(mProxy);
+ const char* myServiceName = g_dbus_connection_get_unique_name(connection);
+ if (NS_WARN_IF(!myServiceName)) {
+ return;
+ }
+
+ // FIXME(emilio, bug 1883209): Nothing deletes this as of right now.
+ mAnnotation = xdg_dbus_annotation_manager_v1_create_surface(
+ annotationManager, "com.canonical.dbusmenu", surface);
+
+ xdg_dbus_annotation_v1_set_address(mAnnotation, myServiceName,
+ mObjectPath.get());
+ return;
+ }
+# endif
+# ifdef MOZ_X11
+ // legacy path
+ auto xid = GDK_WINDOW_XID(gdkWin);
+ widget::DBusProxyCall(mProxy, "RegisterWindow",
+ g_variant_new("(uo)", xid, mObjectPath.get()),
+ G_DBUS_CALL_FLAGS_NONE)
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr{this}](RefPtr<GVariant>&& aResult) {
+ self->mMenuModel->Element()->SetBoolAttr(nsGkAtoms::hidden, true);
+ },
+ [self = RefPtr{this}](GUniquePtr<GError>&& aError) {
+ g_printerr("Failed to register window menubar: %s\n",
+ aError->message);
+ self->mMenuModel->Element()->SetBoolAttr(nsGkAtoms::hidden, false);
+ });
+# endif
+}
+
+static unsigned sID = 0;
+
+DBusMenuBar::DBusMenuBar(dom::Element* aElement)
+ : mObjectPath(nsPrintfCString("/com/canonical/menu/%u", sID++)),
+ mMenuModel(MakeRefPtr<MenubarModelDBus>(aElement)),
+ mServer(dont_AddRef(dbusmenu_server_new(mObjectPath.get()))) {
+ mMenuModel->RecomputeModelIfNeeded();
+ dbusmenu_server_set_root(mServer.get(), mMenuModel->Root());
+}
+
+RefPtr<DBusMenuBar> DBusMenuBar::Create(dom::Element* aElement) {
+ RefPtr<DBusMenuBar> self = new DBusMenuBar(aElement);
+ widget::CreateDBusProxyForBus(
+ G_BUS_TYPE_SESSION,
+ GDBusProxyFlags(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
+ nullptr, "com.canonical.AppMenu.Registrar",
+ "/com/canonical/AppMenu/Registrar", "com.canonical.AppMenu.Registrar")
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self](RefPtr<GDBusProxy>&& aProxy) {
+ self->mProxy = std::move(aProxy);
+ g_signal_connect(self->mProxy, "notify::g-name-owner",
+ G_CALLBACK(NameOwnerChangedCallback), self.get());
+ self->OnNameOwnerChanged();
+ },
+ [](GUniquePtr<GError>&& aError) {
+ g_printerr("Failed to create DBUS proxy for menubar: %s\n",
+ aError->message);
+ });
+ return self;
+}
+
+DBusMenuBar::~DBusMenuBar() {
+# ifdef MOZ_WAYLAND
+ MozClearPointer(mAnnotation, xdg_dbus_annotation_v1_destroy);
+# endif
+}
+#endif
+
} // namespace mozilla::widget
diff --git a/widget/gtk/NativeMenuGtk.h b/widget/gtk/NativeMenuGtk.h
index 3f1f3213c1..ca0f64c8ff 100644
--- a/widget/gtk/NativeMenuGtk.h
+++ b/widget/gtk/NativeMenuGtk.h
@@ -1,4 +1,3 @@
-
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
/* 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
@@ -7,10 +6,13 @@
#ifndef mozilla_widget_NativeMenuGtk_h
#define mozilla_widget_NativeMenuGtk_h
+#include "mozilla/RefCounted.h"
#include "mozilla/widget/NativeMenu.h"
#include "mozilla/EventForwards.h"
#include "GRefPtr.h"
+struct xdg_dbus_annotation_v1;
+
namespace mozilla {
namespace dom {
@@ -19,7 +21,8 @@ class Element;
namespace widget {
-class MenuModel;
+class MenuModelGMenu;
+class MenubarModelDBus;
class NativeMenuGtk : public NativeMenu {
public:
@@ -54,10 +57,35 @@ class NativeMenuGtk : public NativeMenu {
bool mPoppedUp = false;
RefPtr<GtkWidget> mNativeMenu;
- RefPtr<MenuModel> mMenuModel;
+ RefPtr<MenuModelGMenu> mMenuModel;
nsTArray<NativeMenu::Observer*> mObservers;
};
+#ifdef MOZ_ENABLE_DBUS
+
+class DBusMenuBar final : public RefCounted<DBusMenuBar> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(DBusMenuBar)
+ static RefPtr<DBusMenuBar> Create(dom::Element*);
+ ~DBusMenuBar();
+
+ protected:
+ explicit DBusMenuBar(dom::Element* aElement);
+
+ static void NameOwnerChangedCallback(GObject*, GParamSpec*, gpointer);
+ void OnNameOwnerChanged();
+
+ nsCString mObjectPath;
+ RefPtr<MenubarModelDBus> mMenuModel;
+ RefPtr<DbusmenuServer> mServer;
+ RefPtr<GDBusProxy> mProxy;
+# ifdef MOZ_WAYLAND
+ xdg_dbus_annotation_v1* mAnnotation = nullptr;
+# endif
+};
+
+#endif
+
} // namespace widget
} // namespace mozilla
diff --git a/widget/gtk/NativeMenuSupport.cpp b/widget/gtk/NativeMenuSupport.cpp
index 4360867fff..60517cd526 100644
--- a/widget/gtk/NativeMenuSupport.cpp
+++ b/widget/gtk/NativeMenuSupport.cpp
@@ -5,8 +5,11 @@
#include "mozilla/widget/NativeMenuSupport.h"
+#include "mozilla/StaticPrefs_widget.h"
#include "MainThreadUtils.h"
#include "NativeMenuGtk.h"
+#include "DBusMenu.h"
+#include "nsWindow.h"
namespace mozilla::widget {
@@ -14,7 +17,14 @@ void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent,
dom::Element* aMenuBarElement) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"Attempting to create native menu bar on wrong thread!");
- // TODO
+
+#ifdef MOZ_ENABLE_DBUS
+ if (aMenuBarElement && StaticPrefs::widget_gtk_global_menu_enabled() &&
+ DBusMenuFunctions::Init()) {
+ static_cast<nsWindow*>(aParent)->SetDBusMenuBar(
+ DBusMenuBar::Create(aMenuBarElement));
+ }
+#endif
}
already_AddRefed<NativeMenu> NativeMenuSupport::CreateNativeContextMenu(
diff --git a/widget/gtk/WakeLockListener.cpp b/widget/gtk/WakeLockListener.cpp
index b2c43cb485..33bb374cef 100644
--- a/widget/gtk/WakeLockListener.cpp
+++ b/widget/gtk/WakeLockListener.cpp
@@ -137,6 +137,7 @@ class WakeLockTopic {
bool UninhibitWaylandIdle();
#endif
+ bool IsNativeWakeLock(int aWakeLockType);
bool IsWakeLockTypeAvailable(int aWakeLockType);
bool SwitchToNextWakeLockType();
@@ -779,8 +780,14 @@ nsresult WakeLockTopic::InhibitScreensaver() {
mShouldInhibit = true;
// Iterate through wake lock types in case of failure.
- while (!SendInhibit() && SwitchToNextWakeLockType()) {
- ;
+ while (!SendInhibit()) {
+ // We don't switch away from native locks. Just try again.
+ if (IsNativeWakeLock(sWakeLockType)) {
+ return NS_ERROR_FAILURE;
+ }
+ if (!SwitchToNextWakeLockType()) {
+ return NS_ERROR_FAILURE;
+ }
}
return (sWakeLockType != Unsupported) ? NS_OK : NS_ERROR_FAILURE;
@@ -850,6 +857,21 @@ bool WakeLockTopic::IsWakeLockTypeAvailable(int aWakeLockType) {
}
}
+bool WakeLockTopic::IsNativeWakeLock(int aWakeLockType) {
+ switch (aWakeLockType) {
+#if defined(MOZ_X11)
+ case XScreenSaver:
+ return true;
+#endif
+#if defined(MOZ_WAYLAND)
+ case WaylandIdleInhibit:
+ return true;
+#endif
+ default:
+ return false;
+ }
+}
+
bool WakeLockTopic::SwitchToNextWakeLockType() {
WAKE_LOCK_LOG("WakeLockTopic::SwitchToNextWakeLockType() WakeLockType %s",
WakeLockTypeNames[sWakeLockType]);
diff --git a/widget/gtk/WidgetStyleCache.cpp b/widget/gtk/WidgetStyleCache.cpp
index b7c1cf8a9f..13b194a64e 100644
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -644,10 +644,7 @@ static void CreateHeaderBarButtons() {
GtkWidget* headerBar = sWidgetStorage[MOZ_GTK_HEADER_BAR];
MOZ_ASSERT(headerBar, "We're missing header bar widget!");
- gint buttonSpacing = 6;
- g_object_get(headerBar, "spacing", &buttonSpacing, nullptr);
-
- GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, buttonSpacing);
+ GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add(GTK_CONTAINER(headerBar), buttonBox);
// We support only LTR headerbar layout for now.
gtk_style_context_add_class(gtk_widget_get_style_context(buttonBox),
diff --git a/widget/gtk/WindowSurfaceProvider.cpp b/widget/gtk/WindowSurfaceProvider.cpp
index b346f0783d..82f9029315 100644
--- a/widget/gtk/WindowSurfaceProvider.cpp
+++ b/widget/gtk/WindowSurfaceProvider.cpp
@@ -63,24 +63,34 @@ WindowSurfaceProvider::~WindowSurfaceProvider() {
}
#ifdef MOZ_WAYLAND
-void WindowSurfaceProvider::Initialize(RefPtr<nsWindow> aWidget) {
+bool WindowSurfaceProvider::Initialize(RefPtr<nsWindow> aWidget) {
mWindowSurfaceValid = false;
mWidget = std::move(aWidget);
+ return true;
}
-void WindowSurfaceProvider::Initialize(GtkCompositorWidget* aCompositorWidget) {
+bool WindowSurfaceProvider::Initialize(GtkCompositorWidget* aCompositorWidget) {
mWindowSurfaceValid = false;
mCompositorWidget = aCompositorWidget;
mWidget = static_cast<nsWindow*>(aCompositorWidget->RealWidget());
+ return true;
}
#endif
#ifdef MOZ_X11
-void WindowSurfaceProvider::Initialize(Window aWindow, Visual* aVisual,
- int aDepth, bool aIsShaped) {
+bool WindowSurfaceProvider::Initialize(Window aWindow, bool aIsShaped) {
mWindowSurfaceValid = false;
+
+ // Grab the window's visual and depth
+ XWindowAttributes windowAttrs;
+ if (!XGetWindowAttributes(DefaultXDisplay(), aWindow, &windowAttrs)) {
+ NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
+ return false;
+ }
+
mXWindow = aWindow;
- mXVisual = aVisual;
- mXDepth = aDepth;
+ mXVisual = windowAttrs.visual;
+ mXDepth = windowAttrs.depth;
mIsShaped = aIsShaped;
+ return true;
}
#endif
diff --git a/widget/gtk/WindowSurfaceProvider.h b/widget/gtk/WindowSurfaceProvider.h
index a040bbe395..6aaf50e2da 100644
--- a/widget/gtk/WindowSurfaceProvider.h
+++ b/widget/gtk/WindowSurfaceProvider.h
@@ -45,11 +45,12 @@ class WindowSurfaceProvider final {
* while WindowSurfaceProvider is used.
*/
#ifdef MOZ_WAYLAND
- void Initialize(RefPtr<nsWindow> aWidget);
- void Initialize(GtkCompositorWidget* aCompositorWidget);
+ bool Initialize(RefPtr<nsWindow> aWidget);
+ bool Initialize(GtkCompositorWidget* aCompositorWidget);
#endif
#ifdef MOZ_X11
- void Initialize(Window aWindow, Visual* aVisual, int aDepth, bool aIsShaped);
+ bool Initialize(Window aWindow, bool aIsShaped);
+ Window GetXWindow() const { return mXWindow; }
#endif
/**
diff --git a/widget/gtk/gtk3drawing.cpp b/widget/gtk/gtk3drawing.cpp
index 1fa8b95606..122b43d688 100644
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -1,4 +1,4 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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/. */
@@ -264,7 +264,6 @@ static void CalculateToolbarButtonMetrics(WidgetNodeType aAppearance,
gint iconWidth, iconHeight;
if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &iconWidth, &iconHeight)) {
NS_WARNING("Failed to get Gtk+ icon size for titlebar button!");
-
// Use some reasonable fallback size
iconWidth = 16;
iconHeight = 16;
@@ -292,37 +291,7 @@ static void CalculateToolbarButtonMetrics(WidgetNodeType aAppearance,
// Place icon at button center.
aMetrics->iconXPosition = (width - iconWidth) / 2;
aMetrics->iconYPosition = (height - iconHeight) / 2;
-
- aMetrics->minSizeWithBorderMargin.width = width;
- aMetrics->minSizeWithBorderMargin.height = height;
-}
-
-// We support LTR layout only here for now.
-static void CalculateToolbarButtonSpacing(WidgetNodeType aAppearance,
- ToolbarButtonGTKMetrics* aMetrics) {
- GtkStyleContext* style = GetStyleContext(aAppearance);
- gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
- &aMetrics->buttonMargin);
-
- // Get titlebar spacing, a default one is 6 pixels (gtk/gtkheaderbar.c)
- gint buttonSpacing = 6;
- g_object_get(GetWidget(MOZ_GTK_HEADER_BAR), "spacing", &buttonSpacing,
- nullptr);
-
- // We apply spacing as a margin equally to both adjacent buttons.
- buttonSpacing /= 2;
-
- if (!aMetrics->firstButton) {
- aMetrics->buttonMargin.left += buttonSpacing;
- }
- if (!aMetrics->lastButton) {
- aMetrics->buttonMargin.right += buttonSpacing;
- }
-
- aMetrics->minSizeWithBorderMargin.width +=
- aMetrics->buttonMargin.right + aMetrics->buttonMargin.left;
- aMetrics->minSizeWithBorderMargin.height +=
- aMetrics->buttonMargin.top + aMetrics->buttonMargin.bottom;
+ aMetrics->minSizeWithBorder = {width, height};
}
size_t GetGtkHeaderBarButtonLayout(Span<ButtonLayout> aButtonLayout,
@@ -388,26 +357,14 @@ static void EnsureToolbarMetrics() {
memset(&sToolbarMetrics, 0, sizeof(sToolbarMetrics));
// Calculate titlebar button visibility and positions.
- ButtonLayout aButtonLayout[TOOLBAR_BUTTONS];
+ ButtonLayout buttonLayout[TOOLBAR_BUTTONS];
size_t activeButtonNums =
- GetGtkHeaderBarButtonLayout(Span(aButtonLayout), nullptr);
-
- for (size_t i = 0; i < activeButtonNums; i++) {
- int buttonIndex =
- (aButtonLayout[i].mType - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
- ToolbarButtonGTKMetrics* metrics = sToolbarMetrics.button + buttonIndex;
- metrics->visible = true;
- // Mark first button
- if (!i) {
- metrics->firstButton = true;
- }
- // Mark last button.
- if (i == (activeButtonNums - 1)) {
- metrics->lastButton = true;
- }
+ GetGtkHeaderBarButtonLayout(Span(buttonLayout), nullptr);
- CalculateToolbarButtonMetrics(aButtonLayout[i].mType, metrics);
- CalculateToolbarButtonSpacing(aButtonLayout[i].mType, metrics);
+ for (const auto& layout : Span(buttonLayout, activeButtonNums)) {
+ int buttonIndex = layout.mType - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
+ ToolbarButtonGTKMetrics* metrics = &sToolbarMetrics.button[buttonIndex];
+ CalculateToolbarButtonMetrics(layout.mType, metrics);
}
sToolbarMetrics.initialized = true;
@@ -506,26 +463,27 @@ static gint moz_gtk_button_paint(cairo_t* cr, const GdkRectangle* rect,
return MOZ_GTK_SUCCESS;
}
-static gint moz_gtk_header_bar_button_paint(cairo_t* cr,
- const GdkRectangle* aRect,
+static gint moz_gtk_header_bar_button_paint(cairo_t* cr, GdkRectangle* aRect,
GtkWidgetState* state,
GtkReliefStyle relief,
WidgetNodeType aIconWidgetType,
GtkTextDirection direction) {
- GdkRectangle rect = *aRect;
- // We need to inset our calculated margin because it also
- // contains titlebar button spacing.
+ GtkWidget* buttonWidget = GetWidget(aIconWidgetType);
+ if (!buttonWidget) {
+ return MOZ_GTK_UNKNOWN_WIDGET;
+ }
+
const ToolbarButtonGTKMetrics* metrics = GetToolbarButtonMetrics(
aIconWidgetType == MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE
? MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE
: aIconWidgetType);
- Inset(&rect, metrics->buttonMargin);
-
- GtkWidget* buttonWidget = GetWidget(aIconWidgetType);
- if (!buttonWidget) {
- return MOZ_GTK_UNKNOWN_WIDGET;
+ // Vertically center and clamp the rect to the desired size.
+ if (aRect->height > metrics->minSizeWithBorder.height) {
+ gint diff = aRect->height - metrics->minSizeWithBorder.height;
+ aRect->y += diff / 2;
+ aRect->height = metrics->minSizeWithBorder.height;
}
- moz_gtk_button_paint(cr, &rect, state, relief, buttonWidget, direction);
+ moz_gtk_button_paint(cr, aRect, state, relief, buttonWidget, direction);
GtkWidget* iconWidget =
gtk_bin_get_child(GTK_BIN(GetWidget(aIconWidgetType)));
@@ -544,8 +502,9 @@ static gint moz_gtk_header_bar_button_paint(cairo_t* cr,
gtk_style_context_set_state(style, state_flags);
/* This is available since Gtk+ 3.10 as well as GtkHeaderBar */
- gtk_render_icon_surface(style, cr, surface, rect.x + metrics->iconXPosition,
- rect.y + metrics->iconYPosition);
+ gtk_render_icon_surface(style, cr, surface,
+ aRect->x + metrics->iconXPosition,
+ aRect->y + metrics->iconYPosition);
gtk_style_context_restore(style);
}
@@ -1700,22 +1659,6 @@ gint moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
return MOZ_GTK_SUCCESS;
}
- case MOZ_GTK_HEADER_BAR_BUTTON_BOX: {
- style = GetStyleContext(MOZ_GTK_HEADER_BAR);
- moz_gtk_add_border_padding(style, left, top, right, bottom);
- *top = *bottom = 0;
- bool leftButtonsPlacement = false;
- GetGtkHeaderBarButtonLayout({}, &leftButtonsPlacement);
- if (direction == GTK_TEXT_DIR_RTL) {
- leftButtonsPlacement = !leftButtonsPlacement;
- }
- if (leftButtonsPlacement) {
- *right = 0;
- } else {
- *left = 0;
- }
- return MOZ_GTK_SUCCESS;
- }
/* These widgets have no borders, since they are not containers. */
case MOZ_GTK_SPLITTER_HORIZONTAL:
case MOZ_GTK_SPLITTER_VERTICAL:
diff --git a/widget/gtk/gtkdrawing.h b/widget/gtk/gtkdrawing.h
index e751dc38c9..4ca226d9c7 100644
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -76,13 +76,9 @@ typedef struct {
} ToggleGTKMetrics;
typedef struct {
- MozGtkSize minSizeWithBorderMargin;
- GtkBorder buttonMargin;
+ MozGtkSize minSizeWithBorder;
gint iconXPosition;
gint iconYPosition;
- bool visible;
- bool firstButton;
- bool lastButton;
} ToolbarButtonGTKMetrics;
#define TOOLBAR_BUTTONS 3
@@ -269,8 +265,6 @@ enum WidgetNodeType : int {
MOZ_GTK_HEADER_BAR,
/* Paints a GtkHeaderBar in maximized state */
MOZ_GTK_HEADER_BAR_MAXIMIZED,
- /* Container for GtkHeaderBar buttons */
- MOZ_GTK_HEADER_BAR_BUTTON_BOX,
/* Paints GtkHeaderBar title buttons.
* Keep the order here as MOZ_GTK_HEADER_BAR_BUTTON_* are processed
* as an array from MOZ_GTK_HEADER_BAR_BUTTON_CLOSE to the last one.
diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build
index 0d3916853c..87866b1a9b 100644
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -173,6 +173,7 @@ if CONFIG["MOZ_ENABLE_DBUS"]:
]
UNIFIED_SOURCES += [
"AsyncDBus.cpp",
+ "DBusMenu.cpp",
]
CXXFLAGS += CONFIG["MOZ_DBUS_CFLAGS"]
diff --git a/widget/gtk/nsGtkKeyUtils.cpp b/widget/gtk/nsGtkKeyUtils.cpp
index 7157a09664..e49f64a64b 100644
--- a/widget/gtk/nsGtkKeyUtils.cpp
+++ b/widget/gtk/nsGtkKeyUtils.cpp
@@ -2125,6 +2125,212 @@ guint KeymapWrapper::GetGDKKeyvalWithoutModifier(
return keyval;
}
+struct KeyCodeData {
+ const char* str;
+ size_t strlength;
+ uint32_t keycode;
+};
+
+static struct KeyCodeData gKeyCodes[] = {
+#define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
+ {#aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode},
+#include "mozilla/VirtualKeyCodeList.h"
+#undef NS_DEFINE_VK
+ {nullptr, 0, 0}};
+
+struct KeyPair {
+ uint32_t DOMKeyCode;
+ guint GDKKeyval;
+};
+
+//
+// Netscape keycodes are defined in widget/public/nsGUIEvent.h
+// GTK keycodes are defined in <gdk/gdkkeysyms.h>
+//
+static const KeyPair gKeyPairs[] = {
+ {NS_VK_CANCEL, GDK_Cancel},
+ {NS_VK_BACK, GDK_BackSpace},
+ {NS_VK_TAB, GDK_Tab},
+ {NS_VK_CLEAR, GDK_Clear},
+ {NS_VK_RETURN, GDK_Return},
+ {NS_VK_SHIFT, GDK_Shift_L},
+ {NS_VK_CONTROL, GDK_Control_L},
+ {NS_VK_ALT, GDK_Alt_L},
+ {NS_VK_META, GDK_Meta_L},
+
+ // Assume that Super or Hyper is always mapped to physical Win key.
+ {NS_VK_WIN, GDK_Super_L},
+
+ // GTK's AltGraph key is similar to Mac's Option (Alt) key. However,
+ // unfortunately, browsers on Mac are using NS_VK_ALT for it even though
+ // it's really different from Alt key on Windows.
+ // On the other hand, GTK's AltGrapsh keys are really different from
+ // Alt key. However, there is no AltGrapsh key on Windows. On Windows,
+ // both Ctrl and Alt keys are pressed internally when AltGr key is pressed.
+ // For some languages' users, AltGraph key is important, so, web
+ // applications on such locale may want to know AltGraph key press.
+ // Therefore, we should map AltGr keycode for them only on GTK.
+ {NS_VK_ALTGR, GDK_ISO_Level3_Shift},
+
+ {NS_VK_PAUSE, GDK_Pause},
+ {NS_VK_CAPS_LOCK, GDK_Caps_Lock},
+ {NS_VK_ESCAPE, GDK_Escape},
+ // { NS_VK_ACCEPT, GDK_XXX },
+ // { NS_VK_MODECHANGE, GDK_XXX },
+ {NS_VK_SPACE, GDK_space},
+ {NS_VK_PAGE_UP, GDK_Page_Up},
+ {NS_VK_PAGE_DOWN, GDK_Page_Down},
+ {NS_VK_END, GDK_End},
+ {NS_VK_HOME, GDK_Home},
+ {NS_VK_LEFT, GDK_Left},
+ {NS_VK_UP, GDK_Up},
+ {NS_VK_RIGHT, GDK_Right},
+ {NS_VK_DOWN, GDK_Down},
+ {NS_VK_SELECT, GDK_Select},
+ {NS_VK_PRINT, GDK_Print},
+ {NS_VK_EXECUTE, GDK_Execute},
+ {NS_VK_PRINTSCREEN, GDK_Print},
+ {NS_VK_INSERT, GDK_Insert},
+ {NS_VK_DELETE, GDK_Delete},
+ {NS_VK_HELP, GDK_Help},
+
+ {NS_VK_NUM_LOCK, GDK_Num_Lock},
+ {NS_VK_SCROLL_LOCK, GDK_Scroll_Lock},
+
+ // Function keys
+ {NS_VK_F1, GDK_F1},
+ {NS_VK_F2, GDK_F2},
+ {NS_VK_F3, GDK_F3},
+ {NS_VK_F4, GDK_F4},
+ {NS_VK_F5, GDK_F5},
+ {NS_VK_F6, GDK_F6},
+ {NS_VK_F7, GDK_F7},
+ {NS_VK_F8, GDK_F8},
+ {NS_VK_F9, GDK_F9},
+ {NS_VK_F10, GDK_F10},
+ {NS_VK_F11, GDK_F11},
+ {NS_VK_F12, GDK_F12},
+ {NS_VK_F13, GDK_F13},
+ {NS_VK_F14, GDK_F14},
+ {NS_VK_F15, GDK_F15},
+ {NS_VK_F16, GDK_F16},
+ {NS_VK_F17, GDK_F17},
+ {NS_VK_F18, GDK_F18},
+ {NS_VK_F19, GDK_F19},
+ {NS_VK_F20, GDK_F20},
+ {NS_VK_F21, GDK_F21},
+ {NS_VK_F22, GDK_F22},
+ {NS_VK_F23, GDK_F23},
+ {NS_VK_F24, GDK_F24},
+
+ // context menu key, keysym 0xff67, typically keycode 117 on 105-key
+ // (Microsoft) x86 keyboards, located between right 'Windows' key and right
+ // Ctrl key
+ {NS_VK_CONTEXT_MENU, GDK_Menu},
+ {NS_VK_SLEEP, GDK_Sleep},
+
+ {NS_VK_ATTN, GDK_3270_Attn},
+ {NS_VK_CRSEL, GDK_3270_CursorSelect},
+ {NS_VK_EXSEL, GDK_3270_ExSelect},
+ {NS_VK_EREOF, GDK_3270_EraseEOF},
+ {NS_VK_PLAY, GDK_3270_Play},
+ //{ NS_VK_ZOOM, GDK_XXX },
+ {NS_VK_PA1, GDK_3270_PA1},
+
+ {NS_VK_MULTIPLY, GDK_KP_Multiply},
+ {NS_VK_ADD, GDK_KP_Add},
+ {NS_VK_SEPARATOR, GDK_KP_Separator},
+ {NS_VK_SUBTRACT, GDK_KP_Subtract},
+ {NS_VK_DECIMAL, GDK_KP_Decimal},
+ {NS_VK_DIVIDE, GDK_KP_Divide},
+ {NS_VK_NUMPAD0, GDK_KP_0},
+ {NS_VK_NUMPAD1, GDK_KP_1},
+ {NS_VK_NUMPAD2, GDK_KP_2},
+ {NS_VK_NUMPAD3, GDK_KP_3},
+ {NS_VK_NUMPAD4, GDK_KP_4},
+ {NS_VK_NUMPAD5, GDK_KP_5},
+ {NS_VK_NUMPAD6, GDK_KP_6},
+ {NS_VK_NUMPAD7, GDK_KP_7},
+ {NS_VK_NUMPAD8, GDK_KP_8},
+ {NS_VK_NUMPAD9, GDK_KP_9},
+ {NS_VK_SPACE, GDK_space},
+ {NS_VK_COLON, GDK_colon},
+ {NS_VK_SEMICOLON, GDK_semicolon},
+ {NS_VK_LESS_THAN, GDK_less},
+ {NS_VK_EQUALS, GDK_equal},
+ {NS_VK_GREATER_THAN, GDK_greater},
+ {NS_VK_QUESTION_MARK, GDK_question},
+ {NS_VK_AT, GDK_at},
+ {NS_VK_CIRCUMFLEX, GDK_asciicircum},
+ {NS_VK_EXCLAMATION, GDK_exclam},
+ {NS_VK_DOUBLE_QUOTE, GDK_quotedbl},
+ {NS_VK_HASH, GDK_numbersign},
+ {NS_VK_DOLLAR, GDK_dollar},
+ {NS_VK_PERCENT, GDK_percent},
+ {NS_VK_AMPERSAND, GDK_ampersand},
+ {NS_VK_UNDERSCORE, GDK_underscore},
+ {NS_VK_OPEN_PAREN, GDK_parenleft},
+ {NS_VK_CLOSE_PAREN, GDK_parenright},
+ {NS_VK_ASTERISK, GDK_asterisk},
+ {NS_VK_PLUS, GDK_plus},
+ {NS_VK_PIPE, GDK_bar},
+ {NS_VK_HYPHEN_MINUS, GDK_minus},
+ {NS_VK_OPEN_CURLY_BRACKET, GDK_braceleft},
+ {NS_VK_CLOSE_CURLY_BRACKET, GDK_braceright},
+ {NS_VK_TILDE, GDK_asciitilde},
+ {NS_VK_COMMA, GDK_comma},
+ {NS_VK_PERIOD, GDK_period},
+ {NS_VK_SLASH, GDK_slash},
+ {NS_VK_BACK_QUOTE, GDK_grave},
+ {NS_VK_OPEN_BRACKET, GDK_bracketleft},
+ {NS_VK_BACK_SLASH, GDK_backslash},
+ {NS_VK_CLOSE_BRACKET, GDK_bracketright},
+ {NS_VK_QUOTE, GDK_apostrophe},
+};
+
+/* static */
+guint KeymapWrapper::ConvertGeckoKeyCodeToGDKKeyval(const nsAString& aKeyCode) {
+ NS_ConvertUTF16toUTF8 keyName(aKeyCode);
+ ToUpperCase(keyName); // We want case-insensitive comparison with data
+ // stored as uppercase.
+
+ uint32_t keyCode = 0;
+
+ uint32_t keyNameLength = keyName.Length();
+ const char* keyNameStr = keyName.get();
+ for (const auto& code : gKeyCodes) {
+ if (keyNameLength == code.strlength &&
+ !nsCRT::strcmp(code.str, keyNameStr)) {
+ keyCode = code.keycode;
+ break;
+ }
+ }
+
+ // First, try to handle alphanumeric input, not listed in nsKeycodes:
+ // most likely, more letters will be getting typed in than things in
+ // the key list, so we will look through these first.
+
+ if (keyCode >= NS_VK_A && keyCode <= NS_VK_Z) {
+ // gdk and DOM both use the ASCII codes for these keys.
+ return keyCode;
+ }
+
+ // numbers
+ if (keyCode >= NS_VK_0 && keyCode <= NS_VK_9) {
+ // gdk and DOM both use the ASCII codes for these keys.
+ return keyCode - NS_VK_0 + GDK_0;
+ }
+
+ // misc other things
+ for (const auto& pair : gKeyPairs) {
+ if (pair.DOMKeyCode == keyCode) {
+ return pair.GDKKeyval;
+ }
+ }
+
+ return 0;
+}
+
/* static */
uint32_t KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval) {
switch (aGdkKeyval) {
diff --git a/widget/gtk/nsGtkKeyUtils.h b/widget/gtk/nsGtkKeyUtils.h
index aac9d446f3..b1f1fae138 100644
--- a/widget/gtk/nsGtkKeyUtils.h
+++ b/widget/gtk/nsGtkKeyUtils.h
@@ -55,6 +55,8 @@ class KeymapWrapper {
*/
static CodeNameIndex ComputeDOMCodeNameIndex(const GdkEventKey* aGdkKeyEvent);
+ static guint ConvertGeckoKeyCodeToGDKKeyval(const nsAString& aKeyCode);
+
/**
* We need to translate modifiers masks from Gdk to Gecko.
* MappedModifier is a table of mapped modifiers, we ignore other
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
index c4b430d2eb..040d942cdf 100644
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -905,10 +905,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = (int32_t)delay;
break;
}
- case IntID::TooltipDelay: {
- aResult = 500;
- break;
- }
case IntID::MenusCanOverlapOSBar:
// we want XUL popups to be able to overlap the task bar.
aResult = 1;
@@ -1035,6 +1031,11 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = EffectiveTheme().mTitlebarRadius;
break;
}
+ case IntID::TitlebarButtonSpacing: {
+ EnsureInit();
+ aResult = EffectiveTheme().mTitlebarButtonSpacing;
+ break;
+ }
case IntID::AllowOverlayScrollbarsOverlap: {
aResult = 1;
break;
@@ -1976,6 +1977,10 @@ void nsLookAndFeel::PerThemeData::Init() {
mTitlebar = GetColorPair(style, GTK_STATE_FLAG_NORMAL);
mTitlebarInactive = GetColorPair(style, GTK_STATE_FLAG_BACKDROP);
mTitlebarRadius = IsSolidCSDStyleUsed() ? 0 : GetBorderRadius(style);
+ // Get titlebar spacing, a default one is 6 pixels (gtk/gtkheaderbar.c)
+ mTitlebarButtonSpacing = 6;
+ g_object_get(GetWidget(MOZ_GTK_HEADER_BAR), "spacing",
+ &mTitlebarButtonSpacing, nullptr);
}
// We special-case the header bar color in Adwaita, Yaru and Breeze to be the
diff --git a/widget/gtk/nsLookAndFeel.h b/widget/gtk/nsLookAndFeel.h
index 56608d331f..1ef28afe21 100644
--- a/widget/gtk/nsLookAndFeel.h
+++ b/widget/gtk/nsLookAndFeel.h
@@ -137,6 +137,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
float mCaretRatio = 0.0f;
int32_t mTitlebarRadius = 0;
+ int32_t mTitlebarButtonSpacing = 0;
char16_t mInvisibleCharacter = 0;
bool mMenuSupportsDrag = false;
diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp
index 06d9b48007..16945349bb 100644
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -191,6 +191,10 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
aAppearance == StyleAppearance::Toolbarbutton ||
aAppearance == StyleAppearance::Dualbutton ||
aAppearance == StyleAppearance::ToolbarbuttonDropdown ||
+ aAppearance == StyleAppearance::MozWindowButtonMinimize ||
+ aAppearance == StyleAppearance::MozWindowButtonRestore ||
+ aAppearance == StyleAppearance::MozWindowButtonMaximize ||
+ aAppearance == StyleAppearance::MozWindowButtonClose ||
aAppearance == StyleAppearance::Menulist ||
aAppearance == StyleAppearance::MenulistButton) {
aState->active &= aState->inHover;
@@ -392,9 +396,6 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
case StyleAppearance::MozWindowTitlebarMaximized:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_MAXIMIZED;
break;
- case StyleAppearance::MozWindowButtonBox:
- aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_BOX;
- break;
case StyleAppearance::MozWindowButtonClose:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
break;
@@ -676,16 +677,6 @@ CSSIntMargin nsNativeThemeGTK::GetExtraSizeForWidget(
return extra;
}
-bool nsNativeThemeGTK::IsWidgetVisible(StyleAppearance aAppearance) {
- switch (aAppearance) {
- case StyleAppearance::MozWindowButtonBox:
- return false;
- default:
- break;
- }
- return true;
-}
-
NS_IMETHODIMP
nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
@@ -702,8 +693,7 @@ nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
GtkTextDirection direction = GetTextDirection(aFrame);
gint flags;
- if (!IsWidgetVisible(aAppearance) ||
- !GetGtkWidgetAndState(aAppearance, aFrame, gtkWidgetType, &state,
+ if (!GetGtkWidgetAndState(aAppearance, aFrame, gtkWidgetType, &state,
&flags)) {
return NS_OK;
}
@@ -937,7 +927,6 @@ bool nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
switch (aAppearance) {
case StyleAppearance::Toolbarbutton:
case StyleAppearance::Tooltip:
- case StyleAppearance::MozWindowButtonBox:
case StyleAppearance::MozWindowButtonClose:
case StyleAppearance::MozWindowButtonMinimize:
case StyleAppearance::MozWindowButtonMaximize:
@@ -1072,23 +1061,23 @@ LayoutDeviceIntSize nsNativeThemeGTK::GetMinimumWidgetSize(
case StyleAppearance::MozWindowButtonClose: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
- result.width = metrics->minSizeWithBorderMargin.width;
- result.height = metrics->minSizeWithBorderMargin.height;
+ result.width = metrics->minSizeWithBorder.width;
+ result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::MozWindowButtonMinimize: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE);
- result.width = metrics->minSizeWithBorderMargin.width;
- result.height = metrics->minSizeWithBorderMargin.height;
+ result.width = metrics->minSizeWithBorder.width;
+ result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::MozWindowButtonMaximize:
case StyleAppearance::MozWindowButtonRestore: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE);
- result.width = metrics->minSizeWithBorderMargin.width;
- result.height = metrics->minSizeWithBorderMargin.height;
+ result.width = metrics->minSizeWithBorder.width;
+ result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::Button:
@@ -1288,7 +1277,6 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::Range:
case StyleAppearance::RangeThumb:
case StyleAppearance::Splitter:
- case StyleAppearance::MozWindowButtonBox:
case StyleAppearance::MozWindowButtonClose:
case StyleAppearance::MozWindowButtonMinimize:
case StyleAppearance::MozWindowButtonMaximize:
diff --git a/widget/gtk/nsNativeThemeGTK.h b/widget/gtk/nsNativeThemeGTK.h
index 2d0878290e..62a046c959 100644
--- a/widget/gtk/nsNativeThemeGTK.h
+++ b/widget/gtk/nsNativeThemeGTK.h
@@ -93,7 +93,6 @@ class nsNativeThemeGTK final : public mozilla::widget::Theme {
WidgetNodeType& aGtkWidgetType,
GtkWidgetState* aState, gint* aWidgetFlags);
mozilla::CSSIntMargin GetExtraSizeForWidget(nsIFrame*, StyleAppearance);
- bool IsWidgetVisible(StyleAppearance aAppearance);
void RefreshWidgetWindow(nsIFrame* aFrame);
WidgetNodeType NativeThemeToGtkTheme(StyleAppearance aAppearance,
diff --git a/widget/gtk/nsWaylandDisplay.cpp b/widget/gtk/nsWaylandDisplay.cpp
index 2a1021457a..1ea87b3bc5 100644
--- a/widget/gtk/nsWaylandDisplay.cpp
+++ b/widget/gtk/nsWaylandDisplay.cpp
@@ -93,6 +93,11 @@ void nsWaylandDisplay::SetXdgActivation(xdg_activation_v1* aXdgActivation) {
mXdgActivation = aXdgActivation;
}
+void nsWaylandDisplay::SetXdgDbusAnnotationManager(
+ xdg_dbus_annotation_manager_v1* aXdgDbusAnnotationManager) {
+ mXdgDbusAnnotationManager = aXdgDbusAnnotationManager;
+}
+
static void global_registry_handler(void* data, wl_registry* registry,
uint32_t id, const char* interface,
uint32_t version) {
@@ -140,6 +145,11 @@ static void global_registry_handler(void* data, wl_registry* registry,
auto* activation = WaylandRegistryBind<xdg_activation_v1>(
registry, id, &xdg_activation_v1_interface, 1);
display->SetXdgActivation(activation);
+ } else if (iface.EqualsLiteral("xdg_dbus_annotation_manager_v1")) {
+ auto* annotationManager =
+ WaylandRegistryBind<xdg_dbus_annotation_manager_v1>(
+ registry, id, &xdg_dbus_annotation_manager_v1_interface, 1);
+ display->SetXdgDbusAnnotationManager(annotationManager);
} else if (iface.EqualsLiteral("wl_seat")) {
// Install keyboard handlers for main thread only
auto* seat =
diff --git a/widget/gtk/nsWaylandDisplay.h b/widget/gtk/nsWaylandDisplay.h
index cd8124d97f..40250c2bf2 100644
--- a/widget/gtk/nsWaylandDisplay.h
+++ b/widget/gtk/nsWaylandDisplay.h
@@ -19,6 +19,7 @@
#include "mozilla/widget/linux-dmabuf-unstable-v1-client-protocol.h"
#include "mozilla/widget/viewporter-client-protocol.h"
#include "mozilla/widget/xdg-activation-v1-client-protocol.h"
+#include "mozilla/widget/xdg-dbus-annotation-v1-client-protocol.h"
#include "mozilla/widget/xdg-output-unstable-v1-client-protocol.h"
namespace mozilla::widget {
@@ -48,6 +49,9 @@ class nsWaylandDisplay {
}
zwp_linux_dmabuf_v1* GetDmabuf() { return mDmabuf; };
xdg_activation_v1* GetXdgActivation() { return mXdgActivation; };
+ xdg_dbus_annotation_manager_v1* GetXdgDbusAnnotationManager() {
+ return mXdgDbusAnnotationManager;
+ }
wp_fractional_scale_manager_v1* GetFractionalScaleManager() {
return mFractionalScaleManager;
}
@@ -64,6 +68,8 @@ class nsWaylandDisplay {
void SetPointerConstraints(zwp_pointer_constraints_v1* aPointerConstraints);
void SetDmabuf(zwp_linux_dmabuf_v1* aDmabuf);
void SetXdgActivation(xdg_activation_v1* aXdgActivation);
+ void SetXdgDbusAnnotationManager(
+ xdg_dbus_annotation_manager_v1* aXdgDbusAnnotationManager);
void SetFractionalScaleManager(wp_fractional_scale_manager_v1* aManager) {
mFractionalScaleManager = aManager;
}
@@ -84,6 +90,7 @@ class nsWaylandDisplay {
wp_viewporter* mViewporter = nullptr;
zwp_linux_dmabuf_v1* mDmabuf = nullptr;
xdg_activation_v1* mXdgActivation = nullptr;
+ xdg_dbus_annotation_manager_v1* mXdgDbusAnnotationManager = nullptr;
wp_fractional_scale_manager_v1* mFractionalScaleManager = nullptr;
bool mExplicitSync = false;
bool mIsPrimarySelectionEnabled = false;
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
index 8185c7bda9..e84044990c 100644
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -100,6 +100,7 @@
#include "ScreenHelperGTK.h"
#include "SystemTimeConverter.h"
#include "WidgetUtilsGtk.h"
+#include "NativeMenuGtk.h"
#ifdef ACCESSIBILITY
# include "mozilla/a11y/LocalAccessible.h"
@@ -182,8 +183,6 @@ static nsWindow* get_window_for_gtk_widget(GtkWidget* widget);
static nsWindow* get_window_for_gdk_window(GdkWindow* window);
static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window);
static GdkCursor* get_gtk_cursor(nsCursor aCursor);
-static GdkWindow* get_inner_gdk_window(GdkWindow* aWindow, gint x, gint y,
- gint* retx, gint* rety);
/* callbacks from widgets */
static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
@@ -404,6 +403,7 @@ nsWindow::nsWindow()
mIsDragPopup(false),
mCompositedScreen(gdk_screen_is_composited(gdk_screen_get_default())),
mIsAccelerated(false),
+ mIsAlert(false),
mWindowShouldStartDragging(false),
mHasMappedToplevel(false),
mRetryPointerGrab(false),
@@ -572,21 +572,6 @@ bool nsWindow::AreBoundsSane() {
return !mLastSizeRequest.IsEmpty();
}
-// Walk the list of child windows and call destroy on them.
-void nsWindow::DestroyChildWindows() {
- LOG("nsWindow::DestroyChildWindows()");
- if (!mGdkWindow) {
- return;
- }
- while (GList* children = gdk_window_peek_children(mGdkWindow)) {
- GdkWindow* child = GDK_WINDOW(children->data);
- nsWindow* kid = get_window_for_gdk_window(child);
- if (kid) {
- kid->Destroy();
- }
- }
-}
-
void nsWindow::Destroy() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
@@ -4141,6 +4126,16 @@ void nsWindow::OnUnmap() {
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) {
@@ -5394,6 +5389,7 @@ void nsWindow::OnDPIChanged() {
}
mWidgetListener->UIResolutionChanged();
}
+ NotifyAPZOfDPIChange();
}
void nsWindow::OnCheckResize() { mPendingConfigures++; }
@@ -5427,6 +5423,8 @@ void nsWindow::OnScaleChanged(bool aNotify) {
return;
}
+ NotifyAPZOfDPIChange();
+
LOG("OnScaleChanged %d, %f -> %d, %f\n", int(mCeiledScaleFactor),
mFractionalScaleFactor, newCeiled, newFractional);
@@ -5816,9 +5814,6 @@ void nsWindow::EnsureGdkWindow() {
if (!mGdkWindow) {
mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer));
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
- if (mIMContext) {
- mIMContext->SetGdkWindow(mGdkWindow);
- }
}
}
@@ -5871,13 +5866,13 @@ void nsWindow::ConfigureGdkWindow() {
EnsureGdkWindow();
OnScaleChanged(/* aNotify = */ false);
+ if (mIsAlert) {
+ gdk_window_set_override_redirect(mGdkWindow, TRUE);
+ }
+
#ifdef MOZ_X11
if (GdkIsX11Display()) {
- GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow);
- Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
- int depth = gdk_visual_get_depth(gdkVisual);
- mSurfaceProvider.Initialize(GetX11Window(), visual, depth,
- GetShapedState());
+ mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
// Set window manager hint to keep fullscreen windows composited.
//
@@ -6019,6 +6014,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
// and can be changed so we use WaylandPopupIsPermanent() to get
// recent popup config (Bug 1728952).
mNoAutoHide = aInitData && aInitData->mNoAutoHide;
+ mIsAlert = aInitData && aInitData->mIsAlert;
// Popups that are not noautohide are only temporary. The are used
// for menus and the like and disappear when another window is used.
@@ -6108,10 +6104,11 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
if (mIsPIPWindow) {
LOG(" Is PIP window\n");
gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_UTILITY);
- } else if (aInitData && aInitData->mIsAlert) {
+ } else if (mIsAlert) {
LOG(" Is alert window\n");
gtk_window_set_type_hint(GTK_WINDOW(mShell),
GDK_WINDOW_TYPE_HINT_NOTIFICATION);
+ gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE);
} else if (mWindowType == WindowType::Dialog) {
mGtkWindowRoleName = "Dialog";
@@ -6706,10 +6703,6 @@ void nsWindow::ResumeCompositorImpl() {
LOG("nsWindow::ResumeCompositorImpl()\n");
MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate);
-
- // DisableRendering() clears stored X11Window so we're sure EnableRendering()
- // really updates it.
- mCompositorWidgetDelegate->DisableRendering();
mCompositorWidgetDelegate->EnableRendering(GetX11Window(), GetShapedState());
// As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
@@ -6988,6 +6981,13 @@ void nsWindow::UpdateWindowDraggingRegion(
}
}
+#ifdef MOZ_ENABLE_DBUS
+void nsWindow::SetDBusMenuBar(
+ RefPtr<mozilla::widget::DBusMenuBar> aDbusMenuBar) {
+ mDBusMenuBar = std::move(aDbusMenuBar);
+}
+#endif
+
LayoutDeviceIntCoord nsWindow::GetTitlebarRadius() {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
int32_t cssCoord = LookAndFeel::GetInt(LookAndFeel::IntID::TitlebarRadius);
@@ -7839,14 +7839,246 @@ static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window) {
return GTK_WIDGET(user_data);
}
-static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
+static GdkCursor* get_gtk_cursor_from_type(uint8_t aCursorType) {
+ GdkDisplay* defaultDisplay = gdk_display_get_default();
GdkCursor* gdkcursor = nullptr;
- uint8_t newType = 0xff;
- if ((gdkcursor = gCursorCache[aCursor])) {
- return gdkcursor;
+ // GtkCursors are defined at nsGtkCursors.h
+ if (aCursorType > MOZ_CURSOR_NONE) {
+ return nullptr;
}
+ // If by now we don't have a xcursor, this means we have to make a custom
+ // one. First, we try creating a named cursor based on the hash of our
+ // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
+ // to themed cursors
+ if (GtkCursors[aCursorType].hash) {
+ gdkcursor =
+ gdk_cursor_new_from_name(defaultDisplay, GtkCursors[aCursorType].hash);
+ if (gdkcursor) {
+ return gdkcursor;
+ }
+ }
+
+ LOGW("get_gtk_cursor_from_type(): Failed to get cursor type %d, try bitmap",
+ aCursorType);
+
+ // If we still don't have a xcursor, we now really create a bitmap cursor
+ GdkPixbuf* cursor_pixbuf =
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
+ if (!cursor_pixbuf) {
+ return nullptr;
+ }
+
+ guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
+
+ // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
+ // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
+ // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
+ // there are 32 rows here).
+ const unsigned char* bits = GtkCursors[aCursorType].bits;
+ const unsigned char* mask_bits = GtkCursors[aCursorType].mask_bits;
+
+ for (int i = 0; i < 128; i++) {
+ char bit = (char)*bits++;
+ char mask = (char)*mask_bits++;
+ for (int j = 0; j < 8; j++) {
+ unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
+ *data++ = pix;
+ *data++ = pix;
+ *data++ = pix;
+ *data++ = (((mask >> j) & 0x01) * 0xff);
+ }
+ }
+
+ gdkcursor = gdk_cursor_new_from_pixbuf(
+ gdk_display_get_default(), cursor_pixbuf, GtkCursors[aCursorType].hot_x,
+ GtkCursors[aCursorType].hot_y);
+
+ g_object_unref(cursor_pixbuf);
+ return gdkcursor;
+}
+
+static GdkCursor* get_gtk_cursor_legacy(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
+ Maybe<uint8_t> fallbackType;
+
+ GdkDisplay* defaultDisplay = gdk_display_get_default();
+
+ // The strategy here is to use standard GDK cursors, and, if not available,
+ // load by standard name with gdk_cursor_new_from_name.
+ // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
+ switch (aCursor) {
+ case eCursor_standard:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
+ break;
+ case eCursor_wait:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH);
+ break;
+ case eCursor_select:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM);
+ break;
+ case eCursor_hyperlink:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2);
+ break;
+ case eCursor_n_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE);
+ break;
+ case eCursor_s_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE);
+ break;
+ case eCursor_w_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE);
+ break;
+ case eCursor_e_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE);
+ break;
+ case eCursor_nw_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_LEFT_CORNER);
+ break;
+ case eCursor_se_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_RIGHT_CORNER);
+ break;
+ case eCursor_ne_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_RIGHT_CORNER);
+ break;
+ case eCursor_sw_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_LEFT_CORNER);
+ break;
+ case eCursor_crosshair:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR);
+ break;
+ case eCursor_move:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
+ break;
+ case eCursor_help:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_QUESTION_ARROW);
+ break;
+ case eCursor_copy: // CSS3
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
+ break;
+ case eCursor_alias:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
+ break;
+ case eCursor_context_menu:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
+ break;
+ case eCursor_cell:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS);
+ break;
+ // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
+ case eCursor_grab:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
+ break;
+ case eCursor_grabbing:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
+ if (!gdkcursor) {
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
+ break;
+ case eCursor_spinning:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
+ break;
+ case eCursor_zoom_in:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
+ break;
+ case eCursor_zoom_out:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
+ break;
+ case eCursor_not_allowed:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
+ if (!gdkcursor) { // nonstandard, yet common
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
+ break;
+ case eCursor_no_drop:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
+ if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
+ // GNOME
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
+ }
+ if (!gdkcursor) {
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
+ break;
+ case eCursor_vertical_text:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
+ if (!gdkcursor) {
+ fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
+ }
+ break;
+ case eCursor_all_scroll:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
+ break;
+ case eCursor_nesw_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
+ break;
+ case eCursor_nwse_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
+ break;
+ case eCursor_ns_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
+ break;
+ case eCursor_ew_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
+ break;
+ // Here, two better fitting cursors exist in some cursor themes. Try those
+ // first
+ case eCursor_row_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
+ if (!gdkcursor) {
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
+ }
+ break;
+ case eCursor_col_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
+ if (!gdkcursor) {
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
+ }
+ break;
+ case eCursor_none:
+ fallbackType.emplace(MOZ_CURSOR_NONE);
+ break;
+ default:
+ NS_ASSERTION(aCursor, "Invalid cursor type");
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
+ break;
+ }
+
+ if (!gdkcursor && fallbackType.isSome()) {
+ LOGW("get_gtk_cursor_legacy(): Failed to get cursor %d, try fallback",
+ aCursor);
+ gdkcursor = get_gtk_cursor_from_type(*fallbackType);
+ }
+
+ return gdkcursor;
+}
+
+static GdkCursor* get_gtk_cursor_from_name(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
+ Maybe<uint8_t> fallbackType;
+
GdkDisplay* defaultDisplay = gdk_display_get_default();
switch (aCursor) {
@@ -7897,42 +8129,42 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_copy:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
- if (!gdkcursor) newType = MOZ_CURSOR_COPY;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
break;
case eCursor_alias:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
- if (!gdkcursor) newType = MOZ_CURSOR_ALIAS;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
break;
case eCursor_context_menu:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
- if (!gdkcursor) newType = MOZ_CURSOR_CONTEXT_MENU;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
break;
case eCursor_cell:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "cell");
break;
case eCursor_grab:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grab");
- if (!gdkcursor) newType = MOZ_CURSOR_HAND_GRAB;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
break;
case eCursor_grabbing:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
- if (!gdkcursor) newType = MOZ_CURSOR_HAND_GRABBING;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
break;
case eCursor_spinning:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
- if (!gdkcursor) newType = MOZ_CURSOR_SPINNING;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
break;
case eCursor_zoom_in:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
- if (!gdkcursor) newType = MOZ_CURSOR_ZOOM_IN;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
break;
case eCursor_zoom_out:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
- if (!gdkcursor) newType = MOZ_CURSOR_ZOOM_OUT;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
break;
case eCursor_not_allowed:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
- if (!gdkcursor) newType = MOZ_CURSOR_NOT_ALLOWED;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
break;
case eCursor_no_drop:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
@@ -7943,12 +8175,12 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
if (!gdkcursor) {
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
}
- if (!gdkcursor) newType = MOZ_CURSOR_NOT_ALLOWED;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
break;
case eCursor_vertical_text:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
if (!gdkcursor) {
- newType = MOZ_CURSOR_VERTICAL_TEXT;
+ fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
}
break;
case eCursor_all_scroll:
@@ -7956,11 +8188,11 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_nesw_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nesw-resize");
- if (!gdkcursor) newType = MOZ_CURSOR_NESW_RESIZE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
break;
case eCursor_nwse_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nwse-resize");
- if (!gdkcursor) newType = MOZ_CURSOR_NWSE_RESIZE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
break;
case eCursor_ns_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ns-resize");
@@ -7976,7 +8208,7 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_none:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "none");
- if (!gdkcursor) newType = MOZ_CURSOR_NONE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NONE);
break;
default:
NS_ASSERTION(aCursor, "Invalid cursor type");
@@ -7984,51 +8216,26 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
}
- // If by now we don't have a xcursor, this means we have to make a custom
- // one. First, we try creating a named cursor based on the hash of our
- // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
- // to themed cursors
- if (newType != 0xFF && GtkCursors[newType].hash) {
- gdkcursor =
- gdk_cursor_new_from_name(defaultDisplay, GtkCursors[newType].hash);
+ if (!gdkcursor && fallbackType.isSome()) {
+ LOGW("get_gtk_cursor_from_name(): Failed to get cursor %d, try fallback",
+ aCursor);
+ gdkcursor = get_gtk_cursor_from_type(*fallbackType);
}
- // If we still don't have a xcursor, we now really create a bitmap cursor
- if (newType != 0xff && !gdkcursor) {
- GdkPixbuf* cursor_pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
- if (!cursor_pixbuf) {
- return nullptr;
- }
-
- guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
-
- // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
- // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
- // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
- // there are 32 rows here).
- const unsigned char* bits = GtkCursors[newType].bits;
- const unsigned char* mask_bits = GtkCursors[newType].mask_bits;
-
- for (int i = 0; i < 128; i++) {
- char bit = (char)*bits++;
- char mask = (char)*mask_bits++;
- for (int j = 0; j < 8; j++) {
- unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
- *data++ = pix;
- *data++ = pix;
- *data++ = pix;
- *data++ = (((mask >> j) & 0x01) * 0xff);
- }
- }
+ return gdkcursor;
+}
- gdkcursor = gdk_cursor_new_from_pixbuf(
- gdk_display_get_default(), cursor_pixbuf, GtkCursors[newType].hot_x,
- GtkCursors[newType].hot_y);
+static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
- g_object_unref(cursor_pixbuf);
+ if ((gdkcursor = gCursorCache[aCursor])) {
+ return gdkcursor;
}
+ gdkcursor = StaticPrefs::widget_gtk_legacy_cursors_enabled()
+ ? get_gtk_cursor_legacy(aCursor)
+ : get_gtk_cursor_from_name(aCursor);
+
gCursorCache[aCursor] = gdkcursor;
return gdkcursor;
@@ -8214,6 +8421,10 @@ static gboolean button_press_event_cb(GtkWidget* widget,
GdkEventButton* event) {
UpdateLastInputEventTime(event);
+ if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
+ return FALSE;
+ }
+
RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
if (!window) {
return FALSE;
@@ -8232,6 +8443,10 @@ static gboolean button_release_event_cb(GtkWidget* widget,
GdkEventButton* event) {
UpdateLastInputEventTime(event);
+ if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
+ return FALSE;
+ }
+
RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
if (!window) {
return FALSE;
@@ -8579,28 +8794,26 @@ gboolean WindowDragMotionHandler(GtkWidget* aWidget,
GdkDragContext* aDragContext, gint aX, gint aY,
guint aTime) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
- if (!window) {
+ if (!window || !window->GetGdkWindow()) {
return FALSE;
}
- // figure out which internal widget this drag motion actually happened on
- nscoord retx = 0;
- nscoord rety = 0;
-
- GdkWindow* innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget),
- aX, aY, &retx, &rety);
- RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
- if (!innerMostWindow) {
- innerMostWindow = window;
+ // We're getting aX,aY in mShell coordinates space.
+ // mContainer is shifted by CSD decorations so translate the coords
+ // to mContainer space where our content lives.
+ if (aWidget == window->GetGtkWidget()) {
+ int x, y;
+ gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
+ aX -= x;
+ aY -= y;
}
- LOGDRAG("WindowDragMotionHandler target nsWindow [%p]",
- innerMostWindow.get());
+
+ LOGDRAG("WindowDragMotionHandler target nsWindow [%p]", window.get());
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsDragService::AutoEventLoop loop(dragService);
if (!dragService->ScheduleMotionEvent(
- innerMostWindow, aDragContext,
- GetWindowDropPosition(innerMostWindow, retx, rety), aTime)) {
+ window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime)) {
return FALSE;
}
return TRUE;
@@ -8656,28 +8869,25 @@ static void drag_leave_event_cb(GtkWidget* aWidget,
gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
gint aX, gint aY, guint aTime) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
- if (!window) {
+ if (!window || !window->GetGdkWindow()) {
return FALSE;
}
- // figure out which internal widget this drag motion actually happened on
- nscoord retx = 0;
- nscoord rety = 0;
-
- GdkWindow* innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget),
- aX, aY, &retx, &rety);
- RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
-
- if (!innerMostWindow) {
- innerMostWindow = window;
+ // We're getting aX,aY in mShell coordinates space.
+ // mContainer is shifted by CSD decorations so translate the coords
+ // to mContainer space where our content lives.
+ if (aWidget == window->GetGtkWidget()) {
+ int x, y;
+ gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
+ aX -= x;
+ aY -= y;
}
- LOGDRAG("WindowDragDropHandler nsWindow [%p]", innerMostWindow.get());
+ LOGDRAG("WindowDragDropHandler nsWindow [%p]", window.get());
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsDragService::AutoEventLoop loop(dragService);
return dragService->ScheduleDropEvent(
- innerMostWindow, aDragContext,
- GetWindowDropPosition(innerMostWindow, retx, rety), aTime);
+ window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime);
}
static gboolean drag_drop_event_cb(GtkWidget* aWidget,
@@ -8710,27 +8920,6 @@ static nsresult initialize_prefs(void) {
return NS_OK;
}
-// TODO: Can we simplify it for mShell/mContainer only scenario?
-static GdkWindow* get_inner_gdk_window(GdkWindow* aWindow, gint x, gint y,
- gint* retx, gint* rety) {
- gint cx, cy, cw, ch;
- GList* children = gdk_window_peek_children(aWindow);
- for (GList* child = g_list_last(children); child;
- child = g_list_previous(child)) {
- auto* childWindow = (GdkWindow*)child->data;
- if (get_window_for_gdk_window(childWindow)) {
- gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch);
- if ((cx < x) && (x < (cx + cw)) && (cy < y) && (y < (cy + ch)) &&
- gdk_window_is_visible(childWindow)) {
- return get_inner_gdk_window(childWindow, x - cx, y - cy, retx, rety);
- }
- }
- }
- *retx = x;
- *rety = y;
- return aWindow;
-}
-
#ifdef ACCESSIBILITY
void nsWindow::CreateRootAccessible() {
if (!mRootAccessible) {
@@ -9548,8 +9737,19 @@ void nsWindow::GetCompositorWidgetInitData(
LOG("nsWindow::GetCompositorWidgetInitData");
+ Window window = GetX11Window();
+#ifdef MOZ_X11
+ // We're bit hackish here. Old GLX backend needs XWindow when GLContext
+ // is created so get XWindow now before map signal.
+ // We may see crashes/errors when nsWindow is unmapped (XWindow is
+ // invalidated) but we can't do anything about it.
+ if (!window && !gfxVars::UseEGL()) {
+ window =
+ gdk_x11_window_get_xid(gtk_widget_get_window(GTK_WIDGET(mContainer)));
+ }
+#endif
*aInitData = mozilla::widget::GtkCompositorWidgetInitData(
- GetX11Window(), displayName, GetShapedState(), GdkIsX11Display(),
+ window, displayName, GetShapedState(), GdkIsX11Display(),
GetClientSize());
#ifdef MOZ_X11
@@ -9927,38 +10127,42 @@ void nsWindow::DisableRendering() {
LOG("nsWindow::DisableRendering()");
if (mGdkWindow) {
- if (mIMContext) {
- mIMContext->SetGdkWindow(nullptr);
- }
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
mGdkWindow = nullptr;
}
+ // 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().
- // 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());
+ // 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().
+ // 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());
+ }
}
- }
#endif
+ }
}
// Apply workaround for Mutter compositor bug (mzbz#1777269).
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
index e235d12c08..f8fe344f09 100644
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -113,6 +113,7 @@ class CurrentX11TimeGetter;
#endif
namespace widget {
+class DBusMenuBar;
class Screen;
} // namespace widget
} // namespace mozilla
@@ -373,6 +374,10 @@ class nsWindow final : public nsBaseWidget {
void UpdateWindowDraggingRegion(
const LayoutDeviceIntRegion& aRegion) override;
+#ifdef MOZ_ENABLE_DBUS
+ void SetDBusMenuBar(RefPtr<mozilla::widget::DBusMenuBar> aDbusMenuBar);
+#endif
+
// HiDPI scale conversion
gint GdkCeiledScaleFactor();
double FractionalScaleFactor();
@@ -654,6 +659,7 @@ class nsWindow final : public nsBaseWidget {
bool mIsDragPopup : 1;
bool mCompositedScreen : 1;
bool mIsAccelerated : 1;
+ bool mIsAlert : 1;
bool mWindowShouldStartDragging : 1;
bool mHasMappedToplevel : 1;
bool mRetryPointerGrab : 1;
@@ -904,6 +910,10 @@ class nsWindow final : public nsBaseWidget {
RefPtr<nsWindow> mWaylandPopupNext;
RefPtr<nsWindow> mWaylandPopupPrev;
+#ifdef MOZ_ENABLE_DBUS
+ RefPtr<mozilla::widget::DBusMenuBar> mDBusMenuBar;
+#endif
+
// When popup is resized by Gtk by move-to-rect callback,
// we store final popup size here. Then we use mMoveToRectPopupSize size
// in following popup operations unless mLayoutPopupSizeCleared is set.
diff --git a/widget/gtk/wayland/moz.build b/widget/gtk/wayland/moz.build
index e033187a3b..b9ea6a4f70 100644
--- a/widget/gtk/wayland/moz.build
+++ b/widget/gtk/wayland/moz.build
@@ -15,6 +15,7 @@ SOURCES += [
"relative-pointer-unstable-v1-protocol.c",
"viewporter-protocol.c",
"xdg-activation-v1-protocol.c",
+ "xdg-dbus-annotation-v1-protocol.c",
"xdg-output-unstable-v1-protocol.c",
]
@@ -26,6 +27,7 @@ EXPORTS.mozilla.widget += [
"relative-pointer-unstable-v1-client-protocol.h",
"viewporter-client-protocol.h",
"xdg-activation-v1-client-protocol.h",
+ "xdg-dbus-annotation-v1-client-protocol.h",
"xdg-output-unstable-v1-client-protocol.h",
]
diff --git a/widget/gtk/wayland/xdg-dbus-annotation-v1-client-protocol.h b/widget/gtk/wayland/xdg-dbus-annotation-v1-client-protocol.h
new file mode 100644
index 0000000000..fe5567cf8e
--- /dev/null
+++ b/widget/gtk/wayland/xdg-dbus-annotation-v1-client-protocol.h
@@ -0,0 +1,284 @@
+/* Generated by wayland-scanner 1.19.0 */
+
+#ifndef XDG_DBUS_ANNOTATION_V1_CLIENT_PROTOCOL_H
+#define XDG_DBUS_ANNOTATION_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_xdg_dbus_annotation_v1 The xdg_dbus_annotation_v1 protocol
+ * Wayland protocol for associating DBus objects with toplevels
+ *
+ * @section page_desc_xdg_dbus_annotation_v1 Description
+ *
+ * This description provides a high-level overview of the interplay between
+ * the interfaces defined in this protocol. For details, see the protocol
+ * specification.
+ *
+ * The dbus_annotation_manager allows a client to request the creation of an
+ * annotation object associated with an wl_surface or itself. The annotation
+ * object allows a client to notify the compositor of a DBus object associated
+ * with itself.
+ *
+ * Clients should request the creation of an dbus_annotation object when they
+ * create a DBus object associated with an wl_surface or themselves, and should
+ * release the object when they destroy a DBus object associated with their
+ * wl_surface or themselves.
+ *
+ * Clients should only own at most one dbus_annotation object with a given name
+ * for each of their wl_surface objects or themselves. A protocol error will be
+ * raised if a client requests more than one dbus_annotation object for an
+ * wl_surface or themselves with a given name.
+ *
+ * @section page_ifaces_xdg_dbus_annotation_v1 Interfaces
+ * - @subpage page_iface_xdg_dbus_annotation_manager_v1 - controller object for
+ * registering dbus objects associated with wl_surfaces or clients
+ * - @subpage page_iface_xdg_dbus_annotation_v1 - controller object for
+ * associating dbus objects with an wl_surface
+ * @section page_copyright_xdg_dbus_annotation_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 David Edmundson
+ * Copyrihgt © 2023 Janet Blackquill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_surface;
+struct xdg_dbus_annotation_manager_v1;
+struct xdg_dbus_annotation_v1;
+
+#ifndef XDG_DBUS_ANNOTATION_MANAGER_V1_INTERFACE
+# define XDG_DBUS_ANNOTATION_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_xdg_dbus_annotation_manager_v1
+ * xdg_dbus_annotation_manager_v1
+ * @section page_iface_xdg_dbus_annotation_manager_v1_desc Description
+ *
+ * An object that provides access to the creation of dbus_annotation objects.
+ * @section page_iface_xdg_dbus_annotation_manager_v1_api API
+ * See @ref iface_xdg_dbus_annotation_manager_v1.
+ */
+/**
+ * @defgroup iface_xdg_dbus_annotation_manager_v1 The
+ * xdg_dbus_annotation_manager_v1 interface
+ *
+ * An object that provides access to the creation of dbus_annotation objects.
+ */
+extern const struct wl_interface xdg_dbus_annotation_manager_v1_interface;
+#endif
+#ifndef XDG_DBUS_ANNOTATION_V1_INTERFACE
+# define XDG_DBUS_ANNOTATION_V1_INTERFACE
+/**
+ * @page page_iface_xdg_dbus_annotation_v1 xdg_dbus_annotation_v1
+ * @section page_iface_xdg_dbus_annotation_v1_desc Description
+ *
+ * An object that provides access to clients to notify the compositor of
+ * associated DBus objects for an wl_surface.
+ *
+ * If not applicable, clients should remove this object.
+ * @section page_iface_xdg_dbus_annotation_v1_api API
+ * See @ref iface_xdg_dbus_annotation_v1.
+ */
+/**
+ * @defgroup iface_xdg_dbus_annotation_v1 The xdg_dbus_annotation_v1 interface
+ *
+ * An object that provides access to clients to notify the compositor of
+ * associated DBus objects for an wl_surface.
+ *
+ * If not applicable, clients should remove this object.
+ */
+extern const struct wl_interface xdg_dbus_annotation_v1_interface;
+#endif
+
+#ifndef XDG_DBUS_ANNOTATION_MANAGER_V1_ERROR_ENUM
+# define XDG_DBUS_ANNOTATION_MANAGER_V1_ERROR_ENUM
+enum xdg_dbus_annotation_manager_v1_error {
+ /**
+ * given wl_surface or client already has a dbus_annotation with the same
+ * interface
+ */
+ XDG_DBUS_ANNOTATION_MANAGER_V1_ERROR_ALREADY_ANNOTATED = 0,
+ /**
+ * given wl_surface is invalid
+ */
+ XDG_DBUS_ANNOTATION_MANAGER_V1_ERROR_BAD_TARGET = 1,
+};
+#endif /* XDG_DBUS_ANNOTATION_MANAGER_V1_ERROR_ENUM */
+
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_DESTROY 0
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_CLIENT 1
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_SURFACE 2
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ */
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ */
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_CLIENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ */
+#define XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_SURFACE_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_dbus_annotation_manager_v1 */
+static inline void xdg_dbus_annotation_manager_v1_set_user_data(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1,
+ void* user_data) {
+ wl_proxy_set_user_data((struct wl_proxy*)xdg_dbus_annotation_manager_v1,
+ user_data);
+}
+
+/** @ingroup iface_xdg_dbus_annotation_manager_v1 */
+static inline void* xdg_dbus_annotation_manager_v1_get_user_data(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1) {
+ return wl_proxy_get_user_data(
+ (struct wl_proxy*)xdg_dbus_annotation_manager_v1);
+}
+
+static inline uint32_t xdg_dbus_annotation_manager_v1_get_version(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1) {
+ return wl_proxy_get_version((struct wl_proxy*)xdg_dbus_annotation_manager_v1);
+}
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ *
+ * Destroy the xdg_dbus_annotation_manager object. xdg_dbus_annotation objects
+ * created from this object remain valid and should be destroyed separately.
+ */
+static inline void xdg_dbus_annotation_manager_v1_destroy(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1) {
+ wl_proxy_marshal((struct wl_proxy*)xdg_dbus_annotation_manager_v1,
+ XDG_DBUS_ANNOTATION_MANAGER_V1_DESTROY);
+
+ wl_proxy_destroy((struct wl_proxy*)xdg_dbus_annotation_manager_v1);
+}
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ *
+ * The interface other DBus clients can expect the object specified by the
+ * annotation to implement.
+ */
+static inline struct xdg_dbus_annotation_v1*
+xdg_dbus_annotation_manager_v1_create_client(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1,
+ const char* interface) {
+ struct wl_proxy* id;
+
+ id = wl_proxy_marshal_constructor(
+ (struct wl_proxy*)xdg_dbus_annotation_manager_v1,
+ XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_CLIENT,
+ &xdg_dbus_annotation_v1_interface, interface, NULL);
+
+ return (struct xdg_dbus_annotation_v1*)id;
+}
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_manager_v1
+ *
+ * The surface to associate the annotation with
+ */
+static inline struct xdg_dbus_annotation_v1*
+xdg_dbus_annotation_manager_v1_create_surface(
+ struct xdg_dbus_annotation_manager_v1* xdg_dbus_annotation_manager_v1,
+ const char* interface, struct wl_surface* toplevel) {
+ struct wl_proxy* id;
+
+ id = wl_proxy_marshal_constructor(
+ (struct wl_proxy*)xdg_dbus_annotation_manager_v1,
+ XDG_DBUS_ANNOTATION_MANAGER_V1_CREATE_SURFACE,
+ &xdg_dbus_annotation_v1_interface, interface, NULL, toplevel);
+
+ return (struct xdg_dbus_annotation_v1*)id;
+}
+
+#define XDG_DBUS_ANNOTATION_V1_DESTROY 0
+#define XDG_DBUS_ANNOTATION_V1_SET_ADDRESS 1
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_v1
+ */
+#define XDG_DBUS_ANNOTATION_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_dbus_annotation_v1
+ */
+#define XDG_DBUS_ANNOTATION_V1_SET_ADDRESS_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_dbus_annotation_v1 */
+static inline void xdg_dbus_annotation_v1_set_user_data(
+ struct xdg_dbus_annotation_v1* xdg_dbus_annotation_v1, void* user_data) {
+ wl_proxy_set_user_data((struct wl_proxy*)xdg_dbus_annotation_v1, user_data);
+}
+
+/** @ingroup iface_xdg_dbus_annotation_v1 */
+static inline void* xdg_dbus_annotation_v1_get_user_data(
+ struct xdg_dbus_annotation_v1* xdg_dbus_annotation_v1) {
+ return wl_proxy_get_user_data((struct wl_proxy*)xdg_dbus_annotation_v1);
+}
+
+static inline uint32_t xdg_dbus_annotation_v1_get_version(
+ struct xdg_dbus_annotation_v1* xdg_dbus_annotation_v1) {
+ return wl_proxy_get_version((struct wl_proxy*)xdg_dbus_annotation_v1);
+}
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_v1
+ */
+static inline void xdg_dbus_annotation_v1_destroy(
+ struct xdg_dbus_annotation_v1* xdg_dbus_annotation_v1) {
+ wl_proxy_marshal((struct wl_proxy*)xdg_dbus_annotation_v1,
+ XDG_DBUS_ANNOTATION_V1_DESTROY);
+
+ wl_proxy_destroy((struct wl_proxy*)xdg_dbus_annotation_v1);
+}
+
+/**
+ * @ingroup iface_xdg_dbus_annotation_v1
+ *
+ * Set or update the service name and object path corresponding to the
+ * DBus object. The DBus object should be registered on the session bus
+ * before sending this request.
+ *
+ * Strings should be formatted in Latin-1 matching the relevant DBus
+ * specifications.
+ */
+static inline void xdg_dbus_annotation_v1_set_address(
+ struct xdg_dbus_annotation_v1* xdg_dbus_annotation_v1,
+ const char* service_name, const char* object_path) {
+ wl_proxy_marshal((struct wl_proxy*)xdg_dbus_annotation_v1,
+ XDG_DBUS_ANNOTATION_V1_SET_ADDRESS, service_name,
+ object_path);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/widget/gtk/wayland/xdg-dbus-annotation-v1-protocol.c b/widget/gtk/wayland/xdg-dbus-annotation-v1-protocol.c
new file mode 100644
index 0000000000..af51b3b0e8
--- /dev/null
+++ b/widget/gtk/wayland/xdg-dbus-annotation-v1-protocol.c
@@ -0,0 +1,75 @@
+/* Generated by wayland-scanner 1.19.0 */
+
+/*
+ * Copyright © 2017 David Edmundson
+ * Copyrihgt © 2023 Janet Blackquill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+# define WL_PRIVATE __attribute__((visibility("hidden")))
+#else
+# define WL_PRIVATE
+#endif
+
+#pragma GCC visibility push(default)
+extern const struct wl_interface wl_surface_interface;
+#pragma GCC visibility pop
+extern const struct wl_interface xdg_dbus_annotation_v1_interface;
+
+static const struct wl_interface* xdg_dbus_annotation_v1_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ &xdg_dbus_annotation_v1_interface,
+ NULL,
+ &xdg_dbus_annotation_v1_interface,
+ &wl_surface_interface,
+};
+
+static const struct wl_message xdg_dbus_annotation_manager_v1_requests[] = {
+ {"destroy", "", xdg_dbus_annotation_v1_types + 0},
+ {"create_client", "sn", xdg_dbus_annotation_v1_types + 2},
+ {"create_surface", "sno", xdg_dbus_annotation_v1_types + 4},
+};
+
+WL_PRIVATE const struct wl_interface xdg_dbus_annotation_manager_v1_interface =
+ {
+ "xdg_dbus_annotation_manager_v1", 1, 3,
+ xdg_dbus_annotation_manager_v1_requests, 0, NULL,
+};
+
+static const struct wl_message xdg_dbus_annotation_v1_requests[] = {
+ {"destroy", "", xdg_dbus_annotation_v1_types + 0},
+ {"set_address", "ss", xdg_dbus_annotation_v1_types + 0},
+};
+
+WL_PRIVATE const struct wl_interface xdg_dbus_annotation_v1_interface = {
+ "xdg_dbus_annotation_v1", 1, 2, xdg_dbus_annotation_v1_requests, 0, NULL,
+};
diff --git a/widget/headless/HeadlessLookAndFeelGTK.cpp b/widget/headless/HeadlessLookAndFeelGTK.cpp
index f8f6270cd7..462a877f34 100644
--- a/widget/headless/HeadlessLookAndFeelGTK.cpp
+++ b/widget/headless/HeadlessLookAndFeelGTK.cpp
@@ -118,9 +118,6 @@ nsresult HeadlessLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::ScrollbarButtonAutoRepeatBehavior:
aResult = 0;
break;
- case IntID::TooltipDelay:
- aResult = 500;
- break;
case IntID::SwipeAnimationEnabled:
aResult = 0;
break;
diff --git a/widget/headless/tests/test_headless.js b/widget/headless/tests/test_headless.js
index f9183245d2..4331cb3fe7 100644
--- a/widget/headless/tests/test_headless.js
+++ b/widget/headless/tests/test_headless.js
@@ -22,7 +22,7 @@ registerCleanupFunction(() => {
const progressListeners = new Map();
function loadContentWindow(windowlessBrowser, uri) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
let loadURIOptions = {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
};
@@ -46,7 +46,7 @@ function loadContentWindow(windowlessBrowser, uri) {
progressListeners.delete(progressListener);
contentWindow.addEventListener(
"load",
- event => {
+ () => {
resolve(contentWindow);
},
{ once: true }
diff --git a/widget/moz.build b/widget/moz.build
index 54a231c67d..557db5e288 100644
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -323,7 +323,7 @@ if toolkit in {"gtk", "cocoa", "windows", "android", "uikit"}:
"nsBaseFilePicker.cpp",
]
-if toolkit in ("gtk", "windows", "cocoa", "android"):
+if toolkit in ("gtk", "windows", "cocoa", "uikit", "android"):
UNIFIED_SOURCES += [
"nsNativeTheme.cpp",
]
diff --git a/widget/nsBaseClipboard.cpp b/widget/nsBaseClipboard.cpp
index 40af1de388..333d154e70 100644
--- a/widget/nsBaseClipboard.cpp
+++ b/widget/nsBaseClipboard.cpp
@@ -812,56 +812,124 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetData(
return NS_OK;
}
-void nsBaseClipboard::AsyncGetDataInternal(
+already_AddRefed<nsIAsyncGetClipboardData>
+nsBaseClipboard::MaybeCreateGetRequestFromClipboardCache(
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
- mozilla::dom::WindowContext* aRequestingWindowContext,
- nsIAsyncClipboardGetCallback* aCallback) {
- MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
+ mozilla::dom::WindowContext* aRequestingWindowContext) {
+ MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
- if (mozilla::StaticPrefs::widget_clipboard_use_cached_data_enabled()) {
- // If we were the last ones to put something on the native clipboard, then
- // just use the cached transferable. Otherwise clear it because it isn't
- // relevant any more.
- if (auto* clipboardCache = GetClipboardCacheIfValid(aClipboardType)) {
- nsITransferable* cachedTransferable = clipboardCache->GetTransferable();
- MOZ_ASSERT(cachedTransferable);
-
- nsTArray<nsCString> transferableFlavors;
- if (NS_SUCCEEDED(cachedTransferable->FlavorsTransferableCanExport(
- transferableFlavors))) {
- nsTArray<nsCString> results;
- for (const auto& transferableFlavor : transferableFlavors) {
- for (const auto& flavor : aFlavorList) {
- // XXX We need special check for image as we always put the
- // image as "native" on the clipboard.
- if (transferableFlavor.Equals(flavor) ||
- (transferableFlavor.Equals(kNativeImageMime) &&
- nsContentUtils::IsFlavorImage(flavor))) {
- MOZ_CLIPBOARD_LOG(" has %s", flavor.get());
- results.AppendElement(flavor);
- }
- }
- }
+ if (!mozilla::StaticPrefs::widget_clipboard_use_cached_data_enabled()) {
+ return nullptr;
+ }
+
+ // If we were the last ones to put something on the native clipboard, then
+ // just use the cached transferable. Otherwise clear it because it isn't
+ // relevant any more.
+ ClipboardCache* clipboardCache = GetClipboardCacheIfValid(aClipboardType);
+ if (!clipboardCache) {
+ return nullptr;
+ }
+
+ nsITransferable* cachedTransferable = clipboardCache->GetTransferable();
+ MOZ_ASSERT(cachedTransferable);
+
+ nsTArray<nsCString> transferableFlavors;
+ if (NS_FAILED(cachedTransferable->FlavorsTransferableCanExport(
+ transferableFlavors))) {
+ return nullptr;
+ }
- // XXX Do we need to check system clipboard for the flavors that cannot
- // be found in cache?
- auto asyncGetClipboardData = mozilla::MakeRefPtr<AsyncGetClipboardData>(
- aClipboardType, clipboardCache->GetSequenceNumber(),
- std::move(results), true, this, aRequestingWindowContext);
- aCallback->OnSuccess(asyncGetClipboardData);
- return;
+ nsTArray<nsCString> results;
+ for (const auto& flavor : aFlavorList) {
+ for (const auto& transferableFlavor : transferableFlavors) {
+ // XXX We need special check for image as we always put the
+ // image as "native" on the clipboard.
+ if (transferableFlavor.Equals(flavor) ||
+ (transferableFlavor.Equals(kNativeImageMime) &&
+ nsContentUtils::IsFlavorImage(flavor))) {
+ MOZ_CLIPBOARD_LOG(" has %s", flavor.get());
+ results.AppendElement(flavor);
}
}
+ }
- // At this point we can't satisfy the request from cache data so let's look
- // for things other people put on the system clipboard.
+ // XXX Do we need to check system clipboard for the flavors that cannot
+ // be found in cache?
+ return mozilla::MakeAndAddRef<AsyncGetClipboardData>(
+ aClipboardType, clipboardCache->GetSequenceNumber(), std::move(results),
+ true /* aFromCache */, this, aRequestingWindowContext);
+}
+
+void nsBaseClipboard::AsyncGetDataInternal(
+ const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
+ mozilla::dom::WindowContext* aRequestingWindowContext,
+ nsIAsyncClipboardGetCallback* aCallback) {
+ MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
+
+ if (nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData =
+ MaybeCreateGetRequestFromClipboardCache(aFlavorList, aClipboardType,
+ aRequestingWindowContext)) {
+ aCallback->OnSuccess(asyncGetClipboardData);
+ return;
}
+ // At this point we can't satisfy the request from cache data so let's
+ // look for things other people put on the system clipboard.
MaybeRetryGetAvailableFlavors(aFlavorList, aClipboardType, aCallback,
kGetAvailableFlavorsRetryCount,
aRequestingWindowContext);
}
+NS_IMETHODIMP nsBaseClipboard::GetDataSnapshotSync(
+ const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
+ mozilla::dom::WindowContext* aRequestingWindowContext,
+ nsIAsyncGetClipboardData** _retval) {
+ MOZ_CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
+
+ *_retval = nullptr;
+
+ if (aFlavorList.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
+ MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
+ aWhichClipboard);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData =
+ MaybeCreateGetRequestFromClipboardCache(aFlavorList, aWhichClipboard,
+ aRequestingWindowContext)) {
+ asyncGetClipboardData.forget(_retval);
+ return NS_OK;
+ }
+
+ auto sequenceNumberOrError =
+ GetNativeClipboardSequenceNumber(aWhichClipboard);
+ if (sequenceNumberOrError.isErr()) {
+ MOZ_CLIPBOARD_LOG("%s: unable to get sequence number for clipboard %d.",
+ __FUNCTION__, aWhichClipboard);
+ return sequenceNumberOrError.unwrapErr();
+ }
+
+ nsTArray<nsCString> results;
+ for (const auto& flavor : aFlavorList) {
+ auto resultOrError = HasNativeClipboardDataMatchingFlavors(
+ AutoTArray<nsCString, 1>{flavor}, aWhichClipboard);
+ if (resultOrError.isOk() && resultOrError.unwrap()) {
+ results.AppendElement(flavor);
+ }
+ }
+
+ *_retval =
+ mozilla::MakeAndAddRef<AsyncGetClipboardData>(
+ aWhichClipboard, sequenceNumberOrError.unwrap(), std::move(results),
+ false /* aFromCache */, this, aRequestingWindowContext)
+ .take();
+ return NS_OK;
+}
+
NS_IMETHODIMP nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard) {
MOZ_CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
diff --git a/widget/nsBaseClipboard.h b/widget/nsBaseClipboard.h
index 8f90be725a..ffa68d6240 100644
--- a/widget/nsBaseClipboard.h
+++ b/widget/nsBaseClipboard.h
@@ -55,6 +55,10 @@ class nsBaseClipboard : public nsIClipboard {
mozilla::dom::WindowContext* aRequestingWindowContext,
nsIPrincipal* aRequestingPrincipal,
nsIAsyncClipboardGetCallback* aCallback) override final;
+ NS_IMETHOD GetDataSnapshotSync(
+ const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
+ mozilla::dom::WindowContext* aRequestingWindowContext,
+ nsIAsyncGetClipboardData** _retval) override final;
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override final;
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
int32_t aWhichClipboard,
@@ -206,6 +210,11 @@ class nsBaseClipboard : public nsIClipboard {
nsIPrincipal* aRequestingPrincipal,
nsIAsyncClipboardGetCallback* aCallback);
+ already_AddRefed<nsIAsyncGetClipboardData>
+ MaybeCreateGetRequestFromClipboardCache(
+ const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
+ mozilla::dom::WindowContext* aRequestingWindowContext);
+
// Track the pending request for each clipboard type separately. And only need
// to track the latest request for each clipboard type as the prior pending
// request will be canceled when a new request is made.
diff --git a/widget/nsBaseFilePicker.cpp b/widget/nsBaseFilePicker.cpp
index 53be3d80b7..faa78f06f2 100644
--- a/widget/nsBaseFilePicker.cpp
+++ b/widget/nsBaseFilePicker.cpp
@@ -18,6 +18,7 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/Components.h"
#include "mozilla/StaticPrefs_widget.h"
#include "WidgetUtils.h"
@@ -156,17 +157,16 @@ nsBaseFilePicker::nsBaseFilePicker()
nsBaseFilePicker::~nsBaseFilePicker() = default;
-NS_IMETHODIMP nsBaseFilePicker::Init(
- mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- mozilla::dom::BrowsingContext* aBrowsingContext) {
- MOZ_ASSERT(aParent,
- "Null parent passed to filepicker, no file "
+NS_IMETHODIMP nsBaseFilePicker::Init(BrowsingContext* aBrowsingContext,
+ const nsAString& aTitle,
+ nsIFilePicker::Mode aMode) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(aBrowsingContext,
+ "Null bc passed to filepicker, no file "
"picker for you!");
- mParent = nsPIDOMWindowOuter::From(aParent);
-
- nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(mParent);
+ nsCOMPtr<nsIWidget> widget =
+ aBrowsingContext->Canonical()->GetParentProcessWidgetContaining();
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
mBrowsingContext = aBrowsingContext;
@@ -462,6 +462,8 @@ nsBaseFilePicker::GetOkButtonLabel(nsAString& aLabel) {
NS_IMETHODIMP
nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ NS_ENSURE_ARG_POINTER(mBrowsingContext);
nsCOMPtr<nsIFile> localFile;
nsresult rv = GetFile(getter_AddRefs(localFile));
NS_ENSURE_SUCCESS(rv, rv);
@@ -471,7 +473,10 @@ nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue) {
return NS_OK;
}
- auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr;
+ auto* innerParent =
+ mBrowsingContext->GetDOMWindow()
+ ? mBrowsingContext->GetDOMWindow()->GetCurrentInnerWindow()
+ : nullptr;
if (!innerParent) {
return NS_ERROR_FAILURE;
@@ -485,11 +490,19 @@ NS_IMETHODIMP
nsBaseFilePicker::GetDomFileOrDirectoryEnumerator(
nsISimpleEnumerator** aValue) {
nsCOMPtr<nsISimpleEnumerator> iter;
+ MOZ_ASSERT(XRE_IsParentProcess());
+ NS_ENSURE_ARG_POINTER(mBrowsingContext);
nsresult rv = GetFiles(getter_AddRefs(iter));
NS_ENSURE_SUCCESS(rv, rv);
+ auto* parent = mBrowsingContext->GetDOMWindow();
+
+ if (!parent) {
+ return NS_ERROR_FAILURE;
+ }
+
RefPtr<nsBaseFilePickerEnumerator> retIter =
- new nsBaseFilePickerEnumerator(mParent, iter, mMode);
+ new nsBaseFilePickerEnumerator(parent, iter, mMode);
retIter.forget(aValue);
return NS_OK;
diff --git a/widget/nsBaseFilePicker.h b/widget/nsBaseFilePicker.h
index 3d26a1822e..52b8bc7798 100644
--- a/widget/nsBaseFilePicker.h
+++ b/widget/nsBaseFilePicker.h
@@ -28,9 +28,8 @@ class nsBaseFilePicker : public nsIFilePicker {
nsBaseFilePicker();
virtual ~nsBaseFilePicker();
- NS_IMETHOD Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- mozilla::dom::BrowsingContext* aBrowsingContext) override;
+ NS_IMETHOD Init(mozilla::dom::BrowsingContext* aBrowsingContext,
+ const nsAString& aTitle, nsIFilePicker::Mode aMode) override;
NS_IMETHOD IsModeSupported(nsIFilePicker::Mode aMode, JSContext* aCx,
mozilla::dom::Promise** aPromise) override;
#ifndef XP_WIN
@@ -70,9 +69,6 @@ class nsBaseFilePicker : public nsIFilePicker {
nsCOMPtr<nsIFile> mDisplayDirectory;
nsString mDisplaySpecialDirectory;
- nsCOMPtr<nsPIDOMWindowOuter> mParent;
- // The BrowsingContext from which the file picker is being opened.
- // Used for content analysis.
RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
nsIFilePicker::Mode mMode;
nsString mOkButtonLabel;
diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp
index 35c580c106..d35afb470a 100644
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -547,6 +547,12 @@ nsIWidget* nsBaseWidget::GetSheetWindowParent(void) { return nullptr; }
float nsBaseWidget::GetDPI() { return 96.0f; }
+void nsBaseWidget::NotifyAPZOfDPIChange() {
+ if (mAPZC) {
+ mAPZC->SetDPI(GetDPI());
+ }
+}
+
CSSToLayoutDeviceScale nsIWidget::GetDefaultScale() {
double devPixelsPerCSSPixel = StaticPrefs::layout_css_devPixelsPerPx();
diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h
index 8b6e8ad0eb..756f2ab7eb 100644
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -354,6 +354,8 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
// theme changes.
void NotifyThemeChanged(mozilla::widget::ThemeChangeKind);
+ void NotifyAPZOfDPIChange();
+
#ifdef ACCESSIBILITY
// Get the accessible for the window.
mozilla::a11y::LocalAccessible* GetRootAccessible();
@@ -365,13 +367,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
PopupLevel GetPopupLevel() { return mPopupLevel; }
- // return true if this is a popup widget with a native titlebar
- bool IsPopupWithTitleBar() const {
- return (mWindowType == WindowType::Popup &&
- mBorderStyle != BorderStyle::Default &&
- mBorderStyle & BorderStyle::Title);
- }
-
void ReparentNativeWidget(nsIWidget* aNewParent) override {}
const SizeConstraints GetSizeConstraints() override;
diff --git a/widget/nsClipboardProxy.cpp b/widget/nsClipboardProxy.cpp
index 41f285461b..3b27d5954d 100644
--- a/widget/nsClipboardProxy.cpp
+++ b/widget/nsClipboardProxy.cpp
@@ -174,6 +174,28 @@ NS_IMETHODIMP AsyncGetClipboardDataProxy::GetData(
return NS_OK;
}
+static Result<RefPtr<AsyncGetClipboardDataProxy>, nsresult>
+CreateAsyncGetClipboardDataProxy(
+ ClipboardReadRequestOrError&& aClipboardReadRequestOrError) {
+ if (aClipboardReadRequestOrError.type() ==
+ ClipboardReadRequestOrError::Tnsresult) {
+ MOZ_ASSERT(NS_FAILED(aClipboardReadRequestOrError.get_nsresult()));
+ return Err(aClipboardReadRequestOrError.get_nsresult());
+ }
+
+ ClipboardReadRequest& request =
+ aClipboardReadRequestOrError.get_ClipboardReadRequest();
+ auto requestChild = MakeRefPtr<ClipboardReadRequestChild>(
+ std::move(request.availableTypes()));
+ if (NS_WARN_IF(
+ !ContentChild::GetSingleton()->BindPClipboardReadRequestEndpoint(
+ std::move(request.childEndpoint()), requestChild))) {
+ return Err(NS_ERROR_FAILURE);
+ }
+
+ return MakeRefPtr<AsyncGetClipboardDataProxy>(requestChild);
+}
+
} // namespace
NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
@@ -198,23 +220,16 @@ NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
->Then(
GetMainThreadSerialEventTarget(), __func__,
/* resolve */
- [callback = nsCOMPtr{aCallback}](const PClipboardReadRequestOrError&
- aClipboardReadRequestOrError) {
- if (aClipboardReadRequestOrError.type() ==
- PClipboardReadRequestOrError::Tnsresult) {
- MOZ_ASSERT(
- NS_FAILED(aClipboardReadRequestOrError.get_nsresult()));
- callback->OnError(aClipboardReadRequestOrError.get_nsresult());
+ [callback = nsCOMPtr{aCallback}](
+ ClipboardReadRequestOrError&& aClipboardReadRequestOrError) {
+ auto result = CreateAsyncGetClipboardDataProxy(
+ std::move(aClipboardReadRequestOrError));
+ if (result.isErr()) {
+ callback->OnError(result.unwrapErr());
return;
}
- auto asyncGetClipboardData = MakeRefPtr<AsyncGetClipboardDataProxy>(
- static_cast<ClipboardReadRequestChild*>(
- aClipboardReadRequestOrError.get_PClipboardReadRequest()
- .AsChild()
- .get()));
-
- callback->OnSuccess(asyncGetClipboardData);
+ callback->OnSuccess(result.inspect());
},
/* reject */
[callback = nsCOMPtr{aCallback}](
@@ -224,6 +239,35 @@ NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
return NS_OK;
}
+NS_IMETHODIMP nsClipboardProxy::GetDataSnapshotSync(
+ const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
+ mozilla::dom::WindowContext* aRequestingWindowContext,
+ nsIAsyncGetClipboardData** _retval) {
+ *_retval = nullptr;
+
+ if (aFlavorList.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
+ MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
+ aWhichClipboard);
+ return NS_ERROR_FAILURE;
+ }
+
+ ContentChild* contentChild = ContentChild::GetSingleton();
+ ClipboardReadRequestOrError requestOrError;
+ contentChild->SendGetClipboardDataSnapshotSync(
+ aFlavorList, aWhichClipboard, aRequestingWindowContext, &requestOrError);
+ auto result = CreateAsyncGetClipboardDataProxy(std::move(requestOrError));
+ if (result.isErr()) {
+ return result.unwrapErr();
+ }
+
+ result.unwrap().forget(_retval);
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard) {
ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
diff --git a/widget/nsFilePickerProxy.cpp b/widget/nsFilePickerProxy.cpp
index 8777f338cb..b71ad0920e 100644
--- a/widget/nsFilePickerProxy.cpp
+++ b/widget/nsFilePickerProxy.cpp
@@ -25,19 +25,19 @@ nsFilePickerProxy::nsFilePickerProxy()
nsFilePickerProxy::~nsFilePickerProxy() = default;
NS_IMETHODIMP
-nsFilePickerProxy::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- BrowsingContext* aBrowsingContext) {
- BrowserChild* browserChild = BrowserChild::GetFrom(aParent);
+nsFilePickerProxy::Init(BrowsingContext* aBrowsingContext,
+ const nsAString& aTitle, nsIFilePicker::Mode aMode) {
+ BrowserChild* browserChild =
+ BrowserChild::GetFrom(aBrowsingContext->GetDocShell());
if (!browserChild) {
return NS_ERROR_FAILURE;
}
- mParent = nsPIDOMWindowOuter::From(aParent);
-
+ mBrowsingContext = aBrowsingContext;
mMode = aMode;
- browserChild->SendPFilePickerConstructor(this, aTitle, aMode);
+ browserChild->SendPFilePickerConstructor(this, aTitle, aMode,
+ aBrowsingContext);
mIPCActive = true;
return NS_OK;
@@ -155,8 +155,9 @@ nsFilePickerProxy::Close() {
mozilla::ipc::IPCResult nsFilePickerProxy::Recv__delete__(
const MaybeInputData& aData, const nsIFilePicker::ResultCode& aResult) {
- nsPIDOMWindowInner* inner =
- mParent ? mParent->GetCurrentInnerWindow() : nullptr;
+ auto* inner = mBrowsingContext->GetDOMWindow()
+ ? mBrowsingContext->GetDOMWindow()->GetCurrentInnerWindow()
+ : nullptr;
if (NS_WARN_IF(!inner)) {
return IPC_OK();
diff --git a/widget/nsFilePickerProxy.h b/widget/nsFilePickerProxy.h
index 1b6aef13ed..9f12ded3ab 100644
--- a/widget/nsFilePickerProxy.h
+++ b/widget/nsFilePickerProxy.h
@@ -34,9 +34,8 @@ class nsFilePickerProxy : public nsBaseFilePicker,
NS_DECL_ISUPPORTS
// nsIFilePicker (less what's in nsBaseFilePicker)
- NS_IMETHOD Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- mozilla::dom::BrowsingContext* aBrowsingContext) override;
+ NS_IMETHOD Init(mozilla::dom::BrowsingContext* aBrowsingContext,
+ const nsAString& aTitle, nsIFilePicker::Mode aMode) override;
NS_IMETHOD AppendFilter(const nsAString& aTitle,
const nsAString& aFilter) override;
NS_IMETHOD GetCapture(nsIFilePicker::CaptureTarget* aCapture) override;
diff --git a/widget/nsIClipboard.idl b/widget/nsIClipboard.idl
index 5ed2d22600..a34f0f9298 100644
--- a/widget/nsIClipboard.idl
+++ b/widget/nsIClipboard.idl
@@ -178,6 +178,31 @@ interface nsIClipboard : nsISupports
in nsIPrincipal aRequestingPrincipal,
in nsIAsyncClipboardGetCallback aCallback);
+ /**
+ * Requests getting data from the native clipboard. This does not actually
+ * retreive the data, but returns a nsIAsyncGetClipboardData contains
+ * current avaiable data formats. If the native clipboard is updated, either
+ * by us or other application, the existing nsIAsyncGetClipboardData becomes
+ * invalid.
+ *
+ * @param aFlavorList
+ * Specific data formats ('flavors') that can be retrieved from the
+ * clipboard.
+ * @param aWhichClipboard
+ * Specifies the clipboard to which this operation applies.
+ * @param aRequestingWindowContext [optional]
+ * The window context window that is requesting the clipboard, which is
+ * used for content analysis. Passing null means that the content is
+ * exempt from content analysis. (for example, scripted clipboard read by
+ * system code) This parameter should not be null when calling this from a
+ * content process.
+ * @return nsIAsyncSetClipboardData if successful.
+ * @throws if the request can not be made.
+ */
+ nsIAsyncGetClipboardData getDataSnapshotSync(in Array<ACString> aFlavorList,
+ in long aWhichClipboard,
+ [optional] in WindowContext aRequestingWindowContext);
+
/**
* This empties the clipboard and notifies the clipboard owner.
* This empties the "logical" clipboard. It does not clear the native clipboard.
diff --git a/widget/nsIFilePicker.idl b/widget/nsIFilePicker.idl
index e9bdedfd42..db5ac9f7bd 100644
--- a/widget/nsIFilePicker.idl
+++ b/widget/nsIFilePicker.idl
@@ -66,19 +66,13 @@ interface nsIFilePicker : nsISupports
* Initialize the file picker widget. The file picker is not valid until this
* method is called.
*
- * @param parent mozIDOMWindow parent. This dialog will be dependent
- * on this parent. parent must be non-null.
- * @param title The title for the file widget
- * @param mode load, save, or get folder
- * @param browsingContext [optional]
- * The context in which the file picker is being shown. This is
- * used for content analysis and can be omitted if chrome is
- * showing the file picker.
- */
- void init(in mozIDOMWindowProxy parent,
- in AString title,
- in nsIFilePicker_Mode mode,
- [optional] in BrowsingContext browsingContext);
+ * @param browsingContext The context in which the file picker is being
+ * shown, must be non-null.
+ * @param title The title for the file widget
+ * @param mode load, save, or get folder
+ *
+ */
+ void init(in BrowsingContext browsingContext, in AString title, in nsIFilePicker_Mode mode);
/**
* Returns a Promise that resolves to true if the passed nsIFilePicker mode
diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl
index 4f4f0b7e1e..0df8696da7 100644
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -19,6 +19,8 @@ interface nsIGfxInfo : nsISupports
readonly attribute AString AzureCanvasBackend;
readonly attribute AString AzureContentBackend;
readonly attribute boolean usingGPUProcess;
+ readonly attribute boolean usingRemoteCanvas;
+ readonly attribute boolean usingAcceleratedCanvas;
readonly attribute boolean hasBattery;
readonly attribute AString DWriteVersion;
readonly attribute AString cleartypeParameters;
@@ -215,8 +217,12 @@ interface nsIGfxInfo : nsISupports
const long FEATURE_VIDEO_SOFTWARE_OVERLAY = 46;
/* Whether WebGL is allowed to use hardware rendering, otherwise software fallbacks. */
const long FEATURE_WEBGL_USE_HARDWARE = 47;
+ /* Whether overlay is allowed to VideoProcessor-HDR on SDR content */
+ const long FEATURE_OVERLAY_VP_AUTO_HDR = 48;
+ /* Whether overlay is allowed to VideoProcessor Super Resolution */
+ const long FEATURE_OVERLAY_VP_SUPER_RESOLUTION = 49;
/* the maximum feature value. */
- const long FEATURE_MAX_VALUE = FEATURE_WEBGL_USE_HARDWARE;
+ const long FEATURE_MAX_VALUE = FEATURE_OVERLAY_VP_SUPER_RESOLUTION;
/*
* A set of return values from GetFeatureStatus
diff --git a/widget/nsIPrintDialogService.idl b/widget/nsIPrintDialogService.idl
index 1c79ddd76b..b1e318b948 100644
--- a/widget/nsIPrintDialogService.idl
+++ b/widget/nsIPrintDialogService.idl
@@ -56,11 +56,3 @@ interface nsIPrintDialogService : nsISupports
in nsIPrintSettings aPrintSettings);
};
-
-%{C++
-#define NS_PRINTDIALOGSERVICE_IID \
- {0x88af6712, 0xa9fd, 0x4393, { 0x9a, 0xf3, 0x3f, 0xfb, 0xb1, 0xf2, 0xca, 0xaf}}
-
-#define NS_PRINTDIALOGSERVICE_CONTRACTID \
- ("@mozilla.org/widget/printdialog-service;1")
-%}
diff --git a/widget/nsIPrintSettingsService.idl b/widget/nsIPrintSettingsService.idl
index 3b33724c34..7e57c6766e 100644
--- a/widget/nsIPrintSettingsService.idl
+++ b/widget/nsIPrintSettingsService.idl
@@ -143,9 +143,3 @@ interface nsIPrintSettingsService : nsISupports
in nsIPrintSettings aPrintSettings);
};
-
-%{C++
-// {841387C8-72E6-484b-9296-BF6EEA80D58A}
-#define NS_PRINTSETTINGSSERVICE_IID \
- {0x841387c8, 0x72e6, 0x484b, { 0x92, 0x96, 0xbf, 0x6e, 0xea, 0x80, 0xd5, 0x8a}}
-%}
diff --git a/widget/nsISound.idl b/widget/nsISound.idl
index 8b4a2f29c0..c3aca6674d 100644
--- a/widget/nsISound.idl
+++ b/widget/nsISound.idl
@@ -23,10 +23,6 @@ interface nsISound : nsISupports
/**
* In some situations, playEventSound will be called. Then, each
* implementations will play a system sound for the event if it's necessary.
- *
- * NOTE: Don't change these values because they are used in
- * nsPIPromptService.idl. So, if they are changed, that makes big impact for
- * the embedders.
*/
const unsigned long EVENT_NEW_MAIL_RECEIVED = 0;
const unsigned long EVENT_ALERT_DIALOG_OPEN = 1;
diff --git a/widget/nsNativeTheme.cpp b/widget/nsNativeTheme.cpp
index 2484f802cd..6900414ff3 100644
--- a/widget/nsNativeTheme.cpp
+++ b/widget/nsNativeTheme.cpp
@@ -57,6 +57,12 @@ NS_IMPL_ISUPPORTS(nsNativeTheme, nsITimerCallback, nsINamed)
aAppearance == StyleAppearance::ButtonArrowPrevious ||
aAppearance == StyleAppearance::ButtonArrowNext ||
aAppearance == StyleAppearance::ButtonArrowUp ||
+#ifdef MOZ_WIDGET_GTK
+ aAppearance == StyleAppearance::MozWindowButtonClose ||
+ aAppearance == StyleAppearance::MozWindowButtonMinimize ||
+ aAppearance == StyleAppearance::MozWindowButtonRestore ||
+ aAppearance == StyleAppearance::MozWindowButtonMaximize ||
+#endif
aAppearance == StyleAppearance::ButtonArrowDown) {
aFrame = aFrame->GetParent();
frameContent = aFrame->GetContent();
diff --git a/widget/nsPrinterBase.cpp b/widget/nsPrinterBase.cpp
index 7e01b9e12f..0c8f71d574 100644
--- a/widget/nsPrinterBase.cpp
+++ b/widget/nsPrinterBase.cpp
@@ -10,6 +10,7 @@
#include "nsIPrintSettings.h"
#include "nsPrintSettingsService.h"
#include "PrintBackgroundTask.h"
+#include "mozilla/EnumeratedArrayCycleCollection.h"
#include "mozilla/dom/Promise.h"
using namespace mozilla;
@@ -83,25 +84,6 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterInfo)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterInfo)
-template <typename Index, Index Size, typename Value>
-inline void ImplCycleCollectionTraverse(
- nsCycleCollectionTraversalCallback& aCallback,
- EnumeratedArray<Index, Size, Value>& aArray, const char* aName,
- uint32_t aFlags = 0) {
- aFlags |= CycleCollectionEdgeNameArrayFlag;
- for (Value& element : aArray) {
- ImplCycleCollectionTraverse(aCallback, element, aName, aFlags);
- }
-}
-
-template <typename Index, Index Size, typename Value>
-inline void ImplCycleCollectionUnlink(
- EnumeratedArray<Index, Size, Value>& aArray) {
- for (Value& element : aArray) {
- ImplCycleCollectionUnlink(element);
- }
-}
-
namespace mozilla {
template <>
@@ -143,8 +125,8 @@ nsresult nsPrinterBase::AsyncPromiseAttributeGetter(
BackgroundTask<T, Args...> aBackgroundTask, Args... aArgs) {
MOZ_ASSERT(NS_IsMainThread());
- static constexpr EnumeratedArray<AsyncAttribute, AsyncAttribute::Last,
- nsLiteralCString>
+ static constexpr EnumeratedArray<AsyncAttribute, nsLiteralCString,
+ size_t(AsyncAttribute::Last)>
attributeKeys{"SupportsDuplex"_ns, "SupportsColor"_ns,
"SupportsMonochrome"_ns, "SupportsCollation"_ns,
"PrinterInfo"_ns};
diff --git a/widget/nsPrinterBase.h b/widget/nsPrinterBase.h
index abd4f82705..8ce1f8a90d 100644
--- a/widget/nsPrinterBase.h
+++ b/widget/nsPrinterBase.h
@@ -104,8 +104,8 @@ class nsPrinterBase : public nsIPrinter {
const mozilla::gfx::SizeDouble& aSize) const;
private:
- mozilla::EnumeratedArray<AsyncAttribute, AsyncAttribute::Last,
- RefPtr<Promise>>
+ mozilla::EnumeratedArray<AsyncAttribute, RefPtr<Promise>,
+ size_t(AsyncAttribute::Last)>
mAsyncAttributePromises;
// List of built-in, commonly used paper sizes.
const RefPtr<const mozilla::CommonPaperInfoArray> mCommonPaperInfo;
diff --git a/widget/nsXPLookAndFeel.cpp b/widget/nsXPLookAndFeel.cpp
index 05b8952b04..9eabbd84b6 100644
--- a/widget/nsXPLookAndFeel.cpp
+++ b/widget/nsXPLookAndFeel.cpp
@@ -57,7 +57,7 @@ using FontID = mozilla::LookAndFeel::FontID;
template <typename Index, typename Value, Index kEnd>
class EnumeratedCache {
- mozilla::EnumeratedArray<Index, kEnd, Value> mEntries;
+ mozilla::EnumeratedArray<Index, Value, size_t(kEnd)> mEntries;
std::bitset<size_t(kEnd)> mValidity;
public:
@@ -161,7 +161,6 @@ static const char sIntPrefs[][45] = {
"ui.SpellCheckerUnderlineStyle",
"ui.menuBarDrag",
"ui.scrollbarButtonAutoRepeatBehavior",
- "ui.tooltipDelay",
"ui.swipeAnimationEnabled",
"ui.scrollbarDisplayOnMouseMove",
"ui.scrollbarFadeBeginDelay",
@@ -185,6 +184,7 @@ static const char sIntPrefs[][45] = {
"ui.systemScrollbarSize",
"ui.touchDeviceSupportPresent",
"ui.titlebarRadius",
+ "ui.titlebarButtonSpacing",
"ui.dynamicRange",
"ui.videoDynamicRange",
"ui.panelAnimations",
diff --git a/widget/tests/browser/browser_test_clipboard_contextmenu.js b/widget/tests/browser/browser_test_clipboard_contextmenu.js
index 4d268d5be4..80e8c33282 100644
--- a/widget/tests/browser/browser_test_clipboard_contextmenu.js
+++ b/widget/tests/browser/browser_test_clipboard_contextmenu.js
@@ -63,7 +63,7 @@ async function clipboardAsyncGetData(aBrowser, aClipboardType) {
"nsIAsyncClipboardGetCallback",
]),
// nsIAsyncClipboardGetCallback
- onSuccess: aAsyncGetClipboardData => {
+ onSuccess: () => {
resolve();
},
onError: aResult => {
diff --git a/widget/tests/browser/browser_test_clipboardcache.js b/widget/tests/browser/browser_test_clipboardcache.js
index 8cb6adb8b5..64deb99608 100644
--- a/widget/tests/browser/browser_test_clipboardcache.js
+++ b/widget/tests/browser/browser_test_clipboardcache.js
@@ -103,6 +103,10 @@ async function testCopyPaste(isPrivate) {
document.execCommand("paste");
return pastePromise;
});
+
+ // Don't use Assert.strictEqual here because the test starts timing out,
+ // because the logging creates lots of copies of this very huge string.
+ // eslint-disable-next-line mozilla/no-comparison-or-assignment-inside-ok
ok(readStr === Ipsum, "Read what we pasted");
if (isPrivate) {
diff --git a/widget/tests/browser/browser_test_swipe_gesture.js b/widget/tests/browser/browser_test_swipe_gesture.js
index 0ac85d80c8..0f45672206 100644
--- a/widget/tests/browser/browser_test_swipe_gesture.js
+++ b/widget/tests/browser/browser_test_swipe_gesture.js
@@ -123,9 +123,9 @@ add_task(async () => {
computedOpacity = window
.getComputedStyle(gHistorySwipeAnimation._prevBox)
.getPropertyValue("opacity");
- ok(computedOpacity == 1, "computed opacity of prevbox is 1");
+ Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
opacity = gHistorySwipeAnimation._prevBox.style.opacity;
- ok(opacity == 0, "element.style opacity of prevbox 0");
+ Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
if (isTranslatingIcon) {
// We don't have a transition for translate property so that we still have
@@ -232,9 +232,9 @@ add_task(async () => {
computedOpacity = window
.getComputedStyle(gHistorySwipeAnimation._prevBox)
.getPropertyValue("opacity");
- ok(computedOpacity == 1, "computed opacity of prevbox is 1");
+ Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
opacity = gHistorySwipeAnimation._prevBox.style.opacity;
- ok(opacity == 0, "element.style opacity of prevbox 0");
+ Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
// Make sure the gesture triggered going back to the previous page.
await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
@@ -317,9 +317,9 @@ add_task(async () => {
let computedOpacity = window
.getComputedStyle(gHistorySwipeAnimation._prevBox)
.getPropertyValue("opacity");
- ok(computedOpacity == 1, "computed opacity of prevbox is 1");
+ Assert.equal(computedOpacity, 1, "computed opacity of prevbox is 1");
let opacity = gHistorySwipeAnimation._prevBox.style.opacity;
- ok(opacity == 0, "element.style opacity of prevbox 0");
+ Assert.equal(opacity, 0, "element.style opacity of prevbox 0");
// Make sure the gesture triggered going back to the previous page.
await Promise.all([startLoadingPromise, stoppedLoadingPromise]);
@@ -343,7 +343,7 @@ add_task(async () => {
}
numTries--;
}
- ok(numTries > 0, "never ran the test");
+ Assert.greater(numTries, 0, "never ran the test");
await SpecialPowers.popPrefEnv();
});
@@ -576,7 +576,7 @@ add_task(async () => {
await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 100);
- ok(gHistorySwipeAnimation._prevBox != null, "should have prevbox");
+ Assert.notEqual(gHistorySwipeAnimation._prevBox, null, "should have prevbox");
let transitionCancelPromise = new Promise(resolve => {
gHistorySwipeAnimation._prevBox.addEventListener(
"transitioncancel",
@@ -635,7 +635,7 @@ add_task(async () => {
await panRightToLeftBegin(tab.linkedBrowser, 100, 100, 100);
- ok(gHistorySwipeAnimation._nextBox != null, "should have nextbox");
+ Assert.notEqual(gHistorySwipeAnimation._nextBox, null, "should have nextbox");
transitionCancelPromise = new Promise(resolve => {
gHistorySwipeAnimation._nextBox.addEventListener(
"transitioncancel",
@@ -1131,7 +1131,7 @@ add_task(async () => {
// Set up an APZ aware event listener and...
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
- content.document.documentElement.addEventListener("wheel", e => {}, {
+ content.document.documentElement.addEventListener("wheel", () => {}, {
passive: false,
});
await content.wrappedJSObject.promiseApzFlushedRepaints();
diff --git a/widget/tests/chrome.toml b/widget/tests/chrome.toml
index 08d02d3c36..8706a67185 100644
--- a/widget/tests/chrome.toml
+++ b/widget/tests/chrome.toml
@@ -9,9 +9,6 @@ support-files = [
# Privacy relevant
-["test_bug1123480.xhtml"]
-skip-if = ["win11_2009 && bits == 32"]
-
["test_bug343416.xhtml"]
skip-if = ["debug"]
@@ -66,8 +63,8 @@ run-if = ["os == 'mac'"] # Cocoa widget test
["test_bug760802.xhtml"]
-["test_clipboard_chrome.html"]
-support-files = "file_test_clipboard.js"
+["test_bug1123480.xhtml"]
+skip-if = ["win11_2009 && bits == 32"]
["test_clipboard_asyncGetData_chrome.html"]
support-files = "file_test_clipboard_asyncGetData.js"
@@ -77,11 +74,20 @@ support-files = "file_test_clipboard_asyncSetData.js"
["test_clipboard_cache_chrome.html"]
+["test_clipboard_chrome.html"]
+support-files = "file_test_clipboard.js"
+
+["test_clipboard_getDataSnapshotSync_chrome.html"]
+support-files = "file_test_clipboard_getDataSnapshotSync.js"
+
["test_clipboard_owner_chrome.html"]
["test_composition_text_querycontent.xhtml"]
support-files = ["window_composition_text_querycontent.xhtml"]
+["test_ime_focus_with_multiple_contenteditable.html"]
+support-files = ["file_ime_state_test_helper.js"]
+
["test_ime_state_in_contenteditable_on_readonly_change_in_parent.html"]
support-files = [
"file_ime_state_test_helper.js",
diff --git a/widget/tests/clipboard_helper.js b/widget/tests/clipboard_helper.js
index 96787468fb..76ed2aeb37 100644
--- a/widget/tests/clipboard_helper.js
+++ b/widget/tests/clipboard_helper.js
@@ -157,11 +157,21 @@ function getClipboardData(aFlavor, aClipboardType) {
}
}
-function asyncGetClipboardData(aClipboardType) {
+function getClipboardDataSnapshotSync(aClipboardType) {
+ return clipboard.getDataSnapshotSync(
+ ["text/plain", "text/html", "image/png"],
+ aClipboardType
+ );
+}
+
+function asyncGetClipboardData(
+ aClipboardType,
+ aFormats = ["text/plain", "text/html", "image/png"]
+) {
return new Promise((resolve, reject) => {
try {
clipboard.asyncGetData(
- ["text/plain", "text/html", "image/png"],
+ aFormats,
aClipboardType,
null,
SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
diff --git a/widget/tests/file_test_clipboard_asyncGetData.js b/widget/tests/file_test_clipboard_asyncGetData.js
index e7f2e5f0f1..3ff5700e1a 100644
--- a/widget/tests/file_test_clipboard_asyncGetData.js
+++ b/widget/tests/file_test_clipboard_asyncGetData.js
@@ -94,7 +94,7 @@ clipboardTypes.forEach(function (type) {
() => {
ok(false, "asyncClipboardRequestGetData should not success");
},
- e => {
+ () => {
ok(true, "asyncClipboardRequestGetData should reject");
}
);
@@ -133,7 +133,7 @@ clipboardTypes.forEach(function (type) {
() => {
ok(false, "asyncClipboardRequestGetData should not success");
},
- e => {
+ () => {
ok(true, "asyncClipboardRequestGetData should reject");
}
);
diff --git a/widget/tests/file_test_clipboard_getDataSnapshotSync.js b/widget/tests/file_test_clipboard_getDataSnapshotSync.js
new file mode 100644
index 0000000000..92d7475e9c
--- /dev/null
+++ b/widget/tests/file_test_clipboard_getDataSnapshotSync.js
@@ -0,0 +1,153 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* import-globals-from clipboard_helper.js */
+
+"use strict";
+
+clipboardTypes.forEach(function (type) {
+ if (!clipboard.isClipboardTypeSupported(type)) {
+ add_task(async function test_clipboard_requestGetData_not_support() {
+ info(`Test getDataSnapshotSync request throwing on ${type}`);
+ SimpleTest.doesThrow(
+ () => clipboard.getDataSnapshotSync(["text/plain"], type),
+ "Passing unsupported clipboard type should throw"
+ );
+ });
+ return;
+ }
+
+ add_task(async function test_clipboard_getDataSnapshotSync_throw() {
+ info(`Test getDataSnapshotSync request throwing on ${type}`);
+ SimpleTest.doesThrow(
+ () => clipboard.getDataSnapshotSync([], type),
+ "Passing empty flavor list should throw"
+ );
+ });
+
+ add_task(
+ async function test_clipboard_getDataSnapshotSync_no_matched_flavor() {
+ info(`Test getDataSnapshotSync have no matched flavor on ${type}`);
+ cleanupAllClipboard();
+ is(
+ getClipboardData("text/plain", type),
+ null,
+ "ensure clipboard is empty"
+ );
+
+ writeRandomStringToClipboard("text/plain", type);
+ let request = clipboard.getDataSnapshotSync(["text/html"], type);
+ isDeeply(request.flavorList, [], "Check flavorList");
+ }
+ );
+
+ add_task(async function test_empty_data() {
+ info(`Test getDataSnapshotSync request with empty data on ${type}`);
+ cleanupAllClipboard();
+ is(getClipboardData("text/plain", type), null, "ensure clipboard is empty");
+
+ let request = getClipboardDataSnapshotSync(type);
+ isDeeply(request.flavorList, [], "Check flavorList");
+ await asyncClipboardRequestGetData(request, "text/plain", true).catch(
+ () => {}
+ );
+ });
+
+ add_task(async function test_clipboard_getDataSnapshotSync_after_write() {
+ info(`Test getDataSnapshotSync request after write on ${type}`);
+
+ let str = writeRandomStringToClipboard("text/plain", type);
+ let request = getClipboardDataSnapshotSync(type);
+ isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
+ is(
+ await asyncClipboardRequestGetData(request, "text/plain"),
+ str,
+ "Check data"
+ );
+ ok(request.valid, "request should still be valid");
+ // Requesting a flavor that is not in the list should throw error.
+ await asyncClipboardRequestGetData(request, "text/html", true).catch(
+ () => {}
+ );
+ ok(request.valid, "request should still be valid");
+
+ // Writing a new data should invalid existing get request.
+ str = writeRandomStringToClipboard("text/plain", type);
+ await asyncClipboardRequestGetData(request, "text/plain").then(
+ () => {
+ ok(false, "asyncClipboardRequestGetData should not success");
+ },
+ () => {
+ ok(true, "asyncClipboardRequestGetData should reject");
+ }
+ );
+ ok(!request.valid, "request should no longer be valid");
+
+ info(`check clipboard data again`);
+ request = getClipboardDataSnapshotSync(type);
+ isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
+ is(
+ await asyncClipboardRequestGetData(request, "text/plain"),
+ str,
+ "Check data"
+ );
+
+ cleanupAllClipboard();
+ });
+
+ add_task(async function test_clipboard_getDataSnapshotSync_after_empty() {
+ info(`Test getDataSnapshotSync request after empty on ${type}`);
+
+ let str = writeRandomStringToClipboard("text/plain", type);
+ let request = getClipboardDataSnapshotSync(type);
+ isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
+ is(
+ await asyncClipboardRequestGetData(request, "text/plain"),
+ str,
+ "Check data"
+ );
+ ok(request.valid, "request should still be valid");
+
+ // Empty clipboard data
+ emptyClipboardData(type);
+ is(getClipboardData("text/plain", type), null, "ensure clipboard is empty");
+
+ await asyncClipboardRequestGetData(request, "text/plain").then(
+ () => {
+ ok(false, "asyncClipboardRequestGetData should not success");
+ },
+ () => {
+ ok(true, "asyncClipboardRequestGetData should reject");
+ }
+ );
+ ok(!request.valid, "request should no longer be valid");
+
+ info(`check clipboard data again`);
+ request = getClipboardDataSnapshotSync(type);
+ isDeeply(request.flavorList, [], "Check flavorList");
+
+ cleanupAllClipboard();
+ });
+});
+
+add_task(async function test_clipboard_getDataSnapshotSync_html_data() {
+ info(`Test getDataSnapshotSync request with html data`);
+
+ const html_str = `<img src="https://example.com/oops">`;
+ writeStringToClipboard(html_str, "text/html", clipboard.kGlobalClipboard);
+
+ let request = getClipboardDataSnapshotSync(clipboard.kGlobalClipboard);
+ isDeeply(request.flavorList, ["text/html"], "Check flavorList");
+ is(
+ await asyncClipboardRequestGetData(request, "text/html"),
+ // On Windows, widget adds extra data into HTML clipboard.
+ navigator.platform.includes("Win")
+ ? `<html><body>\n<!--StartFragment-->${html_str}<!--EndFragment-->\n</body>\n</html>`
+ : html_str,
+ "Check data"
+ );
+ // Requesting a flavor that is not in the list should throw error.
+ await asyncClipboardRequestGetData(request, "text/plain", true).catch(
+ () => {}
+ );
+});
diff --git a/widget/tests/mochitest.toml b/widget/tests/mochitest.toml
index 32dcf5c795..4a4a9d2729 100644
--- a/widget/tests/mochitest.toml
+++ b/widget/tests/mochitest.toml
@@ -25,12 +25,16 @@ skip-if = [
support-files = ["file_test_clipboard.js"]
["test_clipboard_asyncGetData.html"]
-skip-if = ["display == 'wayland'"] # Bug 1864211
+skip-if = ["display == 'wayland'"] # Bug 1879835
support-files = ["file_test_clipboard_asyncGetData.js"]
["test_clipboard_asyncSetData.html"]
support-files = ["file_test_clipboard_asyncSetData.js"]
+["test_clipboard_getDataSnapshotSync.html"]
+skip-if = ["display == 'wayland'"] # Bug 1879835
+support-files = "file_test_clipboard_getDataSnapshotSync.js"
+
["test_contextmenu_by_mouse_on_unix.html"]
run-if = ["os == 'linux'"]
skip-if = ["headless"] # headless widget doesn't dispatch contextmenu event by mouse event.
diff --git a/widget/tests/standalone_native_menu_window.xhtml b/widget/tests/standalone_native_menu_window.xhtml
index 4155126ad5..36c65b0e2c 100644
--- a/widget/tests/standalone_native_menu_window.xhtml
+++ b/widget/tests/standalone_native_menu_window.xhtml
@@ -141,13 +141,13 @@
let popupShowingFired = false;
let itemActivated = false;
- menupopup.addEventListener("popupshowing", function (e) {
+ menupopup.addEventListener("popupshowing", function () {
popupShowingFired = true;
let menuitem = document.createElementNS(XUL_NS, "menuitem");
menuitem.setAttribute("label", "detached menu item");
/* eslint-disable-next-line no-shadow */
- menuitem.addEventListener("command", function (e) {
+ menuitem.addEventListener("command", function () {
itemActivated = true;
})
menupopup.appendChild(menuitem);
diff --git a/widget/tests/test_bug343416.xhtml b/widget/tests/test_bug343416.xhtml
index bf4dbbb9b4..32e717d6e5 100644
--- a/widget/tests/test_bug343416.xhtml
+++ b/widget/tests/test_bug343416.xhtml
@@ -30,7 +30,7 @@ SimpleTest.waitForExplicitFinish();
var idleObserver =
{
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
- observe: function _observe(subject, topic, data)
+ observe: function _observe(subject, topic)
{
if (topic != "idle")
return;
diff --git a/widget/tests/test_clipboard_cache_chrome.html b/widget/tests/test_clipboard_cache_chrome.html
index 55b6d41589..81d7a652b6 100644
--- a/widget/tests/test_clipboard_cache_chrome.html
+++ b/widget/tests/test_clipboard_cache_chrome.html
@@ -37,7 +37,12 @@ function testClipboardCache(aClipboardType, aAsync, aIsSupportGetFromCachedTrans
addStringToTransferable("text/foo", string, trans);
// XXX macOS caches the transferable to implement kSelectionCache type, too,
// so it behaves differently than other types.
- if (aClipboardType == clipboard.kSelectionCache && !aIsSupportGetFromCachedTransferable) {
+ if (
+ navigator.platform.includes("Mac") &&
+ aClipboardType == clipboard.kSelectionCache &&
+ !aIsSupportGetFromCachedTransferable &&
+ !SpecialPowers.isHeadless
+ ) {
todo_is(getClipboardData("text/foo", aClipboardType),
aIsSupportGetFromCachedTransferable ? string : null,
`Check text/foo data on clipboard ${aClipboardType}`);
@@ -66,7 +71,12 @@ function testClipboardCache(aClipboardType, aAsync, aIsSupportGetFromCachedTrans
`Check text/plain data on clipboard ${aClipboardType} again`);
// XXX macOS caches the transferable to implement kSelectionCache type, too,
// so it behaves differently than other types.
- if (aClipboardType == clipboard.kSelectionCache && !aIsSupportGetFromCachedTransferable) {
+ if (
+ navigator.platform.includes("Mac") &&
+ aClipboardType == clipboard.kSelectionCache &&
+ !aIsSupportGetFromCachedTransferable &&
+ !SpecialPowers.isHeadless
+ ) {
todo_is(getClipboardData("text/foo", aClipboardType),
aIsSupportGetFromCachedTransferable ? string : null,
`Check text/foo data on clipboard ${aClipboardType} again`);
@@ -118,7 +128,12 @@ function runClipboardCacheTests(aIsSupportGetFromCachedTransferable) {
`Check if there is text/plain flavor on clipboard ${type}`);
// XXX macOS caches the transferable to implement kSelectionCache type, too,
// so it behaves differently than other types.
- if (type == clipboard.kSelectionCache && !aIsSupportGetFromCachedTransferable) {
+ if (
+ navigator.platform.includes("Mac") &&
+ type == clipboard.kSelectionCache &&
+ !aIsSupportGetFromCachedTransferable &&
+ !SpecialPowers.isHeadless
+ ) {
todo_is(clipboard.hasDataMatchingFlavors(["text/foo"], type),
aIsSupportGetFromCachedTransferable,
`Check if there is text/foo flavor on clipboard ${type}`);
@@ -147,7 +162,12 @@ function runClipboardCacheTests(aIsSupportGetFromCachedTransferable) {
`Check if there is text/plain flavor on clipboard ${type}`);
// XXX macOS caches the transferable to implement kSelectionCache type, too,
// so it behaves differently than other types.
- if (type == clipboard.kSelectionCache && !aIsSupportGetFromCachedTransferable) {
+ if (
+ navigator.platform.includes("Mac") &&
+ type == clipboard.kSelectionCache &&
+ !aIsSupportGetFromCachedTransferable &&
+ !SpecialPowers.isHeadless
+ ) {
todo_is(clipboard.hasDataMatchingFlavors(["text/foo"], type),
aIsSupportGetFromCachedTransferable,
`Check if there is text/foo flavor on clipboard ${type}`);
@@ -212,6 +232,33 @@ function runClipboardCacheTests(aIsSupportGetFromCachedTransferable) {
await testClipboardData(await asyncGetClipboardData(type), clipboardData);
});
+ add_task(async function test_flavorList_order() {
+ info(`test_flavorList_order with pref ` +
+ `${aIsSupportGetFromCachedTransferable ? "enabled" : "disabled"}`);
+
+ const trans = generateNewTransferable("text/plain", generateRandomString());
+ addStringToTransferable("text/html", `<div>${generateRandomString()}</div>`, trans);
+
+ info(`Writedata to clipboard ${type}`);
+ clipboard.setData(trans, null, type);
+
+ // Read with reverse order.
+ let flavors = trans.flavorsTransferableCanExport().reverse();
+ let request = await asyncGetClipboardData(type, flavors);
+ // XXX Not all clipboard type supports html format, e.g. kFindClipboard
+ // on macOS only support writing text/plain.
+ if (
+ navigator.platform.includes("Mac") &&
+ type == clipboard.kFindClipboard &&
+ !aIsSupportGetFromCachedTransferable &&
+ !SpecialPowers.isHeadless
+ ) {
+ isDeeply(request.flavorList, ["text/plain"], "check flavor orders");
+ } else {
+ isDeeply(request.flavorList, flavors, "check flavor orders");
+ }
+ });
+
// Test sync set clipboard data.
testClipboardCache(type, false, aIsSupportGetFromCachedTransferable);
diff --git a/widget/tests/test_clipboard_getDataSnapshotSync.html b/widget/tests/test_clipboard_getDataSnapshotSync.html
new file mode 100644
index 0000000000..e800f6a1b0
--- /dev/null
+++ b/widget/tests/test_clipboard_getDataSnapshotSync.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1858627
+-->
+<head>
+<title>Test for Bug 1858627</title>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="clipboard_helper.js"></script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<!-- Tests are in file_test_clipboard_getDataSnapshotSync.js -->
+<script src="file_test_clipboard_getDataSnapshotSync.js"></script>
+</body>
+</html>
diff --git a/widget/tests/test_clipboard_getDataSnapshotSync_chrome.html b/widget/tests/test_clipboard_getDataSnapshotSync_chrome.html
new file mode 100644
index 0000000000..fbc283ccb3
--- /dev/null
+++ b/widget/tests/test_clipboard_getDataSnapshotSync_chrome.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1858627
+-->
+<head>
+<title>Test for Bug 1858627</title>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script src="clipboard_helper.js"></script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<!-- Tests are in file_test_clipboard_getDataSnapshotSync.js -->
+<script src="file_test_clipboard_getDataSnapshotSync.js"></script>
+</body>
+</html>
diff --git a/widget/tests/test_clipboard_owner_chrome.html b/widget/tests/test_clipboard_owner_chrome.html
index 4759b2b14c..2991646616 100644
--- a/widget/tests/test_clipboard_owner_chrome.html
+++ b/widget/tests/test_clipboard_owner_chrome.html
@@ -20,7 +20,7 @@ function testClipboardOwner(aClipboardType, aAsync) {
const clipboardOwner = {
QueryInterface: ChromeUtils.generateQI(["nsIClipboardOwner"]),
// nsIClipboardOwner
- LosingOwnership(aTransferable) {
+ LosingOwnership() {
losingOwnership = true;
},
};
diff --git a/widget/tests/test_contextmenu_by_mouse_on_unix.html b/widget/tests/test_contextmenu_by_mouse_on_unix.html
index 2b1f643dfc..04bca8116c 100644
--- a/widget/tests/test_contextmenu_by_mouse_on_unix.html
+++ b/widget/tests/test_contextmenu_by_mouse_on_unix.html
@@ -60,7 +60,7 @@ async function process_contextmenu_event({ isMousedown, preventEvent }) {
is(count++, 1, "The second event is contextmenu");
e.preventDefault();
}, { once: true });
- target.addEventListener("mouseup", e => {
+ target.addEventListener("mouseup", () => {
is(count++, 2, "The third event is mouseup");
resolve();
}, { once: true} );
diff --git a/widget/tests/test_ime_focus_with_multiple_contenteditable.html b/widget/tests/test_ime_focus_with_multiple_contenteditable.html
new file mode 100644
index 0000000000..6b435a1a2e
--- /dev/null
+++ b/widget/tests/test_ime_focus_with_multiple_contenteditable.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1872863
+-->
+<head>
+<title>Test IME state and focus with multiple contenteditable elements</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script src="file_ime_state_test_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+
+<style>
+#div0 {
+ width: 200px;
+ height: 50px;
+}
+
+#div3 {
+ background-color: blue;
+ width: 200px;
+ height: 100px;
+}
+
+#div4 {
+ width: 200px;
+ height: 50px;
+}
+</style>
+<script>
+add_task(async function test_modify_contenteditable_on_focused_element() {
+ await SimpleTest.promiseFocus();
+
+ const tipWrapper = new TIPWrapper(window);
+ ok(tipWrapper.isAvailable(), "TextInputProcessor should've been initialized");
+
+ const div1 = document.getElementById("div1");
+ const div2 = document.getElementById("div2");
+ const div3 = document.getElementById("div3");
+
+ div1.addEventListener("mousedown", () => {
+ div2.contentEditable = true;
+ });
+ div3.addEventListener("mousedown", e => {
+ div2.contentEditable = false;
+ e.preventDefault();
+ });
+
+ // Set focus by mouse then contenteditable becomes true by script.
+
+ const promiseFocus = new Promise(resolve => {
+ div2.addEventListener("focus", resolve, { once: true });
+ });
+ synthesizeMouseAtCenter(div1, {});
+ await promiseFocus;
+
+ is(
+ SpecialPowers.DOMWindowUtils.IMEStatus,
+ SpecialPowers.DOMWindowUtils.IME_STATUS_ENABLED,
+ "IMEStatus is enabled on contenteditable=true"
+ );
+ ok(tipWrapper.IMEHasFocus, "IME has focus");
+
+ // Move focus by mouse then contenteditable becomes false by script.
+
+ const promiseMouseUp = new Promise(resolve => {
+ div3.addEventListener("mouseup", resolve, { once: true });
+ });
+ synthesizeMouseAtCenter(div3, {});
+ await promiseMouseUp;
+
+ is(
+ SpecialPowers.DOMWindowUtils.IMEStatus,
+ SpecialPowers.DOMWindowUtils.IME_STATUS_DISABLED,
+ "IMEStatus is disabled on contenteditable=false"
+ );
+ ok(!tipWrapper.IMEHasFocus, "IME losts focus after contenteditable=false");
+
+ // contenteditable changes to true on focused element.
+
+ const promiseMouseUp2 = new Promise(resolve => {
+ div1.addEventListener("mouseup", resolve, { once: true });
+ });
+ synthesizeMouseAtCenter(div1, {});
+ await promiseMouseUp2;
+
+ is(
+ SpecialPowers.DOMWindowUtils.IMEStatus,
+ SpecialPowers.DOMWindowUtils.IME_STATUS_ENABLED,
+ "IMEStatus is enabled on contenteditable=true"
+ );
+
+ ok(tipWrapper.IMEHasFocus, "IME has focus after contenteditable=true again");
+});
+</script>
+</head>
+<body>
+<div id="div0"><div id="div1">
+<div id="div2" contenteditable="false"><div>foo</div></div>
+</div></div>
+<div id="div3"></div>
+<div id="div4" contenteditable></div>
+</body>
+</html>
diff --git a/widget/tests/test_ime_state_others_in_parent.html b/widget/tests/test_ime_state_others_in_parent.html
index e6ae0ab272..e71ef90556 100644
--- a/widget/tests/test_ime_state_others_in_parent.html
+++ b/widget/tests/test_ime_state_others_in_parent.html
@@ -96,7 +96,7 @@ function runTestPasswordFieldOnDialog() {
WindowObserver.prototype = {
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
- observe(subject, topic, data) {
+ observe(subject, topic) {
if (topic === "domwindowopened") {
ok(true, "dialog window is created");
dialog = subject;
diff --git a/widget/tests/test_key_event_counts.xhtml b/widget/tests/test_key_event_counts.xhtml
index 6eda6a52fb..e50164ddfd 100644
--- a/widget/tests/test_key_event_counts.xhtml
+++ b/widget/tests/test_key_event_counts.xhtml
@@ -24,7 +24,7 @@
var gKeyPressEventCount = 0;
var gKeyDownEventCount = 0;
- function onKeyDown(e)
+ function onKeyDown()
{
gKeyDownEventCount++;
}
diff --git a/widget/tests/test_keycodes.xhtml b/widget/tests/test_keycodes.xhtml
index aea6aaae98..5adb07b4d8 100644
--- a/widget/tests/test_keycodes.xhtml
+++ b/widget/tests/test_keycodes.xhtml
@@ -519,14 +519,14 @@ function* runKeyEventTests()
document.addEventListener("keypress", onKeyEvent);
document.addEventListener("keyup", onKeyEvent);
// Prevent almost all shortcut key handlers.
- SpecialPowers.addSystemEventListener(document, "keypress", consumer, true);
+ SpecialPowers.wrap(document).addEventListener("keypress", consumer, { capture: true, mozSystemGroup: true });
function cleanup()
{
document.removeEventListener("keydown", onKeyEvent);
document.removeEventListener("keypress", onKeyEvent);
document.removeEventListener("keyup", onKeyEvent);
- SpecialPowers.removeSystemEventListener(document, "keypress", consumer, true);
+ SpecialPowers.wrap(document).removeEventListener("keypress", consumer, { capture: true, mozSystemGroup: true });
}
function* testKeysOnMac()
@@ -4802,7 +4802,7 @@ function* runAccessKeyTests()
var button = document.getElementById("button");
var activationCount;
- function onClick(e)
+ function onClick()
{
++activationCount;
}
@@ -4968,10 +4968,10 @@ function* runXULKeyTests()
buttonParent.addEventListener("keypress", onKeyInDefaultEventGroup, true);
buttonParent.addEventListener("keydown", onKeyInDefaultEventGroup);
buttonParent.addEventListener("keypress", onKeyInDefaultEventGroup);
- SpecialPowers.addSystemEventListener(buttonParent, "keydown", onKeyInSystemEventGroup, true);
- SpecialPowers.addSystemEventListener(buttonParent, "keypress", onKeyInSystemEventGroup, true);
- SpecialPowers.addSystemEventListener(buttonParent, "keydown", onKeyInSystemEventGroup, false);
- SpecialPowers.addSystemEventListener(buttonParent, "keypress", onKeyInSystemEventGroup, false);
+ SpecialPowers.wrap(buttonParent).addEventListener("keydown", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).addEventListener("keypress", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).addEventListener("keydown", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).addEventListener("keypress", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
function finializeKeyElementTest()
{
@@ -4979,10 +4979,10 @@ function* runXULKeyTests()
buttonParent.removeEventListener("keypress", onKeyInDefaultEventGroup, true);
buttonParent.removeEventListener("keydown", onKeyInDefaultEventGroup);
buttonParent.removeEventListener("keypress", onKeyInDefaultEventGroup);
- SpecialPowers.removeSystemEventListener(buttonParent, "keydown", onKeyInSystemEventGroup, true);
- SpecialPowers.removeSystemEventListener(buttonParent, "keypress", onKeyInSystemEventGroup, true);
- SpecialPowers.removeSystemEventListener(buttonParent, "keydown", onKeyInSystemEventGroup, false);
- SpecialPowers.removeSystemEventListener(buttonParent, "keypress", onKeyInSystemEventGroup, false);
+ SpecialPowers.wrap(buttonParent).removeEventListener("keydown", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).removeEventListener("keypress", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).removeEventListener("keydown", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
+ SpecialPowers.wrap(buttonParent).removeEventListener("keypress", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
}
// If aKeyElement is empty string, this function tests if the event kicks
@@ -5218,10 +5218,10 @@ function* runReservedKeyTests()
contents[i].addEventListener("keypress", onKeyInDefaultEventGroup, true);
contents[i].addEventListener("keydown", onKeyInDefaultEventGroup);
contents[i].addEventListener("keypress", onKeyInDefaultEventGroup);
- SpecialPowers.addSystemEventListener(contents[i], "keydown", onKeyInSystemEventGroup, true);
- SpecialPowers.addSystemEventListener(contents[i], "keypress", onKeyInSystemEventGroup, true);
- SpecialPowers.addSystemEventListener(contents[i], "keydown", onKeyInSystemEventGroup, false);
- SpecialPowers.addSystemEventListener(contents[i], "keypress", onKeyInSystemEventGroup, false);
+ SpecialPowers.wrap(contents[i]).addEventListener("keydown", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).addEventListener("keypress", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).addEventListener("keydown", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).addEventListener("keypress", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
}
var keyEvents = [];
@@ -5256,10 +5256,10 @@ function* runReservedKeyTests()
contents[i].removeEventListener("keypress", onKeyInDefaultEventGroup, true);
contents[i].removeEventListener("keydown", onKeyInDefaultEventGroup);
contents[i].removeEventListener("keypress", onKeyInDefaultEventGroup);
- SpecialPowers.removeSystemEventListener(contents[i], "keydown", onKeyInSystemEventGroup, true);
- SpecialPowers.removeSystemEventListener(contents[i], "keypress", onKeyInSystemEventGroup, true);
- SpecialPowers.removeSystemEventListener(contents[i], "keydown", onKeyInSystemEventGroup, false);
- SpecialPowers.removeSystemEventListener(contents[i], "keypress", onKeyInSystemEventGroup, false);
+ SpecialPowers.wrap(contents[i]).removeEventListener("keydown", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).removeEventListener("keypress", onKeyInSystemEventGroup, { capture: true, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).removeEventListener("keydown", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
+ SpecialPowers.wrap(contents[i]).removeEventListener("keypress", onKeyInSystemEventGroup, { capture: false, mozSystemGroup: true });
}
}
diff --git a/widget/tests/test_native_key_bindings_mac.html b/widget/tests/test_native_key_bindings_mac.html
index 8767a5a77d..81a13aea0e 100644
--- a/widget/tests/test_native_key_bindings_mac.html
+++ b/widget/tests/test_native_key_bindings_mac.html
@@ -292,7 +292,7 @@
aElement.id + ": Incorrect selection end");
}
- function* testRun(aElement, aSelectionCheck, aCallback) {
+ function* testRun(aElement, aSelectionCheck) {
if (document.activeElement) {
document.activeElement.blur();
}
diff --git a/widget/tests/test_sizemode_events.xhtml b/widget/tests/test_sizemode_events.xhtml
index bd1e3a38d1..c1224fbf70 100644
--- a/widget/tests/test_sizemode_events.xhtml
+++ b/widget/tests/test_sizemode_events.xhtml
@@ -31,7 +31,7 @@ const kAsyncChanges = kIsLinux || kIsMacOS;
let gSizeModeDidChange = false;
let gSizeModeDidChangeTo = 0;
-function sizemodeChanged(e) {
+function sizemodeChanged() {
gSizeModeDidChange = true;
gSizeModeDidChangeTo = gWindow.windowState;
}
diff --git a/widget/tests/window_bug478536.xhtml b/widget/tests/window_bug478536.xhtml
index 7318eb0bff..206226ec74 100644
--- a/widget/tests/window_bug478536.xhtml
+++ b/widget/tests/window_bug478536.xhtml
@@ -177,7 +177,7 @@ function fireWheelScrollEvent(aForward)
}, window);
}
-function onScrollView(aEvent)
+function onScrollView()
{
if (gIgnoreScrollEvent)
return;
@@ -187,7 +187,7 @@ function onScrollView(aEvent)
gTimer = setTimeout(runNextTest, 0);
}
-function onMouseScrollFailed(aEvent)
+function onMouseScrollFailed()
{
clearTimer();
gIgnoreScrollEvent = true;
@@ -197,7 +197,7 @@ function onMouseScrollFailed(aEvent)
runNextTest();
}
-function onTransactionTimeout(aEvent)
+function onTransactionTimeout()
{
if (!gTimer)
return;
diff --git a/widget/tests/window_composition_text_querycontent.xhtml b/widget/tests/window_composition_text_querycontent.xhtml
index db3b10ea30..4806d0d187 100644
--- a/widget/tests/window_composition_text_querycontent.xhtml
+++ b/widget/tests/window_composition_text_querycontent.xhtml
@@ -6270,7 +6270,7 @@ function runQueryContentEventRelativeToInsertionPoint()
synthesizeComposition({ type: "compositioncommitasis" });
// Move start of composition at first compositionupdate event.
- function onCompositionUpdate(aEvent)
+ function onCompositionUpdate()
{
startOffset = textarea.selectionStart = textarea.selectionEnd = textarea.selectionStart - 1;
textarea.removeEventListener("compositionupdate", onCompositionUpdate);
diff --git a/widget/tests/window_imestate_iframes.html b/widget/tests/window_imestate_iframes.html
index c8b182977f..3c2d0908ae 100644
--- a/widget/tests/window_imestate_iframes.html
+++ b/widget/tests/window_imestate_iframes.html
@@ -49,6 +49,8 @@ function onUnload() {
var gFocusObservingElement = null;
var gBlurObservingElement = null;
+var canTabMoveFocusToRootElement =
+ !SpecialPowers.getBoolPref("dom.disable_tab_focus_to_root_element");
function onFocus(aEvent) {
if (aEvent.target != gFocusObservingElement) {
@@ -201,18 +203,30 @@ function runTests() {
root = iframe.contentDocument.documentElement;
resetFocusToInput("initializing for iframe_not_editable");
- testTabKey(true, root, false, prev, true,
- false, "input#prev[readonly] -> html");
- testTabKey(true, editor, true, root, false,
- true, "html -> input in the subdoc");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(true, root, false, prev, true,
+ false, "input#prev[readonly] -> html");
+ testTabKey(true, editor, true, root, false,
+ true, "html -> input in the subdoc");
+ } else {
+ testTabKey(true, editor, true, prev, true,
+ true, "input#prev[readonly] -> input in the subdoc");
+ }
testTabKey(true, next, true, editor, true,
false, "input in the subdoc -> input#next[readonly]");
testTabKey(false, editor, true, next, true,
true, "input#next[readonly] -> input in the subdoc");
- testTabKey(false, root, false, editor, true,
- false, "input in the subdoc -> html");
- testTabKey(false, prev, true, root, false,
- false, "html -> input#next[readonly]");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(false, root, false, editor, true,
+ false, "input in the subdoc -> html");
+ testTabKey(false, prev, true, root, false,
+ false, "html -> input#next[readonly]");
+ } else {
+ testTabKey(false, prev, true, editor, true,
+ false, "input in the subdoc -> input#prev[readonly]");
+ testTabKey(false, next, true, prev, true,
+ false, "input#prev[readonly] -> input#next[readonly]");
+ }
iframe.style.display = "none";
@@ -236,8 +250,13 @@ function runTests() {
resetFocusToParentHTML("testing iframe_html");
testTabKey(true, editor, true, html, false,
true, "html of parent -> html[contentediable=true]");
- testTabKey(false, html, false, editor, true,
- false, "html[contenteditable=true] -> html of parent");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(false, html, false, editor, true,
+ false, "html[contenteditable=true] -> html of parent");
+ } else {
+ testTabKey(false, next, true, editor, true,
+ false, "html[contenteditable=true] -> input#next[readonly]");
+ }
prev.style.display = "inline";
resetFocusToInput("after parent html <-> html[contenteditable=true]");
@@ -270,8 +289,13 @@ function runTests() {
resetFocusToParentHTML("testing iframe_designMode");
testTabKey(true, root, false, html, false,
true, "html of parent -> html in designMode");
- testTabKey(false, html, false, root, false,
- false, "html in designMode -> html of parent");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(false, html, false, root, false,
+ false, "html[contenteditable=true] -> html of parent");
+ } else {
+ testTabKey(false, next, true, root, false,
+ false, "html in designMode -> html of parent");
+ }
prev.style.display = "inline";
resetFocusToInput("after parent html <-> html in designMode");
@@ -302,8 +326,13 @@ function runTests() {
resetFocusToParentHTML("testing iframe_body");
testTabKey(true, editor, true, html, false,
true, "html of parent -> body[contentediable=true]");
- testTabKey(false, html, false, editor, true,
- false, "body[contenteditable=true] -> html of parent");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(false, html, false, editor, true,
+ false, "body[contenteditable=true] -> html of parent");
+ } else {
+ testTabKey(false, next, true, editor, true,
+ false, "body[contenteditable=true] -> input#next[readonly]");
+ }
prev.style.display = "inline";
resetFocusToInput("after parent html <-> body[contenteditable=true]");
@@ -321,25 +350,44 @@ function runTests() {
root = iframe.contentDocument.documentElement;
resetFocusToInput("initializing for iframe_p");
- testTabKey(true, root, false, prev, true,
- false, "input#prev[readonly] -> html (has p[contenteditable=true])");
- testTabKey(true, editor, true, root, false,
- true, "html (has p[contenteditable=true]) -> p[contentediable=true]");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(true, root, false, prev, true,
+ false, "input#prev[readonly] -> html (has p[contenteditable=true])");
+ testTabKey(true, editor, true, root, false,
+ true, "html (has p[contenteditable=true]) -> p[contentediable=true]");
+ } else {
+ testTabKey(true, editor, true, prev, true,
+ true, "input#prev[readonly] -> p[contenteditable=true]");
+ }
testTabKey(true, next, true, editor, true,
false, "p[contentediable=true] -> input#next[readonly]");
testTabKey(false, editor, true, next, true,
true, "input#next[readonly] -> p[contentediable=true]");
- testTabKey(false, root, false, editor, true,
- false, "p[contenteditable=true] -> html (has p[contenteditable=true])");
- testTabKey(false, prev, true, root, false,
- false, "html (has p[contenteditable=true]) -> input#prev[readonly]");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(false, root, false, editor, true,
+ false, "p[contenteditable=true] -> html (has p[contenteditable=true])");
+ testTabKey(false, prev, true, root, false,
+ false, "html (has p[contenteditable=true]) -> input#prev[readonly]");
+ } else {
+ testTabKey(false, prev, true, editor, true,
+ false, "p[contenteditable=true] -> html (has p[contenteditable=true])");
+ testTabKey(false, next, true, prev, true,
+ false, "html (has p[contenteditable=true]) -> input#next[readonly]");
+ }
prev.style.display = "none";
resetFocusToParentHTML("testing iframe_p");
- testTabKey(true, root, false, html, false,
- false, "html of parent -> html (has p[contentediable=true])");
- testTabKey(false, html, false, root, false,
- false, "html (has p[contentediable=true]) -> html of parent");
+ if (canTabMoveFocusToRootElement) {
+ testTabKey(true, root, false, html, false,
+ false, "html of parent -> html (has p[contentediable=true])");
+ testTabKey(false, html, false, root, false,
+ false, "html (has p[contentediable=true]) -> html of parent");
+ } else {
+ testTabKey(true, editor, true, html, false,
+ true, "html of parent -> p[contentediable=true]");
+ testTabKey(false, next, true, editor, true,
+ false, "p[contentediable=true] -> input#next[readonly]");
+ }
prev.style.display = "inline";
resetFocusToInput("after parent html <-> html (has p[contentediable=true])");
diff --git a/widget/tests/window_mouse_scroll_win.html b/widget/tests/window_mouse_scroll_win.html
index bf90abb1b5..48ccc1fed4 100644
--- a/widget/tests/window_mouse_scroll_win.html
+++ b/widget/tests/window_mouse_scroll_win.html
@@ -214,7 +214,7 @@ var gPreparingSteps = [
target: gP1, x: 10, y: 10, window,
modifiers: 0,
additionalFlags: 0,
- onLineScrollEvent(aEvent) {
+ onLineScrollEvent() {
return true;
},
onPixelScrollEvent(aEvent) {
@@ -234,7 +234,7 @@ var gPreparingSteps = [
target: gP1, x: 10, y: 10, window,
modifiers: 0,
additionalFlags: 0,
- onLineScrollEvent(aEvent) {
+ onLineScrollEvent() {
return true;
},
onPixelScrollEvent(aEvent) {
@@ -250,7 +250,7 @@ var gPreparingSteps = [
target: gP1, x: 10, y: 10, window,
modifiers: 0,
additionalFlags: 0,
- onLineScrollEvent(aEvent) {
+ onLineScrollEvent() {
return true;
},
onPixelScrollEvent(aEvent) {
@@ -270,7 +270,7 @@ var gPreparingSteps = [
target: gP1, x: 10, y: 10, window,
modifiers: 0,
additionalFlags: 0,
- onLineScrollEvent(aEvent) {
+ onLineScrollEvent() {
return true;
},
onPixelScrollEvent(aEvent) {
@@ -1100,7 +1100,7 @@ var gDeactiveWindowTests = [
SpecialPowers.setIntPref(kVAmountPref, 3);
SpecialPowers.setIntPref(kHAmountPref, 3);
},
- onLineScrollEvent(aEvent) {
+ onLineScrollEvent() {
var fm = Services.focus;
is(fm.activeWindow, gOtherWindow, "The other window isn't activated");
},
diff --git a/widget/uikit/GfxInfo.cpp b/widget/uikit/GfxInfo.cpp
index d797e4f4a0..cb378915aa 100644
--- a/widget/uikit/GfxInfo.cpp
+++ b/widget/uikit/GfxInfo.cpp
@@ -17,9 +17,19 @@ GfxInfo::GfxInfo() {}
GfxInfo::~GfxInfo() {}
-nsresult GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
+NS_IMETHODIMP
+GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
+
+NS_IMETHODIMP
+GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
-nsresult GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
+NS_IMETHODIMP
+GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetHasBattery(bool* aHasBattery) { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
@@ -32,6 +42,14 @@ GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
}
NS_IMETHODIMP
+GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
+
+NS_IMETHODIMP
GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
return NS_ERROR_FAILURE;
}
@@ -48,6 +66,16 @@ NS_IMETHODIMP
GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) { return NS_ERROR_FAILURE; }
NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor2) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
return NS_ERROR_FAILURE;
}
@@ -90,7 +118,6 @@ GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
return NS_ERROR_FAILURE;
- return NS_OK;
}
NS_IMETHODIMP
@@ -111,12 +138,18 @@ GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
NS_IMETHODIMP
GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
+NS_IMETHODIMP
+GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
if (sDriverInfo->IsEmpty()) {
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Ios, DeviceFamily::All,
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK,
- DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions);
+ DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions,
+ "FEATURE_OK_FORCE_OPENGL");
}
return *sDriverInfo;
@@ -124,7 +157,7 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
nsresult GfxInfo::GetFeatureStatusImpl(
int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
- const nsTArray<GfxDriverInfo>& aDriverInfo,
+ const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
OperatingSystem* aOS /* = nullptr */) {
NS_ENSURE_ARG_POINTER(aStatus);
aSuggestedDriverVersion.SetIsVoid(true);
@@ -145,7 +178,7 @@ nsresult GfxInfo::GetFeatureStatusImpl(
}
return GfxInfoBase::GetFeatureStatusImpl(
- aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aOS);
+ aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, aOS);
}
#ifdef DEBUG
diff --git a/widget/uikit/GfxInfo.h b/widget/uikit/GfxInfo.h
index fe75e28d23..55deb58544 100644
--- a/widget/uikit/GfxInfo.h
+++ b/widget/uikit/GfxInfo.h
@@ -29,18 +29,26 @@ class GfxInfo : public GfxInfoBase {
public:
GfxInfo();
+ OperatingSystem GetOperatingSystem() override { return OperatingSystem::Ios; }
+
// We only declare the subset of nsIGfxInfo that we actually implement. The
// rest is brought forward from GfxInfoBase.
NS_IMETHOD GetD2DEnabled(bool* aD2DEnabled) override;
NS_IMETHOD GetDWriteEnabled(bool* aDWriteEnabled) override;
+ NS_IMETHOD GetEmbeddedInFirefoxReality(
+ bool* aEmbeddedInFirefoxReality) override;
+ NS_IMETHOD GetHasBattery(bool* aHasBattery) override;
NS_IMETHOD GetDWriteVersion(nsAString& aDwriteVersion) override;
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override;
+ NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override;
+ NS_IMETHOD GetTestType(nsAString& aTestType) override;
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID(nsAString& aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID(nsAString& aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID(nsAString& aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM(uint32_t* aAdapterRAM) override;
+ NS_IMETHOD GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) override;
NS_IMETHOD GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate(nsAString& aAdapterDriverDate) override;
NS_IMETHOD GetAdapterDescription2(nsAString& aAdapterDescription) override;
@@ -49,10 +57,12 @@ class GfxInfo : public GfxInfoBase {
NS_IMETHOD GetAdapterDeviceID2(nsAString& aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID2(nsAString& aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM2(uint32_t* aAdapterRAM) override;
+ NS_IMETHOD GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) override;
NS_IMETHOD GetAdapterDriverVersion2(
nsAString& aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate2(nsAString& aAdapterDriverDate) override;
NS_IMETHOD GetIsGPU2Active(bool* aIsGPU2Active) override;
+ NS_IMETHOD GetDrmRenderDevice(nsACString& aDrmRenderDevice) override;
using GfxInfoBase::GetFeatureStatus;
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
@@ -62,11 +72,12 @@ class GfxInfo : public GfxInfoBase {
#endif
protected:
- virtual nsresult GetFeatureStatusImpl(
- int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
- const nsTArray<GfxDriverInfo>& aDriverInfo,
- OperatingSystem* aOS = nullptr);
- virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo();
+ nsresult GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
+ nsAString& aSuggestedDriverVersion,
+ const nsTArray<GfxDriverInfo>& aDriverInfo,
+ nsACString& aFailureId,
+ OperatingSystem* aOS = nullptr) override;
+ const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
};
} // namespace widget
diff --git a/widget/uikit/MediaKeysEventSourceFactory.cpp b/widget/uikit/MediaKeysEventSourceFactory.cpp
new file mode 100644
index 0000000000..b52919d4cc
--- /dev/null
+++ b/widget/uikit/MediaKeysEventSourceFactory.cpp
@@ -0,0 +1,17 @@
+/* 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 "MediaKeysEventSourceFactory.h"
+
+namespace mozilla {
+namespace widget {
+
+mozilla::dom::MediaControlKeySource* CreateMediaControlKeySource() {
+ // GeckoView uses MediaController.webidl for media session events and control,
+ // see bug 1623715.
+ return nullptr;
+}
+
+} // namespace widget
+} // namespace mozilla
diff --git a/widget/uikit/TextInputHandler.h b/widget/uikit/TextInputHandler.h
new file mode 100644
index 0000000000..1f27bf11f0
--- /dev/null
+++ b/widget/uikit/TextInputHandler.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=80: */
+/* 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/. */
+
+#ifndef TextInputHandler_h_
+#define TextInputHandler_h_
+
+#import <UIKit/UITextInput.h>
+
+#include "mozilla/EventForwards.h"
+#include "mozilla/TextEventDispatcherListener.h"
+#include "mozilla/widget/IMEData.h"
+#include "nsCOMPtr.h"
+
+class nsWindow;
+
+namespace mozilla::widget {
+class TextEventDispatcher;
+
+// This is the temporary input class. When implementing UITextInpt protocol, we
+// should share this class with Cocoa's version.
+class TextInputHandler final : public TextEventDispatcherListener {
+ public:
+ explicit TextInputHandler(nsWindow* aWidget);
+ TextInputHandler() = delete;
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
+ const IMENotification& aNotification) override;
+ NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override;
+ NS_IMETHOD_(void)
+ OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;
+ NS_IMETHOD_(void)
+ WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
+ WidgetKeyboardEvent& aKeyboardEvent,
+ uint32_t aIndexOfKeypress, void* aData) override;
+
+ // UIKeyInput delegation
+ bool InsertText(NSString* aText);
+ bool HandleCommand(Command aCommand);
+
+ void OnDestroyed();
+
+ private:
+ virtual ~TextInputHandler() = default;
+
+ bool DispatchKeyDownEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode, nsEventStatus& aStatus);
+ bool DispatchKeyUpEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode, nsEventStatus& aStatus);
+ bool DispatchKeyPressEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode, nsEventStatus& aStatus);
+
+ bool EmulateKeyboardEvent(uint32_t aKeyCode, KeyNameIndex aKeyNameIndex,
+ char16_t charCode);
+
+ bool Destroyed() { return !mWidget; }
+
+ nsWindow* mWidget; // weak ref
+ RefPtr<TextEventDispatcher> mDispatcher;
+};
+
+} // namespace mozilla::widget
+#endif
diff --git a/widget/uikit/TextInputHandler.mm b/widget/uikit/TextInputHandler.mm
new file mode 100644
index 0000000000..9a4a6ae226
--- /dev/null
+++ b/widget/uikit/TextInputHandler.mm
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=80: */
+/* 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 "TextInputHandler.h"
+
+#import <UIKit/UIKit.h>
+
+#include "mozilla/EventForwards.h"
+#include "mozilla/Logging.h"
+#include "mozilla/MiscEvents.h"
+#include "mozilla/TextEventDispatcher.h"
+#include "mozilla/TextEvents.h"
+#include "mozilla/WidgetUtils.h"
+#include "nsIWidget.h"
+#include "nsObjCExceptions.h"
+#include "nsString.h"
+#include "nsWindow.h"
+
+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)
+
+TextInputHandler::TextInputHandler(nsWindow* aWidget)
+ : mWidget(aWidget), mDispatcher(aWidget->GetTextEventDispatcher()) {}
+
+nsresult TextInputHandler::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
+ const IMENotification& aNotification) {
+ return NS_OK;
+}
+
+IMENotificationRequests TextInputHandler::GetIMENotificationRequests() {
+ return IMENotificationRequests();
+}
+
+void TextInputHandler::OnRemovedFrom(
+ TextEventDispatcher* aTextEventDispatcher) {}
+
+void TextInputHandler::WillDispatchKeyboardEvent(
+ TextEventDispatcher* aTextEventDispatcher,
+ WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
+ void* aData) {}
+
+bool TextInputHandler::InsertText(NSString* aText) {
+ nsString str;
+ GetStringForNSString(aText, str);
+
+ MOZ_LOG(gIMELog, LogLevel::Info,
+ ("%p TextInputHandler::InsertText(aText=%s)", this,
+ NS_ConvertUTF16toUTF8(str).get()));
+
+ if (Destroyed()) {
+ return false;
+ }
+
+ if (str.Length() == 1) {
+ char16_t charCode = str[0];
+ if (charCode == 0x0a) {
+ return EmulateKeyboardEvent(NS_VK_RETURN, KEY_NAME_INDEX_Enter, charCode);
+ }
+ if (charCode == 0x08) {
+ return EmulateKeyboardEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace,
+ charCode);
+ }
+ if (uint32_t keyCode = WidgetUtils::ComputeKeyCodeFromChar(charCode)) {
+ return EmulateKeyboardEvent(keyCode, KEY_NAME_INDEX_USE_STRING, charCode);
+ }
+ }
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ RefPtr<nsWindow> widget(mWidget);
+ if (!DispatchKeyDownEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0,
+ status)) {
+ return false;
+ }
+ if (Destroyed()) {
+ return false;
+ }
+
+ mDispatcher->CommitComposition(status, &str, nullptr);
+ if (widget->Destroyed()) {
+ return false;
+ }
+
+ DispatchKeyUpEvent(NS_VK_PROCESSKEY, KEY_NAME_INDEX_Process, 0, status);
+
+ return true;
+}
+
+bool TextInputHandler::HandleCommand(Command aCommand) {
+ MOZ_LOG(gIMELog, LogLevel::Info,
+ ("%p TextInputHandler::HandleCommand, aCommand=%s", this,
+ ToChar(aCommand)));
+
+ if (Destroyed()) {
+ return false;
+ }
+
+ if (aCommand != Command::DeleteCharBackward) {
+ return false;
+ }
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ if (!DispatchKeyDownEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
+ return true;
+ }
+ if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
+ return true;
+ }
+
+ // TODO: Focus check
+
+ if (!DispatchKeyPressEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status)) {
+ return true;
+ }
+ if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
+ return true;
+ }
+
+ // TODO: Focus check
+
+ DispatchKeyUpEvent(NS_VK_BACK, KEY_NAME_INDEX_Backspace, 0, status);
+
+ return true;
+}
+
+static uint32_t ComputeKeyModifiers(uint32_t aCharCode) {
+ if (aCharCode >= 'A' && aCharCode <= 'Z') {
+ return MODIFIER_SHIFT;
+ }
+ return 0;
+}
+
+static void InitKeyEvent(WidgetKeyboardEvent& aEvent, uint32_t aKeyCode,
+ KeyNameIndex aKeyNameIndex, char16_t aCharCode) {
+ aEvent.mKeyCode = aKeyCode;
+ aEvent.mIsRepeat = false;
+ aEvent.mKeyNameIndex = aKeyNameIndex;
+ // TODO(m_kato):
+ // How to get native key? Then, implement NativeKeyToDOM*.h for iOS
+ aEvent.mCodeNameIndex = CODE_NAME_INDEX_UNKNOWN;
+ if (aEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
+ aEvent.mKeyValue = aCharCode;
+ }
+ aEvent.mModifiers = ComputeKeyModifiers(aCharCode);
+ aEvent.mLocation = eKeyLocationStandard;
+ aEvent.mTimeStamp = TimeStamp::Now();
+}
+
+bool TextInputHandler::DispatchKeyDownEvent(uint32_t aKeyCode,
+ KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode,
+ nsEventStatus& aStatus) {
+ MOZ_ASSERT(aKeyCode);
+ MOZ_ASSERT(mWidget);
+
+ WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget);
+ InitKeyEvent(keydownEvent, aKeyCode, aKeyNameIndex, aCharCode);
+ nsresult rv = mDispatcher->BeginNativeInputTransaction();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("BeginNativeInputTransaction is failed");
+ return false;
+ }
+ return mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, aStatus);
+}
+
+bool TextInputHandler::DispatchKeyUpEvent(uint32_t aKeyCode,
+ KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode,
+ nsEventStatus& aStatus) {
+ MOZ_ASSERT(aKeyCode);
+ MOZ_ASSERT(mWidget);
+
+ WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
+ InitKeyEvent(keyupEvent, aKeyCode, aKeyNameIndex, aCharCode);
+ nsresult rv = mDispatcher->BeginNativeInputTransaction();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("BeginNativeInputTransaction is failed");
+ return false;
+ }
+ return mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, aStatus);
+}
+
+bool TextInputHandler::DispatchKeyPressEvent(uint32_t aKeyCode,
+ KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode,
+ nsEventStatus& aStatus) {
+ MOZ_ASSERT(aKeyCode);
+ MOZ_ASSERT(mWidget);
+
+ WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
+ InitKeyEvent(keypressEvent, aKeyCode, aKeyNameIndex, aCharCode);
+ nsresult rv = mDispatcher->BeginNativeInputTransaction();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("BeginNativeInputTransaction is failed");
+ return false;
+ }
+ return mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, aStatus);
+}
+
+bool TextInputHandler::EmulateKeyboardEvent(uint32_t aKeyCode,
+ KeyNameIndex aKeyNameIndex,
+ char16_t aCharCode) {
+ MOZ_ASSERT(aCharCode);
+
+ MOZ_LOG(gIMELog, LogLevel::Info,
+ ("%p TextInputHandler::EmulateKeyboardEvent(aKeyCode=%x, "
+ "aKeyNameIndex=%x, aCharCode=%x)",
+ this, aKeyCode, aKeyNameIndex, aCharCode));
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ if (!DispatchKeyDownEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) {
+ return true;
+ }
+ if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
+ return true;
+ }
+ // TODO: Focus check
+
+ if (!DispatchKeyPressEvent(aKeyCode, aKeyNameIndex, aCharCode, status)) {
+ return true;
+ }
+ if (Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
+ return true;
+ }
+ // TODO: Focus check
+
+ DispatchKeyUpEvent(aKeyCode, aKeyNameIndex, aCharCode, status);
+ return true;
+}
+
+void TextInputHandler::OnDestroyed() { mWidget = nullptr; }
+
+} // namespace mozilla::widget
diff --git a/widget/uikit/UIKitUtils.h b/widget/uikit/UIKitUtils.h
new file mode 100644
index 0000000000..2e34b126fd
--- /dev/null
+++ b/widget/uikit/UIKitUtils.h
@@ -0,0 +1,23 @@
+/* -*- 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/. */
+
+#import <UIKit/UIKit.h>
+
+#include "IMEData.h"
+
+namespace mozilla::widget {
+
+class UIKitUtils final {
+ public:
+ UIKitUtils() = delete;
+ ~UIKitUtils() = delete;
+
+ static UIKeyboardType GetUIKeyboardType(const InputContext& aContext);
+ static UIReturnKeyType GetUIReturnKeyType(const InputContext& aContext);
+ static UITextAutocapitalizationType GetUITextAutocapitalizationType(
+ const InputContext& aContext);
+};
+
+} // namespace mozilla::widget
diff --git a/widget/uikit/UIKitUtils.mm b/widget/uikit/UIKitUtils.mm
new file mode 100644
index 0000000000..ddcd2312b0
--- /dev/null
+++ b/widget/uikit/UIKitUtils.mm
@@ -0,0 +1,89 @@
+/* -*- 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 "UIKitUtils.h"
+
+namespace mozilla::widget {
+
+// static
+UIKeyboardType UIKitUtils::GetUIKeyboardType(const InputContext& aContext) {
+ if (aContext.mHTMLInputMode.EqualsLiteral("email")) {
+ return UIKeyboardTypeEmailAddress;
+ }
+ if (aContext.mHTMLInputMode.EqualsLiteral("deciaml")) {
+ return UIKeyboardTypeDecimalPad;
+ }
+ if (aContext.mHTMLInputMode.EqualsLiteral("numeric")) {
+ return UIKeyboardTypeNumberPad;
+ }
+ if (aContext.mHTMLInputMode.EqualsLiteral("search")) {
+ return UIKeyboardTypeWebSearch;
+ }
+ if (aContext.mHTMLInputMode.EqualsLiteral("tel")) {
+ return UIKeyboardTypePhonePad;
+ }
+ if (aContext.mHTMLInputMode.EqualsLiteral("url")) {
+ return UIKeyboardTypeURL;
+ }
+
+ if (aContext.mHTMLInputType.EqualsLiteral("email")) {
+ return UIKeyboardTypeEmailAddress;
+ }
+ if (aContext.mHTMLInputType.EqualsLiteral("number")) {
+ return UIKeyboardTypeNumberPad;
+ }
+ if (aContext.mHTMLInputType.EqualsLiteral("tel")) {
+ return UIKeyboardTypePhonePad;
+ }
+ if (aContext.mHTMLInputType.EqualsLiteral("url")) {
+ return UIKeyboardTypeURL;
+ }
+
+ return UIKeyboardTypeDefault;
+}
+
+// static
+UIReturnKeyType UIKitUtils::GetUIReturnKeyType(const InputContext& aContext) {
+ if (aContext.mActionHint.EqualsLiteral("done")) {
+ return UIReturnKeyDone;
+ }
+ if (aContext.mActionHint.EqualsLiteral("go")) {
+ return UIReturnKeyGo;
+ }
+ if (aContext.mActionHint.EqualsLiteral("next") ||
+ aContext.mActionHint.EqualsLiteral("maybenext")) {
+ return UIReturnKeyNext;
+ }
+ if (aContext.mActionHint.EqualsLiteral("search")) {
+ return UIReturnKeySearch;
+ }
+ if (aContext.mActionHint.EqualsLiteral("send")) {
+ return UIReturnKeySend;
+ }
+
+ return UIReturnKeyDefault;
+}
+
+// static
+UITextAutocapitalizationType UIKitUtils::GetUITextAutocapitalizationType(
+ const InputContext& aContext) {
+ if (aContext.mAutocapitalize.EqualsLiteral("characters")) {
+ return UITextAutocapitalizationTypeAllCharacters;
+ }
+ if (aContext.mAutocapitalize.EqualsLiteral("none")) {
+ return UITextAutocapitalizationTypeNone;
+ }
+ if (aContext.mAutocapitalize.EqualsLiteral("sentences")) {
+ return UITextAutocapitalizationTypeSentences;
+ }
+ if (aContext.mAutocapitalize.EqualsLiteral("words")) {
+ return UITextAutocapitalizationTypeWords;
+ }
+ // TODO(m_kato):
+ // Infer autocapitalization type by input type like GeckoView.
+ return UITextAutocapitalizationTypeNone;
+}
+
+} // namespace mozilla::widget
diff --git a/widget/uikit/components.conf b/widget/uikit/components.conf
new file mode 100644
index 0000000000..0a4480ee4a
--- /dev/null
+++ b/widget/uikit/components.conf
@@ -0,0 +1,28 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+Headers = '/widget/uikit/nsWidgetFactory.h',
+
+InitFunc = 'nsWidgetUIKitModuleCtor'
+UnloadFunc = 'nsWidgetUIKitModuleDtor'
+
+Classes = [
+ {
+ 'name': 'GfxInfo',
+ 'cid': '{d755a760-9f27-11df-0800-200c9a664242}',
+ 'contract_ids': ['@mozilla.org/gfx/info;1'],
+ 'type': 'mozilla::widget::GfxInfo',
+ 'headers': ['/widget/uikit/GfxInfo.h'],
+ 'init_method': 'Init',
+ },
+ {
+ 'cid': '{2d96b3df-c051-11d1-a827-0040959a28c9}',
+ 'contract_ids': ['@mozilla.org/widget/appshell/uikit;1'],
+ 'legacy_constructor': 'nsAppShellConstructor',
+ 'headers': ['/widget/uikit/nsWidgetFactory.h'],
+ 'processes': ProcessSelector.ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS,
+ },
+]
diff --git a/widget/uikit/moz.build b/widget/uikit/moz.build
index 6a3c2db994..88780c9690 100644
--- a/widget/uikit/moz.build
+++ b/widget/uikit/moz.build
@@ -7,13 +7,20 @@
with Files("**"):
BUG_COMPONENT = ("Core", "Widget")
+with Files("*TextInput*"):
+ BUG_COMPONENT = ("Core", "DOM: UI Events & Focus Handling")
+
SOURCES += [
"GfxInfo.cpp",
+ "MediaKeysEventSourceFactory.cpp",
"nsAppShell.mm",
+ "nsBidiKeyboard.mm",
"nsLookAndFeel.mm",
- "nsScreenManager.mm",
+ "nsNativeThemeUIKit.mm",
"nsWidgetFactory.mm",
"nsWindow.mm",
+ "TextInputHandler.mm",
+ "UIKitUtils.mm",
]
include("/ipc/chromium/chromium-config.mozbuild")
@@ -22,3 +29,11 @@ FINAL_LIBRARY = "xul"
LOCAL_INCLUDES += [
"/widget",
]
+
+XPCOM_MANIFESTS += [
+ "components.conf",
+]
+
+OS_LIBS += [
+ "-framework UIKit",
+]
diff --git a/widget/uikit/nsAppShell.h b/widget/uikit/nsAppShell.h
index fd46a51025..c8ae7ce9ef 100644
--- a/widget/uikit/nsAppShell.h
+++ b/widget/uikit/nsAppShell.h
@@ -41,8 +41,8 @@ class nsAppShell : public nsBaseAppShell {
virtual ~nsAppShell();
static void ProcessGeckoEvents(void* aInfo);
- virtual void ScheduleNativeEventCallback();
- virtual bool ProcessNextNativeEvent(bool aMayWait);
+ void ScheduleNativeEventCallback() override;
+ bool ProcessNextNativeEvent(bool aMayWait) override;
NSAutoreleasePool* mAutoreleasePool;
AppShellDelegate* mDelegate;
diff --git a/widget/uikit/nsBidiKeyboard.h b/widget/uikit/nsBidiKeyboard.h
new file mode 100644
index 0000000000..3a9a6fe2fb
--- /dev/null
+++ b/widget/uikit/nsBidiKeyboard.h
@@ -0,0 +1,23 @@
+/* -*- 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/. */
+
+#ifndef nsBidiKeyboard_h_
+#define nsBidiKeyboard_h_
+
+#include "nsIBidiKeyboard.h"
+
+class nsBidiKeyboard : public nsIBidiKeyboard {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIBIDIKEYBOARD
+
+ nsBidiKeyboard();
+
+ protected:
+ virtual ~nsBidiKeyboard();
+};
+
+#endif // nsBidiKeyboard_h_
diff --git a/widget/uikit/nsBidiKeyboard.mm b/widget/uikit/nsBidiKeyboard.mm
new file mode 100644
index 0000000000..bbe1eff92f
--- /dev/null
+++ b/widget/uikit/nsBidiKeyboard.mm
@@ -0,0 +1,35 @@
+/* -*- 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 "nsBidiKeyboard.h"
+#include "nsIWidget.h"
+
+// This must be the last include:
+#include "nsObjCExceptions.h"
+
+using namespace mozilla::widget;
+
+NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard)
+
+nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard() { Reset(); }
+
+nsBidiKeyboard::~nsBidiKeyboard() {}
+
+NS_IMETHODIMP nsBidiKeyboard::Reset() { return NS_OK; }
+
+NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool* aIsRTL) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult) {
+ // not implemented yet
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// static
+already_AddRefed<nsIBidiKeyboard> nsIWidget::CreateBidiKeyboardInner() {
+ return do_AddRef(new nsBidiKeyboard());
+}
diff --git a/widget/uikit/nsLookAndFeel.h b/widget/uikit/nsLookAndFeel.h
index 7de7e0712b..c696502ec1 100644
--- a/widget/uikit/nsLookAndFeel.h
+++ b/widget/uikit/nsLookAndFeel.h
@@ -14,13 +14,13 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
virtual ~nsLookAndFeel();
void NativeInit() final;
- virtual void RefreshImpl();
- nsresult NativeGetImpl(IntID aID, int32_t& aResult) override;
+ void RefreshImpl() override;
+ nsresult NativeGetInt(IntID aID, int32_t& aResult) override;
nsresult NativeGetFloat(FloatID aID, float& aResult) override;
nsresult NativeGetColor(ColorID, ColorScheme, nscolor& aResult) override;
bool NativeGetFont(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle) override;
- virtual char16_t GetPasswordCharacterImpl() {
+ char16_t GetPasswordCharacterImpl() override {
// unicode value for the bullet character, used for password textfields.
return 0x2022;
}
@@ -28,7 +28,6 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
static bool UseOverlayScrollbars() { return true; }
private:
- nscolor mColorTextSelectForeground;
nscolor mColorDarkText;
bool mInitialized;
diff --git a/widget/uikit/nsLookAndFeel.mm b/widget/uikit/nsLookAndFeel.mm
index 29eb52a234..b420cc9a1d 100644
--- a/widget/uikit/nsLookAndFeel.mm
+++ b/widget/uikit/nsLookAndFeel.mm
@@ -13,6 +13,8 @@
#include "gfxFont.h"
#include "gfxFontConstants.h"
+using namespace mozilla;
+
nsLookAndFeel::nsLookAndFeel() : mInitialized(false) {}
nsLookAndFeel::~nsLookAndFeel() {}
@@ -41,7 +43,8 @@ void nsLookAndFeel::RefreshImpl() {
mInitialized = false;
}
-nsresult nsLookAndFeel::NativeGetColor(ColorID, ColorScheme, nscolor& aResult) {
+nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme,
+ nscolor& aResult) {
EnsureInit();
nsresult res = NS_OK;
@@ -55,7 +58,7 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID, ColorScheme, nscolor& aResult) {
break;
case ColorID::Highlighttext:
case ColorID::MozMenuhovertext:
- aResult = mColorTextSelectForeground;
+ aResult = NS_SAME_AS_FOREGROUND_COLOR;
break;
case ColorID::IMESelectedRawTextBackground:
case ColorID::IMESelectedConvertedTextBackground:
@@ -154,11 +157,11 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID, ColorScheme, nscolor& aResult) {
aResult = NS_RGB(0xaa, 0xaa, 0xaa);
break;
case ColorID::Window:
- case ColorID::MozField:
+ case ColorID::Field:
case ColorID::MozCombobox:
aResult = NS_RGB(0xff, 0xff, 0xff);
break;
- case ColorID::MozFieldtext:
+ case ColorID::Fieldtext:
case ColorID::MozComboboxtext:
aResult = mColorDarkText;
break;
@@ -175,12 +178,6 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID, ColorScheme, nscolor& aResult) {
case ColorID::MozMacFocusring:
aResult = NS_RGB(0x3F, 0x98, 0xDD);
break;
- case ColorID::MozMacMenutextdisable:
- aResult = NS_RGB(0x88, 0x88, 0x88);
- break;
- case ColorID::MozMacMenutextselect:
- aResult = NS_RGB(0xaa, 0xaa, 0xaa);
- break;
case ColorID::MozMacDisabledtoolbartext:
aResult = NS_RGB(0x3F, 0x3F, 0x3F);
break;
@@ -260,6 +257,19 @@ nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::ScrollArrowStyle:
aResult = eScrollArrow_None;
break;
+ case IntID::UseOverlayScrollbars:
+ case IntID::AllowOverlayScrollbarsOverlap:
+ aResult = 1;
+ break;
+ case IntID::ScrollbarDisplayOnMouseMove:
+ aResult = 0;
+ break;
+ case IntID::ScrollbarFadeBeginDelay:
+ aResult = 450;
+ break;
+ case IntID::ScrollbarFadeDuration:
+ aResult = 200;
+ break;
case IntID::TreeOpenDelay:
aResult = 1000;
break;
@@ -326,10 +336,10 @@ nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle) {
// hack for now
- if (aID == FontID::Window || aID == FontID::Document) {
- aFontStyle.style = FontSlantStyle::Normal();
- aFontStyle.weight = FontWeight::Normal();
- aFontStyle.stretch = FontStretch::Normal();
+ if (aID == FontID::Caption || aID == FontID::Menu) {
+ aFontStyle.style = FontSlantStyle::NORMAL;
+ aFontStyle.weight = FontWeight::NORMAL;
+ aFontStyle.stretch = FontStretch::NORMAL;
aFontStyle.size = 14;
aFontStyle.systemFont = true;
@@ -347,14 +357,6 @@ void nsLookAndFeel::EnsureInit() {
}
mInitialized = true;
- nscolor color;
- GetColor(ColorID::TextSelectBackground, color);
- if (color == 0x000000) {
- mColorTextSelectForeground = NS_RGB(0xff, 0xff, 0xff);
- } else {
- mColorTextSelectForeground = NS_SAME_AS_FOREGROUND_COLOR;
- }
-
mColorDarkText = GetColorFromUIColor([UIColor darkTextColor]);
RecordTelemetry();
diff --git a/widget/uikit/nsNativeThemeUIKit.h b/widget/uikit/nsNativeThemeUIKit.h
new file mode 100644
index 0000000000..87c631a8b8
--- /dev/null
+++ b/widget/uikit/nsNativeThemeUIKit.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef nsNativeThemeUIKit_h
+#define nsNativeThemeUIKit_h
+
+#include "nsITheme.h"
+#include "Theme.h"
+
+class nsNativeThemeUIKit final : public mozilla::widget::Theme {
+ public:
+ nsNativeThemeUIKit();
+
+ protected:
+ virtual ~nsNativeThemeUIKit() = default;
+};
+
+#endif // nsNativeThemeUIKit_h
diff --git a/widget/uikit/nsNativeThemeUIKit.mm b/widget/uikit/nsNativeThemeUIKit.mm
new file mode 100644
index 0000000000..19cde52426
--- /dev/null
+++ b/widget/uikit/nsNativeThemeUIKit.mm
@@ -0,0 +1,19 @@
+/* -*- 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 "nsNativeThemeUIKit.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::widget;
+
+nsNativeThemeUIKit::nsNativeThemeUIKit() : Theme(ScrollbarStyle()) {}
+
+already_AddRefed<Theme> do_CreateNativeThemeDoNotUseDirectly() {
+ if (gfxPlatform::IsHeadless()) {
+ return do_AddRef(new Theme(Theme::ScrollbarStyle()));
+ }
+ return do_AddRef(new nsNativeThemeUIKit());
+}
diff --git a/widget/uikit/nsScreenManager.h b/widget/uikit/nsScreenManager.h
deleted file mode 100644
index 0d19728264..0000000000
--- a/widget/uikit/nsScreenManager.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; 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/. */
-
-#ifndef nsScreenManager_h_
-#define nsScreenManager_h_
-
-#include "nsBaseScreen.h"
-#include "nsIScreenManager.h"
-#include "nsCOMPtr.h"
-#include "nsRect.h"
-
-@class UIScreen;
-
-class UIKitScreen : public nsBaseScreen {
- public:
- explicit UIKitScreen(UIScreen* screen);
- ~UIKitScreen() {}
-
- NS_IMETHOD GetId(uint32_t* outId) override {
- *outId = 0;
- return NS_OK;
- }
-
- NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth,
- int32_t* aHeight) override;
- NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth,
- int32_t* aHeight) override;
- NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth,
- int32_t* aHeight) override;
- NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft, int32_t* aTop,
- int32_t* aWidth, int32_t* aHeight) override;
- NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
- NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
- NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override;
- NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override {
- return GetContentsScaleFactor(aScaleFactor);
- }
-
- private:
- UIScreen* mScreen;
-};
-
-class UIKitScreenManager : public nsIScreenManager {
- public:
- UIKitScreenManager();
-
- NS_DECL_ISUPPORTS
-
- NS_DECL_NSISCREENMANAGER
-
- static LayoutDeviceIntRect GetBounds();
-
- private:
- virtual ~UIKitScreenManager() {}
- // TODO: support >1 screen, iPad supports external displays
- nsCOMPtr<nsIScreen> mScreen;
-};
-
-#endif // nsScreenManager_h_
diff --git a/widget/uikit/nsScreenManager.mm b/widget/uikit/nsScreenManager.mm
deleted file mode 100644
index da37a4199d..0000000000
--- a/widget/uikit/nsScreenManager.mm
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; 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/. */
-
-#import <UIKit/UIScreen.h>
-
-#include "gfxPoint.h"
-#include "nsScreenManager.h"
-#include "nsAppShell.h"
-
-static LayoutDeviceIntRect gScreenBounds;
-static bool gScreenBoundsSet = false;
-
-UIKitScreen::UIKitScreen(UIScreen* aScreen) { mScreen = [aScreen retain]; }
-
-NS_IMETHODIMP
-UIKitScreen::GetRect(int32_t* outX, int32_t* outY, int32_t* outWidth,
- int32_t* outHeight) {
- return GetRectDisplayPix(outX, outY, outWidth, outHeight);
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetAvailRect(int32_t* outX, int32_t* outY, int32_t* outWidth,
- int32_t* outHeight) {
- return GetAvailRectDisplayPix(outX, outY, outWidth, outHeight);
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetRectDisplayPix(int32_t* outX, int32_t* outY, int32_t* outWidth,
- int32_t* outHeight) {
- nsIntRect rect = UIKitScreenManager::GetBounds();
- *outX = rect.x;
- *outY = rect.y;
- *outWidth = rect.width;
- *outHeight = rect.height;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetAvailRectDisplayPix(int32_t* outX, int32_t* outY,
- int32_t* outWidth, int32_t* outHeight) {
- CGRect rect = [mScreen applicationFrame];
- CGFloat scale = [mScreen scale];
-
- *outX = rect.origin.x * scale;
- *outY = rect.origin.y * scale;
- *outWidth = rect.size.width * scale;
- *outHeight = rect.size.height * scale;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetPixelDepth(int32_t* aPixelDepth) {
- // Close enough.
- *aPixelDepth = 24;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetColorDepth(int32_t* aColorDepth) {
- return GetPixelDepth(aColorDepth);
-}
-
-NS_IMETHODIMP
-UIKitScreen::GetContentsScaleFactor(double* aContentsScaleFactor) {
- *aContentsScaleFactor = [mScreen scale];
- return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS(UIKitScreenManager, nsIScreenManager)
-
-UIKitScreenManager::UIKitScreenManager()
- : mScreen(new UIKitScreen([UIScreen mainScreen])) {}
-
-LayoutDeviceIntRect UIKitScreenManager::GetBounds() {
- if (!gScreenBoundsSet) {
- CGRect rect = [[UIScreen mainScreen] bounds];
- CGFloat scale = [[UIScreen mainScreen] scale];
- gScreenBounds.x = rect.origin.x * scale;
- gScreenBounds.y = rect.origin.y * scale;
- gScreenBounds.width = rect.size.width * scale;
- gScreenBounds.height = rect.size.height * scale;
- gScreenBoundsSet = true;
- }
- printf("UIKitScreenManager::GetBounds: %d %d %d %d\n", gScreenBounds.x,
- gScreenBounds.y, gScreenBounds.width, gScreenBounds.height);
- return gScreenBounds;
-}
-
-NS_IMETHODIMP
-UIKitScreenManager::GetPrimaryScreen(nsIScreen** outScreen) {
- NS_IF_ADDREF(*outScreen = mScreen.get());
- return NS_OK;
-}
-
-NS_IMETHODIMP
-UIKitScreenManager::ScreenForRect(int32_t inLeft, int32_t inTop,
- int32_t inWidth, int32_t inHeight,
- nsIScreen** outScreen) {
- return GetPrimaryScreen(outScreen);
-}
diff --git a/widget/uikit/nsWidgetFactory.h b/widget/uikit/nsWidgetFactory.h
new file mode 100644
index 0000000000..570639e495
--- /dev/null
+++ b/widget/uikit/nsWidgetFactory.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* 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/. */
+
+#ifndef widget_uikit_nsWidgetFactory_h
+#define widget_uikit_nsWidgetFactory_h
+
+#include "nscore.h"
+#include "nsID.h"
+
+class nsISupports;
+
+nsresult nsAppShellConstructor(const nsIID& iid, void** result);
+
+void nsWidgetUIKitModuleCtor();
+void nsWidgetUIKitModuleDtor();
+
+#endif // defined widget_uikit_nsWidgetFactory_h
diff --git a/widget/uikit/nsWidgetFactory.mm b/widget/uikit/nsWidgetFactory.mm
index 356e5b8cdf..e5b24d200f 100644
--- a/widget/uikit/nsWidgetFactory.mm
+++ b/widget/uikit/nsWidgetFactory.mm
@@ -3,51 +3,18 @@
* 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.h"
-#include "mozilla/ModuleUtils.h"
-
-#include "nsWidgetsCID.h"
-
#include "nsAppShell.h"
#include "nsAppShellSingleton.h"
#include "nsLookAndFeel.h"
-#include "nsScreenManager.h"
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(UIKitScreenManager)
+#include "nsWidgetFactory.h"
+#include "mozilla/WidgetUtils.h"
-#include "GfxInfo.h"
-namespace mozilla {
-namespace widget {
-// This constructor should really be shared with all platforms.
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init)
-} // namespace widget
-} // namespace mozilla
+using namespace mozilla::widget;
-NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
-NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
-NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
+void nsWidgetUIKitModuleCtor() { nsAppShellInit(); }
-static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
- {&kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor},
- {&kNS_SCREENMANAGER_CID, false, nullptr, UIKitScreenManagerConstructor},
- {&kNS_GFXINFO_CID, false, nullptr, mozilla::widget::GfxInfoConstructor},
- {nullptr}};
-
-static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
- {"@mozilla.org/widget/appshell/uikit;1", &kNS_APPSHELL_CID},
- {"@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID},
- {"@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID},
- {nullptr}};
-
-static void nsWidgetUIKitModuleDtor() {
+void nsWidgetUIKitModuleDtor() {
+ WidgetUtils::Shutdown();
nsLookAndFeel::Shutdown();
nsAppShellShutdown();
}
-
-extern const mozilla::Module kWidgetModule = {mozilla::Module::kVersion,
- kWidgetCIDs,
- kWidgetContracts,
- nullptr,
- nullptr,
- nsAppShellInit,
- nsWidgetUIKitModuleDtor};
diff --git a/widget/uikit/nsWindow.h b/widget/uikit/nsWindow.h
index 5dad452930..cb5d676d7c 100644
--- a/widget/uikit/nsWindow.h
+++ b/widget/uikit/nsWindow.h
@@ -15,6 +15,10 @@
@class UIView;
@class ChildView;
+namespace mozilla::widget {
+class TextInputHandler;
+}
+
class nsWindow final : public nsBaseWidget {
typedef nsBaseWidget Inherited;
@@ -27,49 +31,47 @@ class nsWindow final : public nsBaseWidget {
// nsIWidget
//
- [[nodiscard]] virtual nsresult Create(
+ [[nodiscard]] nsresult Create(
nsIWidget* aParent, nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
- widget::InitData* aInitData = nullptr) override;
- virtual void Destroy() override;
- virtual void Show(bool aState) override;
- virtual void Enable(bool aState) override {}
- virtual bool IsEnabled() const override { return true; }
- virtual bool IsVisible() const override { return mVisible; }
- virtual void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
- virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
-
- virtual void SetBackgroundColor(const nscolor& aColor) override;
- virtual void* GetNativeData(uint32_t aDataType) override;
-
- virtual void Move(double aX, double aY) override;
- virtual nsSizeMode SizeMode() override { return mSizeMode; }
- virtual void SetSizeMode(nsSizeMode aMode) override;
+ mozilla::widget::InitData* aInitData = nullptr) override;
+ void Destroy() override;
+ void Show(bool aState) override;
+ void Enable(bool aState) override {}
+ bool IsEnabled() const override { return true; }
+ bool IsVisible() const override { return mVisible; }
+ void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
+ LayoutDeviceIntPoint WidgetToScreenOffset() override;
+
+ void SetBackgroundColor(const nscolor& aColor) override;
+ void* GetNativeData(uint32_t aDataType) override;
+
+ void Move(double aX, double aY) override;
+ nsSizeMode SizeMode() override { return mSizeMode; }
+ void SetSizeMode(nsSizeMode aMode) override;
void EnteredFullScreen(bool aFullScreen);
- virtual void Resize(double aWidth, double aHeight, bool aRepaint) override;
- virtual void Resize(double aX, double aY, double aWidth, double aHeight,
- bool aRepaint) override;
- virtual LayoutDeviceIntRect GetScreenBounds() override;
+ void Resize(double aWidth, double aHeight, bool aRepaint) override;
+ void Resize(double aX, double aY, double aWidth, double aHeight,
+ bool aRepaint) override;
+ LayoutDeviceIntRect GetScreenBounds() override;
void ReportMoveEvent();
void ReportSizeEvent();
void ReportSizeModeEvent(nsSizeMode aMode);
CGFloat BackingScaleFactor();
void BackingScaleFactorChanged();
- virtual float GetDPI() override {
+ float GetDPI() override {
// XXX: terrible
return 326.0f;
}
- virtual double GetDefaultScaleInternal() override {
- return BackingScaleFactor();
- }
- virtual int32_t RoundsWidgetCoordinatesTo() override;
+ double GetDefaultScaleInternal() override { return BackingScaleFactor(); }
+ int32_t RoundsWidgetCoordinatesTo() override;
- virtual nsresult SetTitle(const nsAString& aTitle) override { return NS_OK; }
+ nsresult SetTitle(const nsAString& aTitle) override { return NS_OK; }
- virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
- virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
- nsEventStatus& aStatus) override;
+ void Invalidate(const LayoutDeviceIntRect& aRect) override;
+ nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus& aStatus) override;
void WillPaintWindow();
bool PaintWindow(LayoutDeviceIntRegion aRegion);
@@ -78,9 +80,16 @@ class nsWindow final : public nsBaseWidget {
// virtual nsresult
// NotifyIME(const IMENotification& aIMENotification) override;
- virtual void SetInputContext(const InputContext& aContext,
- const InputContextAction& aAction);
- virtual InputContext GetInputContext();
+ void SetInputContext(const InputContext& aContext,
+ const InputContextAction& aAction) override;
+ InputContext GetInputContext() override;
+ TextEventDispatcherListener* GetNativeTextEventDispatcherListener() override;
+
+ mozilla::widget::TextInputHandler* GetTextInputHandler() const {
+ return mTextInputHandler;
+ }
+ bool IsVirtualKeyboardDisabled() const;
+
/*
virtual bool ExecuteNativeKeyBinding(
NativeKeyBindingsType aType,
@@ -104,7 +113,9 @@ class nsWindow final : public nsBaseWidget {
nsSizeMode mSizeMode;
nsTArray<nsWindow*> mChildren;
nsWindow* mParent;
- InputContext mInputContext;
+
+ mozilla::widget::InputContext mInputContext;
+ RefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
void OnSizeChanged(const mozilla::gfx::IntSize& aSize);
diff --git a/widget/uikit/nsWindow.mm b/widget/uikit/nsWindow.mm
index 0c1a38c27c..51b317ee61 100644
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#import <UIKit/UIEvent.h>
+#import <UIKit/UIKit.h>
#import <UIKit/UIGraphics.h>
#import <UIKit/UIInterface.h>
#import <UIKit/UIScreen.h>
@@ -17,29 +18,41 @@
#include <algorithm>
#include "nsWindow.h"
-#include "nsScreenManager.h"
#include "nsAppShell.h"
+#ifdef ACCESSIBILITY
+# include "nsAccessibilityService.h"
+# include "mozilla/a11y/LocalAccessible.h"
+#endif
#include "nsWidgetsCID.h"
#include "nsGfxCIID.h"
+#include "gfxPlatform.h"
#include "gfxQuartzSurface.h"
#include "gfxUtils.h"
#include "gfxImageSurface.h"
#include "gfxContext.h"
+#include "nsObjCExceptions.h"
#include "nsRegion.h"
-#include "Layers.h"
#include "nsTArray.h"
+#include "TextInputHandler.h"
+#include "UIKitUtils.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/MouseEventBinding.h"
+#include "mozilla/gfx/Logging.h"
+#ifdef ACCESSIBILITY
+# include "mozilla/a11y/MUIRootAccessibleProtocol.h"
+#endif
using namespace mozilla;
-using namespace mozilla::dom;
+using namespace mozilla::gfx;
using namespace mozilla::layers;
+using mozilla::dom::Touch;
+using mozilla::widget::UIKitUtils;
#define ALOG(args...) \
fprintf(stderr, args); \
@@ -62,18 +75,22 @@ static CGRect DevPixelsToUIKitPoints(const LayoutDeviceIntRect& aRect,
// Used to retain a Cocoa object for the remainder of a method's execution.
class nsAutoRetainUIKitObject {
public:
- nsAutoRetainUIKitObject(id anObject) { mObject = [anObject retain]; }
+ explicit nsAutoRetainUIKitObject(id anObject) { mObject = [anObject retain]; }
~nsAutoRetainUIKitObject() { [mObject release]; }
private:
id mObject; // [STRONG]
};
-@interface ChildView : UIView {
+#ifdef ACCESSIBILITY
+@interface ChildView : UIView <UIKeyInput, MUIRootAccessibleProtocol> {
+#else
+@interface ChildView : UIView <UIKeyInput> {
+#endif
@public
nsWindow* mGeckoChild; // weak ref
BOOL mWaitingForPaint;
- CFMutableDictionaryRef mTouches;
+ NSMapTable<UITouch*, NSNumber*>* mTouches;
int mNextTouchID;
}
// sets up our view, attaching it to its owning gecko view
@@ -93,10 +110,32 @@ class nsAutoRetainUIKitObject {
touches:(NSSet*)aTouches
widget:(nsWindow*)aWindow;
// Event handling (UIResponder)
-- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
-- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;
-- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
-- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
+- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event;
+- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event;
+- (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event;
+- (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event;
+
+- (void)activateWindow:(NSNotification*)notification;
+- (void)deactivateWindow:(NSNotification*)notification;
+
+#ifdef ACCESSIBILITY
+// MUIRootAccessible
+- (BOOL)hasRepresentedView;
+- (id)representedView;
+
+// MUIAccessible
+- (BOOL)isAccessibilityElement;
+- (NSString*)accessibilityLabel;
+- (CGRect)accessibilityFrame;
+- (NSString*)accessibilityValue;
+- (uint64_t)accessibilityTraits;
+- (NSInteger)accessibilityElementCount;
+- (nullable id)accessibilityElementAtIndex:(NSInteger)index;
+- (NSInteger)indexOfAccessibilityElement:(id)element;
+- (NSArray* _Nullable)accessibilityElements;
+- (UIAccessibilityContainerType)accessibilityContainerType;
+#endif
+
@end
@implementation ChildView
@@ -120,15 +159,29 @@ class nsAutoRetainUIKitObject {
tapRecognizer.numberOfTapsRequired = 1;
[self addGestureRecognizer:tapRecognizer];
- mTouches =
- CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
+ mTouches = [[NSMapTable alloc] init];
mNextTouchID = 0;
+
+ // This is managed with weak references by the notification center so that we
+ // do not need to call removeObserver.
+ // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415360-addobserver#discussion
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(activateWindow:)
+ name:UIWindowDidBecomeKeyNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(deactivateWindow:)
+ name:UIWindowDidResignKeyNotification
+ object:nil];
+
return self;
}
- (void)widgetDestroyed {
mGeckoChild = nullptr;
- CFRelease(mTouches);
+ [mTouches release];
}
- (void)delayedTearDown {
@@ -136,6 +189,30 @@ class nsAutoRetainUIKitObject {
[self release];
}
+- (void)activateWindow:(NSNotification*)notification {
+ ALOG("[[ChildView[%p] activateWindow]", (void*)self);
+
+ if (!mGeckoChild) {
+ return;
+ }
+
+ if (nsIWidgetListener* listener = mGeckoChild->GetWidgetListener()) {
+ listener->WindowActivated();
+ }
+}
+
+- (void)deactivateWindow:(NSNotification*)notification {
+ ALOG("[[ChildView[%p] deactivateWindow]", (void*)self);
+
+ if (!mGeckoChild) {
+ return;
+ }
+
+ if (nsIWidgetListener* listener = mGeckoChild->GetWidgetListener()) {
+ listener->WindowDeactivated();
+ }
+}
+
- (void)sendMouseEvent:(EventMessage)aType
point:(LayoutDeviceIntPoint)aPoint
widget:(nsWindow*)aWindow {
@@ -144,9 +221,8 @@ class nsAutoRetainUIKitObject {
event.mRefPoint = aPoint;
event.mClickCount = 1;
- event.button = MouseButton::ePrimary;
- event.mTime = PR_IntervalNow();
- event.inputSource = MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
+ event.mButton = MouseButton::ePrimary;
+ event.mInputSource = mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
nsEventStatus status;
aWindow->DispatchEvent(&event, status);
@@ -169,20 +245,20 @@ class nsAutoRetainUIKitObject {
WidgetTouchEvent event(true, aType, aWindow);
// XXX: I think nativeEvent.timestamp * 1000 is probably usable here but
// I don't care that much right now.
- event.mTime = PR_IntervalNow();
event.mTouches.SetCapacity(aTouches.count);
for (UITouch* touch in aTouches) {
LayoutDeviceIntPoint loc = UIKitPointsToDevPixels(
[touch locationInView:self], [self contentScaleFactor]);
- LayoutDeviceIntPoint radius =
- UIKitPointsToDevPixels([touch majorRadius], [touch majorRadius]);
- void* value;
- if (!CFDictionaryGetValueIfPresent(mTouches, touch, (const void**)&value)) {
+ LayoutDeviceIntPoint radius = UIKitPointsToDevPixels(
+ CGPointMake([touch majorRadius], [touch majorRadius]),
+ [self contentScaleFactor]);
+ NSNumber* value = [mTouches objectForKey:touch];
+ if (value == nil) {
// This shouldn't happen.
NS_ASSERTION(false, "Got a touch that we didn't know about");
continue;
}
- int id = reinterpret_cast<int>(value);
+ int id = [value intValue];
RefPtr<Touch> t = new Touch(id, loc, radius, 0.0f, 1.0f);
event.mRefPoint = loc;
event.mTouches.AppendElement(t);
@@ -190,12 +266,12 @@ class nsAutoRetainUIKitObject {
aWindow->DispatchInputEvent(&event);
}
-- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
+- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
ALOG("[ChildView[%p] touchesBegan", self);
if (!mGeckoChild) return;
for (UITouch* touch : touches) {
- CFDictionaryAddValue(mTouches, touch, (void*)mNextTouchID);
+ [mTouches setObject:[NSNumber numberWithInt:mNextTouchID] forKey:touch];
mNextTouchID++;
}
[self sendTouchEvent:eTouchStart
@@ -203,31 +279,31 @@ class nsAutoRetainUIKitObject {
widget:mGeckoChild];
}
-- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
+- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
ALOG("[ChildView[%p] touchesCancelled", self);
[self sendTouchEvent:eTouchCancel touches:touches widget:mGeckoChild];
for (UITouch* touch : touches) {
- CFDictionaryRemoveValue(mTouches, touch);
+ [mTouches removeObjectForKey:touch];
}
- if (CFDictionaryGetCount(mTouches) == 0) {
+ if (mTouches.count == 0) {
mNextTouchID = 0;
}
}
-- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
+- (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
ALOG("[ChildView[%p] touchesEnded", self);
if (!mGeckoChild) return;
[self sendTouchEvent:eTouchEnd touches:touches widget:mGeckoChild];
for (UITouch* touch : touches) {
- CFDictionaryRemoveValue(mTouches, touch);
+ [mTouches removeObjectForKey:touch];
}
- if (CFDictionaryGetCount(mTouches) == 0) {
+ if (mTouches.count == 0) {
mNextTouchID = 0;
}
}
-- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
+- (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
ALOG("[ChildView[%p] touchesMoved", self);
if (!mGeckoChild) return;
@@ -236,6 +312,17 @@ class nsAutoRetainUIKitObject {
widget:mGeckoChild];
}
+- (BOOL)canBecomeFirstResponder {
+ if (!mGeckoChild) {
+ return NO;
+ }
+
+ if (mGeckoChild->IsVirtualKeyboardDisabled()) {
+ return NO;
+ }
+ return YES;
+}
+
- (void)setNeedsDisplayInRect:(CGRect)aRect {
if ([self isUsingMainThreadOpenGL]) {
// Draw without calling drawRect. This prevent us from
@@ -326,7 +413,8 @@ class nsAutoRetainUIKitObject {
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
CGSize viewSize = [self bounds].size;
- gfx::IntSize backingSize(viewSize.width * scale, viewSize.height * scale);
+ gfx::IntSize backingSize(NSToIntRound(viewSize.width * scale),
+ NSToIntRound(viewSize.height * scale));
CGContextSaveGState(aContext);
@@ -339,13 +427,12 @@ class nsAutoRetainUIKitObject {
// Create Cairo objects.
RefPtr<gfxQuartzSurface> targetSurface;
- UniquePtrPtr<gfxContext> targetContext;
+ UniquePtr<gfxContext> targetContext;
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(
gfx::BackendType::CAIRO)) {
// This is dead code unless you mess with prefs, but keep it around for
// debugging.
targetSurface = new gfxQuartzSurface(aContext, backingSize);
- targetSurface->SetAllowUseAsSource(false);
RefPtr<gfx::DrawTarget> dt =
gfxPlatform::CreateDrawTargetForSurface(targetSurface, backingSize);
if (!dt || !dt->IsValid()) {
@@ -399,6 +486,183 @@ class nsAutoRetainUIKitObject {
CGContextStrokeRect(aContext, aRect);
#endif
}
+
+// UIKeyInput
+
+- (void)insertText:(NSString*)text {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return;
+ }
+ widget::TextInputHandler* textInputHandler =
+ mGeckoChild->GetTextInputHandler();
+ if (!textInputHandler) {
+ return;
+ }
+ textInputHandler->InsertText(text);
+}
+
+- (void)deleteBackward {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return;
+ }
+ widget::TextInputHandler* textInputHandler =
+ mGeckoChild->GetTextInputHandler();
+ if (!textInputHandler) {
+ return;
+ }
+ textInputHandler->HandleCommand(Command::DeleteCharBackward);
+}
+
+- (BOOL)hasText {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return NO;
+ }
+ widget::InputContext context = mGeckoChild->GetInputContext();
+ if (context.mIMEState.mEnabled == mozilla::widget::IMEEnabled::Disabled) {
+ return NO;
+ }
+ return YES;
+}
+
+// UITextInputTraits
+
+- (UIKeyboardType)keyboardType {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return UIKeyboardTypeDefault;
+ }
+ return UIKitUtils::GetUIKeyboardType(mGeckoChild->GetInputContext());
+}
+
+- (UIReturnKeyType)returnKeyType {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return UIReturnKeyDefault;
+ }
+ return UIKitUtils::GetUIReturnKeyType(mGeckoChild->GetInputContext());
+}
+
+- (UITextAutocapitalizationType)autocapitalizationType {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return UITextAutocapitalizationTypeNone;
+ }
+ return UIKitUtils::GetUITextAutocapitalizationType(
+ mGeckoChild->GetInputContext());
+}
+
+- (BOOL)isSecureTextEntry {
+ if (!mGeckoChild || mGeckoChild->Destroyed()) {
+ return NO;
+ }
+ if (mGeckoChild->GetInputContext().IsPasswordEditor()) {
+ return YES;
+ }
+ return NO;
+}
+
+#ifdef ACCESSIBILITY
+// MUIRootAccessible
+
+- (id<MUIRootAccessibleProtocol>)accessible {
+ if (!mGeckoChild) return nil;
+
+ id<MUIRootAccessibleProtocol> nativeAccessible = nil;
+
+ // nsAutoRetainCocoaObject kungFuDeathGrip(self);
+ RefPtr<nsWindow> geckoChild(mGeckoChild);
+ RefPtr<a11y::LocalAccessible> accessible = geckoChild->GetRootAccessible();
+ if (!accessible) return nil;
+
+ accessible->GetNativeInterface((void**)&nativeAccessible);
+
+ return nativeAccessible;
+}
+
+- (BOOL)hasRepresentedView {
+ return YES;
+}
+
+- (id)representedView {
+ return self;
+}
+
+- (BOOL)isAccessibilityElement {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super isAccessibilityElement];
+ }
+
+ return [[self accessible] isAccessibilityElement];
+}
+
+- (NSString*)accessibilityLabel {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityLabel];
+ }
+
+ return [[self accessible] accessibilityLabel];
+}
+
+- (CGRect)accessibilityFrame {
+ // Use the UIView implementation here. We rely on the position of this
+ // frame to place gecko bounds in the right offset.
+ return [super accessibilityFrame];
+}
+
+- (NSString*)accessibilityValue {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityValue];
+ }
+
+ return [[self accessible] accessibilityValue];
+}
+
+- (uint64_t)accessibilityTraits {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityTraits];
+ }
+
+ return [[self accessible] accessibilityTraits];
+}
+
+- (NSInteger)accessibilityElementCount {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityElementCount];
+ }
+
+ return [[self accessible] accessibilityElementCount];
+}
+
+- (nullable id)accessibilityElementAtIndex:(NSInteger)index {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityElementAtIndex:index];
+ }
+
+ return [[self accessible] accessibilityElementAtIndex:index];
+}
+
+- (NSInteger)indexOfAccessibilityElement:(id)element {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super indexOfAccessibilityElement:element];
+ }
+
+ return [[self accessible] indexOfAccessibilityElement:element];
+}
+
+- (NSArray* _Nullable)accessibilityElements {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityElements];
+ }
+
+ return [[self accessible] accessibilityElements];
+}
+
+- (UIAccessibilityContainerType)accessibilityContainerType {
+ if (!mozilla::a11y::ShouldA11yBeEnabled()) {
+ return [super accessibilityContainerType];
+ }
+
+ return [[self accessible] accessibilityContainerType];
+}
+#endif
+
@end
nsWindow::nsWindow()
@@ -442,20 +706,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
if (parent == nullptr && nativeParent) parent = nativeParent->mGeckoChild;
if (parent && nativeParent == nullptr) nativeParent = parent->mNativeView;
- // for toplevel windows, bounds are fixed to full screen size
- if (parent == nullptr) {
- if (nsAppShell::gWindow == nil) {
- mBounds = UIKitScreenManager::GetBounds();
- } else {
- CGRect cgRect = [nsAppShell::gWindow bounds];
- mBounds.x = cgRect.origin.x;
- mBounds.y = cgRect.origin.y;
- mBounds.width = cgRect.size.width;
- mBounds.height = cgRect.size.height;
- }
- } else {
- mBounds = aRect;
- }
+ mBounds = aRect;
ALOG("nsWindow[%p]::Create bounds: %d %d %d %d", (void*)this, mBounds.x,
mBounds.y, mBounds.width, mBounds.height);
@@ -487,6 +738,8 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
[nsAppShell::gTopLevelViews addObject:mNativeView];
}
+ mTextInputHandler = new widget::TextInputHandler(this);
+
return NS_OK;
}
@@ -498,6 +751,11 @@ void nsWindow::Destroy() {
if (mParent) mParent->mChildren.RemoveElement(this);
+ if (mTextInputHandler) {
+ mTextInputHandler->OnDestroyed();
+ }
+ mTextInputHandler = nullptr;
+
[mNativeView widgetDestroyed];
nsBaseWidget::Destroy();
@@ -507,8 +765,6 @@ void nsWindow::Destroy() {
TearDownView();
nsBaseWidget::OnDestroy();
-
- return NS_OK;
}
void nsWindow::Show(bool aState) {
@@ -595,16 +851,12 @@ void nsWindow::SetSizeMode(nsSizeMode aMode) {
void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {
if (!mNativeView || !mVisible) return;
- MOZ_RELEASE_ASSERT(
- GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_WR,
- "Shouldn't need to invalidate with accelerated OMTC layers!");
-
[mNativeView setNeedsLayout];
[mNativeView setNeedsDisplayInRect:DevPixelsToUIKitPoints(
mBounds, BackingScaleFactor())];
}
-void nsWindow::SetFocus(Raise) {
+void nsWindow::SetFocus(Raise, mozilla::dom::CallerType) {
[[mNativeView window] makeKeyWindow];
[mNativeView becomeFirstResponder];
}
@@ -649,10 +901,16 @@ void nsWindow::ReportSizeModeEvent(nsSizeMode aMode) {
}
void nsWindow::ReportSizeEvent() {
+ LayoutDeviceIntRect innerBounds = GetClientBounds();
+
if (mWidgetListener) {
- LayoutDeviceIntRect innerBounds = GetClientBounds();
mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
}
+
+ if (mAttachedWidgetListener) {
+ mAttachedWidgetListener->WindowResized(this, innerBounds.width,
+ innerBounds.height);
+ }
}
LayoutDeviceIntRect nsWindow::GetScreenBounds() {
@@ -672,8 +930,8 @@ LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
temp = [nsAppShell::gWindow convertPoint:temp toWindow:nil];
}
- offset.x += temp.x;
- offset.y += temp.y;
+ offset.x += static_cast<int32_t>(temp.x);
+ offset.y += static_cast<int32_t>(temp.y);
return offset;
}
@@ -682,23 +940,63 @@ nsresult nsWindow::DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus) {
aStatus = nsEventStatus_eIgnore;
nsCOMPtr<nsIWidget> kungFuDeathGrip(aEvent->mWidget);
+ mozilla::Unused << kungFuDeathGrip; // Not used within this function
- if (mWidgetListener)
+ if (mAttachedWidgetListener) {
+ aStatus = mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
+ } else if (mWidgetListener) {
aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
+ }
return NS_OK;
}
void nsWindow::SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) {
- // TODO: actually show VKB
+ NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
+
+ const bool changingEnabledState =
+ aContext.IsInputAttributeChanged(mInputContext);
+
mInputContext = aContext;
+
+ if (IsVirtualKeyboardDisabled()) {
+ [mNativeView resignFirstResponder];
+ return;
+ }
+
+ [mNativeView becomeFirstResponder];
+
+ if (aAction.UserMightRequestOpenVKB() || changingEnabledState) {
+ // TODO(m_kato):
+ // It is unnecessary to call reloadInputViews with changingEnabledState if
+ // virtual keyboard is disappeared.
+ [mNativeView reloadInputViews];
+ }
+
+ NS_OBJC_END_TRY_IGNORE_BLOCK;
}
-mozilla::widget::InputContext nsWindow::GetInputContext() {
+widget::InputContext nsWindow::GetInputContext() {
+ if (!mTextInputHandler) {
+ InputContext context;
+ context.mIMEState.mEnabled = IMEEnabled::Disabled;
+ context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
+ return context;
+ }
return mInputContext;
}
+widget::TextEventDispatcherListener*
+nsWindow::GetNativeTextEventDispatcherListener() {
+ return mTextInputHandler;
+}
+
+bool nsWindow::IsVirtualKeyboardDisabled() const {
+ return mInputContext.mIMEState.mEnabled == IMEEnabled::Disabled ||
+ mInputContext.mHTMLInputMode.EqualsLiteral("none");
+}
+
void nsWindow::SetBackgroundColor(const nscolor& aColor) {
mNativeView.backgroundColor = [UIColor colorWithRed:NS_GET_R(aColor)
green:NS_GET_G(aColor)
diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp
index 6f033785f5..0e1b4002d3 100644
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -1092,25 +1092,20 @@ void GfxInfo::AddCrashReportAnnotations() {
}
nsString deviceID, vendorID, driverVersion, subsysID;
- nsCString narrowDeviceID, narrowVendorID, narrowDriverVersion, narrowSubsysID;
GetAdapterDeviceID(deviceID);
- CopyUTF16toUTF8(deviceID, narrowDeviceID);
GetAdapterVendorID(vendorID);
- CopyUTF16toUTF8(vendorID, narrowVendorID);
GetAdapterDriverVersion(driverVersion);
- CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
GetAdapterSubsysID(subsysID);
- CopyUTF16toUTF8(subsysID, narrowSubsysID);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
- narrowVendorID);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
- narrowDeviceID);
- CrashReporter::AnnotateCrashReport(
- CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
- CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterSubsysID,
- narrowSubsysID);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterVendorID, vendorID);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterDeviceID, deviceID);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterDriverVersion, driverVersion);
+ CrashReporter::RecordAnnotationNSString(
+ CrashReporter::Annotation::AdapterSubsysID, subsysID);
/* Add an App Note, this contains extra information. */
nsAutoCString note;
@@ -1741,24 +1736,6 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
"FEATURE_UNQUALIFIED_P010_NVIDIA");
////////////////////////////////////
- // FEATURE_VIDEO_OVERLAY - ALLOWLIST
-#ifdef EARLY_BETA_OR_EARLIER
- APPEND_TO_DRIVER_BLOCKLIST2(
- OperatingSystem::Windows, DeviceFamily::All,
- nsIGfxInfo::FEATURE_VIDEO_OVERLAY, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
- DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), "FEATURE_ROLLOUT_ALL");
-#else
- APPEND_TO_DRIVER_BLOCKLIST2(
- OperatingSystem::Windows, DeviceFamily::IntelAll,
- nsIGfxInfo::FEATURE_VIDEO_OVERLAY, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
- DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), "FEATURE_ROLLOUT_INTEL");
- APPEND_TO_DRIVER_BLOCKLIST2(
- OperatingSystem::Windows, DeviceFamily::NvidiaAll,
- nsIGfxInfo::FEATURE_VIDEO_OVERLAY, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
- DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), "FEATURE_ROLLOUT_NVIDIA");
-#endif
-
- ////////////////////////////////////
// FEATURE_HW_DECODED_VIDEO_ZERO_COPY
APPEND_TO_DRIVER_BLOCKLIST_RANGE(
@@ -1801,9 +1778,13 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
////////////////////////////////////
// FEATURE_HW_DECODED_VIDEO_ZERO_COPY - ALLOWLIST
-
- // XXX ZeroCopyNV12Texture is disabled with non-intel GPUs for now.
- // See Bug 1798242
+#ifdef EARLY_BETA_OR_EARLIER
+ APPEND_TO_DRIVER_BLOCKLIST2(
+ OperatingSystem::Windows, DeviceFamily::NvidiaAll,
+ nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY,
+ nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_COMPARISON_IGNORED,
+ V(0, 0, 0, 0), "FEATURE_ROLLOUT_ALL");
+#endif
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Windows, DeviceFamily::IntelAll,
nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY,
@@ -1828,6 +1809,26 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
"Intel driver 10.18.15.*");
////////////////////////////////////
+ // FEATURE_OVERLAY_VP_AUTO_HDR
+
+ APPEND_TO_DRIVER_BLOCKLIST(
+ OperatingSystem::Windows, DeviceFamily::NvidiaAll,
+ nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR,
+ nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN_OR_EQUAL,
+ V(31, 0, 15, 5050), "FEATURE_FAILURE_VP_AUTO_HDR",
+ "nVidia driver > 550.50");
+
+ ////////////////////////////////////
+ // FEATURE_OVERLAY_VP_SUPER_RESOLUTION
+
+ APPEND_TO_DRIVER_BLOCKLIST(
+ OperatingSystem::Windows, DeviceFamily::NvidiaAll,
+ nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION,
+ nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN_OR_EQUAL,
+ V(31, 0, 15, 3000), "FEATURE_FAILURE_VP_AUTO_HDR",
+ "nVidia driver > 530.00");
+
+ ////////////////////////////////////
// FEATURE_WEBRENDER
// Block 8.56.1.15/16
APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows, DeviceFamily::AtiAll,
diff --git a/widget/windows/JumpListBuilder.cpp b/widget/windows/JumpListBuilder.cpp
index 80b1c29aa7..e25c8c038f 100644
--- a/widget/windows/JumpListBuilder.cpp
+++ b/widget/windows/JumpListBuilder.cpp
@@ -176,8 +176,9 @@ JumpListBuilder::JumpListBuilder(const nsAString& aAppUserModelId,
// the app, as it is set in the package manifest instead.
if (!mozilla::widget::WinUtils::HasPackageIdentity()) {
mIOThread->Dispatch(
- NewRunnableMethod<nsString>(
- "SetAppID", this, &JumpListBuilder::DoSetAppID, aAppUserModelId),
+ NewRunnableMethod<nsString>("SetAppID", this,
+ &JumpListBuilder::DoSetAppIDIfAvailable,
+ aAppUserModelId),
NS_DISPATCH_NORMAL);
}
}
@@ -203,10 +204,13 @@ void JumpListBuilder::DoShutdownBackend() {
mJumpListBackend = nullptr;
}
-void JumpListBuilder::DoSetAppID(nsString aAppUserModelID) {
+void JumpListBuilder::DoSetAppIDIfAvailable(nsString aAppUserModelID) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mJumpListBackend);
- mJumpListBackend->SetAppID(aAppUserModelID.get());
+
+ if (mJumpListBackend->IsAvailable()) {
+ mJumpListBackend->SetAppID(aAppUserModelID.get());
+ }
}
NS_IMETHODIMP
diff --git a/widget/windows/JumpListBuilder.h b/widget/windows/JumpListBuilder.h
index e228669f11..b8d5253153 100644
--- a/widget/windows/JumpListBuilder.h
+++ b/widget/windows/JumpListBuilder.h
@@ -64,7 +64,7 @@ class JumpListBuilder : public nsIJumpListBuilder, public nsIObserver {
void DoSetupBackend();
void DoSetupTestingBackend(RefPtr<JumpListBackend> aTestingBackend);
void DoShutdownBackend();
- void DoSetAppID(nsString aAppUserModelID);
+ void DoSetAppIDIfAvailable(nsString aAppUserModelID);
void DoIsAvailable(const nsMainThreadPtrHandle<dom::Promise>& aPromiseHolder);
void DoCheckForRemovals(
const nsMainThreadPtrHandle<dom::Promise>& aPromiseHolder);
diff --git a/widget/windows/WinTaskbar.cpp b/widget/windows/WinTaskbar.cpp
index 56608503da..66854f3ee2 100644
--- a/widget/windows/WinTaskbar.cpp
+++ b/widget/windows/WinTaskbar.cpp
@@ -223,6 +223,11 @@ bool WinTaskbar::GenerateAppUserModelID(nsAString& aAppUserModelId,
id.AppendInt(HashString(path));
if (!id.IsEmpty()) {
aAppUserModelId.Assign(id);
+
+ if (aPrivateBrowsing) {
+ aAppUserModelId.AppendLiteral(";PrivateBrowsingAUMID");
+ }
+
return true;
}
}
diff --git a/widget/windows/WindowsSMTCProvider.cpp b/widget/windows/WindowsSMTCProvider.cpp
index 04d833a8e7..69915cafd8 100644
--- a/widget/windows/WindowsSMTCProvider.cpp
+++ b/widget/windows/WindowsSMTCProvider.cpp
@@ -255,6 +255,25 @@ void WindowsSMTCProvider::UnregisterEvents() {
if (mControls && mButtonPressedToken.value != 0) {
mControls->remove_ButtonPressed(mButtonPressedToken);
}
+
+ if (mControls && mSeekRegistrationToken.value != 0) {
+ ComPtr<ISystemMediaTransportControls2> smtc2;
+ HRESULT hr = mControls.As(&smtc2);
+ if (FAILED(hr)) {
+ LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)",
+ hr);
+ return;
+ }
+ MOZ_ASSERT(smtc2);
+
+ hr = smtc2->remove_PlaybackPositionChangeRequested(mSeekRegistrationToken);
+ if (FAILED(hr)) {
+ LOG("SystemMediaTransportControls: Failed unregister position change "
+ "event (hr=%lx)",
+ hr);
+ return;
+ }
+ }
}
bool WindowsSMTCProvider::RegisterEvents() {
@@ -289,6 +308,48 @@ bool WindowsSMTCProvider::RegisterEvents() {
return false;
}
+ ComPtr<ISystemMediaTransportControls2> smtc2;
+ HRESULT hr = mControls.As(&smtc2);
+ if (FAILED(hr)) {
+ LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)",
+ hr);
+ return false;
+ }
+ MOZ_ASSERT(smtc2);
+
+ auto positionChangeRequested =
+ Callback<ITypedEventHandler<SystemMediaTransportControls*,
+ PlaybackPositionChangeRequestedEventArgs*>>(
+ [this, self](
+ ISystemMediaTransportControls*,
+ IPlaybackPositionChangeRequestedEventArgs* pArgs) -> HRESULT {
+ MOZ_ASSERT(pArgs);
+
+ TimeSpan value;
+ HRESULT hr = pArgs->get_RequestedPlaybackPosition(&value);
+ if (FAILED(hr)) {
+ LOG("SystemMediaTransportControls: Playback Position Change - "
+ "failed to get requested position (hr=%lx)",
+ hr);
+ return S_OK; // Propagating the error probably wouldn't help.
+ }
+
+ double position =
+ static_cast<double>(value.Duration) / (1e6 * 10.0);
+ this->OnPositionChangeRequested(position);
+
+ return S_OK;
+ });
+
+ hr = smtc2->add_PlaybackPositionChangeRequested(positionChangeRequested.Get(),
+ &mSeekRegistrationToken);
+ if (FAILED(hr)) {
+ LOG("SystemMediaTransportControls: Failed to register position change "
+ "event (hr=%lx)",
+ hr);
+ return false;
+ }
+
return true;
}
@@ -309,12 +370,14 @@ bool WindowsSMTCProvider::EnableControl(bool aEnabled) const {
return SUCCEEDED(mControls->put_IsEnabled(aEnabled));
}
-bool WindowsSMTCProvider::UpdateButtons() const {
+bool WindowsSMTCProvider::UpdateButtons() {
static const mozilla::dom::MediaControlKey kKeys[] = {
- mozilla::dom::MediaControlKey::Play, mozilla::dom::MediaControlKey::Pause,
+ mozilla::dom::MediaControlKey::Play,
+ mozilla::dom::MediaControlKey::Pause,
mozilla::dom::MediaControlKey::Previoustrack,
mozilla::dom::MediaControlKey::Nexttrack,
- mozilla::dom::MediaControlKey::Stop};
+ mozilla::dom::MediaControlKey::Stop,
+ mozilla::dom::MediaControlKey::Seekto};
bool success = true;
for (const mozilla::dom::MediaControlKey& key : kKeys) {
@@ -347,12 +410,28 @@ bool WindowsSMTCProvider::EnableKey(mozilla::dom::MediaControlKey aKey,
return SUCCEEDED(mControls->put_IsNextEnabled(aEnable));
case mozilla::dom::MediaControlKey::Stop:
return SUCCEEDED(mControls->put_IsStopEnabled(aEnable));
+ case mozilla::dom::MediaControlKey::Seekto:
+ // The callback for the event checks if the key is supported
+ return mSeekRegistrationToken.value != 0;
default:
LOG("No button for %s", ToMediaControlKeyStr(aKey));
return false;
}
}
+void WindowsSMTCProvider::OnPositionChangeRequested(double aPosition) const {
+ if (!IsKeySupported(mozilla::dom::MediaControlKey::Seekto)) {
+ LOG("Seekto is not supported");
+ return;
+ }
+
+ for (const auto& listener : mListeners) {
+ listener->OnActionPerformed(
+ mozilla::dom::MediaControlAction(mozilla::dom::MediaControlKey::Seekto,
+ mozilla::dom::SeekDetails(aPosition)));
+ }
+}
+
bool WindowsSMTCProvider::InitDisplayAndControls() {
// As Open() might be called multiple times, "cache" the results of the COM
// API
@@ -422,6 +501,100 @@ bool WindowsSMTCProvider::SetMusicMetadata(const nsString& aArtist,
return true;
}
+void WindowsSMTCProvider::SetPositionState(
+ const mozilla::Maybe<mozilla::dom::PositionState>& aState) {
+ ComPtr<ISystemMediaTransportControls2> smtc2;
+ HRESULT hr = mControls.As(&smtc2);
+ if (FAILED(hr)) {
+ LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)",
+ hr);
+ return;
+ }
+ MOZ_ASSERT(smtc2);
+
+ ComPtr<ISystemMediaTransportControlsTimelineProperties> properties;
+ hr = RoActivateInstance(
+ HStringReference(
+ RuntimeClass_Windows_Media_SystemMediaTransportControlsTimelineProperties)
+ .Get(),
+ &properties);
+ if (FAILED(hr)) {
+ LOG("Failed to create timeline properties (hr=%lx)", hr);
+ return;
+ }
+ MOZ_ASSERT(properties);
+
+ // Converts a value in seconds to a TimeSpan
+ // The TimeSpan's Duration is a value in 100ns ticks
+ // https://learn.microsoft.com/en-us/windows/win32/api/windows.foundation/ns-windows-foundation-timespan#members
+ auto toTimeSpan = [this](double seconds) {
+ constexpr double kMaxMicroseconds =
+ static_cast<double>(std::numeric_limits<LONG64>::max() / 10);
+
+ double microseconds = seconds * 1e6;
+
+ if (microseconds > kMaxMicroseconds) {
+ LOG("Failed to convert %f microseconds to TimeSpan (overflow)",
+ microseconds);
+ return TimeSpan{0};
+ }
+
+ return TimeSpan{static_cast<LONG64>(microseconds * 10.0)};
+ };
+
+ TimeSpan endTime{0};
+ TimeSpan position{0};
+ double playbackRate = 1.0;
+
+ if (aState) {
+ endTime = toTimeSpan(aState->mDuration);
+ position = toTimeSpan(aState->CurrentPlaybackPosition());
+ playbackRate = aState->mPlaybackRate;
+ }
+
+ hr = properties->put_StartTime({0});
+ if (FAILED(hr)) {
+ LOG("Failed to set the start time (hr=%lx)", hr);
+ return;
+ }
+
+ hr = properties->put_MinSeekTime({0});
+ if (FAILED(hr)) {
+ LOG("Failed to set the min seek time (hr=%lx)", hr);
+ return;
+ }
+
+ hr = properties->put_EndTime(endTime);
+ if (FAILED(hr)) {
+ LOG("Failed to set the end time (hr=%lx)", hr);
+ return;
+ }
+
+ hr = properties->put_MaxSeekTime(endTime);
+ if (FAILED(hr)) {
+ LOG("Failed to set the max seek time (hr=%lx)", hr);
+ return;
+ }
+
+ hr = properties->put_Position(position);
+ if (FAILED(hr)) {
+ LOG("Failed to set the playback position (hr=%lx)", hr);
+ return;
+ }
+
+ hr = smtc2->UpdateTimelineProperties(properties.Get());
+ if (FAILED(hr)) {
+ LOG("Failed to update timeline properties (hr=%lx)", hr);
+ return;
+ }
+
+ hr = smtc2->put_PlaybackRate(playbackRate);
+ if (FAILED(hr)) {
+ LOG("Failed to set the playback rate (hr=%lx)", hr);
+ return;
+ }
+}
+
void WindowsSMTCProvider::LoadThumbnail(
const nsTArray<mozilla::dom::MediaImage>& aArtwork) {
MOZ_ASSERT(NS_IsMainThread());
diff --git a/widget/windows/WindowsSMTCProvider.h b/widget/windows/WindowsSMTCProvider.h
index 3926618d1f..2f0d1f8344 100644
--- a/widget/windows/WindowsSMTCProvider.h
+++ b/widget/windows/WindowsSMTCProvider.h
@@ -46,6 +46,9 @@ class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource {
void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override;
+ void SetPositionState(
+ const mozilla::Maybe<mozilla::dom::PositionState>& aState) override;
+
private:
~WindowsSMTCProvider();
void UnregisterEvents();
@@ -54,12 +57,14 @@ class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource {
void OnButtonPressed(mozilla::dom::MediaControlKey aKey) const;
// Enable the SMTC interface
bool EnableControl(bool aEnabled) const;
- // Sets the play, pause, next, previous buttons on the SMTC interface by
- // mSupportedKeys
- bool UpdateButtons() const;
+ // Sets the play, pause, next, previous, seekto buttons on the SMTC interface
+ // by mSupportedKeys
+ bool UpdateButtons();
bool IsKeySupported(mozilla::dom::MediaControlKey aKey) const;
bool EnableKey(mozilla::dom::MediaControlKey aKey, bool aEnable) const;
+ void OnPositionChangeRequested(double aPosition) const;
+
bool InitDisplayAndControls();
// Sets the Metadata for the currently playing media and sets the playback
@@ -122,6 +127,7 @@ class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource {
// EventRegistrationTokens are used to have a handle on a callback (to remove
// it again)
EventRegistrationToken mButtonPressedToken;
+ EventRegistrationToken mSeekRegistrationToken;
};
#endif // __MINGW32__
diff --git a/widget/windows/filedialog/WinFileDialogChild.cpp b/widget/windows/filedialog/WinFileDialogChild.cpp
index 1a2903f8ec..a41018ff0e 100644
--- a/widget/windows/filedialog/WinFileDialogChild.cpp
+++ b/widget/windows/filedialog/WinFileDialogChild.cpp
@@ -40,11 +40,8 @@ WinFileDialogChild::~WinFileDialogChild() {
template <size_t N>
WinFileDialogChild::IPCResult WinFileDialogChild::MakeIpcFailure(
HRESULT hr, const char (&what)[N]) {
- // The crash-report annotator stringifies integer values anyway. We do so
- // eagerly here to avoid questions about C int/long conversion semantics.
- nsPrintfCString data("%lu", hr);
- CrashReporter::AnnotateCrashReport(
- CrashReporter::Annotation::WindowsFileDialogErrorCode, data);
+ CrashReporter::RecordAnnotationU32(
+ CrashReporter::Annotation::WindowsFileDialogErrorCode, hr);
return IPC_FAIL(this, what);
}
diff --git a/widget/windows/filedialog/WinFileDialogCommands.cpp b/widget/windows/filedialog/WinFileDialogCommands.cpp
index f0503ab8f0..838856893d 100644
--- a/widget/windows/filedialog/WinFileDialogCommands.cpp
+++ b/widget/windows/filedialog/WinFileDialogCommands.cpp
@@ -294,7 +294,7 @@ void LogProcessingError(LogModule* aModule, ipc::IProtocol* aCaller,
ipc::SandboxingKind::WINDOWS_FILE_DIALOG);
} else {
// ... which (presumably) is us
- CrashReporter::AnnotateCrashReport(
+ CrashReporter::AutoRecordAnnotation(
CrashReporter::Annotation::ipc_channel_error, reason);
MOZ_CRASH("IPC error");
diff --git a/widget/windows/nsFilePicker.cpp b/widget/windows/nsFilePicker.cpp
index 310c54bb40..fb4c6e80b5 100644
--- a/widget/windows/nsFilePicker.cpp
+++ b/widget/windows/nsFilePicker.cpp
@@ -19,6 +19,7 @@
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/Components.h"
#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/Logging.h"
#include "mozilla/ipc/UtilityProcessManager.h"
@@ -94,19 +95,14 @@ nsFilePicker::nsFilePicker() : mSelectedType(1) {}
NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
NS_IMETHODIMP nsFilePicker::Init(
- mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- mozilla::dom::BrowsingContext* aBrowsingContext) {
+ mozilla::dom::BrowsingContext* aBrowsingContext, const nsAString& aTitle,
+ nsIFilePicker::Mode aMode) {
// Don't attempt to open a real file-picker in headless mode.
if (gfxPlatform::IsHeadless()) {
return nsresult::NS_ERROR_NOT_AVAILABLE;
}
- nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aParent);
- nsIDocShell* docShell = window ? window->GetDocShell() : nullptr;
- mLoadContext = do_QueryInterface(docShell);
-
- return nsBaseFilePicker::Init(aParent, aTitle, aMode, aBrowsingContext);
+ return nsBaseFilePicker::Init(aBrowsingContext, aTitle, aMode);
}
namespace mozilla::detail {
@@ -1053,7 +1049,7 @@ void nsFilePicker::RememberLastUsedDirectory() {
}
bool nsFilePicker::IsPrivacyModeEnabled() {
- return mLoadContext && mLoadContext->UsePrivateBrowsing();
+ return mBrowsingContext && mBrowsingContext->UsePrivateBrowsing();
}
bool nsFilePicker::IsDefaultPathLink() {
diff --git a/widget/windows/nsFilePicker.h b/widget/windows/nsFilePicker.h
index 1938b8bcb6..59108bc0dd 100644
--- a/widget/windows/nsFilePicker.h
+++ b/widget/windows/nsFilePicker.h
@@ -66,9 +66,8 @@ class nsFilePicker final : public nsBaseWinFilePicker {
public:
nsFilePicker();
- NS_IMETHOD Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
- nsIFilePicker::Mode aMode,
- mozilla::dom::BrowsingContext* aBrowsingContext) override;
+ NS_IMETHOD Init(mozilla::dom::BrowsingContext* aBrowsingContext,
+ const nsAString& aTitle, nsIFilePicker::Mode aMode) override;
NS_DECL_ISUPPORTS
@@ -117,7 +116,6 @@ class nsFilePicker final : public nsBaseWinFilePicker {
bool IsDefaultPathLink();
bool IsDefaultPathHtml();
- nsCOMPtr<nsILoadContext> mLoadContext;
nsCOMPtr<nsIWidget> mParentWidget;
nsString mTitle;
nsCString mFile;
diff --git a/widget/windows/nsLookAndFeel.cpp b/widget/windows/nsLookAndFeel.cpp
index 01b126cd42..6122000c9e 100644
--- a/widget/windows/nsLookAndFeel.cpp
+++ b/widget/windows/nsLookAndFeel.cpp
@@ -409,9 +409,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
// (400ms) on error.
aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400);
break;
- case IntID::TooltipDelay:
- aResult = 500;
- break;
case IntID::MenusCanOverlapOSBar:
// we want XUL popups to be able to overlap the task bar.
aResult = 1;
diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp
index 1a8646d620..b304d2efac 100644
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -175,12 +175,11 @@
#include <zmouse.h>
#include <richedit.h>
-#if defined(ACCESSIBILITY)
-
+#ifdef ACCESSIBILITY
# ifdef DEBUG
# include "mozilla/a11y/Logging.h"
# endif
-
+# include "mozilla/a11y/Compatibility.h"
# include "oleidl.h"
# include <winuser.h>
# include "nsAccessibilityService.h"
@@ -190,7 +189,7 @@
# if !defined(WINABLEAPI)
# include <winable.h>
# endif // !defined(WINABLEAPI)
-#endif // defined(ACCESSIBILITY)
+#endif
#include "WindowsUIUtils.h"
@@ -1221,18 +1220,19 @@ static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
/* static */
const wchar_t* nsWindow::ChooseWindowClass(WindowType aWindowType) {
- switch (aWindowType) {
- case WindowType::Invisible:
- return RegisterWindowClass(kClassNameHidden, 0, gStockApplicationIcon);
- case WindowType::Dialog:
- return RegisterWindowClass(kClassNameDialog, 0, nullptr);
- case WindowType::Popup:
- return RegisterWindowClass(kClassNameDropShadow, 0,
- gStockApplicationIcon);
- default:
- return RegisterWindowClass(GetMainWindowClass(), 0,
- gStockApplicationIcon);
- }
+ const wchar_t* className = [aWindowType] {
+ switch (aWindowType) {
+ case WindowType::Invisible:
+ return kClassNameHidden;
+ case WindowType::Dialog:
+ return kClassNameDialog;
+ case WindowType::Popup:
+ return kClassNameDropShadow;
+ default:
+ return GetMainWindowClass();
+ }
+ }();
+ return RegisterWindowClass(className, 0, gStockApplicationIcon);
}
/**************************************************************
@@ -1310,13 +1310,6 @@ DWORD nsWindow::WindowStyle() {
if (mBorderStyle == BorderStyle::None ||
!(mBorderStyle & BorderStyle::Maximize))
style &= ~WS_MAXIMIZEBOX;
-
- if (IsPopupWithTitleBar()) {
- style |= WS_CAPTION;
- if (mBorderStyle & BorderStyle::Close) {
- style |= WS_SYSMENU;
- }
- }
}
if (mIsChildWindow) {
@@ -1332,7 +1325,6 @@ DWORD nsWindow::WindowStyle() {
// Return nsWindow extended styles
DWORD nsWindow::WindowExStyle() {
- MOZ_ASSERT_IF(mIsAlert, mWindowType == WindowType::Dialog);
switch (mWindowType) {
case WindowType::Child:
return 0;
@@ -1343,18 +1335,18 @@ DWORD nsWindow::WindowExStyle() {
}
return extendedStyle;
}
- case WindowType::Dialog: {
- if (mIsAlert) {
- return WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
- }
- return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
- }
case WindowType::Sheet:
MOZ_FALLTHROUGH_ASSERT("Sheets are macOS specific");
+ case WindowType::Dialog:
case WindowType::TopLevel:
case WindowType::Invisible:
break;
}
+ if (mIsAlert) {
+ MOZ_ASSERT(mWindowType == WindowType::Dialog,
+ "Expect alert windows to have type=dialog");
+ return WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+ }
return WS_EX_WINDOWEDGE;
}
@@ -3058,9 +3050,7 @@ void nsWindow::SetTransparencyMode(TransparencyMode aMode) {
void nsWindow::UpdateWindowDraggingRegion(
const LayoutDeviceIntRegion& aRegion) {
- if (mDraggableRegion != aRegion) {
- mDraggableRegion = aRegion;
- }
+ mDraggableRegion = aRegion;
}
/**************************************************************
@@ -3674,7 +3664,7 @@ LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
}
LayoutDeviceIntMargin nsWindow::ClientToWindowMargin() {
- if (mWindowType == WindowType::Popup && !IsPopupWithTitleBar()) {
+ if (mWindowType == WindowType::Popup) {
return {};
}
@@ -4420,6 +4410,17 @@ HWND nsWindow::GetTopLevelForFocus(HWND aCurWnd) {
}
void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) {
+ if (aIsActivate && mPickerDisplayCount) {
+ // We disable the root window when a picker opens. See PickerOpen. When the
+ // picker closes (but before PickerClosed is called), our window will get
+ // focus, but it will still be disabled. This confuses the focus system.
+ // Therefore, we ignore this focus and explicitly call this function once
+ // we re-enable the window. Rarely, the picker seems to re-enable our root
+ // window before we do, but for simplicity, we always ignore focus before
+ // the final call to PickerClosed. See bug 1883568 for further details.
+ return;
+ }
+
if (aIsActivate) {
sJustGotActivate = false;
}
@@ -5039,6 +5040,44 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
break;
}
+ case WM_GETTITLEBARINFOEX: {
+ if (!mCustomNonClient) {
+ break;
+ }
+ auto* info = reinterpret_cast<TITLEBARINFOEX*>(lParam);
+ const LayoutDeviceIntPoint origin = WidgetToScreenOffset();
+ auto GeckoClientToWinScreenRect =
+ [&origin](LayoutDeviceIntRect aRect) -> RECT {
+ aRect.MoveBy(origin);
+ return {
+ .left = aRect.x,
+ .top = aRect.y,
+ .right = aRect.XMost(),
+ .bottom = aRect.YMost(),
+ };
+ };
+ auto SetButton = [&](size_t aIndex, WindowButtonType aType) {
+ info->rgrect[aIndex] =
+ GeckoClientToWinScreenRect(mWindowBtnRect[aType]);
+ DWORD& state = info->rgstate[aIndex];
+ if (mWindowBtnRect[aType].IsEmpty()) {
+ state = STATE_SYSTEM_INVISIBLE;
+ } else {
+ state = STATE_SYSTEM_FOCUSABLE;
+ }
+ };
+ info->rgrect[0] = info->rcTitleBar =
+ GeckoClientToWinScreenRect(mDraggableRegion.GetBounds());
+ info->rgstate[0] = 0;
+ SetButton(2, WindowButtonType::Minimize);
+ SetButton(3, WindowButtonType::Maximize);
+ SetButton(5, WindowButtonType::Close);
+ // We don't have a help button.
+ info->rgstate[4] = STATE_SYSTEM_INVISIBLE;
+ info->rgrect[4] = {0, 0, 0, 0};
+ result = true;
+ } break;
+
case WM_NCHITTEST: {
if (mInputRegion.mFullyTransparent) {
// Treat this window as transparent.
@@ -6169,6 +6208,9 @@ int32_t nsWindow::ClientMarginHitTestPoint(int32_t aX, int32_t aY) {
if (mWindowBtnRect[WindowButtonType::Minimize].Contains(pt)) {
testResult = HTMINBUTTON;
} else if (mWindowBtnRect[WindowButtonType::Maximize].Contains(pt)) {
+#ifdef ACCESSIBILITY
+ a11y::Compatibility::SuppressA11yForSnapLayouts();
+#endif
testResult = HTMAXBUTTON;
} else if (mWindowBtnRect[WindowButtonType::Close].Contains(pt)) {
testResult = HTCLOSE;
@@ -8168,8 +8210,23 @@ WPARAM nsWindow::wParamFromGlobalMouseState() {
return result;
}
+// WORKAROUND FOR UNDOCUMENTED BEHAVIOR: `IFileDialog::Show` disables the
+// top-level ancestor of its provided owner-window. If the modal window's
+// container process crashes, it will never get a chance to undo that.
+//
+// For simplicity's sake we simply unconditionally perform both the disabling
+// and reenabling here, synchronously, on the main thread, rather than leaving
+// it to happen in our asynchronously-operated IFileDialog.
+
void nsWindow::PickerOpen() {
AssertIsOnMainThread();
+
+ // Disable the root-level window synchronously before any file-dialogs get a
+ // chance to fight over doing it asynchronously.
+ if (!mPickerDisplayCount) {
+ ::EnableWindow(::GetAncestor(GetWindowHandle(), GA_ROOT), FALSE);
+ }
+
mPickerDisplayCount++;
}
@@ -8179,16 +8236,10 @@ void nsWindow::PickerClosed() {
if (!mPickerDisplayCount) return;
mPickerDisplayCount--;
- // WORKAROUND FOR UNDOCUMENTED BEHAVIOR: `IFileDialog::Show` disables the
- // top-level ancestor of its provided owner-window. If the modal window's
- // container process crashes, it will never get a chance to undo that, so we
- // do it manually here.
- //
- // Note that this may cause problems in the embedded case if you reparent a
- // subtree of the native window hierarchy containing a Gecko window while that
- // Gecko window has a file-dialog open.
+ // Once all the file-dialogs are gone, reenable the root-level window.
if (!mPickerDisplayCount) {
::EnableWindow(::GetAncestor(GetWindowHandle(), GA_ROOT), TRUE);
+ DispatchFocusToTopLevelWindow(true);
}
if (!mPickerDisplayCount && mDestroyCalled) {
@@ -8528,6 +8579,7 @@ void nsWindow::ChangedDPI() {
presShell->BackingScaleFactorChanged();
}
}
+ NotifyAPZOfDPIChange();
}
static Result<POINTER_FLAGS, nsresult> PointerStateToFlag(
diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h
index c75c9d174d..3a521fb978 100644
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -887,8 +887,8 @@ class nsWindow final : public nsBaseWidget {
mozilla::UniquePtr<mozilla::widget::DirectManipulationOwner> mDmOwner;
// Client rect for minimize, maximize and close buttons.
- mozilla::EnumeratedArray<WindowButtonType, WindowButtonType::Count,
- LayoutDeviceIntRect>
+ mozilla::EnumeratedArray<WindowButtonType, LayoutDeviceIntRect,
+ size_t(WindowButtonType::Count)>
mWindowBtnRect;
mozilla::DataMutex<Desktop> mDesktopId;