tdf#140225 call cancel before destroying menubar

a) in case there are some menus open cancel them before removing
their parent menubar
b) before a GtkSalMenu is deleted clear the action-group of its members

squash of...

Related: tdf#140225 ignore activate/deactivate of a disposed VclMenu

prep work for improved solution for tdf#140225

Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110699
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>

Related: tdf#140225 when clearing pItemList, keep SalMenu in sync

with their removal during menu teardown

Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110703
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>

Resolves: tdf#140225 remove action when item is removed from GtkSalMenu

and we have previously ensured that all items are removed by
Menu::dispose before GtkSalMenu dtor is called

Change-Id: I9ec59c52c72b8b58976a8ee41727ca7612ebf6b1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110564
Tested-by: Jenkins
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index eacfb86..7d4a346 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -213,7 +213,18 @@ void Menu::dispose()

    bKilled = true;

    pItemList->Clear();
    // tdf#140225 when clearing pItemList, keep SalMenu in sync with
    // their removal during menu teardown
    for (size_t n = pItemList->size(); n;)
    {
        --n;
        if (mpSalMenu)
            mpSalMenu->RemoveItem(n);
        pItemList->Remove(n);
    }

    assert(!pItemList->size());

    mpLayoutData.reset();

    // Native-support: destroy SalMenu
diff --git a/vcl/unx/gtk3/gtk3gtksalmenu.cxx b/vcl/unx/gtk3/gtk3gtksalmenu.cxx
index f78bbab..3ed2487 100644
--- a/vcl/unx/gtk3/gtk3gtksalmenu.cxx
+++ b/vcl/unx/gtk3/gtk3gtksalmenu.cxx
@@ -596,13 +596,15 @@ GtkSalMenu::~GtkSalMenu()
{
    SolarMutexGuard aGuard;

    // tdf#140225 we expect all items to be removed by Menu::dispose
    // before this dtor is called
    assert(maItems.empty());

    DestroyMenuBarWidget();

    if (mpMenuModel)
        g_object_unref(mpMenuModel);

    maItems.clear();

    if (mpFrame)
        mpFrame->SetMenu(nullptr);
}
@@ -630,6 +632,16 @@ void GtkSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
void GtkSalMenu::RemoveItem( unsigned nPos )
{
    SolarMutexGuard aGuard;

    // tdf#140225 clear associated action when the item is removed
    if (mpActionGroup)
    {
        GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP(mpActionGroup);
        gchar* pCommand = GetCommandForItem(maItems[nPos]);
        g_lo_action_group_remove(pActionGroup, pCommand);
        g_free(pCommand);
    }

    maItems.erase( maItems.begin() + nPos );
    SetNeedsUpdate();
}
@@ -998,6 +1010,10 @@ void GtkSalMenu::DestroyMenuBarWidget()
{
    if (mpMenuBarContainerWidget)
    {
        // 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);
        mpMenuBarContainerWidget = nullptr;
        mpCloseButton = nullptr;
@@ -1345,8 +1361,10 @@ void GtkSalMenu::Activate(const gchar* pCommand)
{
    MenuAndId aMenuAndId = decode_command(pCommand);
    GtkSalMenu* pSalMenu = aMenuAndId.first;
    GtkSalMenu* pTopLevel = pSalMenu->GetTopLevel();
    Menu* pVclMenu = pSalMenu->GetMenu();
    if (pVclMenu->isDisposed())
        return;
    GtkSalMenu* pTopLevel = pSalMenu->GetTopLevel();
    Menu* pVclSubMenu = pVclMenu->GetPopupMenu(aMenuAndId.second);
    GtkSalMenu* pSubMenu = pSalMenu->GetItemAtPos(pVclMenu->GetItemPos(aMenuAndId.second))->mpSubMenu;

@@ -1360,8 +1378,10 @@ void GtkSalMenu::Deactivate(const gchar* pCommand)
{
    MenuAndId aMenuAndId = decode_command(pCommand);
    GtkSalMenu* pSalMenu = aMenuAndId.first;
    GtkSalMenu* pTopLevel = pSalMenu->GetTopLevel();
    Menu* pVclMenu = pSalMenu->GetMenu();
    if (pVclMenu->isDisposed())
        return;
    GtkSalMenu* pTopLevel = pSalMenu->GetTopLevel();
    Menu* pVclSubMenu = pVclMenu->GetPopupMenu(aMenuAndId.second);
    pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pVclSubMenu);
}