diff options
author | Caolán McNamara <caolanm@redhat.com> | 2021-02-25 17:03:31 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2021-02-26 20:57:31 +0100 |
commit | a5a71c7bb58a16a64c586c3ea142e0dd88cf7104 (patch) | |
tree | be9545002fd9b32441b14f04505f0f4c1f05171d /vcl | |
parent | bbb3f36877807a5f6106956d7497f281169d9421 (diff) |
drop intermediate vcl container for these welded floating toplevels
Change-Id: I4a528485de62a0e0acabd41abf6872e2f0e1710e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111567
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/salvtables.hxx | 2 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 62 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 120 |
3 files changed, 165 insertions, 19 deletions
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index b8c5888572d0..4322cb242b1b 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -121,6 +121,8 @@ public: virtual std::unique_ptr<weld::Menu> weld_menu(const OString& id) override; + virtual std::unique_ptr<weld::Popover> weld_popover(const OString& id) override; + virtual std::unique_ptr<weld::Toolbar> weld_toolbar(const OString& id) override; virtual std::unique_ptr<weld::SizeGroup> create_size_group() override; diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 7bb05907ecba..6c86215bd808 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -6611,6 +6611,54 @@ IMPL_LINK(SalInstanceEntryTreeView, AutocompleteHdl, Edit&, rEdit, void) } } +namespace +{ +class SalInstancePopover : public SalInstanceContainer, public virtual weld::Popover +{ +private: + VclPtr<DockingWindow> m_xPopover; + + DECL_LINK(PopupModeEndHdl, FloatingWindow*, void); + +public: + SalInstancePopover(DockingWindow* pPopover, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pPopover, pBuilder, bTakeOwnership) + , m_xPopover(pPopover) + { + } + + virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) override + { + SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pParent); + assert(pVclWidget); + vcl::Window* pWidget = pVclWidget->getWidget(); + + tools::Rectangle aRect; + Point aPt = pWidget->OutputToScreenPixel(rRect.TopLeft()); + aRect.SetLeft(aPt.X()); + aRect.SetTop(aPt.Y()); + aPt = pWidget->OutputToScreenPixel(rRect.BottomRight()); + aRect.SetRight(aPt.X()); + aRect.SetBottom(aPt.Y()); + + FloatWinPopupFlags nFlags = FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus; + m_xPopover->EnableDocking(); + DockingManager* pDockingManager = vcl::Window::GetDockingManager(); + pDockingManager->SetPopupModeEndHdl(m_xPopover, + LINK(this, SalInstancePopover, PopupModeEndHdl)); + pDockingManager->StartPopupMode(m_xPopover, aRect, nFlags); + } + + virtual void popdown() override + { + vcl::Window::GetDockingManager()->EndPopupMode(m_xPopover); + m_xPopover->EnableDocking(false); + } +}; +} + +IMPL_LINK_NOARG(SalInstancePopover, PopupModeEndHdl, FloatingWindow*, void) { signal_closed(); } + SalInstanceBuilder::SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile, const css::uno::Reference<css::frame::XFrame>& rFrame) @@ -6922,6 +6970,20 @@ std::unique_ptr<weld::Menu> SalInstanceBuilder::weld_menu(const OString& id) return pMenu ? std::make_unique<SalInstanceMenu>(pMenu, true) : nullptr; } +std::unique_ptr<weld::Popover> SalInstanceBuilder::weld_popover(const OString& id) +{ + DockingWindow* pDockingWindow = m_xBuilder->get<DockingWindow>(id); + std::unique_ptr<weld::Popover> pRet( + pDockingWindow ? new SalInstancePopover(pDockingWindow, this, false) : nullptr); + if (pDockingWindow) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pDockingWindow); + m_xBuilder->drop_ownership(pDockingWindow); + } + return pRet; +} + std::unique_ptr<weld::Toolbar> SalInstanceBuilder::weld_toolbar(const OString& id) { ToolBox* pToolBox = m_xBuilder->get<ToolBox>(id); diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 1c9e284be0c3..682f4ebe757f 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -1754,6 +1754,30 @@ namespace return AllSettings::GetLayoutRTL(); } + GtkWidget* getPopupRect(GtkWidget* pWidget, const tools::Rectangle& rInRect, GdkRectangle& rOutRect) + { + if (GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pWidget)) + { + // this is the relatively unusual case where pParent is the toplevel GtkSalFrame and not a stock GtkWidget + // so use the same style of logic as GtkSalMenu::ShowNativePopupMenu to get the right position + tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(pFrame->GetWindow(), rInRect); + aFloatRect.Move(-pFrame->maGeometry.nX, -pFrame->maGeometry.nY); + + rOutRect = GdkRectangle{static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()), + static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())}; + + pWidget = pFrame->getMouseEventWidget(); + } + else + { + rOutRect = GdkRectangle{static_cast<int>(rInRect.Left()), static_cast<int>(rInRect.Top()), + static_cast<int>(rInRect.GetWidth()), static_cast<int>(rInRect.GetHeight())}; + if (SwapForRTL(pWidget)) + rOutRect.x = gtk_widget_get_allocated_width(pWidget) - rOutRect.width - 1 - rOutRect.x; + } + return pWidget; + } + void replaceWidget(GtkWidget* pWidget, GtkWidget* pReplacement) { // remove the widget and replace it with pReplacement @@ -8150,25 +8174,7 @@ public: if (gtk_check_version(3, 22, 0) == nullptr) { GdkRectangle aRect; - if (GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pWidget)) - { - // this is the relatively unusual case where pParent is the toplevel GtkSalFrame and not a stock GtkWidget - // so use the same style of logic as GtkSalMenu::ShowNativePopupMenu to get the right position - tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(pFrame->GetWindow(), rRect); - aFloatRect.Move(-pFrame->maGeometry.nX, -pFrame->maGeometry.nY); - - aRect = GdkRectangle{static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()), - static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())}; - - pWidget = pFrame->getMouseEventWidget(); - } - else - { - aRect = GdkRectangle{static_cast<int>(rRect.Left()), static_cast<int>(rRect.Top()), - static_cast<int>(rRect.GetWidth()), static_cast<int>(rRect.GetHeight())}; - if (SwapForRTL(pWidget)) - aRect.x = gtk_widget_get_allocated_width(pWidget) - aRect.width - 1 - aRect.x; - } + pWidget = getPopupRect(pWidget, rRect, aRect); // Send a keyboard event through gtk_main_do_event to toggle any active tooltip offs // before trying to launch the menu @@ -16579,6 +16585,74 @@ public: return false; } + +class GtkInstancePopover : public GtkInstanceContainer, public virtual weld::Popover +{ +private: + GtkPopover* m_pPopover; + gulong m_nSignalId; + ImplSVEvent* m_pClosedEvent; + + static void signalClosed(GtkPopover*, gpointer widget) + { + GtkInstancePopover* pThis = static_cast<GtkInstancePopover*>(widget); + // call signal-closed async so the closed callback isn't called + // whilc the GtkPopover handler is still in-execution + pThis->launch_signal_closed(); + } + + DECL_LINK(async_signal_closed, void*, void); + + void launch_signal_closed() + { + if (m_pClosedEvent) + Application::RemoveUserEvent(m_pClosedEvent); + m_pClosedEvent = Application::PostUserEvent(LINK(this, GtkInstancePopover, async_signal_closed)); + } + +public: + GtkInstancePopover(GtkPopover* pPopover, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pPopover), pBuilder, bTakeOwnership) + , m_pPopover(pPopover) + , m_nSignalId(g_signal_connect(m_pPopover, "closed", G_CALLBACK(signalClosed), this)) + , m_pClosedEvent(nullptr) + { + } + + virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) override + { + GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pParent); + assert(pGtkWidget); + + GtkWidget* pWidget = pGtkWidget->getWidget(); + + GdkRectangle aRect; + pWidget = getPopupRect(pWidget, rRect, aRect); + + gtk_popover_set_relative_to(m_pPopover, pWidget); + gtk_popover_set_pointing_to(m_pPopover, &aRect); + gtk_popover_popup(m_pPopover); + } + + virtual void popdown() override + { + gtk_popover_popdown(m_pPopover); + } + + virtual ~GtkInstancePopover() override + { + if (m_pClosedEvent) + Application::RemoveUserEvent(m_pClosedEvent); + g_signal_handler_disconnect(m_pPopover, m_nSignalId); + } +}; + +IMPL_LINK_NOARG(GtkInstancePopover, async_signal_closed, void*, void) +{ + m_pClosedEvent = nullptr; + signal_closed(); +} + } namespace @@ -17375,6 +17449,14 @@ public: return std::make_unique<GtkInstanceMenu>(pMenu, true); } + virtual std::unique_ptr<weld::Popover> weld_popover(const OString &id) override + { + GtkPopover* pPopover = GTK_POPOVER(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pPopover) + return nullptr; + return std::make_unique<GtkInstancePopover>(pPopover, this, true); + } + virtual std::unique_ptr<weld::Toolbar> weld_toolbar(const OString &id) override { GtkToolbar* pToolbar = GTK_TOOLBAR(gtk_builder_get_object(m_pBuilder, id.getStr())); |