bodge a gtk4 starting point into existence

this is not supposed to work or anything even close to that

Change-Id: I46b4fed6a1e6cfc885cb4f7c24660bb6438d5101
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115293
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/Repository.mk b/Repository.mk
index db52290..e95ea30 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -280,6 +280,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,onlineupdate, \
$(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,gnome, \
	$(if $(ENABLE_EVOAB2),evoab) \
	$(if $(ENABLE_GTK3),vclplug_gtk3) \
	$(if $(ENABLE_GTK4),vclplug_gtk4) \
	$(if $(ENABLE_GIO),losessioninstall) \
	$(if $(ENABLE_GIO),ucpgio1) \
))
diff --git a/config_host.mk.in b/config_host.mk.in
index d455110..f7fa8ca 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -159,6 +159,7 @@ export ENABLE_GIO=@ENABLE_GIO@
export ENABLE_GPGMEPP=@ENABLE_GPGMEPP@
export ENABLE_GSTREAMER_1_0=@ENABLE_GSTREAMER_1_0@
export ENABLE_GTK3=@ENABLE_GTK3@
export ENABLE_GTK4=@ENABLE_GTK4@
export DISABLE_GUI=@DISABLE_GUI@
export ENABLE_HTMLHELP=@ENABLE_HTMLHELP@
export ENABLE_JAVA=@ENABLE_JAVA@
@@ -255,6 +256,8 @@ export GSTREAMER_1_0_CFLAGS=$(gb_SPACE)@GSTREAMER_1_0_CFLAGS@
export GSTREAMER_1_0_LIBS=$(gb_SPACE)@GSTREAMER_1_0_LIBS@
export GTK3_CFLAGS=$(gb_SPACE)@GTK3_CFLAGS@
export GTK3_LIBS=$(gb_SPACE)@GTK3_LIBS@
export GTK4_CFLAGS=$(gb_SPACE)@GTK4_CFLAGS@
export GTK4_LIBS=$(gb_SPACE)@GTK4_LIBS@
export USING_X11=@USING_X11@
export HAMCREST_JAR=@HAMCREST_JAR@
export HAVE_BROKEN_GCC_WMAYBE_UNINITIALIZED=@HAVE_BROKEN_GCC_WMAYBE_UNINITIALIZED@
diff --git a/configure.ac b/configure.ac
index d802a66..f40314d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1564,6 +1564,10 @@ libo_FUZZ_ARG_ENABLE(gtk3,
        [Determines whether to use Gtk+ 3.0 vclplug on platforms where Gtk+ 3.0 is available.]),
,test "${enable_gtk3+set}" = set || enable_gtk3=yes)

AC_ARG_ENABLE(gtk4,
    AS_HELP_STRING([--enable-gtk4],
        [Determines whether to use Gtk+ 4.0 vclplug on platforms where Gtk+ 4.0 is available.]))

AC_ARG_ENABLE(introspection,
    AS_HELP_STRING([--enable-introspection],
        [Generate files for GObject introspection.  Requires --enable-gtk3.  (Typically used by
@@ -11426,6 +11430,14 @@ if test "x$enable_gtk3_kde5" = "xyes"; then
fi
AC_SUBST(ENABLE_GTK3_KDE5)

ENABLE_GTK4=""
if test "x$enable_gtk4" = "xyes"; then
    ENABLE_GTK4="TRUE"
    AC_DEFINE(ENABLE_GTK4)
    R="$R gtk4"
fi
AC_SUBST(ENABLE_GTK4)

ENABLE_QT5=""
if test "x$enable_qt5" = "xyes"; then
    ENABLE_QT5="TRUE"
@@ -11465,6 +11477,29 @@ fi
AC_SUBST(GTK3_LIBS)
AC_SUBST(GTK3_CFLAGS)

GTK4_CFLAGS=""
GTK4_LIBS=""
if test "x$enable_gtk4" = "xyes"; then
    if test "$with_system_cairo" = no; then
        add_warning 'Non-system cairo combined with gtk4 is assumed to cause trouble; proceed at your own risk.'
    fi
    : ${with_system_cairo:=yes}
    PKG_CHECK_MODULES(GTK4, gtk4 gmodule-no-export-2.0 glib-2.0 >= 2.38 cairo atk)
    GTK4_CFLAGS=$(printf '%s' "$GTK4_CFLAGS" | sed -e "s/-I/${ISYSTEM?}/g")
    GTK4_CFLAGS="$GTK4_CFLAGS -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
    FilterLibs "${GTK4_LIBS}"
    GTK4_LIBS="${filteredlibs}"

    dnl We require egl only for the gtk4 plugin. Otherwise we use glx.
    if test "$with_system_epoxy" != "yes"; then
        AC_CHECK_LIB(EGL, eglMakeCurrent, [:], AC_MSG_ERROR([libEGL required.]))
        AC_CHECK_HEADER(EGL/eglplatform.h, [],
                        [AC_MSG_ERROR(EGL headers not found. install mesa-libEGL-devel)], [])
    fi
fi
AC_SUBST(GTK4_LIBS)
AC_SUBST(GTK4_CFLAGS)

if test "$enable_introspection" = yes; then
    if test "$ENABLE_GTK3" = "TRUE" -o "$ENABLE_GTK3_KDE5" = "TRUE"; then
        GOBJECT_INTROSPECTION_REQUIRE(INTROSPECTION_REQUIRED_VERSION)
@@ -11606,7 +11641,7 @@ AC_SUBST(SYSTEM_BLUEZ)
dnl ===================================================================
dnl Check whether to enable GIO support
dnl ===================================================================
if test "$ENABLE_GTK3" = "TRUE" -o "$ENABLE_GTK3_KDE5" = "TRUE"; then
if test "$ENABLE_GTK4" = "TRUE" -o "$ENABLE_GTK3" = "TRUE" -o "$ENABLE_GTK3_KDE5" = "TRUE"; then
    AC_MSG_CHECKING([whether to enable GIO support])
    if test "$_os" != "WINNT" -a "$_os" != "Darwin" -a "$enable_gio" = "yes"; then
        dnl Need at least 2.26 for the dbus support.
diff --git a/solenv/gbuild/CppunitTest.mk b/solenv/gbuild/CppunitTest.mk
index a296ef7..53a8831 100644
--- a/solenv/gbuild/CppunitTest.mk
+++ b/solenv/gbuild/CppunitTest.mk
@@ -236,6 +236,7 @@ $(call gb_CppunitTest_get_target,$(1)) : $(call gb_Library_get_target,desktop_de
$(call gb_CppunitTest_get_target,$(1)) : $(if $(filter $(2),$(true)),, \
    $(call gb_Library_get_target,vclplug_gen) \
        $(if $(ENABLE_GTK3),$(call gb_Library_get_target,vclplug_gtk3)) \
        $(if $(ENABLE_GTK4),$(call gb_Library_get_target,vclplug_gtk4)) \
        $(if $(ENABLE_QT5),$(call gb_Library_get_target,vclplug_qt5)) \
	 )
else ifeq ($(OS),MACOSX)
diff --git a/vcl/Library_vclplug_gtk4.mk b/vcl/Library_vclplug_gtk4.mk
new file mode 100644
index 0000000..3f1c3eb
--- /dev/null
+++ b/vcl/Library_vclplug_gtk4.mk
@@ -0,0 +1,107 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# 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/.
#
# This file incorporates work covered by the following license notice:
#
#   Licensed to the Apache Software Foundation (ASF) under one or more
#   contributor license agreements. See the NOTICE file distributed
#   with this work for additional information regarding copyright
#   ownership. The ASF licenses this file to you under the Apache
#   License, Version 2.0 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
#

$(eval $(call gb_Library_Library,vclplug_gtk4))

# Silence deprecation warnings wholesale as long as vcl/unx/gtk4/*.cxx just
# forward to vcl/unx/gtk/*.cxx:
$(eval $(call gb_Library_add_cxxflags,vclplug_gtk4, \
    -Wno-deprecated-declarations \
))

$(eval $(call gb_Library_set_include,vclplug_gtk4,\
    $$(INCLUDE) \
    $$(GTK4_CFLAGS) \
    $$(GSTREAMER_1_0_CFLAGS) \
    -I$(SRCDIR)/vcl/inc \
    -I$(SRCDIR)/vcl/unx \
    -I$(SRCDIR)/vcl/unx/gtk4 \
))

$(eval $(call gb_Library_add_defs,vclplug_gtk4,\
    -DVCLPLUG_GTK_IMPLEMENTATION \
    -DVCL_INTERNALS \
))

$(eval $(call gb_Library_use_custom_headers,vclplug_gtk4,\
	officecfg/registry \
))

$(eval $(call gb_Library_use_sdk_api,vclplug_gtk4))

$(eval $(call gb_Library_add_libs,vclplug_gtk4,\
	$(GTK4_LIBS) \
	-lX11 \
	-lXext \
	-lSM \
	-lICE \
))

$(eval $(call gb_Library_use_libraries,vclplug_gtk4,\
    vcl \
    svl \
    tl \
    utl \
    sot \
    ucbhelper \
    basegfx \
    comphelper \
    cppuhelper \
    i18nlangtag \
    i18nutil \
    $(if $(ENABLE_JAVA), \
        jvmaccess) \
    cppu \
    sal \
))

$(eval $(call gb_Library_use_externals,vclplug_gtk4,\
	boost_headers \
	epoxy \
	dbus \
	graphite \
	harfbuzz \
))

$(eval $(call gb_Library_add_exception_objects,vclplug_gtk4,\
    vcl/unx/gtk4/fpicker/resourceprovider \
    vcl/unx/gtk4/fpicker/SalGtkFilePicker \
    vcl/unx/gtk4/fpicker/SalGtkFolderPicker \
    vcl/unx/gtk4/fpicker/SalGtkPicker \
    vcl/unx/gtk4/gtkdata \
    vcl/unx/gtk4/gtkinst \
    vcl/unx/gtk4/gtksys \
    vcl/unx/gtk4/gtkcairo \
    vcl/unx/gtk4/salnativewidgets-gtk \
    vcl/unx/gtk4/gtkframe \
    vcl/unx/gtk4/gtkobject \
	vcl/unx/gtk4/gtksalmenu \
	vcl/unx/gtk4/glomenu \
	vcl/unx/gtk4/gloactiongroup \
    vcl/unx/gtk4/hudawareness \
))

ifeq ($(OS),LINUX)
$(eval $(call gb_Library_add_libs,vclplug_gtk4,\
	-lm \
	-ldl \
))
endif

# vim: set noet sw=4 ts=4:
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index 3a36261..9bb22e0 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -72,6 +72,11 @@ $(eval $(call gb_Module_add_targets,vcl,\
    Library_vclplug_gtk3 \
))
endif
ifneq ($(ENABLE_GTK4),)
$(eval $(call gb_Module_add_targets,vcl,\
    Library_vclplug_gtk4 \
))
endif
ifneq ($(ENABLE_KF5),)
$(eval $(call gb_Module_add_targets,vcl,\
    CustomTarget_kf5_moc \
diff --git a/vcl/inc/unx/gtk/gtkbackend.hxx b/vcl/inc/unx/gtk/gtkbackend.hxx
index 288311b..03b2e02 100644
--- a/vcl/inc/unx/gtk/gtkbackend.hxx
+++ b/vcl/inc/unx/gtk/gtkbackend.hxx
@@ -12,11 +12,19 @@

#include <gtk/gtk.h>
#if defined(GDK_WINDOWING_X11)
#if GTK_CHECK_VERSION(4, 0, 0)
#include <gdk/x11/gdkx.h>
#else
#include <gdk/gdkx.h>
#endif
bool DLSYM_GDK_IS_X11_DISPLAY(GdkDisplay* pDisplay);
#endif
#if defined(GDK_WINDOWING_WAYLAND)
#if GTK_CHECK_VERSION(4, 0, 0)
#include <gdk/wayland/gdkwayland.h>
#else
#include <gdk/gdkwayland.h>
#endif
bool DLSYM_GDK_IS_WAYLAND_DISPLAY(GdkDisplay* pDisplay);
#endif

diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index 976412c..2a741e8 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -21,9 +21,13 @@
#define INCLUDED_VCL_INC_UNX_GTK_GTKDATA_HXX

#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#if GTK_CHECK_VERSION(4,0,0)
#include <gdk/x11/gdkx.h>
#else
#include <gdk/gdkx.h>
#endif

#include <com/sun/star/accessibility/XAccessibleContext.hpp>
#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
@@ -42,10 +46,12 @@ namespace com::sun::star::accessibility { class XAccessibleEventListener; }
class GtkSalDisplay;
class DocumentFocusListener;

#if !GTK_CHECK_VERSION(4,0,0)
inline ::Window widget_get_xid(GtkWidget *widget)
{
    return GDK_WINDOW_XID(gtk_widget_get_window(widget));
}
#endif

class GtkSalTimer final : public SalTimer
{
@@ -182,11 +188,13 @@ public:
    SalX11Screen GetDefaultXScreen() { return m_pSys->GetDisplayDefaultXScreen(); }
    Size         GetScreenSize( int nDisplayScreen );

    GdkFilterReturn filterGdkEvent( GdkXEvent* sys_event );
    void startupNotificationCompleted() { m_bStartupCompleted = true; }

#if !GTK_CHECK_VERSION(4,0,0)
    GdkFilterReturn filterGdkEvent( GdkXEvent* sys_event );
    void screenSizeChanged( GdkScreen const * );
    void monitorsChanged( GdkScreen const * );
#endif

    virtual void TriggerUserEventProcessing() override;
    virtual void TriggerAllUserEventsProcessed() override;
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index f2e2386..ab54f8f 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -22,9 +22,10 @@

#include <cairo.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#if !GTK_CHECK_VERSION(4,0,0)
#include <gtk/gtkx.h>
#endif
#include <gdk/gdkkeysyms.h>

#include <salframe.hxx>
@@ -63,6 +64,7 @@ class GtkSalFrame final : public SalFrame
    struct IMHandler
    {

#if !GTK_CHECK_VERSION(4, 0, 0)
        // Not all GTK Input Methods swallow key release
        // events.  Since they swallow the key press events and we
        // are left with the key release events, we need to
@@ -125,9 +127,12 @@ class GtkSalFrame final : public SalFrame
                    ;
            }
        };
#endif

        GtkSalFrame*                    m_pFrame;
#if !GTK_CHECK_VERSION(4, 0, 0)
        std::list< PreviousKeyPress >   m_aPrevKeyPresses;
#endif
        int                             m_nPrevKeyPresses; // avoid using size()
        GtkIMContext*                   m_pIMContext;
        bool                            m_bFocused;
@@ -142,7 +147,9 @@ class GtkSalFrame final : public SalFrame
        void            deleteIMContext();
        void            updateIMSpotLocation();
        void            endExtTextInput( EndExtTextInputFlags nFlags );
#if !GTK_CHECK_VERSION(4, 0, 0)
        bool            handleKeyEvent( GdkEventKey* pEvent );
#endif
        void            focusChanged( bool bFocusIn );

        void            doCallEndExtTextInput();
@@ -163,16 +170,22 @@ class GtkSalFrame final : public SalFrame
    GtkWidget*                      m_pWindow;
    GtkHeaderBar*                   m_pHeaderBar;
    GtkGrid*                        m_pTopLevelGrid;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkEventBox*                    m_pEventBox;
#endif
    GtkFixed*                       m_pFixedContainer;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkWindow*                      m_pForeignParent;
    GdkNativeWindow                 m_aForeignParentWindow;
    GdkWindow*                      m_pForeignTopLevel;
    GdkNativeWindow                 m_aForeignTopLevelWindow;
#endif
    SalFrameStyleFlags              m_nStyle;
    GtkSalFrame*                    m_pParent;
    std::list< GtkSalFrame* >       m_aChildren;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkWindowState                  m_nState;
#endif
    SystemEnvData                   m_aSystemData;
    std::unique_ptr<GtkSalGraphics> m_pGraphics;
    bool                            m_bGraphics;
@@ -208,12 +221,14 @@ class GtkSalFrame final : public SalFrame

    GtkSalMenu*                     m_pSalMenu;

#if !GTK_CHECK_VERSION(4, 0, 0)
#if ENABLE_DBUS && ENABLE_GIO
    private:
    friend void ensure_dbus_setup(GdkWindow* gdkWindow, GtkSalFrame* pSalFrame);
    friend void on_registrar_available (GDBusConnection*, const gchar*, const gchar*, gpointer);
    friend void on_registrar_unavailable (GDBusConnection*, const gchar*, gpointer);
#endif
#endif
    guint                           m_nWatcherId;

    void Init( SalFrame* pParent, SalFrameStyleFlags nStyle );
@@ -221,6 +236,7 @@ class GtkSalFrame final : public SalFrame
    void InitCommon();
    void InvalidateGraphics();

#if !GTK_CHECK_VERSION(4, 0, 0)
    // signals
    static gboolean     signalButton( GtkWidget*, GdkEventButton*, gpointer );
    static void         signalStyleUpdated(GtkWidget*, gpointer);
@@ -258,6 +274,7 @@ class GtkSalFrame final : public SalFrame
    static gboolean     signalScroll( GtkWidget*, GdkEvent*, gpointer );
    static gboolean     signalCrossing( GtkWidget*, GdkEventCrossing*, gpointer );
    static void         signalDestroy( GtkWidget*, gpointer );
#endif

    void            Center();
    void            SetDefaultSize();
@@ -271,7 +288,9 @@ class GtkSalFrame final : public SalFrame
                                   bool bSendRelease
                                   );

#if !GTK_CHECK_VERSION(4, 0, 0)
    static GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow );
#endif

    static int m_nFloats;

@@ -338,7 +357,9 @@ public:
    static GdkDisplay*     getGdkDisplay();
    GtkWidget*  getWindow() const { return m_pWindow; }
    GtkFixed*   getFixedContainer() const { return m_pFixedContainer; }
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkEventBox* getEventBox() const { return m_pEventBox; }
#endif
    GtkWidget*  getMouseEventWidget() const;
    GtkGrid*    getTopLevelGridWidget() const { return m_pTopLevelGrid; }
    const SalX11Screen& getXScreenNumber() const { return m_nXScreen; }
@@ -373,15 +394,19 @@ public:
        m_pDragSource = nullptr;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY,
                   GdkDragAction sourceActions, GtkTargetList* pTargetList);
#endif

    void closePopup();

    void addGrabLevel();
    void removeGrabLevel();

#if !GTK_CHECK_VERSION(4, 0, 0)
    void nopaint_container_resize_children(GtkContainer*);
#endif

    void LaunchAsyncScroll(GdkEvent const * pEvent);
    DECL_LINK(AsyncScroll, Timer *, void);
@@ -515,12 +540,16 @@ public:
    static void                 UpdateLastInputEventTime(guint32 nUserInputTime);
    static sal_uInt16           GetMouseModCode(guint nState);
    static sal_uInt16           GetKeyCode(guint nKeyVal);
#if !GTK_CHECK_VERSION(4, 0, 0)
    static guint                GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, guint8 group);
#endif
    static sal_uInt16           GetKeyModCode(guint nState);
    static GdkEvent*            makeFakeKeyPress(GtkWidget* pWidget);
#if !GTK_CHECK_VERSION(4, 0, 0)
    static SalWheelMouseEvent   GetWheelEvent(const GdkEventScroll& rEvent);
    static gboolean             NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint,
        GdkModifierType, gpointer pFrame);
#endif
    static OUString             GetPreeditDetails(GtkIMContext* pIMContext, std::vector<ExtTextInputAttr>& rInputFlags, sal_Int32& rCursorPos, sal_uInt8& rCursorFlags);
    static Selection            CalcDeleteSurroundingSelection(const OUString& rSurroundingText, sal_Int32 nCursorIndex, int nOffset, int nChars);

@@ -531,12 +560,14 @@ public:

#define OOO_TYPE_FIXED ooo_fixed_get_type()

#if !GTK_CHECK_VERSION(4, 0, 0)
extern "C" {

GType ooo_fixed_get_type();
AtkObject* ooo_fixed_get_accessible(GtkWidget *obj);

} // extern "C"
#endif

#if !GTK_CHECK_VERSION(3, 22, 0)
enum GdkAnchorHints
diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx
index 5ff7a56..44bcec7 100644
--- a/vcl/inc/unx/gtk/gtkgdi.hxx
+++ b/vcl/inc/unx/gtk/gtkgdi.hxx
@@ -98,6 +98,7 @@ class GtkSalGraphics : public SvpSalGraphics
    GtkSalFrame * const mpFrame;

protected:
#if !GTK_CHECK_VERSION(4, 0, 0)
    bool isNativeControlSupported(ControlType, ControlPart) override;
    virtual bool        drawNativeControl( ControlType nType, ControlPart nPart,
                                               const tools::Rectangle& rControlRegion,
@@ -111,6 +112,7 @@ protected:
                                                    const OUString& rCaption,
                                                    tools::Rectangle &rNativeBoundingRegion,
                                                    tools::Rectangle &rNativeContentRegion ) override;
#endif
    bool updateSettings(AllSettings&) override;
    void handleDamage(const tools::Rectangle&) override;

@@ -118,11 +120,9 @@ public:
    GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow );

#if ENABLE_CAIRO_CANVAS

    virtual bool        SupportsCairo() const override;
    virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override;
    virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override;

#endif

    void WidgetQueueDraw() const;
@@ -132,7 +132,9 @@ public:
    virtual OUString getRenderBackendName() const override { return "gtk3svp"; }

    GtkStyleContext* createStyleContext(GtkControlPart ePart);
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkStyleContext* makeContext(GtkWidgetPath *pPath, GtkStyleContext *pParent);
#endif
private:
    GtkWidget              *mpWindow;
    static GtkStyleContext *mpWindowStyle;
@@ -201,6 +203,7 @@ private:
    static GtkStyleContext *mpSeparatorMenuItemStyle;
    static GtkStyleContext *mpSeparatorMenuItemSeparatorStyle;

#if !GTK_CHECK_VERSION(4, 0, 0)
    static tools::Rectangle NWGetScrollButtonRect( ControlPart nPart, tools::Rectangle aAreaRect );
    static tools::Rectangle NWGetSpinButtonRect( ControlPart nPart, tools::Rectangle aAreaRect);
    static tools::Rectangle NWGetComboBoxButtonRect(ControlType nType, ControlPart nPart, tools::Rectangle aAreaRect);
@@ -234,7 +237,7 @@ private:

    static void PaintRadio(cairo_t *cr, GtkStyleContext *context,
                           const tools::Rectangle& rControlRectangle, bool bInMenu);

#endif

    static bool style_loaded;
};
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index 565a72c..ce3e123 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -53,6 +53,11 @@ public:

class GtkSalFrame;

#if GTK_CHECK_VERSION(4, 0, 0)
gint gtk_dialog_run(GtkDialog *dialog);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
struct VclToGtkHelper
{
    std::vector<css::datatransfer::DataFlavor> aInfoToFlavor;
@@ -62,13 +67,16 @@ struct VclToGtkHelper
private:
    GtkTargetEntry makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor);
};
#endif

class GtkTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable>
{
#if !GTK_CHECK_VERSION(4, 0, 0)
protected:
    std::map<OUString, GdkAtom> m_aMimeTypeToAtom;

    std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector(GdkAtom *targets, gint n_targets);
#endif

public:
    virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override = 0;
@@ -87,7 +95,9 @@ class GtkInstDropTarget final : public cppu::WeakComponentImplHelper<css::datatr
    GtkSalFrame* m_pFrame;
    GtkDnDTransferable* m_pFormatConversionRequest;
    bool m_bActive;
#if !GTK_CHECK_VERSION(4, 0, 0)
    bool m_bInDrag;
#endif
    sal_Int8 m_nDefaultActions;
    std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners;
public:
@@ -122,10 +132,12 @@ public:
        m_pFormatConversionRequest = pRequest;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    gboolean signalDragDrop(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time);
    gboolean signalDragMotion(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time);
    void signalDragDropReceived(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint ttype, guint time);
    void signalDragLeave(GtkWidget* pWidget, GdkDragContext* context, guint time);
#endif
};

class GtkInstDragSource final : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDragSource,
@@ -136,7 +148,9 @@ class GtkInstDragSource final : public cppu::WeakComponentImplHelper<css::datatr
    GtkSalFrame* m_pFrame;
    css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener;
    css::uno::Reference<css::datatransfer::XTransferable> m_xTrans;
#if !GTK_CHECK_VERSION(4, 0, 0)
    VclToGtkHelper m_aConversionHelper;
#endif
public:
    GtkInstDragSource()
        : WeakComponentImplHelper(m_aMutex)
@@ -147,7 +161,9 @@ public:
    void set_datatransfer(const css::uno::Reference<css::datatransfer::XTransferable>& rTrans,
                          const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener);

#if !GTK_CHECK_VERSION(4, 0, 0)
    std::vector<GtkTargetEntry> FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats);
#endif

    void setActiveDragSource();

@@ -173,8 +189,10 @@ public:

    void dragFailed();
    void dragDelete();
#if !GTK_CHECK_VERSION(4, 0, 0)
    void dragEnd(GdkDragContext* context);
    void dragDataGet(GtkSelectionData *data, guint info);
#endif

    // For LibreOffice internal D&D we provide the Transferable without Gtk
    // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this
@@ -226,9 +244,11 @@ public:
    virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override;
    virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override;
    virtual OpenGLContext* CreateOpenGLContext() override;
#if !GTK_CHECK_VERSION(4, 0, 0)
    virtual weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) override;
    virtual weld::Builder* CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile,
                                                bool bAllowCycleFocusOut, sal_uInt64 nLOKWindowId = 0) override;
#endif
    virtual weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage) override;
    virtual weld::Window* GetFrameWeld(const css::uno::Reference<css::awt::XWindow>& rWindow) override;

@@ -242,7 +262,9 @@ public:

private:
    GtkSalTimer *m_pTimer;
#if !GTK_CHECK_VERSION(4, 0, 0)
    std::unordered_map< GdkAtom, css::uno::Reference<css::uno::XInterface> > m_aClipboards;
#endif
    bool                        IsTimerExpired();
    bool                        bNeedsInit;
    cairo_font_options_t*       m_pLastCairoFontOptions;
diff --git a/vcl/inc/unx/gtk/gtkobject.hxx b/vcl/inc/unx/gtk/gtkobject.hxx
index 8b37492..ee06387 100644
--- a/vcl/inc/unx/gtk/gtkobject.hxx
+++ b/vcl/inc/unx/gtk/gtkobject.hxx
@@ -50,8 +50,10 @@ public:

private:
    // signals
#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean     signalButton( GtkWidget*, GdkEventButton*, gpointer );
    static gboolean     signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
#endif
};

// this attempts to clip the hosted native window using gdk_window_shape_combine_region
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 8af690d..e55cb79 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -125,7 +125,9 @@ public:

    void CreateMenuBarWidget();
    void DestroyMenuBarWidget();
#if !GTK_CHECK_VERSION(4, 0, 0)
    gboolean SignalKey(GdkEventKey const * pEvent);
#endif
    void ReturnFocus();

    virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override;
diff --git a/vcl/inc/unx/gtk/gtksys.hxx b/vcl/inc/unx/gtk/gtksys.hxx
index fa6879c..ef0376b 100644
--- a/vcl/inc/unx/gtk/gtksys.hxx
+++ b/vcl/inc/unx/gtk/gtksys.hxx
@@ -17,8 +17,10 @@
class GtkSalSystem final : public SalGenericSystem
{
    GdkDisplay *mpDisplay;
#if !GTK_CHECK_VERSION(4,0,0)
    // Number of monitors for every active screen.
    std::deque<std::pair<GdkScreen*, int> > maScreenMonitors;
#endif
public:
             GtkSalSystem();
    virtual ~GtkSalSystem() override;
@@ -35,10 +37,12 @@ public:
            { return getXScreenFromDisplayScreen( GetDisplayBuiltInScreen() ); }
    SalX11Screen      getXScreenFromDisplayScreen(unsigned int nDisplayScreen);
    void              countScreenMonitors();
#if !GTK_CHECK_VERSION(4,0,0)
    // We have a 'screen' number that is combined from screen-idx + monitor-idx
    int        getScreenIdxFromPtr     (GdkScreen *pScreen);
    int        getScreenMonitorIdx     (GdkScreen *pScreen, int nX, int nY);
    GdkScreen *getScreenMonitorFromIdx (int nIdx, gint &nMonitor);
#endif
};

#endif // INCLUDED_VCL_INC_UNX_GTK_GTKSYS_HXX
diff --git a/vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx b/vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx
index bf9336f..66e5670 100644
--- a/vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx
+++ b/vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx
@@ -73,7 +73,9 @@ void SalGtkFilePicker::InitialMapping()
    if (!mbPreviewState )
    {
        gtk_widget_hide( m_pPreview );
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), false);
#endif
    }
    gtk_widget_set_size_request (m_pPreview, -1, -1);
}
@@ -125,9 +127,12 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext

    gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );

#if !GTK_CHECK_VERSION(4, 0, 0)
#if ENABLE_GIO
    gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( m_pDialog ), false );
#endif
#endif

    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( m_pDialog ), false );

    m_pVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
@@ -136,8 +141,13 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
    GtkWidget *pHBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    GtkWidget *pThinVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_box_pack_end (GTK_BOX( m_pVBox ), pHBox, false, false, 0);
    gtk_box_pack_start (GTK_BOX( pHBox ), pThinVBox, false, false, 0);
#else
    gtk_box_append(GTK_BOX(m_pVBox), pHBox);
    gtk_box_prepend(GTK_BOX(m_pVBox), pThinVBox);
#endif
    gtk_widget_show( pHBox );
    gtk_widget_show( pThinVBox );

@@ -167,7 +177,11 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
            break;
        }

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_box_pack_end( GTK_BOX( pThinVBox ), m_pToggles[i], false, false, 0 );
#else
        gtk_box_append(GTK_BOX(pThinVBox), m_pToggles[i]);
#endif
    }

    for( i = 0; i < LIST_LAST; i++ )
@@ -203,26 +217,48 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
                break;
        }

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pLists[i], false, false, 0 );
        gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pListLabels[i], false, false, 0 );
#else
        gtk_box_append(GTK_BOX(m_pHBoxs[i]), m_pLists[i]);
        gtk_box_append(GTK_BOX(m_pHBoxs[i]), m_pListLabels[i]);
#endif
        gtk_label_set_mnemonic_widget( GTK_LABEL(m_pListLabels[i]), m_pLists[i] );
        gtk_box_set_spacing( GTK_BOX( m_pHBoxs[i] ), 12 );

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pHBoxs[i], false, false, 0 );
#else
        gtk_box_append(GTK_BOX(m_pVBox), m_pHBoxs[i]);
#endif
    }

    aLabel = getResString( FILE_PICKER_FILE_TYPE );
    m_pFilterExpander = gtk_expander_new_with_mnemonic(
        OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pFilterExpander, false, true, 0 );
#else
    gtk_box_append(GTK_BOX(m_pVBox), m_pFilterExpander);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget *scrolled_window = gtk_scrolled_window_new (nullptr, nullptr);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
        GTK_SHADOW_IN);
#else
    GtkWidget *scrolled_window = gtk_scrolled_window_new();
    gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrolled_window), true);
#endif
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add (GTK_CONTAINER (m_pFilterExpander), scrolled_window);
#else
    gtk_expander_set_child(GTK_EXPANDER(m_pFilterExpander), scrolled_window);
#endif
    gtk_widget_show (scrolled_window);

    m_pFilterStore = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING,
@@ -242,13 +278,21 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
        gtk_tree_view_append_column (GTK_TREE_VIEW(m_pFilterView), column);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add (GTK_CONTAINER (scrolled_window), m_pFilterView);
#else
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window), m_pFilterView);
#endif
    gtk_widget_show (m_pFilterView);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pVBox );
#endif

    m_pPreview = gtk_image_new();
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_file_chooser_set_preview_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pPreview );
#endif

    g_signal_connect( G_OBJECT( m_pToggles[PREVIEW] ), "toggled",
                      G_CALLBACK( preview_toggled_cb ), this );
@@ -275,7 +319,9 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
    gtk_widget_set_size_request (m_pFilterView, -1, height);
    gtk_widget_set_size_request (m_pPreview, 1, height);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), true);
#endif
}

// XFilePickerNotifier
@@ -407,6 +453,7 @@ shrinkFilterName( const OUString &rFilterName, bool bAllowNoStar = false )
    return aRealName;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
static void
dialog_remove_buttons(GtkWidget *pActionArea)
{
@@ -437,6 +484,7 @@ dialog_remove_buttons( GtkDialog *pDialog )
    else
        dialog_remove_buttons(gtk_dialog_get_action_area(pDialog));
}
#endif

namespace {

@@ -721,9 +769,14 @@ uno::Sequence<OUString> SAL_CALL SalGtkFilePicker::getSelectedFiles()

    OSL_ASSERT( m_pDialog != nullptr );

#if !GTK_CHECK_VERSION(4, 0, 0)
    GSList* pPathList = gtk_file_chooser_get_uris( GTK_FILE_CHOOSER(m_pDialog) );

    int nCount = g_slist_length( pPathList );
#else
    GListModel* pPathList = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(m_pDialog));
    int nCount = g_list_model_get_n_items(pPathList);
#endif

    int nIndex = 0;

    // get the current action setting
@@ -733,9 +786,16 @@ uno::Sequence<OUString> SAL_CALL SalGtkFilePicker::getSelectedFiles()
    uno::Sequence< OUString > aSelectedFiles(nCount);

    // Convert to OOo
#if !GTK_CHECK_VERSION(4, 0, 0)
    for( GSList *pElem = pPathList; pElem; pElem = pElem->next)
    {
        gchar *pURI = static_cast<gchar*>(pElem->data);
#else
    while (gpointer pElem = g_list_model_get_item(pPathList, nIndex))
    {
        gchar *pURI = g_file_get_uri(static_cast<GFile*>(pElem));
#endif

        aSelectedFiles[ nIndex ] = uritounicode(pURI);

        if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
@@ -854,7 +914,11 @@ uno::Sequence<OUString> SAL_CALL SalGtkFilePicker::getSelectedFiles()
        g_free( pURI );
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    g_slist_free( pPathList );
#else
    g_object_unref(pPathList);
#endif

    return aSelectedFiles;
}
@@ -998,7 +1062,11 @@ sal_Int16 SAL_CALL SalGtkFilePicker::execute()
                            rtl::Reference<RunDialog> pAnotherDialog = new RunDialog(dlg, xToolkit, xDesktop);
                            btn = pAnotherDialog->run();

                            gtk_widget_destroy( dlg );
#if !GTK_CHECK_VERSION(4, 0, 0)
                            gtk_widget_destroy(dlg);
#else
                            gtk_window_destroy(GTK_WINDOW(dlg));
#endif
                        }
                        g_free (gFileName);

@@ -1096,7 +1164,9 @@ GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType )
static void HackWidthToFirst(GtkComboBox *pWidget)
{
    GtkRequisition requisition;
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_size_request(GTK_WIDGET(pWidget), &requisition);
#endif
    gtk_widget_set_size_request(GTK_WIDGET(pWidget), requisition.width, -1);
}

@@ -1461,6 +1531,7 @@ void SalGtkFilePicker::selection_changed_cb( GtkFileChooser *, SalGtkFilePicker 

void SalGtkFilePicker::update_preview_cb( GtkFileChooser *file_chooser, SalGtkFilePicker* pobjFP )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    bool have_preview = false;

    GtkWidget* preview = pobjFP->m_pPreview;
@@ -1485,6 +1556,10 @@ void SalGtkFilePicker::update_preview_cb( GtkFileChooser *file_chooser, SalGtkFi

    if( filename )
        g_free( filename );
#else
    (void)file_chooser;
    (void)pobjFP;
#endif
}

sal_Bool SAL_CALL SalGtkFilePicker::setShowState( sal_Bool bShowState )
@@ -1691,7 +1766,9 @@ void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArgu
    }

    gtk_file_chooser_set_action( GTK_FILE_CHOOSER( m_pDialog ), eAction);
#if !GTK_CHECK_VERSION(4, 0, 0)
    dialog_remove_buttons( GTK_DIALOG( m_pDialog ) );
#endif
    gtk_dialog_add_button(GTK_DIALOG( m_pDialog ),
                          getCancelText().getStr(),
                          GTK_RESPONSE_CANCEL);
@@ -1747,6 +1824,7 @@ void SAL_CALL SalGtkFilePicker::cancel()

void SalGtkFilePicker::SetCurFilter( const OUString& rFilter )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    // Get all the filters already added
    GSList *filters = gtk_file_chooser_list_filters ( GTK_FILE_CHOOSER( m_pDialog ) );
    bool bFound = false;
@@ -1767,8 +1845,12 @@ void SalGtkFilePicker::SetCurFilter( const OUString& rFilter )
    }

    g_slist_free( filters );
#else
    (void)rFilter;
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
extern "C"
{
static gboolean
@@ -1796,6 +1878,7 @@ case_insensitive_filter (const GtkFileFilterInfo *filter_info, gpointer data)
    return bRetval;
}
}
#endif

GtkFileFilter* SalGtkFilePicker::implAddFilter( const OUString& rFilter, const OUString& rType )
{
@@ -1825,10 +1908,12 @@ GtkFileFilter* SalGtkFilePicker::implAddFilter( const OUString& rFilter, const O
                if (!aTokens.isEmpty())
                    aTokens.append(",");
                aTokens.append(aToken);
#if !GTK_CHECK_VERSION(4, 0, 0)
                gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_URI,
                    case_insensitive_filter,
                    g_strdup( OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr() ),
                    g_free );
#endif

                SAL_INFO( "vcl.gtk", "fustering with " << aToken );
            }
@@ -1942,6 +2027,7 @@ void SalGtkFilePicker::SetFilters()

SalGtkFilePicker::~SalGtkFilePicker()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    SolarMutexGuard g;

    int i;
@@ -1959,6 +2045,7 @@ SalGtkFilePicker::~SalGtkFilePicker()
    m_pFilterVector.reset();

    gtk_widget_destroy( m_pVBox );
#endif
}

uno::Reference< ui::dialogs::XFilePicker2 >
diff --git a/vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx b/vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx
index 24bf857..2f79e3d 100644
--- a/vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx
+++ b/vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx
@@ -49,9 +49,11 @@ SalGtkFolderPicker::SalGtkFolderPicker( const uno::Reference< uno::XComponentCon
        getOKText().getStr(), GTK_RESPONSE_ACCEPT, nullptr );

    gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
#if !GTK_CHECK_VERSION(4, 0, 0)
#if ENABLE_GIO
    gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( m_pDialog ), false );
#endif
#endif
    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( m_pDialog ), false );
}

@@ -71,8 +73,13 @@ void SAL_CALL SalGtkFolderPicker::setDisplayDirectory( const OUString& aDirector

    SAL_INFO( "vcl", "setting path to " << aTxt );

    gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( m_pDialog ),
        aTxt.getStr() );
#if GTK_CHECK_VERSION(4, 0, 0)
    GFile* pPath = g_file_new_for_uri(aTxt.getStr());
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_pDialog), pPath, nullptr);
    g_object_unref(pPath);
#else
    gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(m_pDialog), aTxt.getStr());
#endif
}

OUString SAL_CALL SalGtkFolderPicker::getDisplayDirectory()
@@ -81,8 +88,16 @@ OUString SAL_CALL SalGtkFolderPicker::getDisplayDirectory()

    assert( m_pDialog != nullptr );

#if GTK_CHECK_VERSION(4, 0, 0)
    GFile* pPath =
        gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(m_pDialog));
    gchar* pCurrentFolder = g_file_get_uri(pPath);
    g_object_unref(pPath);
#else
    gchar* pCurrentFolder =
        gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( m_pDialog ) );
        gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(m_pDialog));
#endif

    OUString aCurrentFolderName = uritounicode(pCurrentFolder);
    g_free( pCurrentFolder );

@@ -95,8 +110,15 @@ OUString SAL_CALL SalGtkFolderPicker::getDirectory()

    assert( m_pDialog != nullptr );

#if GTK_CHECK_VERSION(4, 0, 0)
    GFile* pPath =
        gtk_file_chooser_get_file(GTK_FILE_CHOOSER(m_pDialog));
    gchar* pSelectedFolder = g_file_get_uri(pPath);
    g_object_unref(pPath);
#else
    gchar* pSelectedFolder =
        gtk_file_chooser_get_uri( GTK_FILE_CHOOSER( m_pDialog ) );
#endif
    OUString aSelectedFolderName = uritounicode(pSelectedFolder);
    g_free( pSelectedFolder );

diff --git a/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx b/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
index 7502d5a..76c7739 100644
--- a/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
+++ b/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
@@ -35,6 +35,7 @@

#include <vcl/window.hxx>
#include <unx/gtk/gtkframe.hxx>
#include <unx/gtk/gtkinst.hxx>
#include "SalGtkPicker.hxx"

using namespace ::rtl;
@@ -100,7 +101,13 @@ GtkWindow* RunDialog::GetTransientFor()
    {
        GtkSalFrame *pFrame = dynamic_cast<GtkSalFrame *>( pWindow->ImplGetFrame() );
        if( pFrame )
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            pParent = GTK_WINDOW(gtk_widget_get_toplevel(pFrame->getWindow()));
#else
            pParent = GTK_WINDOW(gtk_widget_get_root(pFrame->getWindow()));
#endif
        }
    }

    return pParent;
@@ -181,6 +188,13 @@ namespace
    };
}

#if GTK_CHECK_VERSION(4, 0, 0)
gint gtk_dialog_run(GtkDialog*)
{
    return 0;
}
#endif

gint RunDialog::run()
{
    if (mxToolkit.is())
@@ -238,7 +252,11 @@ SalGtkPicker::~SalGtkPicker()

    if (m_pDialog)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_destroy(m_pDialog);
#else
        gtk_window_destroy(GTK_WINDOW(m_pDialog));
#endif
    }
}

@@ -256,16 +274,28 @@ void SalGtkPicker::implsetDisplayDirectory( const OUString& aDirectory )

    SAL_INFO( "vcl", "setting path to " << aTxt );

    gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( m_pDialog ),
        aTxt.getStr() );
#if GTK_CHECK_VERSION(4, 0, 0)
    GFile* pPath = g_file_new_for_uri(aTxt.getStr());
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_pDialog), pPath, nullptr);
    g_object_unref(pPath);
#else
    gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(m_pDialog), aTxt.getStr());
#endif
}

OUString SalGtkPicker::implgetDisplayDirectory()
{
    OSL_ASSERT( m_pDialog != nullptr );

#if GTK_CHECK_VERSION(4, 0, 0)
    GFile* pPath =
        gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(m_pDialog));
    gchar* pCurrentFolder = g_file_get_uri(pPath);
    g_object_unref(pPath);
#else
    gchar* pCurrentFolder =
        gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( m_pDialog ) );
        gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(m_pDialog));
#endif
    OUString aCurrentFolderName = uritounicode(pCurrentFolder);
    g_free( pCurrentFolder );

diff --git a/vcl/unx/gtk3/gtkdata.cxx b/vcl/unx/gtk3/gtkdata.cxx
index 8626252..f515d93 100644
--- a/vcl/unx/gtk3/gtkdata.cxx
+++ b/vcl/unx/gtk3/gtkdata.cxx
@@ -44,6 +44,7 @@

using namespace vcl_sal;

#if !GTK_CHECK_VERSION(4, 0, 0)
/***************************************************************
 * class GtkSalDisplay                                         *
 ***************************************************************/
@@ -56,6 +57,7 @@ static GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
    return pDisplay->filterGdkEvent( sys_event );
}
}
#endif

GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
            m_pSys( GtkSalSystem::GetSingleton() ),
@@ -65,8 +67,10 @@ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
    for(GdkCursor* & rpCsr : m_aCursors)
        rpCsr = nullptr;

#if !GTK_CHECK_VERSION(4, 0, 0)
    // FIXME: unify this with SalInst's filter too ?
    gdk_window_add_filter( nullptr, call_filterGdkEvent, this );
#endif

    if ( getenv( "SAL_IGNOREXERRORS" ) )
        GetGenericUnixSalData()->ErrorTrapPush(); // and leak the trap
@@ -78,6 +82,7 @@ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :

GtkSalDisplay::~GtkSalDisplay()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gdk_window_remove_filter( nullptr, call_filterGdkEvent, this );

    if( !m_bStartupCompleted )
@@ -86,8 +91,10 @@ GtkSalDisplay::~GtkSalDisplay()
    for(GdkCursor* & rpCsr : m_aCursors)
        if( rpCsr )
            gdk_cursor_unref( rpCsr );
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
extern "C" {

static void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
@@ -124,14 +131,21 @@ void GtkSalDisplay::monitorsChanged( GdkScreen const * pScreen )
    if (pScreen)
        emitDisplayChanged();
}
#endif

GdkCursor* GtkSalDisplay::getFromSvg(OUString const & name, int nXHot, int nYHot)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkPixbuf* pPixBuf = load_icon_by_name(name);
#else
    (void)name;
    GdkPixbuf* pPixBuf = nullptr;
#endif
    assert(pPixBuf && "missing image?");
    if (!pPixBuf)
        return nullptr;

#if !GTK_CHECK_VERSION(4, 0, 0)
    guint nDefaultCursorSize = gdk_display_get_default_cursor_size( m_pGdkDisplay );
    int nPixWidth = gdk_pixbuf_get_width(pPixBuf);
    int nPixHeight = gdk_pixbuf_get_height(pPixBuf);
@@ -141,19 +155,32 @@ GdkCursor* GtkSalDisplay::getFromSvg(OUString const & name, int nXHot, int nYHot
                                                       nPixHeight * fScalefactor,
                                                       GDK_INTERP_HYPER);
    g_object_unref(pPixBuf);
    GdkCursor* pCursor = gdk_cursor_new_from_pixbuf(m_pGdkDisplay, pScaledPixBuf,
                                                    nXHot * fScalefactor, nYHot * fScalefactor);
    return pCursor;
    return gdk_cursor_new_from_pixbuf(m_pGdkDisplay, pScaledPixBuf,
                                      nXHot * fScalefactor, nYHot * fScalefactor);
#else
    GdkTexture* pTexture = gdk_texture_new_for_pixbuf(pPixBuf);
    g_object_unref(pPixBuf);
    return gdk_cursor_new_from_texture(pTexture, nXHot, nYHot, nullptr);
#endif
}

#define MAKE_CURSOR( vcl_name, name, name2 ) \
    case vcl_name: \
        pCursor = getFromSvg(name2, name##curs_x_hot, name##curs_y_hot); \
        break

#if !GTK_CHECK_VERSION(4, 0, 0)
#define MAP_BUILTIN( vcl_name, gdk_name ) \
    case vcl_name: \
        pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
        break
#else
// TODO, the rest of these
#define MAP_BUILTIN( vcl_name, gdk_name ) \
    case vcl_name: \
        pCursor = gdk_cursor_new_from_name("normal", nullptr); \
        break
#endif

GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
{
@@ -273,7 +300,13 @@ GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
            break;
        }
        if( !pCursor )
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
#else
            pCursor = gdk_cursor_new_from_name("normal", nullptr);
#endif
        }

        m_aCursors[ ePointerStyle ] = pCursor;
    }
@@ -466,8 +499,10 @@ void GtkSalData::Init()
    }

    // init gtk/gdk
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_init_check( &nParams, &pCmdLineAry );
    gdk_error_trap_push();
#endif

    for (int i = 0; i < nParams; ++i)
        g_free( pCmdLineAry[i] );
@@ -505,6 +540,7 @@ void GtkSalData::Init()
    GtkSalDisplay *pDisplay = new GtkSalDisplay( pGdkDisp );
    SetDisplay( pDisplay );

#if !GTK_CHECK_VERSION(4, 0, 0)
    int nScreens = gdk_display_get_n_screens( pGdkDisp );
    for( int n = 0; n < nScreens; n++ )
    {
@@ -545,21 +581,29 @@ void GtkSalData::Init()
        gtk_style_context_add_provider_for_screen(pScreen, GTK_STYLE_PROVIDER(pSmallButtonProvider),
            GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    }
#endif
}

void GtkSalData::ErrorTrapPush()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gdk_error_trap_push ();
#endif
}

bool GtkSalData::ErrorTrapPop( bool bIgnoreError )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (bIgnoreError)
    {
        gdk_error_trap_pop_ignored (); // faster
        return false;
    }
    return gdk_error_trap_pop () != 0;
#else
    (void)bIgnoreError;
    return false;
#endif
}

#if !GLIB_CHECK_VERSION(2,32,0)
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index 79f2f73..fb2c255 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -74,8 +74,13 @@ sal_uInt16 GtkSalFrame::GetKeyModCode( guint state )
        nCode |= KEY_SHIFT;
    if( state & GDK_CONTROL_MASK )
        nCode |= KEY_MOD1;
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( state & GDK_MOD1_MASK )
        nCode |= KEY_MOD2;
#else
    if (state & GDK_ALT_MASK)
        nCode |= KEY_MOD2;
#endif
    if( state & GDK_SUPER_MASK )
        nCode |= KEY_MOD3;
    return nCode;
@@ -295,6 +300,7 @@ sal_uInt16 GtkSalFrame::GetKeyCode(guint keyval)
    return nCode;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
guint GtkSalFrame::GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, guint8 group)
{
    guint updated_keyval = 0;
@@ -302,6 +308,7 @@ guint GtkSalFrame::GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, gu
        GdkModifierType(0), group, &updated_keyval, nullptr, nullptr, nullptr);
    return updated_keyval;
}
#endif

namespace {

@@ -393,6 +400,7 @@ bool GtkSalFrame::doKeyCallback( guint state,
     *  be used to input Latin text and use that if possible
     */
    aEvent.mnCode = GetKeyCode( keyval );
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( aEvent.mnCode == 0 )
    {
        gint best_group = SAL_MAX_INT32;
@@ -422,6 +430,10 @@ bool GtkSalFrame::doKeyCallback( guint state,
        guint updated_keyval = GetKeyValFor(keymap, hardware_keycode, best_group);
        aEvent.mnCode = GetKeyCode(updated_keyval);
    }
#else
    (void)hardware_keycode;
    (void)group;
#endif

    aEvent.mnCode   |= GetKeyModCode( state );

@@ -479,6 +491,7 @@ GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )

// AppMenu watch functions.

#if !GTK_CHECK_VERSION(4,0,0)
static void ObjectDestroyedNotify( gpointer data )
{
    if ( data ) {
@@ -528,6 +541,7 @@ static bool ensure_dbus_setup( gpointer data )
        g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", pActionGroup, ObjectDestroyedNotify );

        GdkDisplay *pDisplay = GtkSalFrame::getGdkDisplay();
#if !GTK_CHECK_VERSION(4,0,0)
#if defined(GDK_WINDOWING_X11)
        if (DLSYM_GDK_IS_X11_DISPLAY(pDisplay))
        {
@@ -538,6 +552,7 @@ static bool ensure_dbus_setup( gpointer data )
            gdk_x11_window_set_utf8_property( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) );
        }
#endif
#endif
#if defined(GDK_WINDOWING_WAYLAND)
        if (DLSYM_GDK_IS_WAYLAND_DISPLAY(pDisplay))
        {
@@ -559,9 +574,9 @@ static bool ensure_dbus_setup( gpointer data )
        g_free( aDBusWindowPath );
        g_free( aDBusMenubarPath );
    }

    return false;
}
#endif

void on_registrar_available( GDBusConnection * /*connection*/,
                             const gchar     * /*name*/,
@@ -674,12 +689,14 @@ GtkSalFrame::~GtkSalFrame()
    GtkWidget *pEventWidget = getMouseEventWidget();
    for (auto handler_id : m_aMouseSignalIds)
        g_signal_handler_disconnect(G_OBJECT(pEventWidget), handler_id);
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pFixedContainer )
        gtk_widget_destroy( GTK_WIDGET( m_pFixedContainer ) );
    if( m_pEventBox )
        gtk_widget_destroy( GTK_WIDGET(m_pEventBox) );
    if( m_pTopLevelGrid )
        gtk_widget_destroy( GTK_WIDGET(m_pTopLevelGrid) );
#endif
    {
        SolarMutexGuard aGuard;

@@ -699,13 +716,20 @@ GtkSalFrame::~GtkSalFrame()
                if ( m_nActionGroupExportId )
                    g_dbus_connection_unexport_action_group( pSessionBus, m_nActionGroupExportId );
            }
#if !GTK_CHECK_VERSION(4,0,0)
            gtk_widget_destroy( m_pWindow );
#else
            gtk_window_destroy(GTK_WINDOW(m_pWindow));
#endif
        }
    }

#if !GTK_CHECK_VERSION(4,0,0)
    if( m_pForeignParent )
        g_object_unref( G_OBJECT( m_pForeignParent ) );
    if( m_pForeignTopLevel )
        g_object_unref( G_OBJECT( m_pForeignTopLevel) );
#endif

    m_pGraphics.reset();

@@ -727,8 +751,10 @@ void GtkSalFrame::moveWindow( tools::Long nX, tools::Long nY )
                            nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
        }
    }
#if !GTK_CHECK_VERSION(4,0,0)
    else
        gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
#endif
}

void GtkSalFrame::widget_set_size_request(tools::Long nWidth, tools::Long nHeight)
@@ -741,8 +767,10 @@ void GtkSalFrame::window_resize(tools::Long nWidth, tools::Long nHeight)
    m_nWidthRequest = nWidth;
    m_nHeightRequest = nHeight;
    gtk_window_set_default_size(GTK_WINDOW(m_pWindow), nWidth, nHeight);
#if !GTK_CHECK_VERSION(4,0,0)
    if (gtk_widget_get_visible(m_pWindow))
        gtk_window_resize(GTK_WINDOW(m_pWindow), nWidth, nHeight);
#endif
}

void GtkSalFrame::resizeWindow( tools::Long nWidth, tools::Long nHeight )
@@ -755,6 +783,7 @@ void GtkSalFrame::resizeWindow( tools::Long nWidth, tools::Long nHeight )
        window_resize(nWidth, nHeight);
}

#if !GTK_CHECK_VERSION(4,0,0)
// tdf#124694 GtkFixed takes the max size of all its children as its
// preferred size, causing it to not clip its child, but grow instead.

@@ -771,14 +800,19 @@ ooo_fixed_get_preferred_width(GtkWidget*, gint *minimum, gint *natural)
    *minimum = 0;
    *natural = 0;
}
#endif

static void
ooo_fixed_class_init(GtkFixedClass *klass)
{
#if !GTK_CHECK_VERSION(4,0,0)
    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
    widget_class->get_accessible = ooo_fixed_get_accessible;
    widget_class->get_preferred_height = ooo_fixed_get_preferred_height;
    widget_class->get_preferred_width = ooo_fixed_get_preferred_width;
#else
    (void)klass;
#endif
}

/*
@@ -816,16 +850,22 @@ ooo_fixed_get_type()

void GtkSalFrame::updateScreenNumber()
{
#if !GTK_CHECK_VERSION(4,0,0)
    int nScreen = 0;
    GdkScreen *pScreen = gtk_widget_get_screen( m_pWindow );
    if( pScreen )
        nScreen = getDisplay()->getSystem()->getScreenMonitorIdx( pScreen, maGeometry.nX, maGeometry.nY );
    maGeometry.nDisplayScreenNumber = nScreen;
#endif
}

GtkWidget *GtkSalFrame::getMouseEventWidget() const
{
#if !GTK_CHECK_VERSION(4,0,0)
    return GTK_WIDGET(m_pEventBox);
#else
    return GTK_WIDGET(m_pFixedContainer);
#endif
}

static void damaged(void *handle,
@@ -848,6 +888,7 @@ void GtkSalFrame::InitCommon()
    m_aSmoothScrollIdle.SetInvokeHandler(LINK(this, GtkSalFrame, AsyncScroll));

    m_pTopLevelGrid = GTK_GRID(gtk_grid_new());
#if !GTK_CHECK_VERSION(4,0,0)
    gtk_container_add(GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pTopLevelGrid));

    m_pEventBox = GTK_EVENT_BOX(gtk_event_box_new());
@@ -856,19 +897,30 @@ void GtkSalFrame::InitCommon()
    gtk_widget_set_vexpand(GTK_WIDGET(m_pEventBox), true);
    gtk_widget_set_hexpand(GTK_WIDGET(m_pEventBox), true);
    gtk_grid_attach(m_pTopLevelGrid, GTK_WIDGET(m_pEventBox), 0, 0, 1, 1);
#else
    gtk_window_set_child(GTK_WINDOW(m_pWindow),  GTK_WIDGET(m_pTopLevelGrid));
#endif

    // add the fixed container child,
    // fixed is needed since we have to position plugin windows
    m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), nullptr ));
    gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), true);
    gtk_widget_set_size_request(GTK_WIDGET(m_pFixedContainer), 1, 1);
#if !GTK_CHECK_VERSION(4,0,0)
    gtk_container_add( GTK_CONTAINER(m_pEventBox), GTK_WIDGET(m_pFixedContainer) );
#else
    gtk_widget_set_vexpand(GTK_WIDGET(m_pFixedContainer), true);
    gtk_widget_set_hexpand(GTK_WIDGET(m_pFixedContainer), true);
    gtk_grid_attach(m_pTopLevelGrid, GTK_WIDGET(m_pFixedContainer), 0, 0, 1, 1);
#endif

#if !GTK_CHECK_VERSION(4,0,0)
    GtkWidget *pEventWidget = getMouseEventWidget();

    gtk_widget_set_app_paintable(GTK_WIDGET(m_pFixedContainer), true);
    gtk_widget_set_redraw_on_allocate(GTK_WIDGET(m_pFixedContainer), false);
#endif

#if !GTK_CHECK_VERSION(4,0,0)
    // connect signals
    // use pEventWidget instead of m_pWindow to avoid infinite event loop under Linux Mint Mate 18.3
    g_signal_connect( G_OBJECT(pEventWidget), "style-updated", G_CALLBACK(signalStyleUpdated), this );
@@ -923,11 +975,15 @@ void GtkSalFrame::InitCommon()
    g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalWindowState), this );
    g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );

#endif

    // init members
    m_nKeyModifiers     = ModKeyFlags::NONE;
    m_bFullscreen       = false;
    m_bSpanMonitorsWhenFullscreen = false;
#if !GTK_CHECK_VERSION(4,0,0)
    m_nState            = GDK_WINDOW_STATE_WITHDRAWN;
#endif
    m_pIMHandler        = nullptr;
    m_pRegion           = nullptr;
    m_pDropTarget       = nullptr;
@@ -942,14 +998,20 @@ void GtkSalFrame::InitCommon()
    m_nActionGroupExportId = 0;
    m_nHudAwarenessId   = 0;

#if !GTK_CHECK_VERSION(4,0,0)
    gtk_widget_add_events( m_pWindow,
                           GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
                           GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
                           GDK_SCROLL_MASK
                           );
#endif

    // show the widgets
#if !GTK_CHECK_VERSION(4,0,0)
    gtk_widget_show_all(GTK_WIDGET(m_pTopLevelGrid));
#else
    gtk_widget_show(GTK_WIDGET(m_pTopLevelGrid));
#endif

    // realize the window, we need an XWindow id
    gtk_widget_realize( m_pWindow );
@@ -968,9 +1030,11 @@ void GtkSalFrame::InitCommon()
    {
        m_aSystemData.pDisplay = gdk_x11_display_get_xdisplay(pDisplay);
        m_aSystemData.platform = SystemEnvData::Platform::Xcb;
#if !GTK_CHECK_VERSION(4,0,0)
        GdkScreen* pScreen = gtk_widget_get_screen(m_pWindow);
        GdkVisual* pVisual = gdk_screen_get_system_visual(pScreen);
        m_aSystemData.pVisual = gdk_x11_visual_get_xvisual(pVisual);
#endif
    }
#endif
#if defined(GDK_WINDOWING_WAYLAND)
@@ -1037,9 +1101,11 @@ void GtkSalFrame::AllowCycleFocusOut()
{
    if (m_nSetFocusSignalId)
        return;
#if !GTK_CHECK_VERSION(4,0,0)
    // enable/disable can-focus as control enters and leaves
    // embedded native gtk widgets
    m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "set-focus", G_CALLBACK(signalSetFocus), this);
#endif

    // set container without can-focus and focus will tab between
    // the native embedded widgets using the default gtk handling for
@@ -1057,19 +1123,24 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
    }

    m_pParent = static_cast<GtkSalFrame*>(pParent);
#if !GTK_CHECK_VERSION(4,0,0)
    m_pForeignParent = nullptr;
    m_aForeignParentWindow = None;
    m_pForeignTopLevel = nullptr;
    m_aForeignTopLevelWindow = None;
#endif
    m_nStyle = nStyle;

#if !GTK_CHECK_VERSION(4,0,0)
    GtkWindowType eWinType = (  (nStyle & SalFrameStyleFlags::FLOAT) &&
                              ! (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
                              )
        ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
#endif

    if( nStyle & SalFrameStyleFlags::SYSTEMCHILD )
    {
#if !GTK_CHECK_VERSION(4,0,0)
        m_pWindow = gtk_event_box_new();
        if( m_pParent )
        {
@@ -1077,16 +1148,23 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
            gtk_fixed_put( m_pParent->getFixedContainer(),
                           m_pWindow, 0, 0 );
        }
#endif
    }
    else
    {
#if !GTK_CHECK_VERSION(4,0,0)
        m_pWindow = gtk_window_new(eWinType);
#else
        m_pWindow = gtk_window_new();
#endif

#if !GTK_CHECK_VERSION(4,0,0)
        // hook up F1 to show help for embedded native gtk widgets
        GtkAccelGroup *pGroup = gtk_accel_group_new();
        GClosure* closure = g_cclosure_new(G_CALLBACK(GtkSalFrame::NativeWidgetHelpPressed), GTK_WINDOW(m_pWindow), nullptr);
        gtk_accel_group_connect(pGroup, GDK_KEY_F1, static_cast<GdkModifierType>(0), GTK_ACCEL_LOCKED, closure);
        gtk_window_add_accel_group(GTK_WINDOW(m_pWindow), pGroup);
#endif
    }

    g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
@@ -1104,9 +1182,13 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
    {
        if (m_pParent)
        {
#if !GTK_CHECK_VERSION(4,0,0)
            GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParent->m_pWindow);
            if (!isChild())
                gtk_window_set_screen(GTK_WINDOW(m_pWindow), gtk_widget_get_screen(pTopLevel));
#else
            GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(m_pParent->m_pWindow));
#endif

            if (!(m_pParent->m_nStyle & SalFrameStyleFlags::PLUG))
                gtk_window_set_transient_for(GTK_WINDOW(m_pWindow), GTK_WINDOW(pTopLevel));
@@ -1128,29 +1210,40 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )

    if( bDecoHandling )
    {
#if !GTK_CHECK_VERSION(4,0,0)
        GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
        if( (nStyle & SalFrameStyleFlags::DIALOG) && m_pParent != nullptr )
            eType = GDK_WINDOW_TYPE_HINT_DIALOG;
#endif
        if( nStyle & SalFrameStyleFlags::INTRO )
        {
#if !GTK_CHECK_VERSION(4,0,0)
            gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
            eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
#endif
        }
        else if( nStyle & SalFrameStyleFlags::TOOLWINDOW )
        {
#if !GTK_CHECK_VERSION(4,0,0)
            eType = GDK_WINDOW_TYPE_HINT_DIALOG;
            gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
#endif
        }
        else if( nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
        {
#if !GTK_CHECK_VERSION(4,0,0)
            eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
            gtk_window_set_focus_on_map(GTK_WINDOW(m_pWindow), false);
#endif
            gtk_window_set_decorated(GTK_WINDOW(m_pWindow), false);
        }
#if !GTK_CHECK_VERSION(4,0,0)
        gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
        gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
#endif
        gtk_window_set_resizable( GTK_WINDOW(m_pWindow), bool(nStyle & SalFrameStyleFlags::SIZEABLE) );

#if !GTK_CHECK_VERSION(4,0,0)
#if defined(GDK_WINDOWING_WAYLAND)
        //rhbz#1392145 under wayland/csd if we've overridden the default widget direction in order to set LibreOffice's
        //UI to the configured ui language but the system ui locale is a different text direction, then the toplevel
@@ -1171,29 +1264,36 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
            }
        }
#endif
#endif
    }
#if !GTK_CHECK_VERSION(4,0,0)
    else if( nStyle & SalFrameStyleFlags::FLOAT )
        gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
#endif

    InitCommon();

#if !GTK_CHECK_VERSION(4,0,0)
    if( eWinType == GTK_WINDOW_TOPLEVEL )
    {
        // Enable DBus native menu if available.
        ensure_dbus_setup( this );

    }
#endif
}

#if !GTK_CHECK_VERSION(4,0,0)
GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow )
{
    //FIXME: no findToplevelSystemWindow
    return 0;
}
#endif

void GtkSalFrame::Init( SystemParentData* pSysData )
{
    m_pParent = nullptr;
#if !GTK_CHECK_VERSION(4,0,0)
    m_aForeignParentWindow = pSysData->aWindow;
    m_pForeignParent = nullptr;
    m_aForeignTopLevelWindow = findTopLevelSystemWindow(pSysData->aWindow);
@@ -1211,11 +1311,16 @@ void GtkSalFrame::Init( SystemParentData* pSysData )
    {
        m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
    }
#endif
    m_nStyle = SalFrameStyleFlags::PLUG;
    InitCommon();

#if !GTK_CHECK_VERSION(4,0,0)
    m_pForeignParent = gdk_x11_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
    gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
#else
    (void)pSysData;
#endif

    //FIXME: Handling embedded windows, is going to be fun ...
}
@@ -1262,8 +1367,10 @@ void GtkSalFrame::SetTitle( const OUString& rTitle )
    {
        OString sTitle(OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8));
        gtk_window_set_title(GTK_WINDOW(m_pWindow), sTitle.getStr());
#if !GTK_CHECK_VERSION(4,0,0)
        if (m_pHeaderBar)
            gtk_header_bar_set_title(m_pHeaderBar, sTitle.getStr());
#endif
    }
}

@@ -1271,6 +1378,7 @@ void GtkSalFrame::SetIcon(const char* appicon)
{
    gtk_window_set_icon_name(GTK_WINDOW(m_pWindow), appicon);

#if !GTK_CHECK_VERSION(4,0,0)
#if defined(GDK_WINDOWING_WAYLAND)
    if (DLSYM_GDK_IS_WAYLAND_DISPLAY(getGdkDisplay()))
    {
@@ -1287,6 +1395,7 @@ void GtkSalFrame::SetIcon(const char* appicon)
        }
    }
#endif
#endif
}

void GtkSalFrame::SetIcon( sal_uInt16 nIcon )
@@ -1335,10 +1444,12 @@ void GtkSalFrame::Center()
{
    if (!GTK_IS_WINDOW(m_pWindow))
        return;
#if !GTK_CHECK_VERSION(4,0,0)
    if (m_pParent)
        gtk_window_set_position(GTK_WINDOW(m_pWindow), GTK_WIN_POS_CENTER_ON_PARENT);
    else
        gtk_window_set_position(GTK_WINDOW(m_pWindow), GTK_WIN_POS_CENTER);
#endif
}

Size GtkSalFrame::calcDefaultSize()
@@ -1452,6 +1563,7 @@ void GtkSalFrame::setMinMaxSize()
    if( !m_pWindow || isChild() )
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkGeometry aGeo;
    int aHints = 0;
    if( m_nStyle & SalFrameStyleFlags::SIZEABLE )
@@ -1496,6 +1608,7 @@ void GtkSalFrame::setMinMaxSize()
                                       &aGeo,
                                       GdkWindowHints( aHints ) );
    }
#endif
}

void GtkSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
@@ -1534,10 +1647,17 @@ void GtkSalFrame::AllocateFrame()
    if (m_pSurface)
        cairo_surface_destroy(m_pSurface);

#if !GTK_CHECK_VERSION(4, 0, 0)
    m_pSurface = gdk_window_create_similar_surface(gtk_widget_get_window(m_pWindow),
                                                   CAIRO_CONTENT_COLOR_ALPHA,
                                                   aFrameSize.getX(),
                                                   aFrameSize.getY());
#else
    m_pSurface = gdk_surface_create_similar_surface(gtk_native_get_surface(gtk_widget_get_native(m_pWindow)),
                                                    CAIRO_CONTENT_COLOR_ALPHA,
                                                    aFrameSize.getX(),
                                                    aFrameSize.getY());
#endif
    m_aFrameSize = aFrameSize;

    cairo_surface_set_user_data(m_pSurface, SvpSalGraphics::getDamageKey(), &m_aDamageHandler, nullptr);
@@ -1568,8 +1688,10 @@ void GtkSalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth

        if( isChild( false ) )
            widget_set_size_request(nWidth, nHeight);
#if !GTK_CHECK_VERSION(4, 0, 0)
        else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
            window_resize(nWidth, nHeight);
#endif

        setMinMaxSize();
    }
@@ -1608,6 +1730,7 @@ void GtkSalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth

void GtkSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
    {
        rWidth = maGeometry.nWidth;
@@ -1615,10 +1738,15 @@ void GtkSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
    }
    else
        rWidth = rHeight = 0;
#else
    rWidth = maGeometry.nWidth;
    rHeight = maGeometry.nHeight;
#endif
}

void GtkSalFrame::GetWorkArea( tools::Rectangle& rRect )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen  *pScreen = gtk_widget_get_screen(m_pWindow);
    tools::Rectangle aRetRect;
    int max = gdk_screen_get_n_monitors (pScreen);
@@ -1630,6 +1758,9 @@ void GtkSalFrame::GetWorkArea( tools::Rectangle& rRect )
        aRetRect.Union(aMonitorRect);
    }
    rRect = aRetRect;
#else
    (void)rRect;
#endif
}

SalFrame* GtkSalFrame::GetParent() const
@@ -1642,6 +1773,7 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState )
    if( ! m_pWindow || ! pState || isChild( true, false ) )
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    const WindowStateMask nMaxGeometryMask =
        WindowStateMask::X | WindowStateMask::Y |
        WindowStateMask::Width | WindowStateMask::Height |
@@ -1683,12 +1815,14 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState )
            nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
        SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
    }
#endif
    if( pState->mnMask & WindowStateMask::State && ! isChild() )
    {
        if( pState->mnState & WindowStateState::Maximized )
            gtk_window_maximize( GTK_WINDOW(m_pWindow) );
        else
            gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
#if !GTK_CHECK_VERSION(4, 0, 0)
        /* #i42379# there is no rollup state in GDK; and rolled up windows are
        *  (probably depending on the WM) reported as iconified. If we iconify a
        *  window here that was e.g. a dialog, then it will be unmapped but still
@@ -1702,10 +1836,12 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState )
            gtk_window_iconify( GTK_WINDOW(m_pWindow) );
        else
            gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
#endif
    }
    TriggerPaintEvent();
}

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    void GetPosAndSize(GtkWindow *pWindow, tools::Long& rX, tools::Long &rY, tools::Long &rWidth, tools::Long &rHeight)
@@ -1727,11 +1863,13 @@ namespace
        return tools::Rectangle(nX, nY, nX + nWidth, nY + nHeight);
    }
}
#endif

bool GtkSalFrame::GetWindowState( SalFrameState* pState )
{
    pState->mnState = WindowStateState::Normal;
    pState->mnMask  = WindowStateMask::State;
#if !GTK_CHECK_VERSION(4, 0, 0)
    // rollup ? gtk 2.2 does not seem to support the shaded state
    if( m_nState & GDK_WINDOW_STATE_ICONIFIED )
        pState->mnState |= WindowStateState::Minimized;
@@ -1754,6 +1892,7 @@ bool GtkSalFrame::GetWindowState( SalFrameState* pState )
        GetPosAndSize(GTK_WINDOW(m_pWindow), pState->mnX, pState->mnY,
                                             pState->mnWidth, pState->mnHeight);
    }
#endif
    pState->mnMask  |= WindowStateMask::X            |
                       WindowStateMask::Y            |
                       WindowStateMask::Width        |
@@ -1764,6 +1903,7 @@ bool GtkSalFrame::GetWindowState( SalFrameState* pState )

void GtkSalFrame::SetScreen( unsigned int nNewScreen, SetType eType, tools::Rectangle const *pSize )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( !m_pWindow )
        return;

@@ -1907,6 +2047,11 @@ void GtkSalFrame::SetScreen( unsigned int nNewScreen, SetType eType, tools::Rect

    if( bVisible )
        Show( true );
#else
    (void)nNewScreen;
    (void)eType;
    (void)pSize;
#endif
}

void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
@@ -1916,6 +2061,7 @@ void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )

void GtkSalFrame::updateWMClass()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    OString aResClass = OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
    const char *pResClass = !aResClass.isEmpty() ? aResClass.getStr() :
                                                    SalGenericSystem::getFrameClassName();
@@ -1937,6 +2083,7 @@ void GtkSalFrame::updateWMClass()
                       pClass );
        XFree( pClass );
    }
#endif
}

void GtkSalFrame::SetApplicationID( const OUString &rWMClass )
@@ -1960,7 +2107,9 @@ void GtkSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )

    if( bFullScreen )
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_aRestorePosSize = GetPosAndSize(GTK_WINDOW(m_pWindow));
#endif
        SetScreen( nScreen, SetType::Fullscreen );
    }
    else
@@ -1975,11 +2124,13 @@ void GtkSalFrame::StartPresentation( bool bStart )
{
    std::optional<guint> aWindow;
    std::optional<Display*> aDisplay;
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( getDisplay()->IsX11Display() )
    {
        aWindow = widget_get_xid(m_pWindow);
        aDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
    }
#endif

    m_ScreenSaverInhibitor.inhibit( bStart,
                                    u"presentation",
@@ -1990,8 +2141,12 @@ void GtkSalFrame::StartPresentation( bool bStart )

void GtkSalFrame::SetAlwaysOnTop( bool bOnTop )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pWindow )
        gtk_window_set_keep_above( GTK_WINDOW( m_pWindow ), bOnTop );
#else
    (void)bOnTop;
#endif
}

static guint32 nLastUserInputTime = GDK_CURRENT_TIME;
@@ -2028,8 +2183,10 @@ void GtkSalFrame::ToTop( SalFrameToTop nFlags )
#endif
        if (!(nFlags & SalFrameToTop::GrabFocusOnly))
            gtk_window_present_with_time(GTK_WINDOW(m_pWindow), nTimestamp);
#if !GTK_CHECK_VERSION(4, 0, 0)
        else
            gdk_window_focus(gtk_widget_get_window(m_pWindow), nTimestamp);
#endif
        GrabFocus();
    }
    else
@@ -2046,7 +2203,11 @@ void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )

    m_ePointerStyle = ePointerStyle;
    GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
#if !GTK_CHECK_VERSION(4, 0, 0)
    gdk_window_set_cursor( gtk_widget_get_window(m_pWindow), pCursor );
#else
    gtk_widget_set_cursor(GTK_WIDGET(m_pWindow), pCursor);
#endif

    // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
    if( getDisplay()->MouseCaptured( this ) )
@@ -2071,6 +2232,7 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bKeyboardAlso, bool bOwnerEvents
    if (!m_pWindow)
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkSeat* pSeat = gdk_display_get_default_seat(getGdkDisplay());
    if (bGrab)
    {
@@ -2082,6 +2244,10 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bKeyboardAlso, bool bOwnerEvents
    {
        gdk_seat_ungrab(pSeat);
    }
#else
    (void)bKeyboardAlso;
    (void)bOwnerEvents;
#endif
}

void GtkSalFrame::CaptureMouse( bool bCapture )
@@ -2097,6 +2263,7 @@ void GtkSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
    if( ! pFrame )
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen *pScreen = gtk_widget_get_screen(pFrame->m_pWindow);
    GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );

@@ -2113,6 +2280,10 @@ void GtkSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
    gint x, y;
    GdkModifierType mask;
    gdk_window_get_pointer( gtk_widget_get_window(pFrame->m_pWindow) , &x, &y, &mask );
#else
    (void)nX;
    (void)nY;
#endif
}

void GtkSalFrame::Flush()
@@ -2136,7 +2307,13 @@ void GtkSalFrame::KeyCodeToGdkKey(const vcl::KeyCode& rKeyCode,
        nModifiers = static_cast<GdkModifierType>( nModifiers | GDK_CONTROL_MASK );

    if ( rKeyCode.IsMod2() )
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        nModifiers = static_cast<GdkModifierType>( nModifiers | GDK_MOD1_MASK );
#else
        nModifiers = static_cast<GdkModifierType>( nModifiers | GDK_ALT_MASK );
#endif
    }

    *pGdkModifiers = nModifiers;

@@ -2228,12 +2405,14 @@ GtkSalDisplay *GtkSalFrame::getDisplay()
SalFrame::SalPointerState GtkSalFrame::GetPointerState()
{
    SalPointerState aState;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen* pScreen;
    gint x, y;
    GdkModifierType aMask;
    gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
    aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
    aState.mnState = GetMouseModCode( aMask );
#endif
    return aState;
}

@@ -2241,6 +2420,7 @@ KeyIndicatorState GtkSalFrame::GetIndicatorState()
{
    KeyIndicatorState nState = KeyIndicatorState::NONE;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkKeymap *pKeyMap = gdk_keymap_get_for_display(getGdkDisplay());

    if (gdk_keymap_get_caps_lock_state(pKeyMap))
@@ -2249,6 +2429,7 @@ KeyIndicatorState GtkSalFrame::GetIndicatorState()
        nState |= KeyIndicatorState::NUMLOCK;
    if (gdk_keymap_get_scroll_lock_state(pKeyMap))
        nState |= KeyIndicatorState::SCROLLLOCK;
#endif

    return nState;
}
@@ -2360,8 +2541,10 @@ bool GtkSalFrame::SetPluginParent( SystemParentData* )

void GtkSalFrame::ResetClipRegion()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pWindow )
        gdk_window_shape_combine_region( gtk_widget_get_window( m_pWindow ), nullptr, 0, 0 );
#endif
}

void GtkSalFrame::BeginSetClipRegion( sal_uInt32 )
@@ -2386,8 +2569,10 @@ void GtkSalFrame::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long n

void GtkSalFrame::EndSetClipRegion()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pWindow && m_pRegion )
        gdk_window_shape_combine_region( gtk_widget_get_window(m_pWindow), m_pRegion, 0, 0 );
#endif
}

void GtkSalFrame::PositionByToolkit(const tools::Rectangle& rRect, FloatWinPopupFlags nFlags)
@@ -2414,6 +2599,7 @@ bool GtkSalFrame::GetModal() const
    return gtk_window_get_modal(GTK_WINDOW(m_pWindow));
}

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalFrame::signalTooltipQuery(GtkWidget*, gint /*x*/, gint /*y*/,
                                     gboolean /*keyboard_mode*/, GtkTooltip *tooltip,
                                     gpointer frame)
@@ -2433,6 +2619,7 @@ gboolean GtkSalFrame::signalTooltipQuery(GtkWidget*, gint /*x*/, gint /*y*/,
    gtk_tooltip_set_tip_area(tooltip, &aHelpArea);
    return true;
}
#endif

bool GtkSalFrame::ShowTooltip(const OUString& rHelpText, const tools::Rectangle& rHelpArea)
{
@@ -2488,10 +2675,19 @@ namespace

void* GtkSalFrame::ShowPopover(const OUString& rHelpText, vcl::Window* pParent, const tools::Rectangle& rHelpArea, QuickHelpFlags nFlags)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget *pWidget = gtk_popover_new(getMouseEventWidget());
#else
    GtkWidget *pWidget = gtk_popover_new();
    gtk_widget_set_parent(pWidget, getMouseEventWidget());
#endif
    OString sUTF = OUStringToOString(rHelpText, RTL_TEXTENCODING_UTF8);
    GtkWidget *pLabel =  gtk_label_new(sUTF.getStr());
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(pWidget), pLabel);
#else
    gtk_popover_set_child(GTK_POPOVER(pWidget), pLabel);
#endif

    if (nFlags & QuickHelpFlags::Top)
        gtk_popover_set_position(GTK_POPOVER(pWidget), GTK_POS_BOTTOM);
@@ -2504,9 +2700,17 @@ void* GtkSalFrame::ShowPopover(const OUString& rHelpText, vcl::Window* pParent, 

    set_pointing_to(GTK_POPOVER(pWidget), pParent, rHelpArea, maGeometry);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_popover_set_modal(GTK_POPOVER(pWidget), false);
#else
    gtk_popover_set_autohide(GTK_POPOVER(pWidget), false);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_show_all(pWidget);
#else
    gtk_widget_show(pWidget);
#endif

    return pWidget;
}
@@ -2517,7 +2721,11 @@ bool GtkSalFrame::UpdatePopover(void* nId, const OUString& rHelpText, vcl::Windo

    set_pointing_to(GTK_POPOVER(pWidget), pParent, rHelpArea, maGeometry);

#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget *pLabel = gtk_bin_get_child(GTK_BIN(pWidget));
#else
    GtkWidget *pLabel = gtk_popover_get_child(GTK_POPOVER(pWidget));
#endif
    OString sUTF = OUStringToOString(rHelpText, RTL_TEXTENCODING_UTF8);
    gtk_label_set_text(GTK_LABEL(pLabel), sUTF.getStr());

@@ -2527,14 +2735,20 @@ bool GtkSalFrame::UpdatePopover(void* nId, const OUString& rHelpText, vcl::Windo
bool GtkSalFrame::HidePopover(void* nId)
{
    GtkWidget *pWidget = static_cast<GtkWidget*>(nId);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_destroy(pWidget);
#else
    g_clear_pointer(&pWidget, gtk_widget_unparent);
#endif
    return true;
}

void GtkSalFrame::addGrabLevel()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (m_nGrabLevel == 0)
        gtk_grab_add(getMouseEventWidget());
#endif
    ++m_nGrabLevel;
}

@@ -2543,8 +2757,10 @@ void GtkSalFrame::removeGrabLevel()
    if (m_nGrabLevel > 0)
    {
        --m_nGrabLevel;
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (m_nGrabLevel == 0)
            gtk_grab_remove(getMouseEventWidget());
#endif
    }
}

@@ -2560,6 +2776,7 @@ void GtkSalFrame::closePopup()
    pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll);
}

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    //tdf#117981 translate embedded video window mouse events to parent coordinates
@@ -2574,14 +2791,19 @@ namespace
        }
    }
}
#endif

void GtkSalFrame::GrabFocus()
{
    GtkWidget* pGrabWidget;
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (GTK_IS_EVENT_BOX(m_pWindow))
        pGrabWidget = GTK_WIDGET(m_pWindow);
    else
        pGrabWidget = GTK_WIDGET(m_pFixedContainer);
#else
    pGrabWidget = GTK_WIDGET(m_pFixedContainer);
#endif
    // m_nSetFocusSignalId is 0 for the DisallowCycleFocusOut case where
    // we don't allow focus to enter the toplevel, but expect it to
    // stay in some embedded native gtk widget
@@ -2595,6 +2817,7 @@ void GtkSalFrame::GrabFocus()
    }
}

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalFrame::signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer frame)
{
    UpdateLastInputEventTime(pEvent->time);
@@ -2706,9 +2929,11 @@ void GtkSalFrame::LaunchAsyncScroll(GdkEvent const * pEvent)
    if (!m_aSmoothScrollIdle.IsActive())
        m_aSmoothScrollIdle.Start();
}
#endif

IMPL_LINK_NOARG(GtkSalFrame, AsyncScroll, Timer *, void)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    assert(!m_aPendingScrollEvents.empty());

    SalWheelMouseEvent aEvent;
@@ -2757,8 +2982,10 @@ IMPL_LINK_NOARG(GtkSalFrame, AsyncScroll, Timer *, void)
        aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
        CallCallbackExc(SalEvent::WheelMouse, &aEvent);
    }
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
SalWheelMouseEvent GtkSalFrame::GetWheelEvent(const GdkEventScroll& rEvent)
{
    SalWheelMouseEvent aEvent;
@@ -2954,6 +3181,7 @@ gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpoi

    return true;
}
#endif

cairo_t* GtkSalFrame::getCairoContext() const
{
@@ -2980,11 +3208,18 @@ void GtkSalFrame::damaged(sal_Int32 nExtentsX, sal_Int32 nExtentsY,
    if (nExtentsWidth <= 0 || nExtentsHeight <= 0)
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_queue_draw_area(GTK_WIDGET(m_pFixedContainer),
                               nExtentsX, nExtentsY,
                               nExtentsWidth, nExtentsHeight);
#else
    gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
    (void)nExtentsX;
    (void)nExtentsY;
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
// blit our backing cairo surface to the target cairo context
gboolean GtkSalFrame::signalDraw(GtkWidget*, cairo_t *cr, gpointer frame)
{
@@ -3118,6 +3353,7 @@ gboolean GtkSalFrame::signalConfigure(GtkWidget*, GdkEventConfigure* pEvent, gpo

    return false;
}
#endif

void GtkSalFrame::TriggerPaintEvent()
{
@@ -3139,6 +3375,7 @@ void GtkSalFrame::TriggerPaintEvent()
    gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
}

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
{
    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
@@ -3514,7 +3751,9 @@ gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer 

    return false;
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    GdkDragAction VclToGdk(sal_Int8 dragOperation)
@@ -3558,10 +3797,12 @@ namespace
        return eAct;
    }
}
#endif

static bool g_DropSuccessSet = false;
static bool g_DropSuccess = false;

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace {

class GtkDropTargetDropContext : public cppu::WeakImplHelper<css::datatransfer::dnd::XDropTargetDropContext>
@@ -3598,7 +3839,9 @@ public:
};

}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
class GtkDnDTransferable : public GtkTransferable
{
    GdkDragContext *m_pContext;
@@ -3640,9 +3883,13 @@ public:

            if (g_main_loop_is_running(m_pLoop))
            {
#if !GTK_CHECK_VERSION(4, 0, 0)
                gdk_threads_leave();
#endif
                g_main_loop_run(m_pLoop);
#if !GTK_CHECK_VERSION(4, 0, 0)
                gdk_threads_enter();
#endif
            }

            g_main_loop_unref(m_pLoop);
@@ -3693,11 +3940,13 @@ public:
        g_main_loop_quit(m_pLoop);
    }
};
#endif

// For LibreOffice internal D&D we provide the Transferable without Gtk
// intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this
GtkInstDragSource* GtkInstDragSource::g_ActiveDragSource;

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalFrame::signalDragDrop(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time, gpointer frame)
{
    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
@@ -3747,7 +3996,9 @@ gboolean GtkInstDropTarget::signalDragDrop(GtkWidget* pWidget, GdkDragContext* c

    return true;
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace {

class GtkDropTargetDragContext : public cppu::WeakImplHelper<css::datatransfer::dnd::XDropTargetDragContext>
@@ -3773,7 +4024,9 @@ public:
};

}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
void GtkSalFrame::signalDragDropReceived(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint ttype, guint time, gpointer frame)
{
    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
@@ -3923,6 +4176,7 @@ void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame )
    pThis->m_xFrameWeld.reset();
    pThis->InvalidateGraphics();
}
#endif

// GtkSalFrame::IMHandler

@@ -3964,7 +4218,9 @@ void GtkSalFrame::IMHandler::createIMContext()
                      G_CALLBACK (signalIMPreeditEnd), this );

    GetGenericUnixSalData()->ErrorTrapPush();
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_im_context_set_client_window(m_pIMContext, gtk_widget_get_window(m_pFrame->getMouseEventWidget()));
#endif
    gtk_im_context_focus_in( m_pIMContext );
    GetGenericUnixSalData()->ErrorTrapPop();
    m_bFocused = true;
@@ -3977,7 +4233,9 @@ void GtkSalFrame::IMHandler::deleteIMContext()
    {
        // first give IC a chance to deinitialize
        GetGenericUnixSalData()->ErrorTrapPush();
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_im_context_set_client_window( m_pIMContext, nullptr );
#endif
        GetGenericUnixSalData()->ErrorTrapPop();
        // destroy old IC
        g_object_unref( m_pIMContext );
@@ -4066,6 +4324,7 @@ void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
    }
}

#if !GTK_CHECK_VERSION(4, 0, 0)
bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
{
    vcl::DeletionListener aDel( m_pFrame );
@@ -4239,6 +4498,11 @@ void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* /*pContext*/, gchar* 
        }
    }
}
#else
void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* /*pContext*/, gchar* /*pText*/, gpointer /*im_handler*/ )
{
}
#endif

OUString GtkSalFrame::GetPreeditDetails(GtkIMContext* pIMContext, std::vector<ExtTextInputAttr>& rInputFlags, sal_Int32& rCursorPos, sal_uInt8& rCursorFlags)
{
@@ -4515,6 +4779,7 @@ Size GtkSalDisplay::GetScreenSize( int nDisplayScreen )

sal_uIntPtr GtkSalFrame::GetNativeWindowHandle(GtkWidget *pWidget) const
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    (void) this;                // Silence loplugin:staticmethods
    GdkDisplay *pDisplay = getGdkDisplay();
    GdkWindow *pWindow = gtk_widget_get_window(pWidget);
@@ -4531,6 +4796,9 @@ sal_uIntPtr GtkSalFrame::GetNativeWindowHandle(GtkWidget *pWidget) const
        return reinterpret_cast<sal_uIntPtr>(gdk_wayland_window_get_wl_surface(pWindow));
    }
#endif
#else
    (void)pWidget;
#endif
    return 0;
}

@@ -4550,16 +4818,19 @@ void GtkInstDragSource::setActiveDragSource()
   g_DropSuccess = false;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
std::vector<GtkTargetEntry> GtkInstDragSource::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats)
{
    return m_aConversionHelper.FormatsToGtk(rFormats);
}
#endif

void GtkInstDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEvent,
                              sal_Int8 sourceActions, sal_Int32 /*cursor*/, sal_Int32 /*image*/,
                              const css::uno::Reference<css::datatransfer::XTransferable>& rTrans,
                              const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    set_datatransfer(rTrans, rListener);

    if (m_pFrame)
@@ -4591,8 +4862,15 @@ void GtkInstDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEv
    }
    else
        dragFailed();
#else
    (void)rEvent;
    (void)sourceActions;
    (void)rTrans;
    (void)rListener;
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
void GtkSalFrame::startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY,
                            GdkDragAction sourceActions, GtkTargetList* pTargetList)
{
@@ -4703,6 +4981,7 @@ void GtkSalFrame::signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*con
        return;
    pThis->m_pDragSource->dragDataGet(data, info);
}
#endif

bool GtkSalFrame::CallCallbackExc(SalEvent nEvent, const void* pEvent) const
{
@@ -4719,6 +4998,7 @@ bool GtkSalFrame::CallCallbackExc(SalEvent nEvent, const void* pEvent) const
    return nRet;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
void GtkSalFrame::nopaint_container_resize_children(GtkContainer *pContainer)
{
    bool bOrigSalObjectSetPosSize = m_bSalObjectSetPosSize;
@@ -4726,9 +5006,11 @@ void GtkSalFrame::nopaint_container_resize_children(GtkContainer *pContainer)
    gtk_container_resize_children(pContainer);
    m_bSalObjectSetPosSize = bOrigSalObjectSetPosSize;
}
#endif

GdkEvent* GtkSalFrame::makeFakeKeyPress(GtkWidget* pWidget)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkEvent *event = gdk_event_new(GDK_KEY_PRESS);
    event->key.window = GDK_WINDOW(g_object_ref(gtk_widget_get_window(pWidget)));

@@ -4745,6 +5027,10 @@ GdkEvent* GtkSalFrame::makeFakeKeyPress(GtkWidget* pWidget)
    event->key.group = 0;
    event->key.is_modifier = false;
    return event;
#else
    (void)pWidget;
    return nullptr;
#endif
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 485ed1d..c696627 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -41,7 +41,9 @@
#include <fcntl.h>
#include <unistd.h>

#if !GTK_CHECK_VERSION(4, 0, 0)
#include "a11y/atkwrapper.hxx"
#endif
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
@@ -97,6 +99,7 @@ using namespace com::sun::star::lang;
extern "C"
{
    #define GET_YIELD_MUTEX() static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
#if !GTK_CHECK_VERSION(4, 0, 0)
    static void GdkThreadsEnter()
    {
        GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
@@ -107,15 +110,16 @@ extern "C"
        GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
        pYieldMutex->ThreadsLeave();
    }
#endif

    VCLPLUG_GTK_PUBLIC SalInstance* create_SalInstance()
    {
        SAL_INFO(
            "vcl.gtk",
            "create vcl plugin instance with gtk version " << gtk_major_version
                << " " << gtk_minor_version << " " << gtk_micro_version);
            "create vcl plugin instance with gtk version " << gtk_get_major_version()
                << " " << gtk_get_minor_version() << " " << gtk_get_micro_version());

        if (gtk_major_version == 3 && gtk_minor_version < 18)
        if (gtk_get_major_version() == 3 && gtk_get_minor_version() < 18)
        {
            g_warning("require gtk >= 3.18 for theme expectations");
            return nullptr;
@@ -145,12 +149,16 @@ extern "C"
        if ( !sup )
            g_thread_init( nullptr );

#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
#endif
        SAL_INFO("vcl.gtk", "Hooked gdk threads locks");

        auto pYieldMutex = std::make_unique<GtkYieldMutex>();

#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_init();
#endif

        GtkInstance* pInstance = new GtkInstance( std::move(pYieldMutex) );
        SAL_INFO("vcl.gtk", "creating GtkInstance " << pInstance);
@@ -162,15 +170,18 @@ extern "C"
    }
}

static VclInputFlags categorizeEvent(const GdkEvent *pEvent)
#if !GTK_CHECK_VERSION(4, 0, 0)
static VclInputFlags categorizeEvent(GdkEvent *pEvent)
{
    VclInputFlags nType = VclInputFlags::NONE;
    switch( pEvent->type )
    switch (gdk_event_get_event_type(pEvent))
    {
    case GDK_MOTION_NOTIFY:
    case GDK_BUTTON_PRESS:
#if !GTK_CHECK_VERSION(4, 0, 0)
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
#endif
    case GDK_BUTTON_RELEASE:
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
@@ -181,15 +192,18 @@ static VclInputFlags categorizeEvent(const GdkEvent *pEvent)
    // case GDK_KEY_RELEASE: //similar to the X11SalInstance one
        nType = VclInputFlags::KEYBOARD;
        break;
#if !GTK_CHECK_VERSION(4, 0, 0)
    case GDK_EXPOSE:
        nType = VclInputFlags::PAINT;
        break;
#endif
    default:
        nType = VclInputFlags::OTHER;
        break;
    }
    return nType;
}
#endif

GtkInstance::GtkInstance( std::unique_ptr<SalYieldMutex> pMutex )
    : SvpSalInstance( std::move(pMutex) )
@@ -217,7 +231,9 @@ void GtkInstance::EnsureInit()
    pSalData->Init();
    GtkSalData::initNWF();

#if !GTK_CHECK_VERSION(4, 0, 0)
    InitAtkBridge();
#endif

    ImplSVData* pSVData = ImplGetSVData();
#ifdef GTK_TOOLKIT_NAME
@@ -232,7 +248,9 @@ void GtkInstance::EnsureInit()
GtkInstance::~GtkInstance()
{
    assert( nullptr == m_pTimer );
#if !GTK_CHECK_VERSION(4, 0, 0)
    DeInitAtkBridge();
#endif
    ResetLastSeenCairoFontOptions(nullptr);
}

@@ -400,13 +418,16 @@ bool GtkInstance::AnyInput( VclInputFlags nType )
    EnsureInit();
    if( (nType & VclInputFlags::TIMER) && IsTimerExpired() )
        return true;
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (!gdk_events_pending())
        return false;
#endif

    if (nType == VCL_INPUT_ANY)
        return true;

    bool bRet = false;
#if !GTK_CHECK_VERSION(4, 0, 0)
    std::deque<GdkEvent*> aEvents;
    GdkEvent *pEvent = nullptr;
    while ((pEvent = gdk_event_get()))
@@ -426,6 +447,7 @@ bool GtkInstance::AnyInput( VclInputFlags nType )
        gdk_event_free(pEvent);
        aEvents.pop_front();
    }
#endif
    return bRet;
}

@@ -437,10 +459,14 @@ std::unique_ptr<GenPspGraphics> GtkInstance::CreatePrintGraphics()

const cairo_font_options_t* GtkInstance::GetCairoFontOptions()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    const cairo_font_options_t* pCairoFontOptions = gdk_screen_get_font_options(gdk_screen_get_default());
    if (!m_pLastCairoFontOptions && pCairoFontOptions)
        m_pLastCairoFontOptions = cairo_font_options_copy(pCairoFontOptions);
    return pCairoFontOptions;
#else
    return nullptr;
#endif
}

const cairo_font_options_t* GtkInstance::GetLastSeenCairoFontOptions() const
@@ -519,6 +545,7 @@ namespace
    };
}

#if !GTK_CHECK_VERSION(4, 0, 0)
std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavorsAsVector(GdkAtom *targets, gint n_targets)
{
    std::vector<css::datatransfer::DataFlavor> aVector;
@@ -560,7 +587,9 @@ std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavo
                                    strlen(pFinalName),
                                    RTL_TEXTENCODING_UTF8);

#if !GTK_CHECK_VERSION(4, 0, 0)
        m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i];
#endif

        aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();

@@ -592,7 +621,7 @@ std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavo

    return aVector;
}

#endif

css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL GtkTransferable::getTransferDataFlavors()
{
@@ -609,6 +638,7 @@ sal_Bool SAL_CALL GtkTransferable::isDataFlavorSupported(const css::datatransfer

namespace {

#if !GTK_CHECK_VERSION(4, 0, 0)
class GtkClipboardTransferable : public GtkTransferable
{
private:
@@ -626,6 +656,8 @@ public:

    virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override
    {
        css::uno::Any aRet;
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
        if (rFlavor.MimeType == "text/plain;charset=utf-16")
        {
@@ -634,7 +666,6 @@ public:
            if (pText)
                aStr = OUString(pText, strlen(pText), RTL_TEXTENCODING_UTF8);
            g_free(pText);
            css::uno::Any aRet;
            aRet <<= aStr.replaceAll("\r\n", "\n");
            return aRet;
        }
@@ -643,7 +674,6 @@ public:
        if (it == m_aMimeTypeToAtom.end())
            return css::uno::Any();

        css::uno::Any aRet;
        GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
                                                                 it->second);
        if (!data)
@@ -657,6 +687,7 @@ public:
        gtk_selection_data_free(data);
        aRet <<= aSeq;
        return aRet;
#endif
    }

    std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector()
@@ -664,6 +695,7 @@ public:
    {
        std::vector<css::datatransfer::DataFlavor> aVector;

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);

        GdkAtom *targets;
@@ -673,10 +705,12 @@ public:
            aVector = GtkTransferable::getTransferDataFlavorsAsVector(targets, n_targets);
            g_free(targets);
        }
#endif

        return aVector;
    }
};
#endif

class VclGtkClipboard :
        public cppu::WeakComponentImplHelper<
@@ -684,20 +718,30 @@ class VclGtkClipboard :
        datatransfer::clipboard::XFlushableClipboard,
        XServiceInfo>
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkAtom                                                  m_nSelection;
#endif
    osl::Mutex                                               m_aMutex;
#if !GTK_CHECK_VERSION(4, 0, 0)
    gulong                                                   m_nOwnerChangedSignalId;
#endif
    ImplSVEvent*                                             m_pSetClipboardEvent;
    Reference<css::datatransfer::XTransferable>              m_aContents;
    Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
    std::vector< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners;
#if !GTK_CHECK_VERSION(4, 0, 0)
    std::vector<GtkTargetEntry> m_aGtkTargets;
    VclToGtkHelper m_aConversionHelper;
#endif

    DECL_LINK(AsyncSetGtkClipboard, void*, void);
public:

#if !GTK_CHECK_VERSION(4, 0, 0)
    explicit VclGtkClipboard(GdkAtom nSelection);
#else
    explicit VclGtkClipboard();
#endif
    virtual ~VclGtkClipboard() override;

    /*
@@ -740,9 +784,11 @@ public:
    virtual void SAL_CALL removeClipboardListener(
        const Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override;

#if !GTK_CHECK_VERSION(4, 0, 0)
    void ClipboardGet(GtkSelectionData *selection_data, guint info);
    void ClipboardClear();
    void OwnerPossiblyChanged(GtkClipboard *clipboard);
#endif
    void ClipboardClear();
    void SetGtkClipboard();
    void SyncGtkClipboard();
};
@@ -767,16 +813,18 @@ sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName )

Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (!m_aContents.is())
    {
        //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
        //the owner of the clipboard and have not already fetched it.
        m_aContents = new GtkClipboardTransferable(m_nSelection);
    }

#endif
    return m_aContents;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
void VclGtkClipboard::ClipboardGet(GtkSelectionData *selection_data, guint info)
{
    if (!m_aContents.is())
@@ -786,7 +834,9 @@ void VclGtkClipboard::ClipboardGet(GtkSelectionData *selection_data, guint info)
    Reference<datatransfer::XTransferable> xCurrentContents(m_aContents);
    m_aConversionHelper.setSelectionData(xCurrentContents, selection_data, info);
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    const OString& getPID()
@@ -804,7 +854,9 @@ namespace
        return sPID;
    }
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    void ClipboardGetFunc(GtkClipboard* /*clipboard*/, GtkSelectionData *selection_data,
@@ -874,6 +926,7 @@ void VclGtkClipboard::OwnerPossiblyChanged(GtkClipboard* clipboard)
                    Reference<css::datatransfer::clipboard::XClipboardOwner>());
    }
}
#endif

void VclGtkClipboard::ClipboardClear()
{
@@ -882,11 +935,14 @@ void VclGtkClipboard::ClipboardClear()
        Application::RemoveUserEvent(m_pSetClipboardEvent);
        m_pSetClipboardEvent = nullptr;
    }
#if !GTK_CHECK_VERSION(4, 0, 0)
    for (auto &a : m_aGtkTargets)
        g_free(a.target);
    m_aGtkTargets.clear();
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
GtkTargetEntry VclToGtkHelper::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
{
    GtkTargetEntry aEntry;
@@ -962,21 +1018,31 @@ void VclToGtkHelper::setSelectionData(const Reference<css::datatransfer::XTransf
                           reinterpret_cast<const guchar *>(aData.getArray()),
                           aData.getLength());
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
#else
VclGtkClipboard::VclGtkClipboard()
#endif
    : cppu::WeakComponentImplHelper<datatransfer::clipboard::XSystemClipboard,
                                    datatransfer::clipboard::XFlushableClipboard, XServiceInfo>
        (m_aMutex)
#if !GTK_CHECK_VERSION(4, 0, 0)
    , m_nSelection(nSelection)
#endif
    , m_pSetClipboardEvent(nullptr)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
    m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
                                               G_CALLBACK(handle_owner_change), this);
#endif
}

void VclGtkClipboard::flushClipboard()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    SolarMutexGuard aGuard;

    if (GDK_SELECTION_CLIPBOARD != m_nSelection)
@@ -984,10 +1050,12 @@ void VclGtkClipboard::flushClipboard()

    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
    gtk_clipboard_store(clipboard);
#endif
}

VclGtkClipboard::~VclGtkClipboard()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
    g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
    if (!m_aGtkTargets.empty())
@@ -997,8 +1065,10 @@ VclGtkClipboard::~VclGtkClipboard()
    }
    assert(!m_pSetClipboardEvent);
    assert(m_aGtkTargets.empty());
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
std::vector<GtkTargetEntry> VclToGtkHelper::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats)
{
    std::vector<GtkTargetEntry> aGtkTargets;
@@ -1037,6 +1107,7 @@ std::vector<GtkTargetEntry> VclToGtkHelper::FormatsToGtk(const css::uno::Sequenc

    return aGtkTargets;
}
#endif

IMPL_LINK_NOARG(VclGtkClipboard, AsyncSetGtkClipboard, void*, void)
{
@@ -1058,10 +1129,12 @@ void VclGtkClipboard::SyncGtkClipboard()

void VclGtkClipboard::SetGtkClipboard()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
    gtk_clipboard_set_with_data(clipboard, m_aGtkTargets.data(), m_aGtkTargets.size(),
                                ClipboardGetFunc, ClipboardClearFunc, this);
    gtk_clipboard_set_can_store(clipboard, m_aGtkTargets.data(), m_aGtkTargets.size());
#endif
}

void VclGtkClipboard::setContents(
@@ -1083,6 +1156,7 @@ void VclGtkClipboard::setContents(
    std::vector< Reference< datatransfer::clipboard::XClipboardListener > > aListeners( m_aListeners );
    datatransfer::clipboard::ClipboardEvent aEv;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
    if (!m_aGtkTargets.empty())
    {
@@ -1108,6 +1182,7 @@ void VclGtkClipboard::setContents(
                m_pSetClipboardEvent = Application::PostUserEvent(LINK(this, VclGtkClipboard, AsyncSetGtkClipboard));
        }
    }
#endif

    aEv.Contents = getContents();

@@ -1123,7 +1198,11 @@ void VclGtkClipboard::setContents(

OUString VclGtkClipboard::getName()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    return (m_nSelection == GDK_SELECTION_CLIPBOARD) ? OUString("CLIPBOARD") : OUString("PRIMARY");
#else
    return "CLIPBOARD";
#endif
}

sal_Int8 VclGtkClipboard::getRenderingCapabilities()
@@ -1163,6 +1242,7 @@ Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& argu
            css::uno::Reference<css::uno::XInterface>(), -1);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkAtom nSelection = (sel == "CLIPBOARD") ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;

    auto it = m_aClipboards.find(nSelection);
@@ -1171,8 +1251,10 @@ Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& argu

    Reference<XInterface> xClipboard(static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)));
    m_aClipboards[nSelection] = xClipboard;

    return xClipboard;
#else
    return nullptr;
#endif
}

GtkInstDropTarget::GtkInstDropTarget()
@@ -1180,7 +1262,9 @@ GtkInstDropTarget::GtkInstDropTarget()
    , m_pFrame(nullptr)
    , m_pFormatConversionRequest(nullptr)
    , m_bActive(false)
#if !GTK_CHECK_VERSION(4, 0, 0)
    , m_bInDrag(false)
#endif
    , m_nDefaultActions(0)
{
}
@@ -1538,8 +1622,17 @@ private:
        gtk_gl_area_set_auto_render(GTK_GL_AREA(m_pGLArea), false);
        gtk_widget_set_hexpand(m_pGLArea, true);
        gtk_widget_set_vexpand(m_pGLArea, true);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_add(GTK_CONTAINER(pParent), m_pGLArea);
        gtk_widget_show_all(pParent);
#else
        gtk_grid_attach(GTK_GRID(pParent), m_pGLArea, 0, 0, 1, 1);
        gtk_widget_show(pParent);
        gtk_widget_realize(m_pGLArea);
        // TODO does realize do the gdk_window_create_gl_context + gdk_gl_context_realize
        // and so gtk_gl_area_make_current then does gdk_gl_context_make_current on its
        // own ?
#endif

        gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
        if (GError *pError = gtk_gl_area_get_error(GTK_GL_AREA(m_pGLArea)))
@@ -1551,6 +1644,7 @@ private:
        gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
        glGenFramebuffersEXT(1, &m_nAreaFrameBuffer);

#if !GTK_CHECK_VERSION(4, 0, 0)
        GdkWindow *pWindow = gtk_widget_get_window(pParent);
        m_pContext = gdk_window_create_gl_context(pWindow, nullptr);
        if (!m_pContext)
@@ -1560,6 +1654,7 @@ private:
            return false;

        gdk_gl_context_make_current(m_pContext);
#endif
        glGenFramebuffersEXT(1, &m_nFrameBuffer);
        glGenRenderbuffersEXT(1, &m_nRenderBuffer);
        glGenRenderbuffersEXT(1, &m_nDepthBuffer);
@@ -1683,6 +1778,7 @@ bool DLSYM_GDK_IS_X11_DISPLAY(GdkDisplay* pDisplay)
    return G_TYPE_CHECK_INSTANCE_TYPE(pDisplay, get_type());
}

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{

@@ -1701,6 +1797,7 @@ class GtkInstanceBuilder;
        return OString(pStr, pStr ? strlen(pStr) : 0);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    KeyEvent GtkToVcl(const GdkEventKey& rEvent)
    {
        sal_uInt16 nKeyCode = GtkSalFrame::GetKeyCode(rEvent.keyval);
@@ -1712,6 +1809,7 @@ class GtkInstanceBuilder;
        nKeyCode |= GtkSalFrame::GetKeyModCode(rEvent.state);
        return KeyEvent(gdk_keyval_to_unicode(rEvent.keyval), nKeyCode, 0);
    }
#endif
}

static MouseEventModifiers ImplGetMouseButtonMode(sal_uInt16 nButton, sal_uInt16 nCode)
@@ -1790,6 +1888,7 @@ namespace
        g_object_ref(pWidget);

        gint nTopAttach(0), nLeftAttach(0), nHeight(1), nWidth(1);
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_GRID(pParent))
        {
            gtk_container_child_get(GTK_CONTAINER(pParent), pWidget,
@@ -1799,7 +1898,9 @@ namespace
                    "height", &nHeight,
                    nullptr);
        }
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
        gboolean bExpand(false), bFill(false);
        GtkPackType ePackType(GTK_PACK_START);
        guint nPadding(0);
@@ -1816,9 +1917,12 @@ namespace
        }

        gtk_container_remove(GTK_CONTAINER(pParent), pWidget);
#endif

        gtk_widget_set_visible(pReplacement, gtk_widget_get_visible(pWidget));
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_set_no_show_all(pReplacement, gtk_widget_get_no_show_all(pWidget));
#endif

        int nReqWidth, nReqHeight;
        gtk_widget_get_size_request(pWidget, &nReqWidth, &nReqHeight);
@@ -1850,17 +1954,22 @@ namespace
        {
            gtk_grid_attach(GTK_GRID(pParent), pReplacement, nLeftAttach, nTopAttach, nWidth, nHeight);
        }

        else if (GTK_IS_BOX(pParent))
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            gtk_box_pack_start(GTK_BOX(pParent), pReplacement, bExpand, bFill, nPadding);
            gtk_container_child_set(GTK_CONTAINER(pParent), pReplacement,
                    "pack-type", ePackType,
                    "position", nPosition,
                    nullptr);
#else
            gtk_box_prepend(GTK_BOX(pParent), pReplacement);
#endif
        }
#if !GTK_CHECK_VERSION(4, 0, 0)
        else
            gtk_container_add(GTK_CONTAINER(pParent), pReplacement);
#endif

        if (gtk_widget_get_hexpand_set(pWidget))
            gtk_widget_set_hexpand(pReplacement, gtk_widget_get_hexpand(pWidget));
@@ -1881,8 +1990,10 @@ namespace

        replaceWidget(pWidget, pReplacement);

#if !GTK_CHECK_VERSION(4, 0, 0)
        // coverity[pass_freed_arg : FALSE] - pWidget is not freed here due to initial g_object_ref
        gtk_container_add(GTK_CONTAINER(pReplacement), pWidget);
#endif

        // coverity[freed_arg : FALSE] - this does not free pWidget, it is reffed by pReplacement
        g_object_unref(pWidget);
@@ -1890,6 +2001,7 @@ namespace

    GtkWidget* ensureEventWidget(GtkWidget* pWidget)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!pWidget)
            return nullptr;

@@ -1911,6 +2023,9 @@ namespace

        return pMouseEventBox;
    }
#else
    return pWidget;
#endif
}

namespace {
@@ -1931,6 +2046,7 @@ GtkWindow* get_focus_window()
{
    GtkWindow* pFocus = nullptr;

#if !GTK_CHECK_VERSION(4, 0, 0)
    GList* pList = gtk_window_list_toplevels();

    for (GList* pEntry = pList; pEntry; pEntry = pEntry->next)
@@ -1943,10 +2059,12 @@ GtkWindow* get_focus_window()
    }

    g_list_free(pList);
#endif

    return pFocus;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
void LocalizeDecimalSeparator(GdkEventKey* pEvent)
{
    // #i1820# use locale specific decimal separator
@@ -1962,9 +2080,11 @@ void LocalizeDecimalSeparator(GdkEventKey* pEvent)
        }
    }
}
#endif

void set_cursor(GtkWidget* pWidget, const char *pName)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (!gtk_widget_get_realized(pWidget))
        gtk_widget_realize(pWidget);
    GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
@@ -1973,6 +2093,10 @@ void set_cursor(GtkWidget* pWidget, const char *pName)
    gdk_display_flush(pDisplay);
    if (pCursor)
        g_object_unref(pCursor);
#else
    (void)pWidget;
    (void)pName;
#endif
}

class GtkInstanceWidget : public virtual weld::Widget
@@ -1996,7 +2120,11 @@ protected:

    void signal_focus_in()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget);
#else
        GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(m_pWidget));
#endif
        // see commentary in GtkSalObjectWidgetClip::Show
        if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange"))
            return;
@@ -2024,6 +2152,7 @@ protected:
        return false;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    void launch_drag_cancel(GdkDragContext* context)
    {
        // post our drag cancel to happen at the next available event cycle
@@ -2032,10 +2161,15 @@ protected:
        g_object_ref(context);
        m_pDragCancelEvent = Application::PostUserEvent(LINK(this, GtkInstanceWidget, async_drag_cancel), context);
    }
#endif

    void signal_focus_out()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget);
#else
        GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(m_pWidget));
#endif
        // see commentary in GtkSalObjectWidgetClip::Show
        if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange"))
            return;
@@ -2054,7 +2188,9 @@ protected:
        if (!m_nButtonPressSignalId)
        {
            ensureMouseEventWidget();
#if !GTK_CHECK_VERSION(4, 0, 0)
            m_nButtonPressSignalId = g_signal_connect(m_pMouseEventBox, "button-press-event", G_CALLBACK(signalButton), this);
#endif
        }
    }

@@ -2078,6 +2214,7 @@ protected:
    {
        ensure_drag_source();

#if !GTK_CHECK_VERSION(4, 0, 0)
        auto aFormats = rHelper->getTransferDataFlavors();
        std::vector<GtkTargetEntry> aGtkTargets(m_xDragSource->FormatsToGtk(aFormats));

@@ -2088,18 +2225,25 @@ protected:
            g_free(a.target);

        m_xDragSource->set_datatransfer(rHelper, rHelper);
#else
        (void)rHelper;
        (void)eDNDConstants;
#endif
    }

    void localizeDecimalSeparator()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // tdf#128867 if localize decimal separator is active we will always
        // need to be able to change the output of the decimal key press
        if (!m_nKeyPressSignalId && Application::GetSettings().GetMiscSettings().GetEnableLocalizedDecimalSep())
            m_nKeyPressSignalId = g_signal_connect(m_pWidget, "key-press-event", G_CALLBACK(signalKey), this);
#endif
    }

    void ensure_drag_begin_end()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nDragBeginSignalId)
        {
            // using "after" due to https://gitlab.gnome.org/GNOME/pygobject/issues/251
@@ -2107,6 +2251,7 @@ protected:
        }
        if (!m_nDragEndSignalId)
            m_nDragEndSignalId = g_signal_connect(m_pWidget, "drag-end", G_CALLBACK(signalDragEnd), this);
#endif
    }

private:
@@ -2153,18 +2298,21 @@ private:
        pThis->signal_size_allocate(allocation->width, allocation->height);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalKey(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
    {
        LocalizeDecimalSeparator(pEvent);
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
        return pThis->signal_key(pEvent);
    }
#endif

    virtual bool signal_popup_menu(const CommandEvent&)
    {
        return false;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
    {
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
@@ -2195,6 +2343,7 @@ private:
        switch (pEvent->type)
        {
            case GDK_BUTTON_PRESS:
#if !GTK_CHECK_VERSION(4, 0, 0)
                if (GdkEvent* pPeekEvent = gdk_event_peek())
                {
                    bool bSkip = pPeekEvent->type == GDK_2BUTTON_PRESS ||
@@ -2205,9 +2354,11 @@ private:
                        return false;
                    }
                }
#endif
                nEventType = SalEvent::MouseButtonDown;
                m_nLastMouseClicks = 1;
                break;
#if !GTK_CHECK_VERSION(4, 0, 0)
            case GDK_2BUTTON_PRESS:
                m_nLastMouseClicks = 2;
                nEventType = SalEvent::MouseButtonDown;
@@ -2216,6 +2367,7 @@ private:
                m_nLastMouseClicks = 3;
                nEventType = SalEvent::MouseButtonDown;
                break;
#endif
            case GDK_BUTTON_RELEASE:
                nEventType = SalEvent::MouseButtonUp;
                break;
@@ -2262,7 +2414,9 @@ private:
            return false;
        return m_aMouseReleaseHdl.Call(aMEvt);
    }
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalMotion(GtkWidget*, GdkEventMotion* pEvent, gpointer widget)
    {
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
@@ -2329,11 +2483,13 @@ private:
        m_aMouseMotionHdl.Call(aMEvt);
        return true;
    }
#endif

    virtual void drag_started()
    {
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalDragMotion(GtkWidget *pWidget, GdkDragContext *context, gint x, gint y, guint time, gpointer widget)
    {
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
@@ -2377,6 +2533,7 @@ private:
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
        pThis->signal_drag_begin(context);
    }
#endif

    void ensure_drag_source()
    {
@@ -2384,9 +2541,11 @@ private:
        {
            m_xDragSource.set(new GtkInstDragSource);

#if !GTK_CHECK_VERSION(4, 0, 0)
            m_nDragFailedSignalId = g_signal_connect(m_pWidget, "drag-failed", G_CALLBACK(signalDragFailed), this);
            m_nDragDataDeleteignalId = g_signal_connect(m_pWidget, "drag-data-delete", G_CALLBACK(signalDragDelete), this);
            m_nDragGetSignalId = g_signal_connect(m_pWidget, "drag-data-get", G_CALLBACK(signalDragDataGet), this);
#endif

            ensure_drag_begin_end();
        }
@@ -2398,28 +2557,37 @@ private:
        return false;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    void signal_drag_begin(GdkDragContext* context)
    {
        bool bUnsetDragIcon(false);
        if (do_signal_drag_begin(bUnsetDragIcon))
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            launch_drag_cancel(context);
#else
            (void)context;
#endif
            return;
        }
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (bUnsetDragIcon)
        {
            cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
            gtk_drag_set_icon_surface(context, surface);
        }
#endif
        if (!m_xDragSource)
            return;
        m_xDragSource->setActiveDragSource();
    }
#endif

    virtual void do_signal_drag_end()
    {
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static void signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer widget)
    {
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
@@ -2447,7 +2615,9 @@ private:
        GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
        pThis->m_xDragSource->dragDataGet(data, info);
    }
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    virtual void drag_source_set(const std::vector<GtkTargetEntry>& rGtkTargets, GdkDragAction eDragAction)
    {
        if (rGtkTargets.empty() && !eDragAction)
@@ -2455,6 +2625,7 @@ private:
        else
            gtk_drag_source_set(m_pWidget, GDK_BUTTON1_MASK, rGtkTargets.data(), rGtkTargets.size(), eDragAction);
    }
#endif

    void do_set_background(const Color& rColor)
    {
@@ -2473,7 +2644,11 @@ private:
        m_pBgCssProvider = gtk_css_provider_new();
        OUString aBuffer = "* { background-color: #" + sColor + "; }";
        OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(m_pBgCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
#else
        gtk_css_provider_load_from_data(m_pBgCssProvider, aResult.getStr(), aResult.getLength());
#endif
        gtk_style_context_add_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pBgCssProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    }
@@ -2524,15 +2699,19 @@ public:

    virtual void connect_key_press(const Link<const KeyEvent&, bool>& rLink) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nKeyPressSignalId)
            m_nKeyPressSignalId = g_signal_connect(m_pWidget, "key-press-event", G_CALLBACK(signalKey), this);
#endif
        weld::Widget::connect_key_press(rLink);
    }

    virtual void connect_key_release(const Link<const KeyEvent&, bool>& rLink) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nKeyReleaseSignalId)
            m_nKeyReleaseSignalId = g_signal_connect(m_pWidget, "key-release-event", G_CALLBACK(signalKey), this);
#endif
        weld::Widget::connect_key_release(rLink);
    }

@@ -2545,20 +2724,24 @@ public:
    virtual void connect_mouse_move(const Link<const MouseEvent&, bool>& rLink) override
    {
        ensureMouseEventWidget();
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nMotionSignalId)
            m_nMotionSignalId = g_signal_connect(m_pMouseEventBox, "motion-notify-event", G_CALLBACK(signalMotion), this);
        if (!m_nLeaveSignalId)
            m_nLeaveSignalId = g_signal_connect(m_pMouseEventBox, "leave-notify-event", G_CALLBACK(signalCrossing), this);
        if (!m_nEnterSignalId)
            m_nEnterSignalId = g_signal_connect(m_pMouseEventBox, "enter-notify-event", G_CALLBACK(signalCrossing), this);
#endif
        weld::Widget::connect_mouse_move(rLink);
    }

    virtual void connect_mouse_release(const Link<const MouseEvent&, bool>& rLink) override
    {
        ensureMouseEventWidget();
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nButtonReleaseSignalId)
            m_nButtonReleaseSignalId = g_signal_connect(m_pMouseEventBox, "button-release-event", G_CALLBACK(signalButton), this);
#endif
        weld::Widget::connect_mouse_release(rLink);
    }

@@ -2601,7 +2784,11 @@ public:

    virtual bool is_active() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWindow* pTopLevel = GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget));
#else
        GtkWindow* pTopLevel = GTK_WINDOW(gtk_widget_get_root(m_pWidget));
#endif
        return pTopLevel && gtk_window_is_active(pTopLevel) && has_focus();
    }

@@ -2615,11 +2802,13 @@ public:
        GtkWidget* pFocus = gtk_window_get_focus(pFocusWin);
        if (pFocus && gtk_widget_is_ancestor(pFocus, m_pWidget))
            return true;
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pAttachedTo = gtk_window_get_attached_to(pFocusWin);
        if (!pAttachedTo)
            return false;
        if (pAttachedTo == m_pWidget || gtk_widget_is_ancestor(pAttachedTo, m_pWidget))
            return true;
#endif
        return false;
    }

@@ -2714,36 +2903,60 @@ public:

    virtual void set_grid_left_attach(int nAttach) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gtk_container_child_set(pParent, m_pWidget, "left-attach", nAttach, nullptr);
#else
        (void)nAttach;
#endif
    }

    virtual int get_grid_left_attach() const override
    {
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gint nAttach(0);
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gtk_container_child_get(pParent, m_pWidget, "left-attach", &nAttach, nullptr);
        return nAttach;
#else
        GtkGrid* pParent = GTK_GRID(gtk_widget_get_parent(m_pWidget));
        gtk_grid_query_child(pParent, m_pWidget, &nAttach, nullptr, nullptr, nullptr);
        return nAttach;
#endif
    }

    virtual void set_grid_width(int nCols) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gtk_container_child_set(pParent, m_pWidget, "width", nCols, nullptr);
#else
        (void)nCols;
#endif
    }

    virtual void set_grid_top_attach(int nAttach) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gtk_container_child_set(pParent, m_pWidget, "top-attach", nAttach, nullptr);
#else
        (void)nAttach;
#endif
    }

    virtual int get_grid_top_attach() const override
    {
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gint nAttach(0);
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget));
        gtk_container_child_get(pParent, m_pWidget, "top-attach", &nAttach, nullptr);
        return nAttach;
#else
        GtkGrid* pParent = GTK_GRID(gtk_widget_get_parent(m_pWidget));
        gtk_grid_query_child(pParent, m_pWidget, nullptr, &nAttach, nullptr, nullptr);
        return nAttach;
#endif
    }

    virtual void set_hexpand(bool bExpand) override
@@ -2768,9 +2981,13 @@ public:

    virtual void set_secondary(bool bSecondary) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
        if (pParent && GTK_IS_BUTTON_BOX(pParent))
            gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(pParent), m_pWidget, bSecondary);
#else
        (void)bSecondary;
#endif
    }

    virtual void set_margin_top(int nMargin) override
@@ -2815,36 +3032,53 @@ public:

    virtual void set_accessible_name(const OUString& rName) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        if (!pAtkObject)
            return;
        atk_object_set_name(pAtkObject, OUStringToOString(rName, RTL_TEXTENCODING_UTF8).getStr());
#else
        (void)rName;
#endif
    }

    virtual void set_accessible_description(const OUString& rDescription) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        if (!pAtkObject)
            return;
        atk_object_set_description(pAtkObject, OUStringToOString(rDescription, RTL_TEXTENCODING_UTF8).getStr());
#else
        (void)rDescription;
#endif
    }

    virtual OUString get_accessible_name() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        const char* pStr = pAtkObject ? atk_object_get_name(pAtkObject) : nullptr;
        return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
#else
        return OUString();
#endif
    }

    virtual OUString get_accessible_description() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        const char* pStr = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr;
        return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
#else
        return OUString();
#endif
    }

    virtual void set_accessible_relation_labeled_by(weld::Widget* pLabel) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        if (!pAtkObject)
            return;
@@ -2861,10 +3095,14 @@ public:
            atk_relation_set_add(pRelationSet, pRelation);
        }
        g_object_unref(pRelationSet);
#else
        (void)pLabel;
#endif
    }

    virtual void set_accessible_relation_label_for(weld::Widget* pLabeled) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
        if (!pAtkObject)
            return;
@@ -2881,15 +3119,27 @@ public:
            atk_relation_set_add(pRelationSet, pRelation);
        }
        g_object_unref(pRelationSet);
#else
        (void)pLabeled;
#endif
    }

    virtual bool get_extents_relative_to(const weld::Widget& rRelative, int& x, int &y, int& width, int &height) const override
    {
        //for toplevel windows this is sadly futile under wayland, so we can't tell where a dialog is in order to allow
        //the document underneath to auto-scroll to place content in a visible location
#if !GTK_CHECK_VERSION(4, 0, 0)
        bool ret = gtk_widget_translate_coordinates(m_pWidget,
                                                    dynamic_cast<const GtkInstanceWidget&>(rRelative).getWidget(),
                                                    0, 0, &x, &y);
#else
        double fX(0.0), fY(0.0);
        bool ret = gtk_widget_translate_coordinates(m_pWidget,
                                                    dynamic_cast<const GtkInstanceWidget&>(rRelative).getWidget(),
                                                    0, 0, &fX, &fY);
        x = fX;
        y = fY;
#endif
        width = gtk_widget_get_allocated_width(m_pWidget);
        height = gtk_widget_get_allocated_height(m_pWidget);
        return ret;
@@ -2910,13 +3160,21 @@ public:

    virtual OString get_buildable_name() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(m_pWidget));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(m_pWidget));
#endif
        return OString(pStr, pStr ? strlen(pStr) : 0);
    }

    virtual void set_buildable_name(const OString& rId) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_buildable_set_name(GTK_BUILDABLE(m_pWidget), rId.getStr());
#else
        (void)rId;
#endif
    }

    virtual void set_help_id(const OString& rHelpId) override
@@ -2939,7 +3197,11 @@ public:

    GtkWindow* getWindow()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget));
#else
        return GTK_WINDOW(gtk_widget_get_root(m_pWidget));
#endif
    }

    virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
@@ -2974,6 +3236,7 @@ public:
        m_aSizeAllocateHdl.Call(Size(nWidth, nHeight));
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    bool signal_key(const GdkEventKey* pEvent)
    {
        if (pEvent->type == GDK_KEY_PRESS && m_aKeyPressHdl.IsSet())
@@ -2988,20 +3251,29 @@ public:
        }
        return false;
    }
#endif

    virtual void grab_add() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_grab_add(m_pWidget);
#endif
    }

    virtual bool has_grab() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return gtk_widget_has_grab(m_pWidget);
#else
        return false;
#endif
    }

    virtual void grab_remove() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_grab_remove(m_pWidget);
#endif
    }

    virtual bool get_direction() const override
@@ -3017,7 +3289,9 @@ public:
    virtual void freeze() override
    {
        ++m_nFreezeCount;
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_freeze_child_notify(m_pWidget);
#endif
        g_object_freeze_notify(G_OBJECT(m_pWidget));
    }

@@ -3025,7 +3299,9 @@ public:
    {
        --m_nFreezeCount;
        g_object_thaw_notify(G_OBJECT(m_pWidget));
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_thaw_child_notify(m_pWidget);
#endif
    }

    virtual void set_busy_cursor(bool bBusy) override
@@ -3051,6 +3327,7 @@ public:
        if (!m_xDropTarget)
        {
            m_xDropTarget.set(new GtkInstDropTarget);
#if !GTK_CHECK_VERSION(4, 0, 0)
            if (!gtk_drag_dest_get_track_motion(m_pWidget))
            {
                gtk_drag_dest_set(m_pWidget, GtkDestDefaults(0), nullptr, 0, GdkDragAction(0));
@@ -3060,6 +3337,7 @@ public:
            m_nDragDropSignalId = g_signal_connect(m_pWidget, "drag-drop", G_CALLBACK(signalDragDrop), this);
            m_nDragDropReceivedSignalId = g_signal_connect(m_pWidget, "drag-data-received", G_CALLBACK(signalDragDropReceived), this);
            m_nDragLeaveSignalId = g_signal_connect(m_pWidget, "drag-leave", G_CALLBACK(signalDragLeave), this);
#endif
        }
        return m_xDropTarget;
    }
@@ -3153,6 +3431,7 @@ public:

        do_set_background(COL_AUTO);

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (m_pMouseEventBox && m_pMouseEventBox != m_pWidget)
        {
            // put things back they way we found them
@@ -3167,11 +3446,16 @@ public:
            // coverity[freed_arg : FALSE] - this does not free m_pWidget, it is reffed by pParent
            g_object_unref(m_pWidget);
        }
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (m_bTakeOwnership)
            gtk_widget_destroy(m_pWidget);
        else
            g_object_unref(m_pWidget);
#else
        g_object_unref(m_pWidget);
#endif
    }

    virtual void disable_notify_events()
@@ -3247,10 +3531,16 @@ public:
                                      aOrigAllocation.y,
                                      static_cast<int>(aSize.Width()),
                                      static_cast<int>(aSize.Height()) };
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_size_allocate(m_pWidget, &aNewAllocation);
#else
        gtk_widget_size_allocate(m_pWidget, &aNewAllocation, 0);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_CONTAINER(m_pWidget))
            gtk_container_resize_children(GTK_CONTAINER(m_pWidget));
#endif

        VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
        xOutput->SetOutputSizePixel(aSize);
@@ -3259,12 +3549,18 @@ public:
        cairo_surface_t* pSurface = get_underlying_cairo_surface(*xOutput);
        cairo_t* cr = cairo_create(pSurface);

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_draw(m_pWidget, cr);
#endif

        cairo_destroy(cr);

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_set_allocation(m_pWidget, &aOrigAllocation);
        gtk_widget_size_allocate(m_pWidget, &aOrigAllocation);
#else
        gtk_widget_size_allocate(m_pWidget, &aOrigAllocation, 0);
#endif

        rOutput.DrawOutDev(rPos, aSize, Point(), aSize, *xOutput);

@@ -3284,6 +3580,7 @@ public:

IMPL_LINK(GtkInstanceWidget, async_drag_cancel, void*, arg, void)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    m_pDragCancelEvent = nullptr;
    GdkDragContext* context = static_cast<GdkDragContext*>(arg);

@@ -3295,6 +3592,9 @@ IMPL_LINK(GtkInstanceWidget, async_drag_cancel, void*, arg, void)
    g_signal_emit_by_name(context, "cancel", 0, GDK_DRAG_CANCEL_USER_CANCELLED);

    g_object_unref(context);
#else
    (void)arg;
#endif
}

namespace
@@ -3461,7 +3761,7 @@ namespace
            return nullptr;

        GdkPixbuf* pixbuf = nullptr;

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (rIconName.lastIndexOf('.') != rIconName.getLength() - 4)
        {
            assert((rIconName== "dialog-warning" || rIconName== "dialog-error" || rIconName== "dialog-information") &&
@@ -3479,7 +3779,7 @@ namespace
                                       rSettings.GetStyleSettings().DetermineIconTheme(),
                                       rSettings.GetUILanguageTag().getBcp47());
        }

#endif
        return pixbuf;
    }

@@ -3498,11 +3798,14 @@ namespace
        cairo_set_source_surface(cr, surface, 0, 0);
        cairo_paint(cr);
        cairo_destroy(cr);
#if !GTK_CHECK_VERSION(4, 0, 0)
        pImage = gtk_image_new_from_surface(target);
#endif
        cairo_surface_destroy(target);
        return pImage;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
class MenuHelper
{
protected:
@@ -3541,7 +3844,11 @@ public:

    void add_to_map(GtkMenuItem* pMenuItem)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pMenuItem));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pMenuItem));
#endif
        OString id(pStr, pStr ? strlen(pStr) : 0);
        m_aMap[id] = pMenuItem;
        g_signal_connect(pMenuItem, "activate", G_CALLBACK(signalActivate), this);
@@ -3549,7 +3856,11 @@ public:

    void remove_from_map(GtkMenuItem* pMenuItem)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pMenuItem));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pMenuItem));
#endif
        OString id(pStr, pStr ? strlen(pStr) : 0);
        auto iter = m_aMap.find(id);
        g_signal_handlers_disconnect_by_data(pMenuItem, this);
@@ -3591,10 +3902,12 @@ public:
            GtkBox *pBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6));
            GtkWidget *pLabel = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr());
            pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new() : gtk_menu_item_new();
#if !GTK_CHECK_VERSION(4, 0, 0)
            gtk_box_pack_start(pBox, pImage, true, true, 0);
            gtk_box_pack_start(pBox, pLabel, true, true, 0);
            gtk_container_add(GTK_CONTAINER(pItem), GTK_WIDGET(pBox));
            gtk_widget_show_all(pItem);
#endif
        }
        else
        {
@@ -3707,6 +4020,7 @@ public:
            gtk_widget_destroy(GTK_WIDGET(m_pMenu));
    }
};
#endif

class GtkInstanceSizeGroup : public weld::SizeGroup
{
@@ -3800,7 +4114,11 @@ IMPL_LINK_NOARG(ChildFrame, ImplHandleLayoutTimerHdl, Timer*, void)
class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Container
{
private:
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkContainer* m_pContainer;
#else
    GtkWidget* m_pContainer;
#endif
    gulong m_nSetFocusChildSignalId;
    bool m_bChildHasFocus;

@@ -3808,8 +4126,12 @@ private:
    {
        if (GTK_IS_BUTTON(pWidget))
            g_object_set(G_OBJECT(pWidget), "has-default", false, nullptr);
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_CONTAINER(pWidget))
            gtk_container_forall(GTK_CONTAINER(pWidget), implResetDefault, user_data);
#else
        (void)user_data;
#endif
    }

    void signal_set_focus_child(bool bChildHasFocus)
@@ -3821,15 +4143,22 @@ private:
        }
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static void signalSetFocusChild(GtkContainer*, GtkWidget* pChild, gpointer widget)
    {
        GtkInstanceContainer* pThis = static_cast<GtkInstanceContainer*>(widget);
        pThis->signal_set_focus_child(pChild != nullptr);
    }
#endif

public:
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkInstanceContainer(GtkContainer* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
        : GtkInstanceWidget(GTK_WIDGET(pContainer), pBuilder, bTakeOwnership)
#else
    GtkInstanceContainer(GtkWidget* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
        : GtkInstanceWidget(pContainer, pBuilder, bTakeOwnership)
#endif
        , m_pContainer(pContainer)
        , m_nSetFocusChildSignalId(0)
        , m_bChildHasFocus(false)
@@ -3838,16 +4167,21 @@ public:

    virtual void connect_container_focus_changed(const Link<Container&, void>& rLink) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_nSetFocusChildSignalId)
            m_nSetFocusChildSignalId = g_signal_connect(G_OBJECT(m_pContainer), "set-focus-child", G_CALLBACK(signalSetFocusChild), this);
#endif
        weld::Container::connect_container_focus_changed(rLink);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkContainer* getContainer() { return m_pContainer; }
#endif

    virtual void child_grab_focus() override
    {
        gtk_widget_grab_focus(m_pWidget);
#if !GTK_CHECK_VERSION(4, 0, 0)
        bool bHasFocusChild = gtk_container_get_focus_child(m_pContainer);
        if (!bHasFocusChild)
        {
@@ -3862,10 +4196,12 @@ public:
        }
        if (bHasFocusChild)
            gtk_widget_child_focus(gtk_container_get_focus_child(GTK_CONTAINER(m_pWidget)), GTK_DIR_TAB_FORWARD);
#endif
    }

    virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pWidget);
        assert(pGtkWidget);
        GtkWidget* pChild = pGtkWidget->getWidget();
@@ -3877,6 +4213,10 @@ public:
        if (pNewGtkParent)
            gtk_container_add(pNewGtkParent->getContainer(), pChild);
        g_object_unref(pChild);
#else
        (void)pWidget;
        (void)pNewParent;
#endif
    }

    virtual void recursively_unset_default_buttons() override
@@ -3886,6 +4226,7 @@ public:

    virtual css::uno::Reference<css::awt::XWindow> CreateChildFrame() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // This will cause a GtkSalFrame to be created. With WB_SYSTEMCHILDWINDOW set it
        // will create a toplevel GtkEventBox window
        auto xEmbedWindow = VclPtr<ChildFrame>::Create(ImplGetDefaultWindow(), WB_SYSTEMCHILDWINDOW | WB_DIALOGCONTROL | WB_CHILDDLGCTRL);
@@ -3912,6 +4253,9 @@ public:
        xEmbedWindow->Show(true, ShowFlags::NoActivate);
        css::uno::Reference<css::awt::XWindow> xWindow(xEmbedWindow->GetComponentInterface(), css::uno::UNO_QUERY);
        return xWindow;
#else
        return nullptr;
#endif
    }

    virtual ~GtkInstanceContainer() override
@@ -3928,7 +4272,11 @@ std::unique_ptr<weld::Container> GtkInstanceWidget::weld_parent() const
    GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
    if (!pParent)
        return nullptr;
#if !GTK_CHECK_VERSION(4, 0, 0)
    return std::make_unique<GtkInstanceContainer>(GTK_CONTAINER(pParent), m_pBuilder, false);
#else
    return std::make_unique<GtkInstanceContainer>(pParent, m_pBuilder, false);
#endif
}

namespace {
@@ -3992,6 +4340,7 @@ bool sortButtons(const GtkWidget* pA, const GtkWidget* pB)

void sort_native_button_order(GtkBox* pContainer)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    std::vector<GtkWidget*> aChildren;
    GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pContainer));
    for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild))
@@ -4003,6 +4352,9 @@ void sort_native_button_order(GtkBox* pContainer)

    for (size_t pos = 0; pos < aChildren.size(); ++pos)
        gtk_box_reorder_child(pContainer, aChildren[pos], pos);
#else
    (void)pContainer;
#endif
}

class GtkInstanceBox : public GtkInstanceContainer, public virtual weld::Box
@@ -4012,17 +4364,26 @@ private:

public:
    GtkInstanceBox(GtkBox* pBox, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pBox), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pBox), pBuilder, bTakeOwnership)
#endif
        , m_pBox(pBox)
    {
    }

    virtual void reorder_child(weld::Widget* pWidget, int nNewPosition) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pWidget);
        assert(pGtkWidget);
        GtkWidget* pChild = pGtkWidget->getWidget();
        gtk_box_reorder_child(m_pBox, pChild, nNewPosition);
#else
        (void)pWidget;
        (void)nNewPosition;
#endif
    }

    virtual void sort_native_button_order() override
@@ -4037,6 +4398,7 @@ namespace
{
    Point get_csd_offset(GtkWidget* pTopLevel)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // try and omit drawing CSD under wayland
        GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pTopLevel));
        GList* pChild = g_list_first(pChildren);
@@ -4055,14 +4417,26 @@ namespace
        y -= totalborder;

        return Point(x, y);
#else
        (void)pTopLevel;
        return Point(0, 0);
#endif
    }

    void do_collect_screenshot_data(GtkWidget* pItem, gpointer data)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(pItem);

        int x, y;
        gtk_widget_translate_coordinates(pItem, pTopLevel, 0, 0, &x, &y);
#else
        GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(pItem));

        double x, y;
        gtk_widget_translate_coordinates(pItem, pTopLevel, 0, 0, &x, &y);
#endif


        Point aOffset = get_csd_offset(pTopLevel);

@@ -4078,17 +4452,24 @@ namespace
            pCollection->emplace_back(::get_help_id(pItem), aCurrentRange);
        }

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_CONTAINER(pItem))
            gtk_container_forall(GTK_CONTAINER(pItem), do_collect_screenshot_data, data);
#endif
    }

    tools::Rectangle get_monitor_workarea(GtkWidget* pWindow)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GdkScreen* pScreen = gtk_widget_get_screen(pWindow);
        gint nMonitor = gdk_screen_get_monitor_at_window(pScreen, gtk_widget_get_window(pWindow));
        GdkRectangle aRect;
        gdk_screen_get_monitor_workarea(pScreen, nMonitor, &aRect);
        return tools::Rectangle(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height);
#else
        (void)pWindow;
        return tools::Rectangle();
#endif
    }


@@ -4099,12 +4480,14 @@ private:
    rtl::Reference<SalGtkXWindow> m_xWindow; //uno api
    gulong m_nToplevelFocusChangedSignalId;

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean help_pressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer widget)
    {
        GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget);
        pThis->help();
        return true;
    }
#endif

    static void signalToplevelFocusChanged(GtkWindow*, GParamSpec*, gpointer widget)
    {
@@ -4127,10 +4510,15 @@ protected:
    void help();
public:
    GtkInstanceWindow(GtkWindow* pWindow, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pWindow), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pWindow), pBuilder, bTakeOwnership)
#endif
        , m_pWindow(pWindow)
        , m_nToplevelFocusChangedSignalId(0)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        const bool bIsFrameWeld = pBuilder == nullptr;
        if (!bIsFrameWeld)
        {
@@ -4140,6 +4528,7 @@ public:
            gtk_accel_group_connect(pGroup, GDK_KEY_F1, static_cast<GdkModifierType>(0), GTK_ACCEL_LOCKED, closure);
            gtk_window_add_accel_group(pWindow, pGroup);
        }
#endif
    }

    virtual void set_title(const OUString& rTitle) override
@@ -4171,12 +4560,19 @@ public:

    virtual void resize_to_request() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_window_resize(m_pWindow, 1, 1);
#endif
    }

    virtual void window_move(int x, int y) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_window_move(m_pWindow, x, y);
#else
        (void)x;
        (void)y;
#endif
    }

    virtual SystemEnvData get_system_data() const override
@@ -4187,15 +4583,21 @@ public:

    virtual Size get_size() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        int current_width, current_height;
        gtk_window_get_size(m_pWindow, &current_width, &current_height);
        return Size(current_width, current_height);
#else
        return Size(0, 0);
#endif
    }

    virtual Point get_position() const override
    {
        int current_x, current_y;
        int current_x(0), current_y(0);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_window_get_position(m_pWindow, &current_x, &current_y);
#endif
        return Point(current_x, current_y);
    }

@@ -4206,10 +4608,14 @@ public:

    virtual void set_centered_on_parent(bool bTrackGeometryRequests) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (bTrackGeometryRequests)
            gtk_window_set_position(m_pWindow, GTK_WIN_POS_CENTER_ALWAYS);
        else
            gtk_window_set_position(m_pWindow, GTK_WIN_POS_CENTER_ON_PARENT);
#else
        (void)bTrackGeometryRequests;
#endif
    }

    virtual bool get_resizable() const override
@@ -4219,7 +4625,11 @@ public:

    virtual bool has_toplevel_focus() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return gtk_window_has_toplevel_focus(m_pWindow);
#else
        return false;
#endif
    }

    virtual void present() override
@@ -4247,10 +4657,12 @@ public:
                gtk_window_unmaximize(m_pWindow);
        }

#if !GTK_CHECK_VERSION(4, 0, 0)
        if (isPositioningAllowed() && (nMask & WindowStateMask::X && nMask & WindowStateMask::Y))
        {
            gtk_window_move(m_pWindow, aData.GetX(), aData.GetY());
        }
#endif
    }

    virtual OString get_window_state(WindowStateMask nMask) const override
@@ -4312,6 +4724,7 @@ public:

    virtual VclPtr<VirtualDevice> screenshot() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // detect if we have to manually setup its size
        bool bAlreadyRealized = gtk_widget_get_realized(GTK_WIDGET(m_pWindow));
        // has to be visible for draw to work
@@ -4350,13 +4763,18 @@ public:
            gtk_widget_unrealize(GTK_WIDGET(m_pWindow));

        return xOutput;
#else
        return nullptr;
#endif
    }

    virtual weld::ScreenShotCollection collect_screenshot_data() override
    {
        weld::ScreenShotCollection aRet;

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_foreach(GTK_CONTAINER(m_pWindow), do_collect_screenshot_data, &aRet);
#endif

        return aRet;
    }
@@ -4407,6 +4825,7 @@ struct DialogRunner
    static void signal_response(GtkDialog*, gint nResponseId, gpointer data);
    static void signal_cancel(GtkAssistant*, gpointer data);

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signal_delete(GtkDialog* pDialog, GdkEventAny*, gpointer data)
    {
        DialogRunner* pThis = static_cast<DialogRunner*>(data);
@@ -4419,6 +4838,7 @@ struct DialogRunner
            pThis->loop_quit();
        return true; /* Do not destroy */
    }
#endif

    static void signal_destroy(GtkDialog*, gpointer data)
    {
@@ -4466,15 +4886,21 @@ struct DialogRunner

        gulong nSignalResponseId = GTK_IS_DIALOG(m_pDialog) ? g_signal_connect(m_pDialog, "response", G_CALLBACK(signal_response), this) : 0;
        gulong nSignalCancelId = GTK_IS_ASSISTANT(m_pDialog) ? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signal_cancel), this) : 0;
#if !GTK_CHECK_VERSION(4, 0, 0)
        gulong nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signal_delete), this);
#endif
        gulong nSignalDestroyId = g_signal_connect(m_pDialog, "destroy", G_CALLBACK(signal_destroy), this);

        m_pLoop = g_main_loop_new(nullptr, false);
        m_nResponseId = GTK_RESPONSE_NONE;

#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_leave();
#endif
        g_main_loop_run(m_pLoop);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_enter();
#endif

        g_main_loop_unref(m_pLoop);

@@ -4487,7 +4913,9 @@ struct DialogRunner
            g_signal_handler_disconnect(m_pDialog, nSignalResponseId);
        if (nSignalCancelId)
            g_signal_handler_disconnect(m_pDialog, nSignalCancelId);
#if !GTK_CHECK_VERSION(4, 0, 0)
        g_signal_handler_disconnect(m_pDialog, nSignalDeleteId);
#endif
        g_signal_handler_disconnect(m_pDialog, nSignalDestroyId);

        dec_modal_count();
@@ -4516,6 +4944,7 @@ typedef std::set<GtkWidget*> winset;

namespace
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    void hideUnless(GtkContainer *pTop, const winset& rVisibleWidgets,
        std::vector<GtkWidget*> &rWasVisibleWidgets)
    {
@@ -4538,6 +4967,7 @@ namespace
        }
        g_list_free(pChildren);
    }
#endif

class GtkInstanceButton;

@@ -4586,6 +5016,7 @@ private:
        pThis->close(false);
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalAsyncDelete(GtkWidget* pDialog, GdkEventAny*, gpointer widget)
    {
        GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
@@ -4596,6 +5027,7 @@ private:
        }
        return true; /* Do not destroy */
    }
#endif

    static int GtkToVcl(int ret)
    {
@@ -4635,12 +5067,15 @@ private:

    void asyncresponse(gint ret);

#if !GTK_CHECK_VERSION(4, 0, 0)
    static void signalActivate(GtkMenuItem*, gpointer data)
    {
        bool* pActivate = static_cast<bool*>(data);
        *pActivate = true;
    }
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    bool signal_screenshot_popup_menu(const GdkEventButton* pEvent)
    {
        GtkWidget *pMenu = gtk_menu_new();
@@ -4692,13 +5127,20 @@ private:

        return false;
    }
#endif

    static gboolean signalScreenshotPopupMenu(GtkWidget*, gpointer widget)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
        return pThis->signal_screenshot_popup_menu(nullptr);
#else
        (void)widget;
        return false;
#endif
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalScreenshotButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
    {
        GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
@@ -4715,6 +5157,7 @@ private:
        }
        return false;
    }
#endif

public:
    GtkInstanceDialog(GtkWindow* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
@@ -4737,7 +5180,9 @@ public:
        if (bScreenshotMode)
        {
            g_signal_connect(m_pDialog, "popup-menu", G_CALLBACK(signalScreenshotPopupMenu), this);
#if !GTK_CHECK_VERSION(4, 0, 0)
            g_signal_connect(m_pDialog, "button-press-event", G_CALLBACK(signalScreenshotButton), this);
#endif
        }
    }

@@ -4754,7 +5199,9 @@ public:

        m_nResponseSignalId = GTK_IS_DIALOG(m_pDialog) ? g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this) : 0;
        m_nCancelSignalId = GTK_IS_ASSISTANT(m_pDialog) ? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signalAsyncCancel), this) : 0;
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this);
#endif

        return true;
    }
@@ -4775,7 +5222,9 @@ public:

        m_nResponseSignalId = GTK_IS_DIALOG(m_pDialog) ? g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this) : 0;
        m_nCancelSignalId = GTK_IS_ASSISTANT(m_pDialog) ? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signalAsyncCancel), this) : 0;
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this);
#endif

        return true;
    }
@@ -4788,8 +5237,10 @@ public:
    {
        if (gtk_widget_get_visible(m_pWidget))
            return;
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_DIALOG(m_pDialog))
            sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog))));
#endif
        GtkInstanceWindow::show();
    }

@@ -4844,7 +5295,11 @@ public:

    virtual Container* weld_content_area() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return new GtkInstanceContainer(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog))), m_pBuilder, false);
#else
        return new GtkInstanceContainer(gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog)), m_pBuilder, false);
#endif
    }

    virtual void collapse(weld::Widget* pEdit, weld::Widget* pButton) override
@@ -4881,6 +5336,7 @@ public:
                break;
        }

#if !GTK_CHECK_VERSION(4, 0, 0)
        //hide everything except the aVisibleWidgets
        hideUnless(GTK_CONTAINER(pContentArea), aVisibleWidgets, m_aHiddenWidgets);

@@ -4889,6 +5345,7 @@ public:
        gtk_container_set_border_width(GTK_CONTAINER(m_pDialog), 0);
        if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))
            gtk_widget_hide(pActionArea);
#endif

        // calc's insert->function is springing back to its original size if the ref-button
        // is used to shrink the dialog down and then the user clicks in the calc area to do
@@ -4921,9 +5378,11 @@ public:

        gtk_widget_set_size_request(m_pRefEdit, m_nOldEditWidthReq, -1);
        m_pRefEdit = nullptr;
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_set_border_width(GTK_CONTAINER(m_pDialog), m_nOldBorderWidth);
        if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))
            gtk_widget_show(pActionArea);
#endif
        resize_to_request();
        present();
    }
@@ -5010,7 +5469,11 @@ public:

    virtual Container* weld_message_area() override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return new GtkInstanceContainer(GTK_CONTAINER(gtk_message_dialog_get_message_area(m_pMessageDialog)), m_pBuilder, false);
#else
        return new GtkInstanceContainer(gtk_message_dialog_get_message_area(m_pMessageDialog), m_pBuilder, false);
#endif
    }
};

@@ -5020,7 +5483,11 @@ private:
    GtkAssistant* m_pAssistant;
    GtkWidget* m_pSidebar;
    GtkWidget* m_pSidebarEventBox;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkButtonBox* m_pButtonBox;
#else
    GtkBox* m_pButtonBox;
#endif
    GtkButton* m_pHelp;
    GtkButton* m_pBack;
    GtkButton* m_pNext;
@@ -5036,7 +5503,11 @@ private:
        for (int i = 0; i < nPages; ++i)
        {
            GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, i);
#if !GTK_CHECK_VERSION(4, 0, 0)
            const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pPage));
#else
            const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pPage));
#endif
            if (g_strcmp0(pStr, rIdent.getStr()) == 0)
                return i;
        }
@@ -5047,7 +5518,9 @@ private:
    {
        if (GTK_IS_LABEL(pWidget))
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            gtk_label_set_line_wrap(GTK_LABEL(pWidget), true);
#endif
            gtk_label_set_width_chars(GTK_LABEL(pWidget), 22);
            gtk_label_set_max_width_chars(GTK_LABEL(pWidget), 22);
        }
@@ -5055,13 +5528,20 @@ private:

    static void find_sidebar(GtkWidget *pWidget, gpointer user_data)
    {
        if (g_strcmp0(gtk_buildable_get_name(GTK_BUILDABLE(pWidget)), "sidebar") == 0)
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pWidget));
#endif
        if (g_strcmp0(pStr, "sidebar") == 0)
        {
            GtkWidget **ppSidebar = static_cast<GtkWidget**>(user_data);
            *ppSidebar = pWidget;
        }
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (GTK_IS_CONTAINER(pWidget))
            gtk_container_forall(GTK_CONTAINER(pWidget), find_sidebar, user_data);
#endif
    }

    static void signalHelpClicked(GtkButton*, gpointer widget)
@@ -5075,6 +5555,7 @@ private:
        help();
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static gboolean signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
    {
        GtkInstanceAssistant* pThis = static_cast<GtkInstanceAssistant*>(widget);
@@ -5089,6 +5570,7 @@ private:
        GtkAllocation allocation;

        int nPageIndex = 0;
#if !GTK_CHECK_VERSION(4, 0, 0)
        GList* pChildren = gtk_container_get_children(GTK_CONTAINER(m_pSidebar));
        for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild))
        {
@@ -5124,6 +5606,7 @@ private:
            ++nPageIndex;
        }
        g_list_free(pChildren);
#endif

        if (nNewCurrentPage != -1 && nNewCurrentPage != get_current_page())
        {
@@ -5134,6 +5617,7 @@ private:

        return false;
    }
#endif

public:
    GtkInstanceAssistant(GtkAssistant* pAssistant, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
@@ -5141,11 +5625,16 @@ public:
        , m_pAssistant(pAssistant)
        , m_pSidebar(nullptr)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_pButtonBox = GTK_BUTTON_BOX(gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL));
        gtk_button_box_set_layout(m_pButtonBox, GTK_BUTTONBOX_END);
        gtk_box_set_spacing(GTK_BOX(m_pButtonBox), 6);
#else
        m_pButtonBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6));
#endif

        m_pBack = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Back)).getStr()));
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_set_can_default(GTK_WIDGET(m_pBack), true);
        gtk_buildable_set_name(GTK_BUILDABLE(m_pBack), "previous");
        gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pBack), false, false, 0);
@@ -5187,12 +5676,17 @@ public:
        }
        g_list_free(pChildren);

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_show_all(GTK_WIDGET(m_pButtonBox));
#else
        gtk_widget_show(GTK_WIDGET(m_pButtonBox));
#endif

        find_sidebar(GTK_WIDGET(m_pAssistant), &m_pSidebar);

        m_pSidebarEventBox = ::ensureEventWidget(m_pSidebar);
        m_nButtonPressSignalId = m_pSidebarEventBox ? g_signal_connect(m_pSidebarEventBox, "button-press-event", G_CALLBACK(signalButton), this) : 0;
#endif
    }

    virtual int get_current_page() const override
@@ -5208,7 +5702,11 @@ public:
    virtual OString get_page_ident(int nPage) const override
    {
        const GtkWidget* pWidget = gtk_assistant_get_nth_page(m_pAssistant, nPage);
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pWidget));
#endif
        return OString(pStr, pStr ? strlen(pStr) : 0);
    }

@@ -5246,7 +5744,9 @@ public:
        GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nIndex);
        gtk_assistant_set_page_title(m_pAssistant, pPage,
                                     OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr());
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_forall(GTK_CONTAINER(m_pSidebar), wrap_sidebar_label, nullptr);
#endif
    }

    virtual OUString get_page_title(const OString& rIdent) const override
@@ -5281,7 +5781,9 @@ public:
        gtk_assistant_insert_page(m_pAssistant, pPage, nNewIndex);
        gtk_assistant_set_page_type(m_pAssistant, pPage, GTK_ASSISTANT_PAGE_CUSTOM);
        gtk_assistant_set_page_title(m_pAssistant, pPage, sTitle.getStr());
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_forall(GTK_CONTAINER(m_pSidebar), wrap_sidebar_label, nullptr);
#endif
        g_object_unref(pPage);
    }

@@ -5290,14 +5792,22 @@ public:
        disable_notify_events();

        GtkWidget *pChild = gtk_grid_new();
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_buildable_set_name(GTK_BUILDABLE(pChild), rIdent.getStr());
#else
        (void)rIdent;
#endif
        gtk_assistant_append_page(m_pAssistant, pChild);
        gtk_assistant_set_page_type(m_pAssistant, pChild, GTK_ASSISTANT_PAGE_CUSTOM);
        gtk_widget_show(pChild);

        enable_notify_events();

#if !GTK_CHECK_VERSION(4, 0, 0)
        m_aPages.emplace_back(new GtkInstanceContainer(GTK_CONTAINER(pChild), m_pBuilder, false));
#else
        m_aPages.emplace_back(new GtkInstanceContainer(pChild, m_pBuilder, false));
#endif

        return m_aPages.back().get();
    }
@@ -5338,7 +5848,11 @@ private:
    GtkFrame* m_pFrame;
public:
    GtkInstanceFrame(GtkFrame* pFrame, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pFrame), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pFrame), pBuilder, bTakeOwnership)
#endif
        , m_pFrame(pFrame)
    {
    }
@@ -5363,7 +5877,11 @@ private:
    GtkPaned* m_pPaned;
public:
    GtkInstancePaned(GtkPaned* pPaned, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pPaned), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pPaned), pBuilder, bTakeOwnership)
#endif
        , m_pPaned(pPaned)
    {
    }
@@ -5393,7 +5911,9 @@ namespace {

struct CrippledViewport
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkViewport viewport;
#endif

    GtkAdjustment  *hadjustment;
    GtkAdjustment  *vadjustment;
@@ -5717,7 +6237,9 @@ void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *kla
    cell_class->get_preferred_width_for_height = custom_cell_renderer_surface_get_preferred_width_for_height;
    cell_class->get_preferred_height_for_width = custom_cell_renderer_surface_get_preferred_height_for_width;

#if !GTK_CHECK_VERSION(4, 0, 0)
    cell_class->render = custom_cell_renderer_surface_render;
#endif

    g_object_class_install_property(object_class,
                                   PROP_ID,
@@ -5734,7 +6256,9 @@ void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *kla
                                                        "The GtkInstanceTreeView",
                                                        G_PARAM_READWRITE));

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_cell_renderer_class_set_accessible_type(cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE);
#endif
}

static GtkCellRenderer* custom_cell_renderer_surface_new()
@@ -5880,7 +6404,11 @@ private:

public:
    GtkInstanceScrolledWindow(GtkScrolledWindow* pScrolledWindow, GtkInstanceBuilder* pBuilder, bool bTakeOwnership, bool bUserManagedScrolling)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pScrolledWindow), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pScrolledWindow), pBuilder, bTakeOwnership)
#endif
        , m_pScrolledWindow(pScrolledWindow)
        , m_pOrigViewport(nullptr)
        , m_pScrollBarCssProvider(nullptr)
@@ -5896,6 +6424,7 @@ public:
    void set_user_managed_scrolling()
    {
        disable_notify_events();
#if !GTK_CHECK_VERSION(4, 0, 0)
        //remove the original viewport and replace it with our bodged one which
        //doesn't do any scrolling and expects its child to figure it out somehow
        assert(!m_pOrigViewport);
@@ -5912,6 +6441,7 @@ public:
        gtk_container_add(GTK_CONTAINER(pNewViewport), pChild);
        g_object_unref(pChild);
        m_pOrigViewport = pViewport;
#endif
        enable_notify_events();
    }

@@ -6133,7 +6663,11 @@ public:
                           "scrollbar contents button { color: #000000; } "
                           "scrollbar contents button:disabled { color: #7f7f7f; }";
        OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(m_pScrollBarCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
#else
        gtk_css_provider_load_from_data(m_pScrollBarCssProvider, aResult.getStr(), aResult.getLength());
#endif

        gtk_style_context_add_provider(pHorzContext, GTK_STYLE_PROVIDER(m_pScrollBarCssProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
@@ -6161,6 +6695,7 @@ public:
        if (!m_pOrigViewport)
            return;

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkInstanceContainer::disable_notify_events();

        // force in new adjustment to drop the built-in handlers on value-changed
@@ -6191,6 +6726,7 @@ public:
        g_object_unref(pViewport);
        m_pOrigViewport = nullptr;
        GtkInstanceContainer::enable_notify_events();
#endif
    }
};

@@ -6323,7 +6859,11 @@ private:
    static OString get_page_ident(GtkNotebook *pNotebook, guint nPage)
    {
        const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(pNotebook, gtk_notebook_get_nth_page(pNotebook, nPage));
#if !GTK_CHECK_VERSION(4, 0, 0)
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget));
#else
        const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pTabWidget));
#endif
        return OString(pStr, pStr ? strlen(pStr) : 0);
    }

@@ -6333,7 +6873,11 @@ private:
        for (gint i = 0; i < nPages; ++i)
        {
            const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(pNotebook, gtk_notebook_get_nth_page(pNotebook, i));
#if !GTK_CHECK_VERSION(4, 0, 0)
            const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget));
#else
            const gchar* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pTabWidget));
#endif
            if (pStr && strcmp(pStr, rIdent.getStr()) == 0)
                return i;
        }
@@ -6379,7 +6923,9 @@ private:
        disable_notify_events();

        GtkWidget *pTabWidget = gtk_fixed_new();
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_buildable_set_name(GTK_BUILDABLE(pTabWidget), "useless");
#endif

        GtkWidget *pChild = gtk_grid_new();
        gtk_notebook_append_page(pNotebook, pChild, pTabWidget);
@@ -6394,8 +6940,11 @@ private:
        disable_notify_events();

        GtkWidget *pTabWidget = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rLabel).getStr());
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_buildable_set_name(GTK_BUILDABLE(pTabWidget), rIdent.getStr());

#else
        (void)rIdent;
#endif
        gtk_notebook_insert_page(pNotebook, pChild, pTabWidget, nPos);
        gtk_widget_show(pChild);
        gtk_widget_show(pTabWidget);
@@ -6412,6 +6961,7 @@ private:

    void make_overflow_boxes()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_pOverFlowBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
        GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pNotebook));
        gtk_container_add(GTK_CONTAINER(pParent), GTK_WIDGET(m_pOverFlowBox));
@@ -6422,6 +6972,7 @@ private:
        // coverity[freed_arg : FALSE] - this does not free m_pNotebook , it is reffed by pParent
        g_object_unref(m_pNotebook);
        gtk_widget_show(GTK_WIDGET(m_pOverFlowBox));
#endif
    }

    void split_notebooks()
@@ -6441,8 +6992,10 @@ private:
        // coverity[pass_freed_arg : FALSE] - m_pNotebook is not freed here
        gtk_notebook_set_scrollable(m_pNotebook, false);

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_freeze_child_notify(GTK_WIDGET(m_pNotebook));
        gtk_widget_freeze_child_notify(GTK_WIDGET(m_pOverFlowNotebook));
#endif

        gtk_widget_show(GTK_WIDGET(m_pOverFlowNotebook));

@@ -6520,8 +7073,10 @@ private:
        // remove it once we've measured it
        remove_page(m_pNotebook, "useless");

#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_thaw_child_notify(GTK_WIDGET(m_pOverFlowNotebook));
        gtk_widget_thaw_child_notify(GTK_WIDGET(m_pNotebook));
#endif

        m_bOverFlowBoxActive = true;
    }
@@ -6618,7 +7173,11 @@ private:

public:
    GtkInstanceNotebook(GtkNotebook* pNotebook, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pNotebook), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pNotebook), pBuilder, bTakeOwnership)
#endif
        , m_pNotebook(pNotebook)
        , m_pOverFlowBox(nullptr)
        , m_pOverFlowNotebook(GTK_NOTEBOOK(gtk_notebook_new()))
@@ -6633,7 +7192,9 @@ public:
        , m_nStartTabCount(0)
        , m_nEndTabCount(0)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_add_events(GTK_WIDGET(pNotebook), GDK_SCROLL_MASK);
#endif
        if (get_n_pages() > 6)
            m_nSizeAllocateSignalId = g_signal_connect_after(pNotebook, "size-allocate", G_CALLBACK(signalSizeAllocate), this);
        else
@@ -6645,7 +7206,11 @@ public:
        GtkStyleContext *pNotebookContext = gtk_widget_get_style_context(GTK_WIDGET(m_pOverFlowNotebook));
        GtkCssProvider *pProvider = gtk_css_provider_new();
        static const gchar data[] = "header.top > tabs > tab:checked { box-shadow: none; padding: 0 0 0 0; margin: 0 0 0 0; border-image: none; border-image-width: 0 0 0 0; background-image: none; background-color: transparent; border-radius: 0 0 0 0; border-width: 0 0 0 0; border-style: none; border-color: transparent; opacity: 0; min-height: 0; min-width: 0; }";
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(pProvider, data, -1, nullptr);
#else
        gtk_css_provider_load_from_data(pProvider, data, -1);
#endif
        gtk_style_context_add_provider(pNotebookContext, GTK_STYLE_PROVIDER(pProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    }
@@ -6726,35 +7291,40 @@ public:
        if (nPage < 0)
            return nullptr;

        GtkContainer* pChild;
        GtkWidget* pChild;
        if (m_bOverFlowBoxIsStart)
        {
            auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
            if (nPage < nOverFlowLen)
                pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage));
                pChild = gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage);
            else
            {
                nPage -= nOverFlowLen;
                pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage));
                pChild = gtk_notebook_get_nth_page(m_pNotebook, nPage);
            }
        }
        else
        {
            auto nMainLen = gtk_notebook_get_n_pages(m_pNotebook);
            if (nPage < nMainLen)
                pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage));
                pChild = gtk_notebook_get_nth_page(m_pNotebook, nPage);
            else
            {
                nPage -= nMainLen;
                pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage));
                pChild = gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage);
            }
        }

        unsigned int nPageIndex = static_cast<unsigned int>(nPage);
        if (m_aPages.size() < nPageIndex + 1)
            m_aPages.resize(nPageIndex + 1);
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (!m_aPages[nPageIndex])
            m_aPages[nPageIndex].reset(new GtkInstanceContainer(GTK_CONTAINER(pChild), m_pBuilder, false));
#else
        if (!m_aPages[nPageIndex])
            m_aPages[nPageIndex].reset(new GtkInstanceContainer(pChild, m_pBuilder, false));
#endif
        return m_aPages[nPageIndex].get();
    }

@@ -6839,14 +7409,20 @@ public:
        g_signal_handler_block(m_pNotebook, m_nFocusSignalId);
        g_signal_handler_block(m_pNotebook, m_nChangeCurrentPageId);
        g_signal_handler_block(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_freeze_child_notify(GTK_WIDGET(m_pOverFlowNotebook));
#endif
        g_object_freeze_notify(G_OBJECT(m_pOverFlowNotebook));
        GtkInstanceContainer::disable_notify_events();
    }

    virtual void enable_notify_events() override
    {
        GtkInstanceContainer::enable_notify_events();
        g_object_thaw_notify(G_OBJECT(m_pOverFlowNotebook));
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_thaw_child_notify(GTK_WIDGET(m_pOverFlowNotebook));
#endif
        g_signal_handler_unblock(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
        g_signal_handler_unblock(m_pNotebook, m_nSwitchPageSignalId);
        g_signal_handler_unblock(m_pNotebook, m_nFocusSignalId);
@@ -6900,14 +7476,20 @@ public:
        g_signal_handler_disconnect(m_pNotebook, m_nFocusSignalId);
        g_signal_handler_disconnect(m_pNotebook, m_nChangeCurrentPageId);
        g_signal_handler_disconnect(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_widget_destroy(GTK_WIDGET(m_pOverFlowNotebook));
#else
        g_clear_pointer(&m_pOverFlowNotebook, gtk_widget_unparent);
#endif
        if (m_pOverFlowBox)
        {
            // put it back to how we found it initially
            GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pOverFlowBox));
            g_object_ref(m_pNotebook);
#if !GTK_CHECK_VERSION(4, 0, 0)
            gtk_container_remove(GTK_CONTAINER(m_pOverFlowBox), GTK_WIDGET(m_pNotebook));
            gtk_container_add(GTK_CONTAINER(pParent), GTK_WIDGET(m_pNotebook));
#endif
            g_object_unref(m_pNotebook);

            gtk_widget_destroy(GTK_WIDGET(m_pOverFlowBox));
@@ -7019,6 +7601,7 @@ private:
            m_pMouseEventBox = m_pWidget;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    static GtkWidget* find_label_widget(GtkContainer* pContainer)
    {
        GList* pChildren = gtk_container_get_children(pContainer);
@@ -7042,6 +7625,7 @@ private:

        return pChild;
    }
#endif

    // See: https://developer.gnome.org/Buttons/
    void use_custom_content(VirtualDevice* pDevice)
@@ -7071,7 +7655,11 @@ private:
                           "background-size: " + OUString::number(aSize.Width()) + "px " + OUString::number(aSize.Height()) + "px; "
                           "border-radius: 0; border-width: 0; }";
        OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(m_pCustomCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
#else
        gtk_css_provider_load_from_data(m_pCustomCssProvider, aResult.getStr(), aResult.getLength());
#endif
        gtk_style_context_add_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pCustomCssProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    }
@@ -7079,6 +7667,7 @@ private:
protected:
    GtkWidget* get_label_widget()
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pButton));

        if (GTK_IS_CONTAINER(pChild))
@@ -7087,11 +7676,18 @@ protected:
            pChild = nullptr;

        return pChild;
#else
        return nullptr;
#endif
    }

public:
    GtkInstanceButton(GtkButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
#if !GTK_CHECK_VERSION(4, 0, 0)
        : GtkInstanceContainer(GTK_CONTAINER(pButton), pBuilder, bTakeOwnership)
#else
        : GtkInstanceContainer(GTK_WIDGET(pButton), pBuilder, bTakeOwnership)
#endif
        , m_pButton(pButton)
        , m_pCustomCssProvider(nullptr)
        , m_nSignalId(g_signal_connect(pButton, "clicked", G_CALLBACK(signalClicked), this))
@@ -7106,12 +7702,16 @@ public:

    virtual void set_image(VirtualDevice* pDevice) override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_button_set_always_show_image(m_pButton, true);
        gtk_button_set_image_position(m_pButton, GTK_POS_LEFT);
        if (pDevice)
            gtk_button_set_image(m_pButton, image_new_from_virtual_device(*pDevice));
        else
            gtk_button_set_image(m_pButton, nullptr);
#else
        (void)pDevice;
#endif
    }

    virtual void set_from_icon_name(const OUString& rIconName) override
@@ -7376,7 +7976,11 @@ public:

    virtual bool get_inconsistent() const override
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        return gtk_toggle_button_get_inconsistent(m_pToggleButton);
#else
        return false;
#endif
    }

    virtual void disable_notify_events() override
@@ -7399,19 +8003,28 @@ public:

void do_grab(GtkWidget* pWidget)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
    GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay);
    gdk_seat_grab(pSeat, gtk_widget_get_window(pWidget),
                  GDK_SEAT_CAPABILITY_ALL, true, nullptr, nullptr, nullptr, nullptr);
#else
    (void)pWidget;
#endif
}

void do_ungrab(GtkWidget* pWidget)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
    GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay);
    gdk_seat_ungrab(pSeat);
#else
    (void)pWidget;
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu)
{
    //place the toplevel just below its launcher button
@@ -7494,9 +8107,11 @@ GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu)

    return ePosUsed;
}
#endif

bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    static auto window_move_to_rect = reinterpret_cast<void (*) (GdkWindow*, const GdkRectangle*, GdkGravity,
                                                                 GdkGravity, GdkAnchorHints, gint, gint)>(
                                                                    dlsym(nullptr, "gdk_window_move_to_rect"));
@@ -7536,6 +8151,11 @@ bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu)
                        0, 0);

    return true;
#else
    (void)pComboBox;
    (void)pMenu;
    return true;
#endif
}

GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu)
@@ -7558,10 +8178,15 @@ GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu)
        pFrame->BlockTooltip();
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    // try with gdk_window_move_to_rect, but if that's not available, try without
    if (!show_menu_newer_gtk(pMenuButton, pMenu))
        ePosUsed = show_menu_older_gtk(pMenuButton, pMenu);
    gtk_widget_show_all(GTK_WIDGET(pMenu));
#else
    show_menu_newer_gtk(pMenuButton, pMenu);
    gtk_widget_show(GTK_WIDGET(pMenu));
#endif
    gtk_widget_grab_focus(GTK_WIDGET(pMenu));
    do_grab(GTK_WIDGET(pMenu));

@@ -8969,7 +9594,12 @@ public:
    {
        if (gtk_widget_has_focus(m_pWidget))
            return true;

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget);
#else
        GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(m_pWidget));
#endif
        if (!GTK_IS_WINDOW(pTopLevel))
            return false;
        GtkWidget* pFocus = gtk_window_get_focus(GTK_WINDOW(pTopLevel));
@@ -14649,7 +15279,11 @@ private:
                tree_view_set_cursor(m_nPrePopupCursorPos);

            // undo show_menu tooltip blocking
#if !GTK_CHECK_VERSION(4, 0, 0)
            GtkWidget* pParent = gtk_widget_get_toplevel(m_pToggleButton);
#else
            GtkWidget* pParent = GTK_WIDGET(gtk_widget_get_root(m_pToggleButton));
#endif
            GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(pParent) : nullptr;
            if (pFrame)
                pFrame->UnblockTooltip();
@@ -14845,7 +15479,11 @@ private:
    bool combobox_activate()
    {
        GtkWidget *pComboBox = GTK_WIDGET(m_pToggleButton);
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget *pToplevel = gtk_widget_get_toplevel(pComboBox);
#else
        GtkWidget *pToplevel = GTK_WIDGET(gtk_widget_get_root(pComboBox));
#endif
        GtkWindow *pWindow = GTK_WINDOW(pToplevel);
        if (!pWindow)
            return false;
@@ -16615,7 +17253,11 @@ private:

        if (gtk_expander_get_resize_toplevel(pExpander))
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            GtkWidget *pToplevel = gtk_widget_get_toplevel(GTK_WIDGET(pExpander));
#else
            GtkWidget *pToplevel = GTK_WIDGET(gtk_widget_get_root(pExpander));
#endif

            // https://gitlab.gnome.org/GNOME/gtk/issues/70
            // I imagine at some point a release with a fix will be available in which
@@ -17040,7 +17682,11 @@ private:
    {
        assert(!m_bAllowCycleFocusOut); // we only expect this to be called when this holds

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget);
#else
        GtkWidget *pToplevel = GTK_WIDGET(gtk_widget_get_root(m_pParentWidget));
#endif
        assert(pTopLevel);
        GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
        assert(pFrame);
@@ -17061,7 +17707,11 @@ private:
    {
        assert(!m_bAllowCycleFocusOut); // we only expect this to be called when this holds

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget);
#else
        GtkWidget *pToplevel = GTK_WIDGET(gtk_widget_get_root(m_pParentWidget));
#endif
        assert(pTopLevel);
        GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
        assert(pFrame);
@@ -17200,8 +17850,12 @@ public:
    //gtk impl emulate this by doing this implicitly at weld time
    void auto_add_parentless_widgets_to_container(GtkWidget* pWidget)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        if (gtk_widget_get_toplevel(pWidget) == pWidget && !GTK_IS_POPOVER(pWidget) && !GTK_IS_WINDOW(pWidget))
            gtk_container_add(GTK_CONTAINER(m_pParentWidget), pWidget);
#else
        (void)pWidget;
#endif
    }

    virtual std::unique_ptr<weld::MessageDialog> weld_message_dialog(const OString &id) override
@@ -17688,13 +18342,19 @@ void GtkInstanceWidget::help_hierarchy_foreach(const std::function<bool(const OS

weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkInstanceWidget* pParentWidget = dynamic_cast<GtkInstanceWidget*>(pParent);
    if (pParent && !pParentWidget) //remove when complete
        return SalInstance::CreateBuilder(pParent, rUIRoot, rUIFile);
    GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr;
    return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr, true);
#else
    return SalInstance::CreateBuilder(pParent, rUIRoot, rUIFile);
#endif
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
// tdf#135965 for the case of native widgets inside a GtkSalFrame and F1 pressed, run help
// on gtk widget help ids until we hit a vcl parent and then use vcl window help ids
gboolean GtkSalFrame::NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer pFrame)
@@ -17769,15 +18429,24 @@ weld::Builder* GtkInstance::CreateInterimBuilder(vcl::Window* pParent, const OUS
    // build the widget tree as a child of the GtkEventBox GtkGrid parent
    return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get(), bAllowCycleFocusOut);
}
#endif

weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkInstanceWidget* pParentInstance = dynamic_cast<GtkInstanceWidget*>(pParent);
    GtkWindow* pParentWindow = pParentInstance ? pParentInstance->getWindow() : nullptr;
    GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL,
                                                          VclToGtk(eMessageType), VclToGtk(eButtonsType), "%s",
                                                          OUStringToOString(rPrimaryMessage, RTL_TEXTENCODING_UTF8).getStr()));
    return new GtkInstanceMessageDialog(pMessageDialog, nullptr, true);
#else
    (void)pParent;
    (void)eMessageType;
    (void)eButtonsType;
    (void)rPrimaryMessage;
    return nullptr;
#endif
}

weld::Window* GtkInstance::GetFrameWeld(const css::uno::Reference<css::awt::XWindow>& rWindow)
@@ -17789,8 +18458,10 @@ weld::Window* GtkInstance::GetFrameWeld(const css::uno::Reference<css::awt::XWin

weld::Window* GtkSalFrame::GetFrameWeld() const
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (!m_xFrameWeld)
        m_xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(gtk_widget_get_toplevel(getWindow())), nullptr, false));
#endif
    return m_xFrameWeld.get();
}

@@ -17815,9 +18486,15 @@ void* GtkInstance::CreateGStreamerSink(const SystemChildWindow *pWindow)
    gtk_widget_set_hexpand(pGstWidget, true);

    GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(pParent), pGstWidget);
#endif
    g_object_unref(pGstWidget);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_show_all(pParent);
#else
    gtk_widget_show(pParent);
#endif

    return pVideosink;
#else
diff --git a/vcl/unx/gtk3/gtkobject.cxx b/vcl/unx/gtk3/gtkobject.cxx
index e6da598..80f981a 100644
--- a/vcl/unx/gtk3/gtkobject.cxx
+++ b/vcl/unx/gtk3/gtkobject.cxx
@@ -72,6 +72,7 @@ void GtkSalObjectBase::Init()
    m_aSystemData.pWidget       = m_pSocket;
    m_aSystemData.nScreen       = m_pParent->getXScreenNumber().getXScreen();
    m_aSystemData.toolkit       = SystemEnvData::Toolkit::Gtk;
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen* pScreen = gtk_widget_get_screen(m_pParent->getWindow());
    GdkVisual* pVisual = gdk_screen_get_system_visual(pScreen);

@@ -96,6 +97,7 @@ void GtkSalObjectBase::Init()
    g_signal_connect( G_OBJECT(m_pSocket), "button-release-event", G_CALLBACK(signalButton), this );
    g_signal_connect( G_OBJECT(m_pSocket), "focus-in-event", G_CALLBACK(signalFocus), this );
    g_signal_connect( G_OBJECT(m_pSocket), "focus-out-event", G_CALLBACK(signalFocus), this );
#endif
}

GtkSalObjectBase::~GtkSalObjectBase()
@@ -108,6 +110,7 @@ GtkSalObjectBase::~GtkSalObjectBase()

GtkSalObject::~GtkSalObject()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pSocket )
    {
        // remove socket from parent frame's fixed container
@@ -120,12 +123,15 @@ GtkSalObject::~GtkSalObject()
        if( m_pSocket )
            gtk_widget_destroy( m_pSocket );
    }
#endif
}

void GtkSalObject::ResetClipRegion()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pSocket )
        gdk_window_shape_combine_region( gtk_widget_get_window(m_pSocket), nullptr, 0, 0 );
#endif
}

void GtkSalObjectBase::BeginSetClipRegion( sal_uInt32 )
@@ -148,8 +154,10 @@ void GtkSalObjectBase::UnionClipRegion( tools::Long nX, tools::Long nY, tools::L

void GtkSalObject::EndSetClipRegion()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( m_pSocket )
        gdk_window_shape_combine_region( gtk_widget_get_window(m_pSocket), m_pRegion, 0, 0 );
#endif
}

void GtkSalObject::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight)
@@ -159,7 +167,9 @@ void GtkSalObject::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth
        GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pSocket));
        gtk_fixed_move( pContainer, m_pSocket, nX, nY );
        gtk_widget_set_size_request( m_pSocket, nWidth, nHeight );
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_pParent->nopaint_container_resize_children(GTK_CONTAINER(pContainer));
#endif
    }
}

@@ -170,14 +180,23 @@ void GtkSalObject::Reparent(SalFrame* pFrame)
    {
        GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pSocket));

#if !GTK_CHECK_VERSION(4, 0, 0)
        gint nX(0), nY(0);
        gtk_container_child_get(GTK_CONTAINER(pContainer), m_pSocket,
                "x", &nX,
                "y", &nY,
                nullptr);
#else
        double nX(0), nY(0);
        gtk_fixed_get_child_position(pContainer, m_pSocket, &nX, &nY);
#endif

        g_object_ref(m_pSocket);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_remove(GTK_CONTAINER(pContainer), m_pSocket);
#else
        gtk_fixed_remove(pContainer, m_pSocket);
#endif

        gtk_fixed_put(pNewParent->getFixedContainer(),
                      m_pSocket,
@@ -230,6 +249,7 @@ const SystemEnvData* GtkSalObjectBase::GetSystemData() const
    return &m_aSystemData;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalObjectBase::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer object )
{
    GtkSalObjectBase* pThis = static_cast<GtkSalObject*>(object);
@@ -250,6 +270,7 @@ gboolean GtkSalObjectBase::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpoin

    return FALSE;
}
#endif

void GtkSalObject::signalDestroy( GtkWidget* pObj, gpointer object )
{
@@ -262,10 +283,14 @@ void GtkSalObject::signalDestroy( GtkWidget* pObj, gpointer object )

void GtkSalObjectBase::SetForwardKey( bool bEnable )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if( bEnable )
        gtk_widget_add_events( GTK_WIDGET( m_pSocket ), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK );
    else
        gtk_widget_set_events( GTK_WIDGET( m_pSocket ), ~(GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK) & gtk_widget_get_events( GTK_WIDGET( m_pSocket ) ) );
#else
    (void)bEnable;
#endif
}

GtkSalObjectWidgetClip::GtkSalObjectWidgetClip(GtkSalFrame* pParent, bool bShow)
@@ -275,7 +300,11 @@ GtkSalObjectWidgetClip::GtkSalObjectWidgetClip(GtkSalFrame* pParent, bool bShow)
    if( !pParent )
        return;

#if !GTK_CHECK_VERSION(4, 0, 0)
    m_pScrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
#else
    m_pScrolledWindow = gtk_scrolled_window_new();
#endif
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(m_pScrolledWindow),
                                   GTK_POLICY_EXTERNAL, GTK_POLICY_EXTERNAL);
    g_signal_connect(m_pScrolledWindow, "scroll-event", G_CALLBACK(signalScroll), this);
@@ -294,16 +323,28 @@ GtkSalObjectWidgetClip::GtkSalObjectWidgetClip(GtkSalFrame* pParent, bool bShow)
    OUString sColor = Application::GetSettings().GetStyleSettings().GetDialogColor().AsRGBHexString();
    OUString aBuffer = "* { background-color: #" + sColor + "; }";
    OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_css_provider_load_from_data(pBgCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
#else
    gtk_css_provider_load_from_data(pBgCssProvider, aResult.getStr(), aResult.getLength());
#endif
    gtk_style_context_add_provider(pWidgetContext, GTK_STYLE_PROVIDER(pBgCssProvider),
                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(m_pScrolledWindow), pViewPort);
#else
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(m_pScrolledWindow), pViewPort);
#endif
    gtk_widget_show(pViewPort);

    // our plug window
    m_pSocket = gtk_grid_new();
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(pViewPort), m_pSocket);
#else
    gtk_viewport_set_child(GTK_VIEWPORT(pViewPort), m_pSocket);
#endif
    gtk_widget_show(m_pSocket);

    Show(bShow);
@@ -318,14 +359,20 @@ GtkSalObjectWidgetClip::~GtkSalObjectWidgetClip()
    if( m_pSocket )
    {
        // remove socket from parent frame's fixed container
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_remove( GTK_CONTAINER(gtk_widget_get_parent(m_pScrolledWindow)),
                              m_pScrolledWindow );

        // get rid of the socket
        // actually the gtk_container_remove should let the ref count
        // of the socket sink to 0 and destroy it (see signalDestroy)
        // this is just a sanity check
        if( m_pScrolledWindow )
            gtk_widget_destroy( m_pScrolledWindow );
#else
        gtk_fixed_remove(GTK_FIXED(gtk_widget_get_parent(m_pScrolledWindow)),
                         m_pScrolledWindow);
#endif
    }
}

@@ -380,7 +427,11 @@ void GtkSalObjectWidgetClip::ApplyClipRegion()
    else
        gtk_fixed_move(pContainer, m_pScrolledWindow, allocation.x, allocation.y);
    gtk_widget_set_size_request(m_pScrolledWindow, allocation.width, allocation.height);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_size_allocate(m_pScrolledWindow, &allocation);
#else
    gtk_widget_size_allocate(m_pScrolledWindow, &allocation, 0);
#endif

    gtk_adjustment_set_value(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(m_pScrolledWindow)), m_aClipRect.Left());
    gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_pScrolledWindow)), m_aClipRect.Top());
@@ -391,10 +442,14 @@ void GtkSalObjectWidgetClip::SetPosSize(tools::Long nX, tools::Long nY, tools::L
    m_aRect = tools::Rectangle(Point(nX, nY), Size(nWidth, nHeight));
    if (m_pSocket)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pScrolledWindow));
#endif
        gtk_widget_set_size_request(m_pSocket, nWidth, nHeight);
        ApplyClipRegion();
#if !GTK_CHECK_VERSION(4, 0, 0)
        m_pParent->nopaint_container_resize_children(GTK_CONTAINER(pContainer));
#endif
    }
}

@@ -405,14 +460,23 @@ void GtkSalObjectWidgetClip::Reparent(SalFrame* pFrame)
    {
        GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pScrolledWindow));

#if !GTK_CHECK_VERSION(4, 0, 0)
        gint nX(0), nY(0);
        gtk_container_child_get(GTK_CONTAINER(pContainer), m_pScrolledWindow,
                "x", &nX,
                "y", &nY,
                nullptr);
#else
        double nX(0), nY(0);
        gtk_fixed_get_child_position(pContainer, m_pScrolledWindow, &nX, &nY);
#endif

        g_object_ref(m_pScrolledWindow);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_remove(GTK_CONTAINER(pContainer), m_pScrolledWindow);
#else
        gtk_fixed_remove(pContainer, m_pScrolledWindow);
#endif

        gtk_fixed_put(pNewParent->getFixedContainer(),
                      m_pScrolledWindow,
@@ -439,7 +503,11 @@ void GtkSalObjectWidgetClip::Show( bool bVisible )
        // cursor in a sidebar comment and scroll the page so the comment is invisible, we want the focus
        // to stay in the invisible widget, so its there when we scroll back or on a keypress the widget
        // gets the keystroke and scrolls back to make it visible again
#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pScrolledWindow);
#else
        GtkWidget* pTopLevel = GTK_WIDGET(gtk_widget_get_root(m_pScrolledWindow));
#endif
        GtkWidget* pOldFocus = GTK_IS_WINDOW(pTopLevel) ? gtk_window_get_focus(GTK_WINDOW(pTopLevel)) : nullptr;

        g_object_set_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange", GINT_TO_POINTER(true) );
@@ -473,6 +541,7 @@ gboolean GtkSalObjectWidgetClip::signalScroll(GtkWidget* pScrolledWindow, GdkEve
// forward the wheel scroll events onto the main window instead
bool GtkSalObjectWidgetClip::signal_scroll(GtkWidget*, GdkEvent* pEvent)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget* pEventWidget = gtk_get_event_widget(pEvent);

    GtkWidget* pMouseEventWidget = m_pParent->getMouseEventWidget();
@@ -488,6 +557,9 @@ bool GtkSalObjectWidgetClip::signal_scroll(GtkWidget*, GdkEvent* pEvent)
    pEvent->scroll.y = dest_y;

    GtkSalFrame::signalScroll(pMouseEventWidget, pEvent, m_pParent);
#else
    (void)pEvent;
#endif
    return true;
}

diff --git a/vcl/unx/gtk3/gtksalmenu.cxx b/vcl/unx/gtk3/gtksalmenu.cxx
index fa379b0..c02ea20 100644
--- a/vcl/unx/gtk3/gtksalmenu.cxx
+++ b/vcl/unx/gtk3/gtksalmenu.cxx
@@ -398,6 +398,7 @@ void GtkSalMenu::Update()
    ImplUpdate(false, !bAlwaysShowDisabledEntries);
}

#if !GTK_CHECK_VERSION(4, 0, 0)
static void MenuPositionFunc(GtkMenu* menu, gint* x, gint* y, gboolean* push_in, gpointer user_data)
{
    Point *pPos = static_cast<Point*>(user_data);
@@ -411,6 +412,7 @@ static void MenuPositionFunc(GtkMenu* menu, gint* x, gint* y, gboolean* push_in,
    *y = pPos->Y();
    *push_in = false;
}
#endif

bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect,
                                     FloatWinPopupFlags nFlags)
@@ -424,8 +426,13 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
    // Generate the main menu structure, populates mpMenuModel
    UpdateFull();

#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget *pWidget = gtk_menu_new_from_model(mpMenuModel);
    gtk_menu_attach_to_widget(GTK_MENU(pWidget), mpFrame->getMouseEventWidget(), nullptr);
#else
    GtkWidget *pWidget = gtk_popover_menu_new_from_model(mpMenuModel);
    gtk_widget_set_parent(pWidget, mpFrame->getMouseEventWidget());
#endif
    gtk_widget_insert_action_group(mpFrame->getMouseEventWidget(), "win", mpActionGroup);

    //run in a sub main loop because we need to keep vcl PopupMenu alive to use
@@ -448,6 +455,12 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
#if GTK_CHECK_VERSION(3,22,0)
    if (gtk_check_version(3, 22, 0) == nullptr)
    {
        tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(xParent, rRect);
        aFloatRect.Move(-mpFrame->maGeometry.nX, -mpFrame->maGeometry.nY);
        GdkRectangle rect {static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()),
                           static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())};

#if !GTK_CHECK_VERSION(4, 0, 0)
        GdkGravity rect_anchor = GDK_GRAVITY_SOUTH_WEST, menu_anchor = GDK_GRAVITY_NORTH_WEST;

        if (nFlags & FloatWinPopupFlags::Left)
@@ -465,17 +478,18 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
            rect_anchor = GDK_GRAVITY_NORTH_EAST;
        }

        tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(xParent, rRect);
        aFloatRect.Move(-mpFrame->maGeometry.nX, -mpFrame->maGeometry.nY);
        GdkRectangle rect {static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()),
                           static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())};

        GdkWindow* gdkWindow = gtk_widget_get_window(mpFrame->getMouseEventWidget());
        gtk_menu_popup_at_rect(GTK_MENU(pWidget), gdkWindow, &rect, rect_anchor, menu_anchor, nullptr);
#else
        gtk_popover_set_pointing_to(GTK_POPOVER(pWidget), &rect);
        (void)nFlags;
        //TODO use gtk_popover_set_position
#endif
    }
    else
#endif
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        guint nButton;
        guint32 nTime;

@@ -502,13 +516,18 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl

        gtk_menu_popup(GTK_MENU(pWidget), nullptr, nullptr, MenuPositionFunc,
                       &aPos, nButton, nTime);
#endif
    }

    if (g_main_loop_is_running(pLoop))
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_leave();
#endif
        g_main_loop_run(pLoop);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gdk_threads_enter();
#endif
    }
    g_main_loop_unref(pLoop);

@@ -516,7 +535,11 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl

    gtk_widget_insert_action_group(mpFrame->getMouseEventWidget(), "win", nullptr);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_destroy(pWidget);
#else
    g_clear_pointer(&pWidget, gtk_widget_unparent);
#endif

    g_object_unref(mpActionGroup);
    ClearActionGroupAndMenuModel();
@@ -670,8 +693,14 @@ GtkWidget* GtkSalMenu::AddButton(GtkWidget *pImage)
{
    GtkWidget* pButton = gtk_button_new();

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_button_set_relief(GTK_BUTTON(pButton), GTK_RELIEF_NONE);
    gtk_button_set_focus_on_click(GTK_BUTTON(pButton), false);
#else
    gtk_button_set_has_frame(GTK_BUTTON(pButton), false);
    gtk_widget_set_focus_on_click(pButton, false);
#endif

    gtk_widget_set_can_focus(pButton, false);

    GtkStyleContext *pButtonContext = gtk_widget_get_style_context(GTK_WIDGET(pButton));
@@ -683,8 +712,12 @@ GtkWidget* GtkSalMenu::AddButton(GtkWidget *pImage)

    gtk_widget_set_valign(pButton, GTK_ALIGN_CENTER);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(pButton), pImage);
    gtk_widget_show_all(pButton);
#else
    gtk_button_set_child(GTK_BUTTON(pButton), pImage);
#endif
    return pButton;
}

@@ -698,7 +731,11 @@ void GtkSalMenu::ShowCloseButton(bool bShow)
    {
        if (mpCloseButton)
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            gtk_widget_destroy(mpCloseButton);
#else
            g_clear_pointer(&mpCloseButton, gtk_widget_unparent);
#endif
            mpCloseButton = nullptr;
        }
        return;
@@ -708,7 +745,11 @@ void GtkSalMenu::ShowCloseButton(bool bShow)
        return;

    GIcon* pIcon = g_themed_icon_new_with_default_fallbacks("window-close-symbolic");
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget* pImage = gtk_image_new_from_gicon(pIcon, GTK_ICON_SIZE_MENU);
#else
    GtkWidget* pImage = gtk_image_new_from_gicon(pIcon);
#endif
    g_object_unref(pIcon);

    mpCloseButton = AddButton(pImage);
@@ -735,7 +776,11 @@ namespace

static void MenuButtonClicked(GtkWidget* pWidget, gpointer pMenu)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget));
#else
    const char* pStr = gtk_buildable_get_buildable_id(GTK_BUILDABLE(pWidget));
#endif
    OString aId(pStr, pStr ? strlen(pStr) : 0);
    static_cast<MenuBar*>(pMenu)->HandleMenuButtonEvent(aId.toUInt32());
}
@@ -761,7 +806,11 @@ bool GtkSalMenu::AddMenuBarButton(const SalMenuButtonItem& rNewItem)
                                                    pMemStm);

        GIcon *pIcon = g_bytes_icon_new(pBytes);
#if !GTK_CHECK_VERSION(4, 0, 0)
        pImage = gtk_image_new_from_gicon(pIcon, GTK_ICON_SIZE_MENU);
#else
        pImage = gtk_image_new_from_gicon(pIcon);
#endif
        g_object_unref(pIcon);
    }

@@ -769,7 +818,9 @@ bool GtkSalMenu::AddMenuBarButton(const SalMenuButtonItem& rNewItem)

    maExtraButtons.emplace_back(rNewItem.mnId, pButton);

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_buildable_set_name(GTK_BUILDABLE(pButton), OString::number(rNewItem.mnId).getStr());
#endif

    gtk_widget_set_tooltip_text(pButton, rNewItem.maToolTipText.toUtf8().getStr());

@@ -795,8 +846,13 @@ void GtkSalMenu::RemoveMenuBarButton( sal_uInt16 nId )
    if (it != maExtraButtons.end())
    {
        gint nAttach(0);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_child_get(GTK_CONTAINER(mpMenuBarContainerWidget), it->second, "left-attach", &nAttach, nullptr);
        gtk_widget_destroy(it->second);
#else
        gtk_grid_query_child(GTK_GRID(mpMenuBarContainerWidget), it->second, &nAttach, nullptr, nullptr, nullptr);
        g_clear_pointer(&(it->second), gtk_widget_unparent);
#endif
        gtk_grid_remove_column(GTK_GRID(mpMenuBarContainerWidget), nAttach);
        maExtraButtons.erase(it);
    }
@@ -816,7 +872,11 @@ tools::Rectangle GtkSalMenu::GetMenuBarButtonRectPixel(sal_uInt16 nId, SalFrame*

    GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pReferenceFrame);

#if !GTK_CHECK_VERSION(4, 0, 0)
    int x, y;
#else
    double x, y;
#endif
    if (!gtk_widget_translate_coordinates(pButton, GTK_WIDGET(pFrame->getMouseEventWidget()), 0, 0, &x, &y))
        return tools::Rectangle();

@@ -836,16 +896,19 @@ void GtkSalMenu::ReturnFocus()
{
    if (mbAddedGrab)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_grab_remove(mpMenuBarWidget);
#endif
        mbAddedGrab = false;
    }
    if (!mbReturnFocusToDocument)
        gtk_widget_grab_focus(GTK_WIDGET(mpFrame->getEventBox()));
        gtk_widget_grab_focus(mpFrame->getMouseEventWidget());
    else
        mpFrame->GetWindow()->GrabFocusToDocument();
    mbReturnFocusToDocument = false;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
gboolean GtkSalMenu::SignalKey(GdkEventKey const * pEvent)
{
    if (pEvent->keyval == GDK_KEY_F6)
@@ -859,8 +922,9 @@ gboolean GtkSalMenu::SignalKey(GdkEventKey const * pEvent)
    }
    return false;
}
#endif

//The GtkSalMenu is owner by a Vcl Menu/MenuBar. In the menubar
//The GtkSalMenu is owned by a Vcl Menu/MenuBar. In the menubar
//case the vcl menubar is present and "visible", but with a 0 height
//so it not apparent. Normally it acts as though it is not there when
//a Native menubar is active. If we return true here, then for keyboard
@@ -877,6 +941,7 @@ bool GtkSalMenu::TakeFocus()
    if (!mpMenuBarWidget)
        return false;

#if !GTK_CHECK_VERSION(4, 0, 0)
    //Send a keyboard event to the gtk menubar to let it know it has been
    //activated via the keyboard. Doesn't do anything except cause the gtk
    //menubar "keyboard_mode" member to get set to true, so typically mnemonics
@@ -889,13 +954,16 @@ bool GtkSalMenu::TakeFocus()
    //this pairing results in a menubar with keyboard focus with no menus
    //auto-popped down
    gtk_grab_add(mpMenuBarWidget);

    mbAddedGrab = true;
    gtk_menu_shell_select_first(GTK_MENU_SHELL(mpMenuBarWidget), false);
    gtk_menu_shell_deselect(GTK_MENU_SHELL(mpMenuBarWidget));
#endif
    mbReturnFocusToDocument = true;
    return true;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
static void MenuBarReturnFocus(GtkMenuShell*, gpointer menu)
{
    GtkSalFrame::UpdateLastInputEventTime(gtk_get_current_event_time());
@@ -908,6 +976,7 @@ static gboolean MenuBarSignalKey(GtkWidget*, GdkEventKey* pEvent, gpointer menu)
    GtkSalMenu* pMenu = static_cast<GtkSalMenu*>(menu);
    return pMenu->SignalKey(pEvent);
}
#endif

void GtkSalMenu::CreateMenuBarWidget()
{
@@ -921,10 +990,15 @@ void GtkSalMenu::CreateMenuBarWidget()
    gtk_grid_insert_row(pGrid, 0);
    gtk_grid_attach(pGrid, mpMenuBarContainerWidget, 0, 0, 1, 1);

#if !GTK_CHECK_VERSION(4, 0, 0)
    mpMenuAllowShrinkWidget = gtk_scrolled_window_new(nullptr, nullptr);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(mpMenuAllowShrinkWidget), GTK_SHADOW_NONE);
#else
    mpMenuAllowShrinkWidget = gtk_scrolled_window_new();
    gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(mpMenuAllowShrinkWidget), false);
#endif
    // tdf#129634 don't allow this scrolled window as a candidate to tab into
    gtk_widget_set_can_focus(GTK_WIDGET(mpMenuAllowShrinkWidget), false);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(mpMenuAllowShrinkWidget), GTK_SHADOW_NONE);
    // tdf#116290 external policy on scrolledwindow will not show a scrollbar,
    // but still allow scrolled window to not be sized to the child content.
    // So the menubar can be shrunk past its nominal smallest width.
@@ -932,17 +1006,31 @@ void GtkSalMenu::CreateMenuBarWidget()
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(mpMenuAllowShrinkWidget), GTK_POLICY_EXTERNAL, GTK_POLICY_NEVER);
    gtk_grid_attach(GTK_GRID(mpMenuBarContainerWidget), mpMenuAllowShrinkWidget, 0, 0, 1, 1);

#if !GTK_CHECK_VERSION(4, 0, 0)
    mpMenuBarWidget = gtk_menu_bar_new_from_model(mpMenuModel);
#else
    mpMenuBarWidget = gtk_popover_menu_bar_new_from_model(mpMenuModel);
#endif

    gtk_widget_insert_action_group(mpMenuBarWidget, "win", mpActionGroup);
    gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarWidget), true);
    gtk_widget_set_hexpand(mpMenuAllowShrinkWidget, true);
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(mpMenuAllowShrinkWidget), mpMenuBarWidget);
#else
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(mpMenuAllowShrinkWidget), mpMenuBarWidget);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    g_signal_connect(G_OBJECT(mpMenuBarWidget), "deactivate", G_CALLBACK(MenuBarReturnFocus), this);
    g_signal_connect(G_OBJECT(mpMenuBarWidget), "key-press-event", G_CALLBACK(MenuBarSignalKey), this);
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_show_all(mpMenuBarContainerWidget);
#else
    gtk_widget_show(mpMenuBarContainerWidget);
#endif

    ShowCloseButton( static_cast<MenuBar*>(mpVCLMenu.get())->HasCloseButton() );

@@ -986,7 +1074,11 @@ void GtkSalMenu::ApplyPersona()
        mpMenuBarContainerProvider = gtk_css_provider_new();
        OUString aBuffer = "* { background-image: url(\"" + mxPersonaImage->GetURL() + "\"); background-position: top right; }";
        OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(mpMenuBarContainerProvider, aResult.getStr(), aResult.getLength(), nullptr);
#else
        gtk_css_provider_load_from_data(mpMenuBarContainerProvider, aResult.getStr(), aResult.getLength());
#endif
        gtk_style_context_add_provider(pMenuBarContainerContext, GTK_STYLE_PROVIDER(mpMenuBarContainerProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

@@ -998,7 +1090,11 @@ void GtkSalMenu::ApplyPersona()
          "background-image: none;"
          "background-color: transparent;"
          "}";
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_css_provider_load_from_data(mpMenuBarProvider, data, -1, nullptr);
#else
        gtk_css_provider_load_from_data(mpMenuBarProvider, data, -1);
#endif
        gtk_style_context_add_provider(pMenuBarContext,
                                       GTK_STYLE_PROVIDER(mpMenuBarProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
@@ -1010,11 +1106,15 @@ void GtkSalMenu::DestroyMenuBarWidget()
{
    if (mpMenuBarContainerWidget)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // tdf#140225 call cancel before destroying it in case there are some
        // active menus popped open
        gtk_menu_shell_cancel(GTK_MENU_SHELL(mpMenuBarWidget));

        gtk_widget_destroy(mpMenuBarContainerWidget);
#else
        g_clear_pointer(&mpMenuBarContainerWidget, gtk_widget_unparent);
#endif
        mpMenuBarContainerWidget = nullptr;
        mpCloseButton = nullptr;
    }
@@ -1033,6 +1133,7 @@ void GtkSalMenu::SetFrame(const SalFrame* pFrame)
    mpFrame->SetMenu( this );
    mpFrame->EnsureAppMenuWatch();

#if !GTK_CHECK_VERSION(4, 0, 0)
    // Clean menu model and action group if needed.
    GtkWidget* pWidget = mpFrame->getWindow();
    GdkWindow* gdkWindow = gtk_widget_get_window( pWidget );
@@ -1066,6 +1167,7 @@ void GtkSalMenu::SetFrame(const SalFrame* pFrame)
        DestroyMenuBarWidget();
        CreateMenuBarWidget();
    }
#endif
}

const GtkSalFrame* GtkSalMenu::GetFrame() const
@@ -1310,6 +1412,7 @@ void GtkSalMenu::DispatchCommand(const gchar *pCommand)
    GtkSalMenu* pTopLevel = pSalSubMenu->GetTopLevel();
    if (pTopLevel->mpMenuBarWidget)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        // tdf#125803 spacebar will toggle radios and checkbuttons without automatically
        // closing the menu. To handle this properly I imagine we need to set groups for the
        // radiobuttons so the others visually untoggle when the active one is toggled and
@@ -1318,6 +1421,7 @@ void GtkSalMenu::DispatchCommand(const gchar *pCommand)
        // or we could unconditionally deactivate the menus if regardless of what particular
        // type of menu item got activated
        gtk_menu_shell_deactivate(GTK_MENU_SHELL(pTopLevel->mpMenuBarWidget));
#endif
    }
    pTopLevel->GetMenu()->HandleMenuCommandEvent(pSalSubMenu->GetMenu(), aMenuAndId.second);
}
diff --git a/vcl/unx/gtk3/gtksys.cxx b/vcl/unx/gtk3/gtksys.cxx
index a0627a6f..79b59d2c 100644
--- a/vcl/unx/gtk3/gtksys.cxx
+++ b/vcl/unx/gtk3/gtksys.cxx
@@ -87,6 +87,7 @@ struct GdkRectangleCoincident
void
GtkSalSystem::countScreenMonitors()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    maScreenMonitors.clear();
    for (gint i = 0; i < gdk_display_get_n_screens(mpDisplay); i++)
    {
@@ -111,11 +112,13 @@ GtkSalSystem::countScreenMonitors()
        }
        maScreenMonitors.emplace_back(pScreen, nMonitors);
    }
#endif
}

SalX11Screen
GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gint nMonitor;

    GdkScreen *pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
@@ -124,8 +127,13 @@ GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
    if (!DLSYM_GDK_IS_X11_DISPLAY(mpDisplay))
        return SalX11Screen (0);
    return SalX11Screen (gdk_x11_screen_get_screen_number (pScreen));
#else
    (void)nScreen;
    return SalX11Screen (0);
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
GdkScreen *
GtkSalSystem::getScreenMonitorFromIdx (int nIdx, gint &nMonitor)
{
@@ -173,28 +181,42 @@ int GtkSalSystem::getScreenMonitorIdx (GdkScreen *pScreen,
    return getScreenIdxFromPtr (pScreen) +
        gdk_screen_get_monitor_at_point (pScreen, nX, nY);
}
#endif

unsigned int GtkSalSystem::GetDisplayScreenCount()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gint nMonitor;
    (void)getScreenMonitorFromIdx (G_MAXINT, nMonitor);
    return G_MAXINT - nMonitor;
#else
    return 1;
#endif
}

bool GtkSalSystem::IsUnifiedDisplay()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    return gdk_display_get_n_screens (mpDisplay) == 1;
#else
    return true;
#endif
}

unsigned int GtkSalSystem::GetDisplayBuiltInScreen()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen *pDefault = gdk_display_get_default_screen (mpDisplay);
    int idx = getScreenIdxFromPtr (pDefault);
    return idx + gdk_screen_get_primary_monitor(pDefault);
#else
    return 0;
#endif
}

tools::Rectangle GtkSalSystem::GetDisplayScreenPosSizePixel (unsigned int nScreen)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gint nMonitor;
    GdkScreen *pScreen;
    GdkRectangle aRect;
@@ -203,6 +225,10 @@ tools::Rectangle GtkSalSystem::GetDisplayScreenPosSizePixel (unsigned int nScree
        return tools::Rectangle();
    gdk_screen_get_monitor_geometry (pScreen, nMonitor, &aRect);
    return tools::Rectangle (Point(aRect.x, aRect.y), Size(aRect.width, aRect.height));
#else
    (void)nScreen;
    return tools::Rectangle();
#endif
}

// convert ~ to indicate mnemonic to '_'
@@ -232,7 +258,11 @@ int GtkSalSystem::ShowNativeDialog (const OUString& rTitle, const OUString& rMes
    if (nButton < 0)
        nButton = -1;

    gtk_widget_destroy (GTK_WIDGET (pDialog));
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_widget_destroy(GTK_WIDGET(pDialog));
#else
    gtk_window_destroy(GTK_WINDOW(pDialog));
#endif

    return nButton;
}
diff --git a/vcl/unx/gtk3/salnativewidgets-gtk.cxx b/vcl/unx/gtk3/salnativewidgets-gtk.cxx
index ae7a7f3..13ba47e 100644
--- a/vcl/unx/gtk3/salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/salnativewidgets-gtk.cxx
@@ -95,6 +95,7 @@ bool GtkSalGraphics::style_loaded = false;
/************************************************************************
 * State conversion
 ************************************************************************/
#if !GTK_CHECK_VERSION(4, 0, 0)
static GtkStateFlags NWConvertVCLStateToGTKState(ControlState nVCLState)
{
    GtkStateFlags nGTKState = GTK_STATE_FLAG_NORMAL;
@@ -220,29 +221,40 @@ tools::Rectangle GtkSalGraphics::NWGetSpinButtonRect( ControlPart nPart, tools::

    return partRect;
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    void QuerySize(GtkStyleContext *pContext, Size &rSize)
    {
        GtkBorder margin, border, padding;
        GtkStateFlags stateflags = gtk_style_context_get_state (pContext);

#if !GTK_CHECK_VERSION(4, 0, 0)
        GtkStateFlags stateflags = gtk_style_context_get_state (pContext);
        gtk_style_context_get_margin(pContext, stateflags, &margin);
        gtk_style_context_get_border(pContext, stateflags, &border);
        gtk_style_context_get_padding(pContext, stateflags, &padding);
#else
        gtk_style_context_get_margin(pContext, &margin);
        gtk_style_context_get_border(pContext, &border);
        gtk_style_context_get_padding(pContext, &padding);
#endif

        int nMinWidth, nMinHeight;
        int nMinWidth(0), nMinHeight(0);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_style_context_get(pContext, stateflags,
                "min-width", &nMinWidth, "min-height", &nMinHeight, nullptr);

#endif
        nMinWidth += margin.left + margin.right + border.left + border.right + padding.left + padding.right;
        nMinHeight += margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom;

        rSize = Size(std::max<tools::Long>(rSize.Width(), nMinWidth), std::max<tools::Long>(rSize.Height(), nMinHeight));
    }
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
tools::Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, tools::Rectangle aAreaRect )
{
    tools::Rectangle  buttonRect;
@@ -315,6 +327,7 @@ tools::Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, tools

    return buttonRect;
}
#endif

static GtkWidget* gCacheWindow;
static GtkWidget* gDumbContainer;
@@ -324,6 +337,7 @@ static GtkWidget* gComboBox;
static GtkWidget* gListBox;
static GtkWidget* gTreeViewWidget;

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    void style_context_set_state(GtkStyleContext* context, GtkStateFlags flags)
@@ -1002,6 +1016,7 @@ static GtkWidgetPath* buildRTLComboSiblingsPath()
    return pSiblingsPath;
}


GtkStyleContext* GtkSalGraphics::makeContext(GtkWidgetPath *pPath, GtkStyleContext *pParent)
{
    GtkStyleContext* context = gtk_style_context_new();
@@ -1527,6 +1542,7 @@ namespace
        gtk_render_frame(context, cr, nX, nY, nWidth, nSeparatorHeight);
    }
}
#endif

void GtkSalGraphics::handleDamage(const tools::Rectangle& rDamagedRegion)
{
@@ -1535,6 +1551,7 @@ void GtkSalGraphics::handleDamage(const tools::Rectangle& rDamagedRegion)
    mpFrame->damaged(rDamagedRegion.Left(), rDamagedRegion.Top(), rDamagedRegion.GetWidth(), rDamagedRegion.GetHeight());
}

#if !GTK_CHECK_VERSION(4, 0, 0)
bool GtkSalGraphics::drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                            ControlState nState, const ImplControlValue& rValue,
                                            const OUString&, const Color& rBackgroundColor)
@@ -2112,6 +2129,7 @@ bool GtkSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPar

    return true;
}

/************************************************************************
 * helper for GtkSalFrame
 ************************************************************************/
@@ -2125,6 +2143,7 @@ static vcl::Font getFont(GtkStyleContext* pStyle, const css::lang::Locale& rLoca
    const PangoFontDescription* font = gtk_style_context_get_font(pStyle, gtk_style_context_get_state(pStyle));
    return pango_to_vcl(font, rLocale);
}
#endif

vcl::Font pango_to_vcl(const PangoFontDescription* font, const css::lang::Locale& rLocale)
{
@@ -2201,6 +2220,7 @@ vcl::Font pango_to_vcl(const PangoFontDescription* font, const css::lang::Locale

bool GtkSalGraphics::updateSettings(AllSettings& rSettings)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    GtkWidget* pTopLevel = gtk_widget_get_toplevel(mpWindow);
    GtkStyleContext* pStyle = gtk_widget_get_style_context(pTopLevel);
    StyleContextSave aContextState;
@@ -2539,9 +2559,13 @@ bool GtkSalGraphics::updateSettings(AllSettings& rSettings)
    g_free(pThemeName);
#endif

#else
    (void)rSettings;
#endif
    return true;
}

#if !GTK_CHECK_VERSION(4, 0, 0)
bool GtkSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart )
{
    switch(nType)
@@ -2647,9 +2671,9 @@ bool GtkSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nP
    }

    SAL_INFO("vcl.gtk", "Unhandled is native supported for Type:" << static_cast<int>(nType) << ", Part" << static_cast<int>(nPart));

    return false;
}
#endif

#if ENABLE_CAIRO_CANVAS

@@ -2677,6 +2701,7 @@ void GtkSalGraphics::WidgetQueueDraw() const
    gtk_widget_queue_draw(pWidget);
}

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace {

void getStyleContext(GtkStyleContext** style, GtkWidget* widget)
@@ -2687,6 +2712,7 @@ void getStyleContext(GtkStyleContext** style, GtkWidget* widget)
}

}
#endif

void GtkSalData::initNWF()
{
@@ -2710,8 +2736,10 @@ void GtkSalData::initNWF()

void GtkSalData::deInitNWF()
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (gCacheWindow)
        gtk_widget_destroy(gCacheWindow);
#endif
}

GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
@@ -2719,6 +2747,7 @@ GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
      mpFrame( pFrame ),
      mpWindow( pWindow )
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    if (style_loaded)
        return;

@@ -2862,6 +2891,7 @@ GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
    mpProgressBarProgressStyle = createStyleContext(GtkControlPart::ProgressBarProgress);

    gtk_widget_show_all(gDumbContainer);
#endif
}

void GtkSalGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
@@ -2874,6 +2904,7 @@ void GtkSalGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
        return;
    }

#if !GTK_CHECK_VERSION(4, 0, 0)
    GdkScreen* pScreen = gtk_widget_get_screen(mpWindow);
    double fResolution = -1.0;
    g_object_get(pScreen, "resolution", &fResolution, nullptr);
@@ -2882,6 +2913,9 @@ void GtkSalGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
        rDPIX = rDPIY = sal_Int32(fResolution);
    else
        rDPIX = rDPIY = 96;
#else
    rDPIX = rDPIY = 96;
#endif
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkFilePicker.cxx b/vcl/unx/gtk4/fpicker/SalGtkFilePicker.cxx
new file mode 100644
index 0000000..a820b49
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkFilePicker.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkFilePicker.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkFilePicker.hxx b/vcl/unx/gtk4/fpicker/SalGtkFilePicker.hxx
new file mode 100644
index 0000000..44ea7bd
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkFilePicker.hxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkFilePicker.hxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.cxx b/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.cxx
new file mode 100644
index 0000000..41dfdf0
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkFolderPicker.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.hxx b/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.hxx
new file mode 100644
index 0000000..129a699
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkFolderPicker.hxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkFolderPicker.hxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkPicker.cxx b/vcl/unx/gtk4/fpicker/SalGtkPicker.cxx
new file mode 100644
index 0000000..159ef470
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkPicker.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkPicker.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/SalGtkPicker.hxx b/vcl/unx/gtk4/fpicker/SalGtkPicker.hxx
new file mode 100644
index 0000000..0432004
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/SalGtkPicker.hxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/SalGtkPicker.hxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/eventnotification.hxx b/vcl/unx/gtk4/fpicker/eventnotification.hxx
new file mode 100644
index 0000000..b1e16bd
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/eventnotification.hxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/eventnotification.hxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/fpicker/resourceprovider.cxx b/vcl/unx/gtk4/fpicker/resourceprovider.cxx
new file mode 100644
index 0000000..d4251cc
--- /dev/null
+++ b/vcl/unx/gtk4/fpicker/resourceprovider.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/fpicker/resourceprovider.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gloactiongroup.cxx b/vcl/unx/gtk4/gloactiongroup.cxx
new file mode 100644
index 0000000..f147af2
--- /dev/null
+++ b/vcl/unx/gtk4/gloactiongroup.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gloactiongroup.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/glomenu.cxx b/vcl/unx/gtk4/glomenu.cxx
new file mode 100644
index 0000000..cae9bc0
--- /dev/null
+++ b/vcl/unx/gtk4/glomenu.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/glomenu.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkcairo.cxx b/vcl/unx/gtk4/gtkcairo.cxx
new file mode 100644
index 0000000..3178fde
--- /dev/null
+++ b/vcl/unx/gtk4/gtkcairo.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtkcairo.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkcairo.hxx b/vcl/unx/gtk4/gtkcairo.hxx
new file mode 100644
index 0000000..97f6310
--- /dev/null
+++ b/vcl/unx/gtk4/gtkcairo.hxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../../gtk3/gtkdata.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkdata.cxx b/vcl/unx/gtk4/gtkdata.cxx
new file mode 100644
index 0000000..41d8521
--- /dev/null
+++ b/vcl/unx/gtk4/gtkdata.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtkdata.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkframe.cxx b/vcl/unx/gtk4/gtkframe.cxx
new file mode 100644
index 0000000..9133b06
--- /dev/null
+++ b/vcl/unx/gtk4/gtkframe.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtkframe.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkinst.cxx b/vcl/unx/gtk4/gtkinst.cxx
new file mode 100644
index 0000000..5037417
--- /dev/null
+++ b/vcl/unx/gtk4/gtkinst.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtkinst.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtkobject.cxx b/vcl/unx/gtk4/gtkobject.cxx
new file mode 100644
index 0000000..8eb5dcf
--- /dev/null
+++ b/vcl/unx/gtk4/gtkobject.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtkobject.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtksalmenu.cxx b/vcl/unx/gtk4/gtksalmenu.cxx
new file mode 100644
index 0000000..8950781
--- /dev/null
+++ b/vcl/unx/gtk4/gtksalmenu.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtksalmenu.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/gtksys.cxx b/vcl/unx/gtk4/gtksys.cxx
new file mode 100644
index 0000000..dfdcf0a
--- /dev/null
+++ b/vcl/unx/gtk4/gtksys.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/gtksys.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/hudawareness.cxx b/vcl/unx/gtk4/hudawareness.cxx
new file mode 100644
index 0000000..b2683b2
--- /dev/null
+++ b/vcl/unx/gtk4/hudawareness.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/hudawareness.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/salnativewidgets-gtk.cxx b/vcl/unx/gtk4/salnativewidgets-gtk.cxx
new file mode 100644
index 0000000..ed036e98c
--- /dev/null
+++ b/vcl/unx/gtk4/salnativewidgets-gtk.cxx
@@ -0,0 +1,12 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 "../gtk3/salnativewidgets-gtk.cxx"

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */