summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2019-10-09 13:55:46 +0100
committerCaolán McNamara <caolanm@redhat.com>2019-10-10 20:25:07 +0200
commitbb6bcabda53dbd64dda43f09fab9f4ad6f34eba6 (patch)
tree4fe51458a061c92587c22be397fd74a2e4436aaf
parent68549e00d5e23aa22bc974a8151d93cd948444b3 (diff)
support screenshotting .ui files with GtkBuilder
so... SAL_USE_VCLPLUGIN=gtk3 make screenshot for the "unknown dialog" cases of make screenshot, which loads .ui files and tries to render them, will render them with the native gtk infrastructure Change-Id: Ifc8fe264155887c4d01b7ce0e2aa53e12acbfcb0 Reviewed-on: https://gerrit.libreoffice.org/80545 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--include/test/screenshot_test.hxx15
-rw-r--r--include/vcl/dialog.hxx18
-rw-r--r--include/vcl/syswin.hxx18
-rw-r--r--include/vcl/weld.hxx57
-rw-r--r--test/source/screenshot_test.cxx106
-rw-r--r--vcl/UIConfig_vcl.mk1
-rw-r--r--vcl/source/app/salvtables.cxx124
-rw-r--r--vcl/source/window/dialog.cxx53
-rw-r--r--vcl/source/window/syswin.cxx54
-rw-r--r--vcl/uiconfig/ui/screenshotparent.ui54
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx377
11 files changed, 511 insertions, 366 deletions
diff --git a/include/test/screenshot_test.hxx b/include/test/screenshot_test.hxx
index 74bcfc721d53..3e1f3f84a06f 100644
--- a/include/test/screenshot_test.hxx
+++ b/include/test/screenshot_test.hxx
@@ -15,7 +15,8 @@
#include <unotest/macros_test.hxx>
#include <com/sun/star/lang/XComponent.hpp>
#include <osl/file.hxx>
-#include <vcl/dialog.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/weld.hxx>
#include <map>
class VclAbstractDialog;
@@ -30,11 +31,18 @@ private:
/// the set of known dialogs and their ID for usage in createDialogByID
mapType maKnownDialogs;
+ /// parent for non-dialog buildables
+ weld::GenericDialogController maParent;
+ std::unique_ptr<weld::Container> mxParentWidget;
+
private:
/// helpers
void implSaveScreenshot(const BitmapEx& rScreenshot, const OString& rScreenshotId);
void saveScreenshot(VclAbstractDialog const & rDialog);
- void saveScreenshot(Dialog& rDialog);
+ void saveScreenshot(weld::Window& rDialog);
+
+ /// helper method to create and dump a dialog based on Builder contents.
+ void dumpDialogToPath(weld::Builder& rDialog);
/// helper method to populate maKnownDialogs, called in setUp(). Needs to be
/// written and has to add entries to maKnownDialogs
@@ -58,9 +66,6 @@ public:
/// version for AbstractDialogs, the ones created in AbstractDialogFactories
void dumpDialogToPath(VclAbstractDialog& rDialog);
- /// version for pure vcl-based dialogs
- void dumpDialogToPath(Dialog& rDialog);
-
/// fallback version for dialogs for which only the UXMLDescription is known.
/// This should be used with care - no active layouting will be done, only the
/// VclBuilder will be activated for layouting. Result can thus vary drastically
diff --git a/include/vcl/dialog.hxx b/include/vcl/dialog.hxx
index cc5355d58132..ee2560abc475 100644
--- a/include/vcl/dialog.hxx
+++ b/include/vcl/dialog.hxx
@@ -50,7 +50,6 @@ private:
bool mbInSyncExecute;
bool mbInClose;
bool mbModalMode;
- bool mbPaintComplete;
bool const mbForceBorderWindow;
InitFlag const mnInitFlag; // used for deferred init
@@ -70,11 +69,6 @@ private:
DECL_DLLPRIVATE_LINK(ImplAsyncCloseHdl, void*, void);
DECL_DLLPRIVATE_LINK(ResponseHdl, Button*, void);
- // ensureRepaint - triggers Application::Yield until the dialog is
- // completely repainted. Sometimes needed for dialogs showing progress
- // during actions
- void ensureRepaint();
-
protected:
using Window::ImplInit;
void ImplInit( vcl::Window* pParent, WinBits nStyle, InitFlag eFlag = InitFlag::Default );
@@ -95,6 +89,7 @@ protected:
protected:
friend class VclBuilder;
+ friend class SalInstanceBuilder;
void set_action_area(VclButtonBox* pBox);
virtual void set_content_area(VclBox* pBox);
@@ -119,17 +114,6 @@ public:
virtual bool Close() override;
- // try to extract content and return as Bitmap. To do that reliably, a Yield-loop
- // like in Execute() has to be executed and it is necessary to detect when the
- // paint is finished
- virtual void PrePaint(vcl::RenderContext& rRenderContext) override;
- virtual void PostPaint(vcl::RenderContext& rRenderContext) override;
-
- // Screenshot interface
- virtual std::vector<OString> getAllPageUIXMLDescriptions() const;
- virtual bool selectPageByUIXMLDescription(const OString& rUIXMLDescription);
- void createScreenshot(VirtualDevice& rOutput);
-
virtual short Execute();
bool IsInExecute() const { return mbInExecute; }
// Return true when dialog is synchronously executed (calling ::Execute())
diff --git a/include/vcl/syswin.hxx b/include/vcl/syswin.hxx
index 402aebeb381e..cb6d15d27ead 100644
--- a/include/vcl/syswin.hxx
+++ b/include/vcl/syswin.hxx
@@ -141,6 +141,7 @@ private:
bool mbHideBtn;
bool mbSysChild;
bool mbIsCalculatingInitialLayoutSize;
+ bool mbPaintComplete;
MenuBarMode mnMenuBarMode;
sal_uInt16 mnIcon;
std::unique_ptr<ImplData> mpImplData;
@@ -159,6 +160,17 @@ private:
SAL_DLLPRIVATE void setPosSizeOnContainee(Size aSize, Window &rBox);
DECL_DLLPRIVATE_LINK( ImplHandleLayoutTimerHdl, Timer*, void );
+ // try to extract content and return as Bitmap. To do that reliably, a Yield-loop
+ // like in Execute() has to be executed and it is necessary to detect when the
+ // paint is finished
+ virtual void PrePaint(vcl::RenderContext& rRenderContext) override;
+ virtual void PostPaint(vcl::RenderContext& rRenderContext) override;
+
+ // ensureRepaint - triggers Application::Yield until the dialog is
+ // completely repainted. Sometimes needed for dialogs showing progress
+ // during actions
+ SAL_DLLPRIVATE void ensureRepaint();
+
protected:
// Single argument ctors shall be explicit.
explicit SystemWindow(WindowType nType);
@@ -171,6 +183,7 @@ protected:
SAL_DLLPRIVATE void DoInitialLayout();
SAL_DLLPRIVATE void SetIdleDebugName( const sal_Char *pDebugName );
+
public:
virtual ~SystemWindow() override;
virtual void dispose() override;
@@ -270,6 +283,11 @@ public:
SAL_DLLPRIVATE bool hasPendingLayout() const { return maLayoutIdle.IsActive(); }
virtual void doDeferredInit(WinBits nBits);
+
+ // Screenshot interface
+ virtual std::vector<OString> getAllPageUIXMLDescriptions() const;
+ virtual bool selectPageByUIXMLDescription(const OString& rUIXMLDescription);
+ void createScreenshot(VirtualDevice& rOutput);
};
inline void SystemWindow::SetIdleDebugName( const sal_Char *pDebugName )
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 20c8d9e5751e..be9cf23f0779 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -351,6 +351,26 @@ public:
void connect_enter_page(const Link<const OString&, void>& rLink) { m_aEnterPageHdl = rLink; }
};
+class VCL_DLLPUBLIC ScreenShotEntry
+{
+public:
+ ScreenShotEntry(const OString& rHelpId, const basegfx::B2IRange& rB2IRange)
+ : msHelpId(rHelpId)
+ , maB2IRange(rB2IRange)
+ {
+ }
+
+ const basegfx::B2IRange& getB2IRange() const { return maB2IRange; }
+
+ const OString& GetHelpId() const { return msHelpId; }
+
+private:
+ OString msHelpId;
+ basegfx::B2IRange maB2IRange;
+};
+
+typedef std::vector<ScreenShotEntry> ScreenShotCollection;
+
class VCL_DLLPUBLIC Window : virtual public Container
{
protected:
@@ -397,6 +417,11 @@ public:
virtual SystemEnvData get_system_data() const = 0;
virtual void resize_to_request() = 0;
+
+ // render the dialog for a screenshot
+ virtual void draw(VirtualDevice& rOutput) = 0;
+ // collect positions of widgets and their help ids for screenshot purposes
+ virtual ScreenShotCollection collect_screenshot_data() = 0;
};
class VCL_DLLPUBLIC WaitObject
@@ -420,26 +445,6 @@ public:
class Button;
-class VCL_DLLPUBLIC ScreenShotEntry
-{
-public:
- ScreenShotEntry(const OString& rHelpId, const basegfx::B2IRange& rB2IRange)
- : msHelpId(rHelpId)
- , maB2IRange(rB2IRange)
- {
- }
-
- const basegfx::B2IRange& getB2IRange() const { return maB2IRange; }
-
- const OString& GetHelpId() const { return msHelpId; }
-
-private:
- OString msHelpId;
- basegfx::B2IRange maB2IRange;
-};
-
-typedef std::vector<ScreenShotEntry> ScreenShotCollection;
-
class VCL_DLLPUBLIC Dialog : virtual public Window
{
private:
@@ -467,11 +472,6 @@ public:
// undo previous dialog collapse
virtual void undo_collapse() = 0;
- // render the dialog for a screenshot
- virtual void draw(VirtualDevice& rOutput) = 0;
- // collect positions of widgets and their help ids for screenshot purposes
- virtual ScreenShotCollection collect_screenshot_data() = 0;
-
virtual void SetInstallLOKNotifierHdl(const Link<void*, vcl::ILibreOfficeKitNotifier*>& rLink)
= 0;
};
@@ -1937,6 +1937,13 @@ public:
virtual std::unique_ptr<Toolbar> weld_toolbar(const OString& id, bool bTakeOwnership = true)
= 0;
virtual std::unique_ptr<SizeGroup> create_size_group() = 0;
+ /* return a Dialog suitable to take a screenshot of containing the contents of the .ui file.
+
+ If the toplevel element is a dialog, that will be returned
+ If the toplevel is not a dialog, a dialog will be created and the contents of the .ui
+ inserted into it
+ */
+ virtual std::unique_ptr<Window> create_screenshot_window() = 0;
virtual ~Builder() {}
};
diff --git a/test/source/screenshot_test.cxx b/test/source/screenshot_test.cxx
index 42dd194d6fe1..6f4d49cc88bd 100644
--- a/test/source/screenshot_test.cxx
+++ b/test/source/screenshot_test.cxx
@@ -20,6 +20,7 @@
#include <vcl/pngwrite.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
#include <unotools/configmgr.hxx>
#include <tools/stream.hxx>
@@ -45,6 +46,8 @@ static constexpr OUStringLiteral g_aScreenshotDirectory("screenshots");
ScreenshotTest::ScreenshotTest()
: maKnownDialogs()
+ , maParent(nullptr, "vcl/ui/screenshotparent.ui", "ScreenShot")
+ , mxParentWidget(maParent.getDialog()->weld_content_area())
{
maCurrentLanguage = OUString::fromUtf8(getenv("LO_TEST_LOCALE"));
}
@@ -109,20 +112,17 @@ void ScreenshotTest::saveScreenshot(VclAbstractDialog const & rDialog)
}
}
-void ScreenshotTest::saveScreenshot(Dialog& rDialog)
+void ScreenshotTest::saveScreenshot(weld::Window& rDialog)
{
VclPtr<VirtualDevice> xDialogSurface(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
- rDialog.createScreenshot(*xDialogSurface);
+ rDialog.draw(*xDialogSurface);
const BitmapEx aScreenshot(xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel()));
if (!aScreenshot.IsEmpty())
{
- const OString aScreenshotId = rDialog.GetScreenshotId();
-
- if (!aScreenshotId.isEmpty())
- {
- implSaveScreenshot(aScreenshot, aScreenshotId);
- }
+ const OString aScreenshotId = rDialog.get_help_id();
+ assert(!aScreenshotId.isEmpty());
+ implSaveScreenshot(aScreenshot, aScreenshotId);
}
}
@@ -162,17 +162,29 @@ void ScreenshotTest::dumpDialogToPath(VclAbstractDialog& rDialog)
}
}
-void ScreenshotTest::dumpDialogToPath(Dialog& rDialog)
+void ScreenshotTest::dumpDialogToPath(weld::Builder& rBuilder)
{
- const std::vector<OString> aPageDescriptions(rDialog.getAllPageUIXMLDescriptions());
+ std::unique_ptr<weld::Window> xDialog(rBuilder.create_screenshot_window());
- if (!aPageDescriptions.empty())
+ auto xTabCtrl = rBuilder.weld_notebook("tabcontrol");
+
+ int nPages = xTabCtrl ? xTabCtrl->get_n_pages() : 0;
+ if (nPages)
{
- for (size_t a(0); a < aPageDescriptions.size(); a++)
+ for (int i = 0; i < nPages; ++i)
{
- if (rDialog.selectPageByUIXMLDescription(aPageDescriptions[a]))
+ OString sIdent(xTabCtrl->get_page_ident(i));
+ xTabCtrl->set_current_page(sIdent);
+ if (xTabCtrl->get_current_page_ident() == sIdent)
{
- saveScreenshot(rDialog);
+ OString sOrigHelpId(xDialog->get_help_id());
+ // skip empty pages
+ weld::Container* pPage = xTabCtrl->get_page(sIdent);
+ OString sBuildableName(pPage->get_buildable_name());
+ if (!sBuildableName.isEmpty() && !sBuildableName.startsWith("__"))
+ xDialog->set_help_id(pPage->get_help_id());
+ saveScreenshot(*xDialog);
+ xDialog->set_help_id(sOrigHelpId);
}
else
{
@@ -182,7 +194,7 @@ void ScreenshotTest::dumpDialogToPath(Dialog& rDialog)
}
else
{
- saveScreenshot(rDialog);
+ saveScreenshot(*xDialog);
}
}
@@ -190,41 +202,33 @@ void ScreenshotTest::dumpDialogToPath(const OString& rUIXMLDescription)
{
if (!rUIXMLDescription.isEmpty())
{
- VclPtrInstance<Dialog> pDialog(Application::GetDefDialogParent(), WB_STDDIALOG | WB_SIZEABLE, Dialog::InitFlag::NoParent);
-
- {
- VclPtr<vcl::Window> aOwnedToplevel;
-
- bool bLegacy = rUIXMLDescription == "fps/ui/remotefilesdialog.ui" ||
- rUIXMLDescription == "modules/swriter/ui/sidebarstylepresets.ui" ||
- rUIXMLDescription == "modules/swriter/ui/sidebartheme.ui" ||
- rUIXMLDescription == "sfx/ui/startcenter.ui" ||
- rUIXMLDescription == "svx/ui/datanavigator.ui";
- std::unique_ptr<VclBuilder> xBuilder(new VclBuilder(pDialog, VclBuilderContainer::getUIRootDir(), OStringToOUString(rUIXMLDescription, RTL_TEXTENCODING_UTF8), OString(), css::uno::Reference<css::frame::XFrame>(), bLegacy));
- vcl::Window *pRoot = xBuilder->get_widget_root();
- Dialog *pRealDialog = dynamic_cast<Dialog*>(pRoot);
-
- if (!pRealDialog)
- {
- pRealDialog = pDialog;
- }
- else
- {
- aOwnedToplevel.set(pRoot);
- xBuilder->drop_ownership(pRoot);
- }
-
- pRealDialog->SetText(utl::ConfigManager::getProductName());
- pRealDialog->SetStyle(pDialog->GetStyle() | WB_CLOSEABLE);
-
- dumpDialogToPath(*pRealDialog);
-
- if (VclBuilderContainer* pOwnedToplevel = dynamic_cast<VclBuilderContainer*>(aOwnedToplevel.get()))
- pOwnedToplevel->m_pUIBuilder = std::move(xBuilder);
- aOwnedToplevel.disposeAndClear();
- }
-
- pDialog.disposeAndClear();
+ bool bNonConforming = rUIXMLDescription == "modules/swriter/ui/sidebarstylepresets.ui" ||
+ rUIXMLDescription == "modules/swriter/ui/sidebarpage.ui" ||
+ rUIXMLDescription == "modules/swriter/ui/sidebartheme.ui" ||
+ rUIXMLDescription == "modules/swriter/ui/sidebarwrap.ui" ||
+ rUIXMLDescription == "modules/swriter/ui/notebookbar.ui" ||
+ rUIXMLDescription == "modules/scalc/ui/sidebaralignment.ui" ||
+ rUIXMLDescription == "modules/scalc/ui/sidebarcellappearance.ui" ||
+ rUIXMLDescription == "modules/scalc/ui/sidebarnumberformat.ui" ||
+ rUIXMLDescription == "sfx/ui/helpbookmarkpage.ui" ||
+ rUIXMLDescription == "sfx/ui/helpcontentpage.ui" ||
+ rUIXMLDescription == "sfx/ui/helpindexpage.ui" ||
+ rUIXMLDescription == "sfx/ui/helpsearchpage.ui" ||
+ rUIXMLDescription == "sfx/ui/startcenter.ui" ||
+ rUIXMLDescription == "svx/ui/datanavigator.ui" ||
+ rUIXMLDescription == "svx/ui/xformspage.ui" ||
+ rUIXMLDescription == "modules/dbreport/ui/conditionwin.ui";
+ if (bNonConforming) // skip these broken ones
+ return;
+ bool bLegacy = rUIXMLDescription == "fps/ui/explorerfiledialog.ui" ||
+ rUIXMLDescription == "fps/ui/remotefilesdialog.ui" ||
+ rUIXMLDescription == "sfx/ui/floatingrecord.ui";
+ std::unique_ptr<weld::Builder> xBuilder;
+ if (bLegacy)
+ xBuilder.reset(Application::CreateInterimBuilder(mxParentWidget.get(), OStringToOUString(rUIXMLDescription, RTL_TEXTENCODING_UTF8)));
+ else
+ xBuilder.reset(Application::CreateBuilder(mxParentWidget.get(), OStringToOUString(rUIXMLDescription, RTL_TEXTENCODING_UTF8)));
+ dumpDialogToPath(*xBuilder);
}
}
@@ -273,7 +277,7 @@ void ScreenshotTest::processDialogBatchFile(const OUString& rFile)
else
{
// unknown dialog, try fallback to generic created
- // VclBuilder-generated instance. Keep in mind that Dialogs
+ // Builder-generated instance. Keep in mind that Dialogs
// using this mechanism will probably not be layouted well
// since the setup/initialization part is missing. Thus,
// only use for fallback when only the UI file is available.
diff --git a/vcl/UIConfig_vcl.mk b/vcl/UIConfig_vcl.mk
index 638fc9a537ae..c00d0d461f23 100644
--- a/vcl/UIConfig_vcl.mk
+++ b/vcl/UIConfig_vcl.mk
@@ -23,6 +23,7 @@ $(eval $(call gb_UIConfig_add_uifiles,vcl,\
vcl/uiconfig/ui/printerpropertiesdialog \
vcl/uiconfig/ui/printprogressdialog \
vcl/uiconfig/ui/querydialog \
+ vcl/uiconfig/ui/screenshotparent \
))
$(eval $(call gb_UIConfig_add_a11yerrors_uifiles,vcl,\
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 416f81071e93..d12c3464c75d 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -35,6 +35,7 @@
#include <messagedialog.hxx>
#include <treeglue.hxx>
#include <unotools/accessiblerelationsethelper.hxx>
+#include <unotools/configmgr.hxx>
#include <utility>
#include <tools/helpers.hxx>
#include <vcl/abstdlg.hxx>
@@ -1059,6 +1060,34 @@ std::unique_ptr<weld::Container> SalInstanceWidget::weld_parent() const
return std::make_unique<SalInstanceContainer>(pParent, m_pBuilder, false);
}
+namespace
+{
+ void CollectChildren(const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft, weld::ScreenShotCollection& rControlDataCollection)
+ {
+ if (rCurrent.IsVisible())
+ {
+ const Point aCurrentPos(rCurrent.GetPosPixel());
+ const Size aCurrentSize(rCurrent.GetSizePixel());
+ const basegfx::B2IPoint aCurrentTopLeft(rTopLeft.getX() + aCurrentPos.X(), rTopLeft.getY() + aCurrentPos.Y());
+ const basegfx::B2IRange aCurrentRange(aCurrentTopLeft, aCurrentTopLeft + basegfx::B2IPoint(aCurrentSize.Width(), aCurrentSize.Height()));
+
+ if (!aCurrentRange.isEmpty())
+ {
+ rControlDataCollection.emplace_back(rCurrent.GetHelpId(), aCurrentRange);
+ }
+
+ for (sal_uInt16 a(0); a < rCurrent.GetChildCount(); a++)
+ {
+ vcl::Window* pChild = rCurrent.GetChild(a);
+ if (nullptr != pChild)
+ {
+ CollectChildren(*pChild, aCurrentTopLeft, rControlDataCollection);
+ }
+ }
+ }
+ }
+}
+
class SalInstanceWindow : public SalInstanceContainer, public virtual weld::Window
{
private:
@@ -1221,6 +1250,26 @@ public:
SalInstanceContainer::HandleEventListener(rEvent);
}
+ virtual void draw(VirtualDevice& rOutput) override
+ {
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ pSysWin->createScreenshot(rOutput);
+ }
+
+ virtual weld::ScreenShotCollection collect_screenshot_data() override
+ {
+ weld::ScreenShotCollection aRet;
+
+ // collect all children. Choose start pos to be negative
+ // of target dialog's position to get all positions relative to (0,0)
+ const Point aParentPos(m_xWindow->GetPosPixel());
+ const basegfx::B2IPoint aTopLeft(-aParentPos.X(), -aParentPos.Y());
+ CollectChildren(*m_xWindow, aTopLeft, aRet);
+
+ return aRet;
+ }
+
virtual ~SalInstanceWindow() override
{
clear_child_help(m_xWindow);
@@ -1258,34 +1307,6 @@ namespace
}
}
-namespace
-{
- void CollectChildren(const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft, weld::ScreenShotCollection& rControlDataCollection)
- {
- if (rCurrent.IsVisible())
- {
- const Point aCurrentPos(rCurrent.GetPosPixel());
- const Size aCurrentSize(rCurrent.GetSizePixel());
- const basegfx::B2IPoint aCurrentTopLeft(rTopLeft.getX() + aCurrentPos.X(), rTopLeft.getY() + aCurrentPos.Y());
- const basegfx::B2IRange aCurrentRange(aCurrentTopLeft, aCurrentTopLeft + basegfx::B2IPoint(aCurrentSize.Width(), aCurrentSize.Height()));
-
- if (!aCurrentRange.isEmpty())
- {
- rControlDataCollection.emplace_back(rCurrent.GetHelpId(), aCurrentRange);
- }
-
- for (sal_uInt16 a(0); a < rCurrent.GetChildCount(); a++)
- {
- vcl::Window* pChild = rCurrent.GetChild(a);
- if (nullptr != pChild)
- {
- CollectChildren(*pChild, aCurrentTopLeft, rControlDataCollection);
- }
- }
- }
- }
-}
-
class SalInstanceDialog : public SalInstanceWindow, public virtual weld::Dialog
{
private:
@@ -1474,23 +1495,6 @@ public:
return new SalInstanceContainer(m_xDialog->get_content_area(), m_pBuilder, false);
}
- virtual void draw(VirtualDevice& rOutput) override
- {
- m_xDialog->createScreenshot(rOutput);
- }
-
- virtual weld::ScreenShotCollection collect_screenshot_data() override
- {
- weld::ScreenShotCollection aRet;
-
- // collect all children. Choose start pos to be negative
- // of target dialog's position to get all positions relative to (0,0)
- const Point aParentPos(m_xDialog->GetPosPixel());
- const basegfx::B2IPoint aTopLeft(-aParentPos.X(), -aParentPos.Y());
- CollectChildren(*m_xDialog, aTopLeft, aRet);
-
- return aRet;
- }
};
IMPL_LINK(SalInstanceDialog, PopupScreenShotMenuHdl, const CommandEvent&, rCEvt, bool)
@@ -5759,6 +5763,34 @@ public:
return pRet;
}
+ virtual std::unique_ptr<weld::Window> create_screenshot_window() override
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+
+ vcl::Window *pRoot = m_xBuilder->get_widget_root();
+ if (SystemWindow *pWindow = dynamic_cast<SystemWindow*>(pRoot))
+ {
+ std::unique_ptr<weld::Window> xRet(new SalInstanceWindow(pWindow, this, false));
+ m_aOwnedToplevel.set(pWindow);
+ m_xBuilder->drop_ownership(pWindow);
+ return xRet;
+ }
+
+ VclPtrInstance<Dialog> xDialog(nullptr, WB_HIDE | WB_STDDIALOG | WB_SIZEABLE | WB_CLOSEABLE, Dialog::InitFlag::NoParent);
+ xDialog->SetText(utl::ConfigManager::getProductName());
+
+ auto xContentArea = VclPtr<VclVBox>::Create(xDialog, false, 12);
+ pRoot->SetParent(xContentArea);
+ assert(pRoot == xContentArea->GetWindow(GetWindowType::FirstChild));
+ xContentArea->Show();
+ pRoot->Show();
+ xDialog->SetHelpId(pRoot->GetHelpId());
+
+ m_aOwnedToplevel.set(xDialog);
+
+ return std::unique_ptr<weld::Dialog>(new SalInstanceDialog(xDialog, this, false));
+ }
+
virtual std::unique_ptr<weld::Window> weld_window(const OString &id, bool bTakeOwnership) override
{
SystemWindow* pWindow = m_xBuilder->get<SystemWindow>(id);
@@ -5799,6 +5831,8 @@ public:
virtual std::unique_ptr<weld::Notebook> weld_notebook(const OString &id, bool bTakeOwnership) override
{
vcl::Window* pNotebook = m_xBuilder->get<vcl::Window>(id);
+ if (!pNotebook)
+ return nullptr;
if (pNotebook->GetType() == WindowType::TABCONTROL)
return std::make_unique<SalInstanceNotebook>(static_cast<TabControl*>(pNotebook), this, bTakeOwnership);
if (pNotebook->GetType() == WindowType::VERTICALTABCONTROL)
diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
index 679403c9efbc..714141ea8131 100644
--- a/vcl/source/window/dialog.cxx
+++ b/vcl/source/window/dialog.cxx
@@ -386,7 +386,6 @@ void Dialog::ImplInitDialogData()
mbInSyncExecute = false;
mbInClose = false;
mbModalMode = false;
- mbPaintComplete = false;
mpContentArea.clear();
mpActionArea.clear();
mnMousePositioned = 0;
@@ -1013,58 +1012,6 @@ void Dialog::ImplEndExecuteModal()
pSVData->maAppData.mnModalMode--;
}
-void Dialog::PrePaint(vcl::RenderContext& rRenderContext)
-{
- SystemWindow::PrePaint(rRenderContext);
- mbPaintComplete = false;
-}
-
-void Dialog::PostPaint(vcl::RenderContext& rRenderContext)
-{
- SystemWindow::PostPaint(rRenderContext);
- mbPaintComplete = true;
-}
-
-std::vector<OString> Dialog::getAllPageUIXMLDescriptions() const
-{
- // default has no pages
- return std::vector<OString>();
-}
-
-bool Dialog::selectPageByUIXMLDescription(const OString& /*rUIXMLDescription*/)
-{
- // default cannot select anything (which is okay, return true)
- return true;
-}
-
-void Dialog::ensureRepaint()
-{
- // ensure repaint
- Invalidate();
- mbPaintComplete = false;
-
- while (!mbPaintComplete)
- {
- Application::Yield();
- }
-}
-
-void Dialog::createScreenshot(VirtualDevice& rOutput)
-{
- // same prerequisites as in Execute()
- setDeferredProperties();
- ImplAdjustNWFSizes();
- Show();
- ToTop();
- ensureRepaint();
-
- Point aPos;
- Size aSize(GetOutputSizePixel());
-
- rOutput.SetOutputSizePixel(aSize);
- rOutput.DrawOutDev(aPos, aSize, aPos, aSize, *this);
-}
-
short Dialog::Execute()
{
// Once the Android app is based on same idea as the iOS one currently
diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx
index aa0964524e35..c6ecb2109a74 100644
--- a/vcl/source/window/syswin.cxx
+++ b/vcl/source/window/syswin.cxx
@@ -31,6 +31,7 @@
#include <vcl/taskpanelist.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>
+#include <vcl/virdev.hxx>
#include <rtl/strbuf.hxx>
@@ -67,6 +68,7 @@ SystemWindow::SystemWindow(WindowType nType)
, mbHideBtn(false)
, mbSysChild(false)
, mbIsCalculatingInitialLayoutSize(false)
+ , mbPaintComplete(false)
, mnMenuBarMode(MenuBarMode::Normal)
, mnIcon(0)
, mpImplData(new ImplData)
@@ -1152,4 +1154,56 @@ void SystemWindow::doDeferredInit(WinBits /*nBits*/)
SAL_WARN("vcl.layout", "SystemWindow in layout without doDeferredInit impl");
}
+std::vector<OString> SystemWindow::getAllPageUIXMLDescriptions() const
+{
+ // default has no pages
+ return std::vector<OString>();
+}
+
+bool SystemWindow::selectPageByUIXMLDescription(const OString& /*rUIXMLDescription*/)
+{
+ // default cannot select anything (which is okay, return true)
+ return true;
+}
+
+void SystemWindow::createScreenshot(VirtualDevice& rOutput)
+{
+ // same prerequisites as in Execute()
+ setDeferredProperties();
+ ImplAdjustNWFSizes();
+ Show();
+ ToTop();
+ ensureRepaint();
+
+ Point aPos;
+ Size aSize(GetOutputSizePixel());
+
+ rOutput.SetOutputSizePixel(aSize);
+ rOutput.DrawOutDev(aPos, aSize, aPos, aSize, *this);
+}
+
+void SystemWindow::PrePaint(vcl::RenderContext& rRenderContext)
+{
+ Window::PrePaint(rRenderContext);
+ mbPaintComplete = false;
+}
+
+void SystemWindow::PostPaint(vcl::RenderContext& rRenderContext)
+{
+ Window::PostPaint(rRenderContext);
+ mbPaintComplete = true;
+}
+
+void SystemWindow::ensureRepaint()
+{
+ // ensure repaint
+ Invalidate();
+ mbPaintComplete = false;
+
+ while (!mbPaintComplete)
+ {
+ Application::Yield();
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/uiconfig/ui/screenshotparent.ui b/vcl/uiconfig/ui/screenshotparent.ui
new file mode 100644
index 000000000000..722a1e810839
--- /dev/null
+++ b/vcl/uiconfig/ui/screenshotparent.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="vcl">
+ <requires lib="gtk+" version="3.18"/>
+ <object class="GtkDialog" id="ScreenShot">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="ScreenShotBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="internalarea">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 1ddbc7f0b180..9dd62384c2da 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -3223,6 +3223,126 @@ namespace
}
}
+namespace
+{
+ struct ButtonOrder
+ {
+ const char * m_aType;
+ int m_nPriority;
+ };
+
+ int getButtonPriority(const OString &rType)
+ {
+ static const size_t N_TYPES = 6;
+ static const ButtonOrder aDiscardCancelSave[N_TYPES] =
+ {
+ { "/discard", 0 },
+ { "/cancel", 1 },
+ { "/no", 2 },
+ { "/save", 3 },
+ { "/yes", 3 },
+ { "/ok", 3 }
+ };
+
+ static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
+ {
+ { "/save", 0 },
+ { "/yes", 0 },
+ { "/ok", 0 },
+ { "/discard", 1 },
+ { "/no", 1 },
+ { "/cancel", 2 }
+ };
+
+ const ButtonOrder* pOrder = &aDiscardCancelSave[0];
+
+ const OUString &rEnv = Application::GetDesktopEnvironment();
+
+ if (rEnv.equalsIgnoreAsciiCase("windows") ||
+ rEnv.equalsIgnoreAsciiCase("tde") ||
+ rEnv.startsWithIgnoreAsciiCase("kde"))
+ {
+ pOrder = &aSaveDiscardCancel[0];
+ }
+
+ for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
+ {
+ if (rType.endsWith(pOrder->m_aType))
+ return pOrder->m_nPriority;
+ }
+
+ return -1;
+ }
+
+ bool sortButtons(const GtkWidget* pA, const GtkWidget* pB)
+ {
+ //order within groups according to platform rules
+ return getButtonPriority(::get_help_id(pA)) < getButtonPriority(::get_help_id(pB));
+ }
+
+ void sort_native_button_order(GtkBox* pContainer)
+ {
+ std::vector<GtkWidget*> aChildren;
+ GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pContainer));
+ for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild))
+ aChildren.push_back(static_cast<GtkWidget*>(pChild->data));
+ g_list_free(pChildren);
+
+ //sort child order within parent so that we match the platform button order
+ std::stable_sort(aChildren.begin(), aChildren.end(), sortButtons);
+
+ for (size_t pos = 0; pos < aChildren.size(); ++pos)
+ gtk_box_reorder_child(pContainer, aChildren[pos], pos);
+ }
+
+ Point get_csd_offset(GtkWidget* pTopLevel)
+ {
+ // try and omit drawing CSD under wayland
+ GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pTopLevel));
+ GList* pChild = g_list_first(pChildren);
+
+ int x, y;
+ gtk_widget_translate_coordinates(GTK_WIDGET(pChild->data),
+ GTK_WIDGET(pTopLevel),
+ 0, 0, &x, &y);
+
+ int innerborder = gtk_container_get_border_width(GTK_CONTAINER(pChild->data));
+ g_list_free(pChildren);
+
+ int outerborder = gtk_container_get_border_width(GTK_CONTAINER(pTopLevel));
+ int totalborder = outerborder + innerborder;
+ x -= totalborder;
+ y -= totalborder;
+
+ return Point(x, y);
+ }
+
+ void do_collect_screenshot_data(GtkWidget* pItem, gpointer data)
+ {
+ GtkWidget* pTopLevel = gtk_widget_get_toplevel(pItem);
+
+ int x, y;
+ gtk_widget_translate_coordinates(pItem, pTopLevel, 0, 0, &x, &y);
+
+ Point aOffset = get_csd_offset(pTopLevel);
+
+ GtkAllocation alloc;
+ gtk_widget_get_allocation(pItem, &alloc);
+
+ const basegfx::B2IPoint aCurrentTopLeft(x - aOffset.X(), y - aOffset.Y());
+ const basegfx::B2IRange aCurrentRange(aCurrentTopLeft, aCurrentTopLeft + basegfx::B2IPoint(alloc.width, alloc.height));
+
+ if (!aCurrentRange.isEmpty())
+ {
+ weld::ScreenShotCollection* pCollection = static_cast<weld::ScreenShotCollection*>(data);
+ pCollection->emplace_back(::get_help_id(pItem), aCurrentRange);
+ }
+
+ if (GTK_IS_CONTAINER(pItem))
+ gtk_container_forall(GTK_CONTAINER(pItem), do_collect_screenshot_data, data);
+ }
+}
+
class GtkInstanceWindow : public GtkInstanceContainer, public virtual weld::Window
{
private:
@@ -3434,87 +3554,68 @@ public:
g_signal_handler_unblock(m_pWidget, m_nToplevelFocusChangedSignalId);
}
- virtual ~GtkInstanceWindow() override
- {
- if (m_nToplevelFocusChangedSignalId)
- g_signal_handler_disconnect(m_pWindow, m_nToplevelFocusChangedSignalId);
- if (m_xWindow.is())
- m_xWindow->clear();
- }
-};
-
-namespace
-{
- struct ButtonOrder
- {
- const char * m_aType;
- int m_nPriority;
- };
-
- int getButtonPriority(const OString &rType)
+ virtual void draw(VirtualDevice& rOutput) override
{
- static const size_t N_TYPES = 6;
- static const ButtonOrder aDiscardCancelSave[N_TYPES] =
+ // detect if we have to manually setup its size
+ bool bAlreadyRealized = gtk_widget_get_realized(GTK_WIDGET(m_pWindow));
+ // has to be visible for draw to work
+ bool bAlreadyVisible = gtk_widget_get_visible(GTK_WIDGET(m_pWindow));
+ if (!bAlreadyVisible)
{
- { "/discard", 0 },
- { "/cancel", 1 },
- { "/no", 2 },
- { "/save", 3 },
- { "/yes", 3 },
- { "/ok", 3 }
- };
+ if (GTK_IS_DIALOG(m_pWindow))
+ sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pWindow))));
+ gtk_widget_show(GTK_WIDGET(m_pWindow));
+ }
- static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
+ if (!bAlreadyRealized)
{
- { "/save", 0 },
- { "/yes", 0 },
- { "/ok", 0 },
- { "/discard", 1 },
- { "/no", 1 },
- { "/cancel", 2 }
- };
+ GtkAllocation allocation;
+ gtk_widget_realize(GTK_WIDGET(m_pWindow));
+ gtk_widget_get_allocation(GTK_WIDGET(m_pWindow), &allocation);
+ gtk_widget_size_allocate(GTK_WIDGET(m_pWindow), &allocation);
+ }
- const ButtonOrder* pOrder = &aDiscardCancelSave[0];
+ rOutput.SetOutputSizePixel(get_size());
+ cairo_surface_t* pSurface = get_underlying_cairo_surface(rOutput);
+ cairo_t* cr = cairo_create(pSurface);
- const OUString &rEnv = Application::GetDesktopEnvironment();
+ Point aOffset = get_csd_offset(GTK_WIDGET(m_pWindow));
- if (rEnv.equalsIgnoreAsciiCase("windows") ||
- rEnv.equalsIgnoreAsciiCase("tde") ||
- rEnv.startsWithIgnoreAsciiCase("kde"))
- {
- pOrder = &aSaveDiscardCancel[0];
- }
+#if defined(GDK_WINDOWING_X11)
+ GdkDisplay *pDisplay = gtk_widget_get_display(GTK_WIDGET(m_pWindow));
+ if (DLSYM_GDK_IS_X11_DISPLAY(pDisplay))
+ assert(aOffset.X() == 0 && aOffset.Y() == 0 && "expected offset of 0 under X");
+#endif
- for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
- {
- if (rType.endsWith(pOrder->m_aType))
- return pOrder->m_nPriority;
- }
+ cairo_translate(cr, -aOffset.X(), -aOffset.Y());
- return -1;
- }
+ gtk_widget_draw(GTK_WIDGET(m_pWindow), cr);
- bool sortButtons(const GtkWidget* pA, const GtkWidget* pB)
- {
- //order within groups according to platform rules
- return getButtonPriority(::get_help_id(pA)) < getButtonPriority(::get_help_id(pB));
+ cairo_destroy(cr);
+
+ if (!bAlreadyVisible)
+ gtk_widget_hide(GTK_WIDGET(m_pWindow));
+ if (!bAlreadyRealized)
+ gtk_widget_unrealize(GTK_WIDGET(m_pWindow));
}
- void sort_native_button_order(GtkBox* pContainer)
+ virtual weld::ScreenShotCollection collect_screenshot_data() override
{
- std::vector<GtkWidget*> aChildren;
- GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pContainer));
- for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild))
- aChildren.push_back(static_cast<GtkWidget*>(pChild->data));
- g_list_free(pChildren);
+ weld::ScreenShotCollection aRet;
- //sort child order within parent so that we match the platform button order
- std::stable_sort(aChildren.begin(), aChildren.end(), sortButtons);
+ gtk_container_foreach(GTK_CONTAINER(m_pWindow), do_collect_screenshot_data, &aRet);
- for (size_t pos = 0; pos < aChildren.size(); ++pos)
- gtk_box_reorder_child(pContainer, aChildren[pos], pos);
+ return aRet;
}
-}
+
+ virtual ~GtkInstanceWindow() override
+ {
+ if (m_nToplevelFocusChangedSignalId)
+ g_signal_handler_disconnect(m_pWindow, m_nToplevelFocusChangedSignalId);
+ if (m_xWindow.is())
+ m_xWindow->clear();
+ }
+};
class GtkInstanceDialog;
@@ -3861,54 +3962,6 @@ private:
return false;
}
- static Point get_csd_offset(GtkWidget* pTopLevel)
- {
- // try and omit drawing CSD under wayland
- GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pTopLevel));
- GList* pChild = g_list_first(pChildren);
-
- int x, y;
- gtk_widget_translate_coordinates(GTK_WIDGET(pChild->data),
- GTK_WIDGET(pTopLevel),
- 0, 0, &x, &y);
-
- int innerborder = gtk_container_get_border_width(GTK_CONTAINER(pChild->data));
- g_list_free(pChildren);
-
- int outerborder = gtk_container_get_border_width(GTK_CONTAINER(pTopLevel));
- int totalborder = outerborder + innerborder;
- x -= totalborder;
- y -= totalborder;
-
- return Point(x, y);
- }
-
- static void do_collect_screenshot_data(GtkWidget* pItem, gpointer data)
- {
- GtkWidget* pTopLevel = gtk_widget_get_toplevel(pItem);
-
- int x, y;
- gtk_widget_translate_coordinates(pItem, pTopLevel, 0, 0, &x, &y);
-
- Point aOffset = get_csd_offset(pTopLevel);
-
- GtkAllocation alloc;
- gtk_widget_get_allocation(pItem, &alloc);
-
- const basegfx::B2IPoint aCurrentTopLeft(x - aOffset.X(), y - aOffset.Y());
- const basegfx::B2IRange aCurrentRange(aCurrentTopLeft, aCurrentTopLeft + basegfx::B2IPoint(alloc.width, alloc.height));
-
- if (!aCurrentRange.isEmpty())
- {
- weld::ScreenShotCollection* pCollection = static_cast<weld::ScreenShotCollection*>(data);
- pCollection->emplace_back(::get_help_id(pItem), aCurrentRange);
- }
-
- if (GTK_IS_CONTAINER(pItem))
- gtk_container_forall(GTK_CONTAINER(pItem), do_collect_screenshot_data, data);
- }
-
-
public:
GtkInstanceDialog(GtkWindow* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
: GtkInstanceWindow(pDialog, pBuilder, bTakeOwnership)
@@ -4125,59 +4178,6 @@ public:
//not implemented for the gtk variant
}
- virtual void draw(VirtualDevice& rOutput) override
- {
- // detect if we have to manually setup its size
- bool bAlreadyRealized = gtk_widget_get_realized(GTK_WIDGET(m_pDialog));
- // has to be visible for draw to work
- bool bAlreadyVisible = gtk_widget_get_visible(GTK_WIDGET(m_pDialog));
- if (!bAlreadyVisible)
- {
- sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog))));
- gtk_widget_show(GTK_WIDGET(m_pDialog));
- }
-
- if (!bAlreadyRealized)
- {
- GtkAllocation allocation;
- gtk_widget_realize(GTK_WIDGET(m_pDialog));
- gtk_widget_get_allocation(GTK_WIDGET(m_pDialog), &allocation);
- gtk_widget_size_allocate(GTK_WIDGET(m_pDialog), &allocation);
- }
-
- rOutput.SetOutputSizePixel(get_size());
- cairo_surface_t* pSurface = get_underlying_cairo_surface(rOutput);
- cairo_t* cr = cairo_create(pSurface);
-
- Point aOffset = get_csd_offset(GTK_WIDGET(m_pDialog));
-
-#if defined(GDK_WINDOWING_X11)
- GdkDisplay *pDisplay = gtk_widget_get_display(GTK_WIDGET(m_pDialog));
- if (DLSYM_GDK_IS_X11_DISPLAY(pDisplay))
- assert(aOffset.X() == 0 && aOffset.Y() == 0 && "expected offset of 0 under X");
-#endif
-
- cairo_translate(cr, -aOffset.X(), -aOffset.Y());
-
- gtk_widget_draw(GTK_WIDGET(m_pDialog), cr);
-
- cairo_destroy(cr);
-
- if (!bAlreadyVisible)
- gtk_widget_hide(GTK_WIDGET(m_pDialog));
- if (!bAlreadyRealized)
- gtk_widget_unrealize(GTK_WIDGET(m_pDialog));
- }
-
- virtual weld::ScreenShotCollection collect_screenshot_data() override
- {
- weld::ScreenShotCollection aRet;
-
- gtk_container_foreach(GTK_CONTAINER(m_pDialog), do_collect_screenshot_data, &aRet);
-
- return aRet;
- }
-
virtual ~GtkInstanceDialog() override
{
if (!m_aHiddenWidgets.empty())
@@ -11748,7 +11748,6 @@ public:
return sPageHelpId;
}
-
virtual ~GtkInstanceBuilder() override
{
g_slist_free(m_pObjectList);
@@ -11795,12 +11794,50 @@ public:
virtual std::unique_ptr<weld::Dialog> weld_dialog(const OString &id, bool bTakeOwnership) override
{
- GtkDialog* pDialog = GTK_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr()));
+ GtkWindow* pDialog = GTK_WINDOW(gtk_builder_get_object(m_pBuilder, id.getStr()));
if (!pDialog)
return nullptr;
if (m_pParentWidget)
- gtk_window_set_transient_for(GTK_WINDOW(pDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget)));
- return std::make_unique<GtkInstanceDialog>(GTK_WINDOW(pDialog), this, bTakeOwnership);
+ gtk_window_set_transient_for(pDialog, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget)));
+ return std::make_unique<GtkInstanceDialog>(pDialog, this, bTakeOwnership);
+ }
+
+ virtual std::unique_ptr<weld::Window> create_screenshot_window() override
+ {
+ GtkWidget* pTopLevel = nullptr;
+
+ for (GSList* l = m_pObjectList; l; l = g_slist_next(l))
+ {
+ GObject* pObj = static_cast<GObject*>(l->data);
+
+ if (!GTK_IS_WIDGET(pObj) || gtk_widget_get_parent(GTK_WIDGET(pObj)))
+ continue;
+
+ if (!pTopLevel)
+ pTopLevel = GTK_WIDGET(pObj);
+ else if (GTK_IS_WINDOW(pObj))
+ pTopLevel = GTK_WIDGET(pObj);
+ }
+
+ if (!pTopLevel)
+ return nullptr;
+
+ GtkWindow* pDialog;
+ if (GTK_IS_WINDOW(pTopLevel))
+ pDialog = GTK_WINDOW(pTopLevel);
+ else
+ {
+ pDialog = GTK_WINDOW(gtk_dialog_new());
+ ::set_help_id(GTK_WIDGET(pDialog), ::get_help_id(pTopLevel));
+
+ GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG(pDialog));
+ gtk_container_add(GTK_CONTAINER(pContentArea), pTopLevel);
+ gtk_widget_show_all(pTopLevel);
+ }
+
+ if (m_pParentWidget)
+ gtk_window_set_transient_for(pDialog, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget)));
+ return std::make_unique<GtkInstanceDialog>(pDialog, this, true);
}
virtual std::unique_ptr<weld::Window> weld_window(const OString &id, bool bTakeOwnership) override