summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2021-02-25 17:03:31 +0000
committerCaolán McNamara <caolanm@redhat.com>2021-02-26 20:57:31 +0100
commita5a71c7bb58a16a64c586c3ea142e0dd88cf7104 (patch)
treebe9545002fd9b32441b14f04505f0f4c1f05171d /vcl
parentbbb3f36877807a5f6106956d7497f281169d9421 (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.hxx2
-rw-r--r--vcl/source/app/salvtables.cxx62
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx120
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()));