add a callback for when a container gains or loses focus

Change-Id: Id8e8e59547280297db9140a840228f62b75593ed
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112021
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 181b356..a42dd09 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -324,6 +324,11 @@ public:

class VCL_DLLPUBLIC Container : virtual public Widget
{
protected:
    Link<Container&, void> m_aContainerFocusChangedHdl;

    void signal_container_focus_changed() { m_aContainerFocusChangedHdl.Call(*this); }

public:
    // remove and add in one go
    virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) = 0;
@@ -332,6 +337,12 @@ public:
    // create an XWindow as a child of this container. The XWindow is
    // suitable to contain css::awt::XControl items
    virtual css::uno::Reference<css::awt::XWindow> CreateChildFrame() = 0;
    // rLink is called when the focus transitions from a widget outside the container
    // to a widget inside the container or vice versa
    virtual void connect_container_focus_changed(const Link<Container&, void>& rLink)
    {
        m_aContainerFocusChangedHdl = rLink;
    }
};

class VCL_DLLPUBLIC Box : virtual public Container
diff --git a/sw/source/uibase/inc/navipi.hxx b/sw/source/uibase/inc/navipi.hxx
index 10044d4..bdcd7ac 100644
--- a/sw/source/uibase/inc/navipi.hxx
+++ b/sw/source/uibase/inc/navipi.hxx
@@ -107,6 +107,8 @@ class SwNavigationPI : public PanelLayout
    DECL_LINK( ChangePageHdl, Timer*, void );
    DECL_LINK( PageEditModifyHdl, weld::SpinButton&, void );
    DECL_LINK( EditActionHdl, weld::Entry&, bool );
    DECL_LINK( SetFocusChildHdl, weld::Container&, void );

    bool EditAction();
    void UsePage();

diff --git a/sw/source/uibase/utlui/navipi.cxx b/sw/source/uibase/utlui/navipi.cxx
index 5a1de15..53fdad3 100644
--- a/sw/source/uibase/utlui/navipi.cxx
+++ b/sw/source/uibase/utlui/navipi.cxx
@@ -534,6 +534,8 @@ SwNavigationPI::SwNavigationPI(vcl::Window* pParent,
    , m_bIsZoomedIn(false)
    , m_bGlobalMode(false)
{
    m_xContainer->connect_container_focus_changed(LINK(this, SwNavigationPI, SetFocusChildHdl));

    set_id("NavigatorPanelParent"); // for uitest/writer_tests5/tdf114724.py

    GetCreateView();
@@ -758,11 +760,12 @@ void SwNavigationPI::StateChanged(StateChangedType nStateChange)
            m_xContentTree->UpdateTracking();
        }
    }
    else if (nStateChange == StateChangedType::ControlFocus)
    {
        // update documents listbox
        UpdateListBox();
    }
}

IMPL_LINK_NOARG(SwNavigationPI, SetFocusChildHdl, weld::Container&, void)
{
    // update documents listbox
    UpdateListBox();
}

// Notification on modified DocInfo
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 4322cb2..badc2ff 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -413,6 +413,8 @@ private:
public:
    SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder,
                         bool bTakeOwnership);
    virtual void HandleEventListener(VclWindowEvent& rEvent) override;
    virtual void connect_container_focus_changed(const Link<Container&, void>& rLink) override;
    virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override;
    virtual void recursively_unset_default_buttons() override;
    virtual css::uno::Reference<css::awt::XWindow> CreateChildFrame() override;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 56f297a..81ceba3 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -1146,6 +1146,23 @@ void SalInstanceContainer::implResetDefault(const vcl::Window* _pWindow)
    }
}

void SalInstanceContainer::connect_container_focus_changed(const Link<Container&, void>& rLink)
{
    ensure_event_listener();
    weld::Container::connect_container_focus_changed(rLink);
}

void SalInstanceContainer::HandleEventListener(VclWindowEvent& rEvent)
{
    if (rEvent.GetId() == VclEventId::WindowActivate
        || rEvent.GetId() == VclEventId::WindowDeactivate)
    {
        signal_container_focus_changed();
        return;
    }
    SalInstanceWidget::HandleEventListener(rEvent);
}

SalInstanceContainer::SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder,
                                           bool bTakeOwnership)
    : SalInstanceWidget(pContainer, pBuilder, bTakeOwnership)
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 63ebf18..7a58dd7 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -3763,6 +3763,8 @@ class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Cont
{
private:
    GtkContainer* m_pContainer;
    gulong m_nSetFocusChildSignalId;
    bool m_bChildHasFocus;

    static void implResetDefault(GtkWidget *pWidget, gpointer user_data)
    {
@@ -3772,13 +3774,37 @@ private:
            gtk_container_forall(GTK_CONTAINER(pWidget), implResetDefault, user_data);
    }

    void signal_set_focus_child(bool bChildHasFocus)
    {
        if (m_bChildHasFocus != bChildHasFocus)
        {
            m_bChildHasFocus = bChildHasFocus;
            signal_container_focus_changed();
        }
    }

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

public:
    GtkInstanceContainer(GtkContainer* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
        : GtkInstanceWidget(GTK_WIDGET(pContainer), pBuilder, bTakeOwnership)
        , m_pContainer(pContainer)
        , m_nSetFocusChildSignalId(0)
        , m_bChildHasFocus(false)
    {
    }

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

    GtkContainer* getContainer() { return m_pContainer; }

    virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override
@@ -3830,6 +3856,12 @@ public:
        css::uno::Reference<css::awt::XWindow> xWindow(xEmbedWindow->GetComponentInterface(), css::uno::UNO_QUERY);
        return xWindow;
    }

    virtual ~GtkInstanceContainer() override
    {
        if (m_nSetFocusChildSignalId)
            g_signal_handler_disconnect(m_pContainer, m_nSetFocusChildSignalId);
    }
};

}