gtk4: implement CreateChildFrame

which gets the extension options tab pages working, e.g.
"English Sentence Checking"

Change-Id: Ib98f366fdcc7c51f4399372a78f78a655b3c0b86
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125242
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index 5299d15..0c6b73ca 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -195,6 +195,9 @@ inline GdkGLContext* surface_create_gl_context(GdkSurface* pSurface)
void set_buildable_id(GtkBuildable* pWidget, const OString& rId);
OString get_buildable_id(GtkBuildable* pWidget);

void container_remove(GtkWidget* pContainer, GtkWidget* pChild);
void container_add(GtkWidget* pContainer, GtkWidget* pChild);

#if !GTK_CHECK_VERSION(4, 0, 0)
typedef GtkClipboard GdkClipboard;
#endif
diff --git a/vcl/unx/gtk3/gtkdata.cxx b/vcl/unx/gtk3/gtkdata.cxx
index 8f2afb4..861ae6e 100644
--- a/vcl/unx/gtk3/gtkdata.cxx
+++ b/vcl/unx/gtk3/gtkdata.cxx
@@ -925,4 +925,44 @@ int getButtonPriority(std::string_view rType)
    return -1;
}

void container_remove(GtkWidget* pContainer, GtkWidget* pChild)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_remove(GTK_CONTAINER(pContainer), pChild);
#else
    assert(GTK_IS_BOX(pContainer) || GTK_IS_GRID(pContainer) || GTK_IS_POPOVER(pContainer) ||
           GTK_IS_FIXED(pContainer) || GTK_IS_WINDOW(pContainer));
    if (GTK_IS_BOX(pContainer))
        gtk_box_remove(GTK_BOX(pContainer), pChild);
    else if (GTK_IS_GRID(pContainer))
        gtk_grid_remove(GTK_GRID(pContainer), pChild);
    else if (GTK_IS_POPOVER(pContainer))
        gtk_popover_set_child(GTK_POPOVER(pContainer), nullptr);
    else if (GTK_IS_WINDOW(pContainer))
        gtk_window_set_child(GTK_WINDOW(pContainer), nullptr);
    else if (GTK_IS_FIXED(pContainer))
        gtk_fixed_remove(GTK_FIXED(pContainer), pChild);
#endif
}

void container_add(GtkWidget* pContainer, GtkWidget* pChild)
{
#if !GTK_CHECK_VERSION(4, 0, 0)
    gtk_container_add(GTK_CONTAINER(pContainer), pChild);
#else
    assert(GTK_IS_BOX(pContainer) || GTK_IS_GRID(pContainer) || GTK_IS_POPOVER(pContainer) ||
           GTK_IS_FIXED(pContainer) || GTK_IS_WINDOW(pContainer));
    if (GTK_IS_BOX(pContainer))
        gtk_box_append(GTK_BOX(pContainer), pChild);
    else if (GTK_IS_GRID(pContainer))
        gtk_grid_attach(GTK_GRID(pContainer), pChild, 0, 0, 1, 1);
    else if (GTK_IS_POPOVER(pContainer))
        gtk_popover_set_child(GTK_POPOVER(pContainer), pChild);
    else if (GTK_IS_WINDOW(pContainer))
        gtk_window_set_child(GTK_WINDOW(pContainer), pChild);
    else if (GTK_IS_FIXED(pContainer))
        gtk_fixed_put(GTK_FIXED(pContainer), pChild, 0, 0);
#endif
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index a4463bd..a42a745 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -735,7 +735,10 @@ GtkSalFrame::~GtkSalFrame()
#if !GTK_CHECK_VERSION(4,0,0)
            gtk_widget_destroy( m_pWindow );
#else
            gtk_window_destroy(GTK_WINDOW(m_pWindow));
            if (GTK_IS_WINDOW(m_pWindow))
                gtk_window_destroy(GTK_WINDOW(m_pWindow));
            else
                g_clear_pointer(&m_pWindow, gtk_widget_unparent);
#endif
        }
    }
@@ -906,17 +909,15 @@ void GtkSalFrame::InitCommon()
#endif

    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));
    container_add(m_pWindow, GTK_WIDGET(m_pTopLevelGrid));

#if !GTK_CHECK_VERSION(4,0,0)
    m_pEventBox = GTK_EVENT_BOX(gtk_event_box_new());
    gtk_widget_add_events( GTK_WIDGET(m_pEventBox),
                           GDK_ALL_EVENTS_MASK );
    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,
@@ -1064,7 +1065,8 @@ void GtkSalFrame::InitCommon()
#else
    g_signal_connect( G_OBJECT(m_pWindow), "map", G_CALLBACK(signalMap), this );
    g_signal_connect( G_OBJECT(m_pWindow), "unmap", G_CALLBACK(signalUnmap), this );
    g_signal_connect( G_OBJECT(m_pWindow), "close-request", G_CALLBACK(signalDelete), this );
    if (GTK_IS_WINDOW(m_pWindow))
        g_signal_connect( G_OBJECT(m_pWindow), "close-request", G_CALLBACK(signalDelete), this );
#endif
#if !GTK_CHECK_VERSION(4,0,0)
    g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
@@ -1122,12 +1124,15 @@ void GtkSalFrame::InitCommon()
    // realize the window, we need an XWindow id
    gtk_widget_realize( m_pWindow );

    if (GTK_IS_WINDOW(m_pWindow))
    {
#if !GTK_CHECK_VERSION(4,0,0)
    g_signal_connect(G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalWindowState), this);
        g_signal_connect(G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalWindowState), this);
#else
    GdkSurface* gdkWindow = widget_get_surface(m_pWindow);
    g_signal_connect(G_OBJECT(gdkWindow), "notify::state", G_CALLBACK(signalWindowState), this);
        GdkSurface* gdkWindow = widget_get_surface(m_pWindow);
        g_signal_connect(G_OBJECT(gdkWindow), "notify::state", G_CALLBACK(signalWindowState), this);
#endif
    }

    //system data
    m_aSystemData.SetWindowHandle(GetNativeWindowHandle(m_pWindow));
@@ -1263,13 +1268,15 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
    {
#if !GTK_CHECK_VERSION(4,0,0)
        m_pWindow = gtk_event_box_new();
#else
        m_pWindow = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
#endif
        if( m_pParent )
        {
            // insert into container
            gtk_fixed_put( m_pParent->getFixedContainer(),
                           m_pWindow, 0, 0 );
        }
#endif
    }
    else
    {
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 45f3639..8960b70 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -2233,36 +2233,6 @@ namespace
        return pWidget;
    }

    void container_remove(GtkWidget* pContainer, GtkWidget* pChild)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_remove(GTK_CONTAINER(pContainer), pChild);
#else
        assert(GTK_IS_BOX(pContainer) || GTK_IS_GRID(pContainer) || GTK_IS_POPOVER(pContainer));
        if (GTK_IS_BOX(pContainer))
            gtk_box_remove(GTK_BOX(pContainer), pChild);
        else if (GTK_IS_GRID(pContainer))
            gtk_grid_remove(GTK_GRID(pContainer), pChild);
        else if (GTK_IS_POPOVER(pContainer))
            gtk_popover_set_child(GTK_POPOVER(pContainer), nullptr);
#endif
    }

    void container_add(GtkWidget* pContainer, GtkWidget* pChild)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_add(GTK_CONTAINER(pContainer), pChild);
#else
        assert(GTK_IS_BOX(pContainer) || GTK_IS_GRID(pContainer) || GTK_IS_POPOVER(pContainer));
        if (GTK_IS_BOX(pContainer))
            gtk_box_append(GTK_BOX(pContainer), pChild);
        else if (GTK_IS_GRID(pContainer))
            gtk_grid_attach(GTK_GRID(pContainer), pChild, 0, 0, 1, 1);
        else if (GTK_IS_POPOVER(pContainer))
            gtk_popover_set_child(GTK_POPOVER(pContainer), pChild);
#endif
    }

    void replaceWidget(GtkWidget* pWidget, GtkWidget* pReplacement)
    {
        // remove the widget and replace it with pReplacement
@@ -5847,7 +5817,6 @@ 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);
@@ -5861,9 +5830,11 @@ public:
        GtkWidget* pParent = gtk_widget_get_parent(pWindow);

        g_object_ref(pWindow);
        gtk_container_remove(GTK_CONTAINER(pParent), pWindow);
        gtk_container_add(m_pContainer, pWindow);
        container_remove(pParent, pWindow);
        container_add(GTK_WIDGET(m_pContainer), pWindow);
#if !GTK_CHECK_VERSION(4, 0, 0)
        gtk_container_child_set(m_pContainer, pWindow, "expand", true, "fill", true, nullptr);
#endif
        gtk_widget_set_hexpand(pWindow, true);
        gtk_widget_set_vexpand(pWindow, true);
        gtk_widget_realize(pWindow);
@@ -5874,9 +5845,6 @@ 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