summaryrefslogtreecommitdiffstats
path: root/widget/gtk
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:33 +0000
commit086c044dc34dfc0f74fbe41f4ecb402b2cd34884 (patch)
treea4f824bd33cb075dd5aa3eb5a0a94af221bbe83a /widget/gtk
parentAdding debian version 124.0.1-1. (diff)
downloadfirefox-086c044dc34dfc0f74fbe41f4ecb402b2cd34884.tar.xz
firefox-086c044dc34dfc0f74fbe41f4ecb402b2cd34884.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/gtk')
-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
34 files changed, 1774 insertions, 575 deletions
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,
+};