tdf#135965 let F1 in gtk widgets embedded in a GtkSalFrame call help

Change-Id: I6eed15a54769a1a1dcc0a8a6ddb226bd9d7a4fcd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101143
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 3d4c803..3b82be6 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -521,6 +521,8 @@ public:
    static sal_uInt16           GetKeyModCode(guint nState);
    static GdkEvent*            makeFakeKeyPress(GtkWidget* pWidget);
    static SalWheelMouseEvent   GetWheelEvent(GdkEventScroll& rEvent);
    static void                 NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint,
        GdkModifierType, gpointer pFrame);
};

#define OOO_TYPE_FIXED ooo_fixed_get_type()
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 48e8f56..b4ddd14 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -1040,6 +1040,12 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
    else
    {
        m_pWindow = gtk_window_new(eWinType);

        // 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);
    }

    g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index b2b5d59..671938d 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -15777,6 +15777,12 @@ public:
        g_slist_foreach(m_pObjectList, postprocess, this);

        GenerateMissingMnemonics();

        if (m_xInterimGlue)
        {
            assert(m_pParentWidget);
            g_object_set_data(G_OBJECT(m_pParentWidget), "InterimWindowGlue", m_xInterimGlue.get());
        }
    }

    void GenerateMissingMnemonics()
@@ -15836,7 +15842,13 @@ public:
    {
        g_slist_free(m_pObjectList);
        g_object_unref(m_pBuilder);
        m_xInterimGlue.disposeAndClear();

        if (m_xInterimGlue)
        {
            assert(m_pParentWidget);
            g_object_set_data(G_OBJECT(m_pParentWidget), "InterimWindowGlue", nullptr);
            m_xInterimGlue.disposeAndClear();
        }
    }

    //ideally we would have/use weld::Container add and explicitly
@@ -16328,6 +16340,58 @@ weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString&
    return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr);
}

// 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
void GtkSalFrame::NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer pFrame)
{
    Help* pHelp = Application::GetHelp();
    if (!pHelp)
        return;

    GtkWindow* pWindow = static_cast<GtkWindow*>(pFrame);

    vcl::Window* pChildWindow = nullptr;

    //show help for widget with keyboard focus
    GtkWidget* pWidget = gtk_window_get_focus(pWindow);
    if (!pWidget)
        pWidget = GTK_WIDGET(pWindow);
    OString sHelpId = ::get_help_id(pWidget);
    while (sHelpId.isEmpty())
    {
        pWidget = gtk_widget_get_parent(pWidget);
        if (!pWidget)
            break;
        pChildWindow = static_cast<vcl::Window*>(g_object_get_data(G_OBJECT(pWidget), "InterimWindowGlue"));
        if (pChildWindow)
        {
            sHelpId = pChildWindow->GetHelpId();
            break;
        }
        sHelpId = ::get_help_id(pWidget);
    }

    if (pChildWindow)
    {
        while (sHelpId.isEmpty())
        {
            pChildWindow = pChildWindow->GetParent();
            if (!pChildWindow)
                break;
            sHelpId = pChildWindow->GetHelpId();
        }
        if (!pChildWindow)
            return;
        pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), pChildWindow);
        return;
    }

    if (!pWidget)
        return;
    std::unique_ptr<weld::Widget> xTemp(new GtkInstanceWidget(pWidget, nullptr, false));
    pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), xTemp.get());
}

weld::Builder* GtkInstance::CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile, sal_uInt64)
{
    // Create a foreign window which we know is a GtkGrid and make the native widgets a child of that, so we can