diff options
-rw-r--r-- | cui/source/dialogs/screenshotannotationdlg.cxx | 115 | ||||
-rw-r--r-- | cui/source/factory/dlgfact.cxx | 6 | ||||
-rw-r--r-- | cui/source/factory/dlgfact.hxx | 2 | ||||
-rw-r--r-- | cui/source/inc/screenshotannotationdlg.hxx | 4 | ||||
-rw-r--r-- | cui/uiconfig/ui/screenshotannotationdialog.ui | 5 | ||||
-rw-r--r-- | include/vcl/abstdlg.hxx | 2 | ||||
-rw-r--r-- | include/vcl/dialog.hxx | 5 | ||||
-rw-r--r-- | include/vcl/layout.hxx | 2 | ||||
-rw-r--r-- | include/vcl/weld.hxx | 26 | ||||
-rw-r--r-- | sc/source/ui/attrdlg/scdlgfact.hxx | 7 | ||||
-rw-r--r-- | solenv/sanitizers/ui/cui.suppr | 4 | ||||
-rw-r--r-- | test/source/screenshot_test.cxx | 5 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 97 | ||||
-rw-r--r-- | vcl/source/window/dialog.cxx | 22 | ||||
-rw-r--r-- | vcl/source/window/layout.cxx | 158 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 203 |
16 files changed, 411 insertions, 252 deletions
diff --git a/cui/source/dialogs/screenshotannotationdlg.cxx b/cui/source/dialogs/screenshotannotationdlg.cxx index b99a87e9689d..582e6cf1c474 100644 --- a/cui/source/dialogs/screenshotannotationdlg.cxx +++ b/cui/source/dialogs/screenshotannotationdlg.cxx @@ -103,31 +103,6 @@ namespace } } -class ControlDataEntry -{ -public: - ControlDataEntry( - const vcl::Window& rControl, - const basegfx::B2IRange& rB2IRange) - : mrControl(rControl), - maB2IRange(rB2IRange) - { - } - - const basegfx::B2IRange& getB2IRange() const - { - return maB2IRange; - } - - OString const & GetHelpId() const { return mrControl.GetHelpId(); } - -private: - const vcl::Window& mrControl; - basegfx::B2IRange maB2IRange; -}; - -typedef std::vector< ControlDataEntry > ControlDataCollection; - class Picture : public weld::CustomWidgetController { private: @@ -156,7 +131,7 @@ public: ScreenshotAnnotationDlg_Impl( weld::Window* pParent, weld::Builder& rParent, - Dialog& rParentDialog); + weld::Dialog& rParentDialog); ~ScreenshotAnnotationDlg_Impl(); private: @@ -167,10 +142,10 @@ private: void CollectChildren( const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft, - ControlDataCollection& rControlDataCollection); - ControlDataEntry* CheckHit(const basegfx::B2IPoint& rPosition); - void PaintControlDataEntry( - const ControlDataEntry& rEntry, + weld::ScreenShotCollection& rControlDataCollection); + weld::ScreenShotEntry* CheckHit(const basegfx::B2IPoint& rPosition); + void PaintScreenShotEntry( + const weld::ScreenShotEntry& rEntry, const Color& rColor, double fLineWidth, double fTransparency); @@ -182,7 +157,7 @@ private: // local variables weld::Window* mpParentWindow; - Dialog& mrParentDialog; + weld::Dialog& mrParentDialog; BitmapEx maParentDialogBitmap; BitmapEx maDimmedDialogBitmap; Size maParentDialogSize; @@ -191,11 +166,11 @@ private: VclPtr<VirtualDevice> mxVirtualBufferDevice; // all detected children - ControlDataCollection maAllChildren; + weld::ScreenShotCollection maAllChildren; // highlighted/selected children - ControlDataEntry* mpHilighted; - std::set< ControlDataEntry* > + weld::ScreenShotEntry* mpHilighted; + std::set< weld::ScreenShotEntry* > maSelected; // list of detected controls @@ -221,12 +196,9 @@ OUString ScreenshotAnnotationDlg_Impl::maLastFolderURL = OUString(); ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl( weld::Window* pParent, weld::Builder& rParentBuilder, - Dialog& rParentDialog) + weld::Dialog& rParentDialog) : mpParentWindow(pParent), mrParentDialog(rParentDialog), - maParentDialogBitmap(rParentDialog.createScreenshot()), - maDimmedDialogBitmap(maParentDialogBitmap), - maParentDialogSize(maParentDialogBitmap.GetSizePixel()), mxVirtualBufferDevice(nullptr), maAllChildren(), mpHilighted(nullptr), @@ -234,6 +206,12 @@ ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl( maPicture(this), maSaveAsText(CuiResId(RID_SVXSTR_SAVE_SCREENSHOT_AS)) { + VclPtr<VirtualDevice> xParentDialogSurface(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); + rParentDialog.draw(*xParentDialogSurface); + maParentDialogSize = xParentDialogSurface->GetOutputSizePixel(); + maParentDialogBitmap = xParentDialogSurface->GetBitmapEx(Point(), maParentDialogSize); + maDimmedDialogBitmap = maParentDialogBitmap; + // image ain't empty assert(!maParentDialogBitmap.IsEmpty()); assert(0 != maParentDialogBitmap.GetSizePixel().Width()); @@ -247,18 +225,10 @@ ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl( mxSave = rParentBuilder.weld_button("save"); assert(mxSave.get()); - // set screenshot image at FixedImage, resize, set event listener + // set screenshot image at DrawingArea, resize, set event listener if (mxPicture) { - // 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(mrParentDialog.GetPosPixel()); - const basegfx::B2IPoint aTopLeft(-aParentPos.X(), -aParentPos.Y()); - - CollectChildren( - mrParentDialog, - aTopLeft, - maAllChildren); + maAllChildren = mrParentDialog.collect_screenshot_data(); // to make clear that maParentDialogBitmap is a background image, adjust // luminance a bit for maDimmedDialogBitmap - other methods may be applied @@ -285,8 +255,8 @@ ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl( if (mxText) { mxText->set_size_request(400, mxText->get_height_rows(10)); - OUString aHelpId = OStringToOUString( mrParentDialog.GetHelpId(), RTL_TEXTENCODING_UTF8 ); - Size aSizeCm = mrParentDialog.PixelToLogic(maParentDialogSize, MapMode(MapUnit::MapCM)); + OUString aHelpId = OStringToOUString( mrParentDialog.get_help_id(), RTL_TEXTENCODING_UTF8 ); + Size aSizeCm = Application::GetDefaultDevice()->PixelToLogic(maParentDialogSize, MapMode(MapUnit::MapCM)); maMainMarkupText = lcl_ParagraphWithImage( aHelpId, aSizeCm ); mxText->set_text( maMainMarkupText ); mxText->set_editable(false); @@ -302,7 +272,7 @@ ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl( void ScreenshotAnnotationDlg_Impl::CollectChildren( const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft, - ControlDataCollection& rControlDataCollection) + weld::ScreenShotCollection& rControlDataCollection) { if (rCurrent.IsVisible()) { @@ -313,7 +283,7 @@ void ScreenshotAnnotationDlg_Impl::CollectChildren( if (!aCurrentRange.isEmpty()) { - rControlDataCollection.emplace_back(rCurrent, aCurrentRange); + rControlDataCollection.emplace_back(rCurrent.GetHelpId(), aCurrentRange); } for (sal_uInt16 a(0); a < rCurrent.GetChildCount(); a++) @@ -337,23 +307,8 @@ IMPL_LINK_NOARG(ScreenshotAnnotationDlg_Impl, saveButtonHandler, weld::Button&, { // 'save screenshot...' pressed, offer to save maParentDialogBitmap // as PNG image, use *.id file name as screenshot file name offering - OString aDerivedFileName; - - // get a suggestion for the filename from ui file name - { - const OString& rUIFileName = mrParentDialog.getUIFile(); - sal_Int32 nIndex(0); - - do - { - const OString aToken(rUIFileName.getToken(0, '/', nIndex)); - - if (!aToken.isEmpty()) - { - aDerivedFileName = aToken; - } - } while (nIndex >= 0); - } + // get a suggestion for the filename from buildable name + OString aDerivedFileName = mrParentDialog.get_buildable_name(); auto xFileDlg = std::make_unique<sfx2::FileDialogHelper>(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, mpParentWindow); @@ -421,9 +376,9 @@ IMPL_LINK_NOARG(ScreenshotAnnotationDlg_Impl, saveButtonHandler, weld::Button&, } } -ControlDataEntry* ScreenshotAnnotationDlg_Impl::CheckHit(const basegfx::B2IPoint& rPosition) +weld::ScreenShotEntry* ScreenshotAnnotationDlg_Impl::CheckHit(const basegfx::B2IPoint& rPosition) { - ControlDataEntry* pRetval = nullptr; + weld::ScreenShotEntry* pRetval = nullptr; for (auto&& rCandidate : maAllChildren) { @@ -447,8 +402,8 @@ ControlDataEntry* ScreenshotAnnotationDlg_Impl::CheckHit(const basegfx::B2IPoint return pRetval; } -void ScreenshotAnnotationDlg_Impl::PaintControlDataEntry( - const ControlDataEntry& rEntry, +void ScreenshotAnnotationDlg_Impl::PaintScreenShotEntry( + const weld::ScreenShotEntry& rEntry, const Color& rColor, double fLineWidth, double fTransparency) @@ -527,14 +482,14 @@ void ScreenshotAnnotationDlg_Impl::RepaintToBuffer( for (auto&& rCandidate : maSelected) { static const double fLineWidthEntries(5.0); - PaintControlDataEntry(*rCandidate, COL_LIGHTRED, fLineWidthEntries, fTransparence * 0.2); + PaintScreenShotEntry(*rCandidate, COL_LIGHTRED, fLineWidthEntries, fTransparence * 0.2); } // paint highlighted entry if (mpHilighted && bPaintHilight) { static const double fLineWidthHilight(7.0); - PaintControlDataEntry(*mpHilighted, aHilightColor, fLineWidthHilight, fTransparence); + PaintScreenShotEntry(*mpHilighted, aHilightColor, fLineWidthHilight, fTransparence); } if (bIsAntiAliasing) @@ -572,16 +527,16 @@ bool ScreenshotAnnotationDlg_Impl::MouseMove(const MouseEvent& rMouseEvent) if (maPicture.IsMouseOver()) { - const ControlDataEntry* pOldHit = mpHilighted; + const weld::ScreenShotEntry* pOldHit = mpHilighted; const Point aOffset(GetOffsetInPicture()); const basegfx::B2IPoint aMousePos( rMouseEvent.GetPosPixel().X() - aOffset.X(), rMouseEvent.GetPosPixel().Y() - aOffset.Y()); - const ControlDataEntry* pHit = CheckHit(aMousePos); + const weld::ScreenShotEntry* pHit = CheckHit(aMousePos); if (pHit && pOldHit != pHit) { - mpHilighted = const_cast<ControlDataEntry*>(pHit); + mpHilighted = const_cast<weld::ScreenShotEntry*>(pHit); bRepaint = true; } } @@ -644,8 +599,8 @@ bool Picture::MouseButtonUp(const MouseEvent&) return m_pDialog->MouseButtonUp(); } -ScreenshotAnnotationDlg::ScreenshotAnnotationDlg(weld::Window* pParent, Dialog& rParentDialog) - : GenericDialogController(pParent, "cui/ui/screenshotannotationdialog.ui", "ScreenshotAnnotationDialog") +ScreenshotAnnotationDlg::ScreenshotAnnotationDlg(weld::Dialog& rParentDialog) + : GenericDialogController(&rParentDialog, "cui/ui/screenshotannotationdialog.ui", "ScreenshotAnnotationDialog") { m_pImpl.reset(new ScreenshotAnnotationDlg_Impl(m_xDialog.get(), *m_xBuilder, rParentDialog)); } diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx index 0a81690478ca..e08cd60cfd7d 100644 --- a/cui/source/factory/dlgfact.cxx +++ b/cui/source/factory/dlgfact.cxx @@ -1608,11 +1608,9 @@ VclPtr<AbstractPasswordToOpenModifyDialog> AbstractDialogFactory_Impl::CreatePas return VclPtr<AbstractPasswordToOpenModifyDialog_Impl>::Create(std::make_unique<PasswordToOpenModifyDialog>(pParent, nMaxPasswdLen, bIsPasswordToModify)); } -VclPtr<AbstractScreenshotAnnotationDlg> AbstractDialogFactory_Impl::CreateScreenshotAnnotationDlg( - weld::Window* pParent, - Dialog& rParentDialog) +VclPtr<AbstractScreenshotAnnotationDlg> AbstractDialogFactory_Impl::CreateScreenshotAnnotationDlg(weld::Dialog& rParentDialog) { - return VclPtr<AbstractScreenshotAnnotationDlg_Impl>::Create(std::make_unique<ScreenshotAnnotationDlg>(pParent, rParentDialog)); + return VclPtr<AbstractScreenshotAnnotationDlg_Impl>::Create(std::make_unique<ScreenshotAnnotationDlg>(rParentDialog)); } VclPtr<AbstractSignatureLineDialog> AbstractDialogFactory_Impl::CreateSignatureLineDialog( diff --git a/cui/source/factory/dlgfact.hxx b/cui/source/factory/dlgfact.hxx index b3ada6ca80e9..3bc6e90cc377 100644 --- a/cui/source/factory/dlgfact.hxx +++ b/cui/source/factory/dlgfact.hxx @@ -930,7 +930,7 @@ public: virtual VclPtr<AbstractPasswordToOpenModifyDialog> CreatePasswordToOpenModifyDialog(weld::Window* pParent, sal_uInt16 nMaxPasswdLen, bool bIsPasswordToModify) override; - virtual VclPtr<AbstractScreenshotAnnotationDlg> CreateScreenshotAnnotationDlg(weld::Window* pParent, Dialog& rParentDialog) override; + virtual VclPtr<AbstractScreenshotAnnotationDlg> CreateScreenshotAnnotationDlg(weld::Dialog& rParentDialog) override; virtual VclPtr<AbstractSignatureLineDialog> CreateSignatureLineDialog(weld::Window* pParent, diff --git a/cui/source/inc/screenshotannotationdlg.hxx b/cui/source/inc/screenshotannotationdlg.hxx index 53df8d4f7ea5..6730ef0514fe 100644 --- a/cui/source/inc/screenshotannotationdlg.hxx +++ b/cui/source/inc/screenshotannotationdlg.hxx @@ -34,9 +34,7 @@ private: ScreenshotAnnotationDlg& operator=(const ScreenshotAnnotationDlg &) = delete; public: - ScreenshotAnnotationDlg( - weld::Window* pParent, - Dialog& rParentDialog); + ScreenshotAnnotationDlg(weld::Dialog& rParentDialog); virtual ~ScreenshotAnnotationDlg() override; }; diff --git a/cui/uiconfig/ui/screenshotannotationdialog.ui b/cui/uiconfig/ui/screenshotannotationdialog.ui index e7e3e78fa3d0..45d8b51b385a 100644 --- a/cui/uiconfig/ui/screenshotannotationdialog.ui +++ b/cui/uiconfig/ui/screenshotannotationdialog.ui @@ -68,6 +68,8 @@ <property name="can_focus">False</property> <property name="halign">start</property> <property name="label" translatable="yes" context="screenshotannotationdialog|label2">Click the widgets to add annotation:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">picture</property> </object> <packing> <property name="expand">False</property> @@ -80,6 +82,7 @@ <property name="name">image</property> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> </object> <packing> <property name="expand">True</property> @@ -93,6 +96,8 @@ <property name="can_focus">False</property> <property name="halign">start</property> <property name="label" translatable="yes" context="screenshotannotationdialog|label1">Paste the following markup into the help file:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">text</property> <property name="ellipsize">end</property> </object> <packing> diff --git a/include/vcl/abstdlg.hxx b/include/vcl/abstdlg.hxx index d9a5058c7e42..ccbc64a753a0 100644 --- a/include/vcl/abstdlg.hxx +++ b/include/vcl/abstdlg.hxx @@ -172,7 +172,7 @@ public: // creates instance of ScreenshotAnnotationDlg from cui virtual VclPtr<AbstractScreenshotAnnotationDlg> CreateScreenshotAnnotationDlg( - weld::Window* pParent, Dialog& rParentDialog) = 0; + weld::Dialog& rParentDialog) = 0; // create info dialog to show tip-of-the-day virtual VclPtr<AbstractTipOfTheDayDialog> diff --git a/include/vcl/dialog.hxx b/include/vcl/dialog.hxx index e2ddea74be78..cc5355d58132 100644 --- a/include/vcl/dialog.hxx +++ b/include/vcl/dialog.hxx @@ -110,6 +110,7 @@ public: virtual bool EventNotify( NotifyEvent& rNEvt ) override; virtual void StateChanged( StateChangedType nStateChange ) override; virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void Command( const CommandEvent& rCEvt ) override; virtual void queue_resize(StateChangedType eReason = StateChangedType::Layout) override; virtual bool set_property(const OString &rKey, const OUString &rValue) override; @@ -127,7 +128,7 @@ public: // Screenshot interface virtual std::vector<OString> getAllPageUIXMLDescriptions() const; virtual bool selectPageByUIXMLDescription(const OString& rUIXMLDescription); - BitmapEx createScreenshot(); + void createScreenshot(VirtualDevice& rOutput); virtual short Execute(); bool IsInExecute() const { return mbInExecute; } @@ -174,7 +175,7 @@ public: void Activate() override; - + void SetPopupMenuHdl(const Link<const CommandEvent&, bool>& rLink); void SetInstallLOKNotifierHdl(const Link<void*, vcl::ILibreOfficeKitNotifier*>& rLink); void add_button(PushButton* pButton, int nResponse, bool bTransferOwnership); diff --git a/include/vcl/layout.hxx b/include/vcl/layout.hxx index 0164b2b09df0..494cb708f292 100644 --- a/include/vcl/layout.hxx +++ b/include/vcl/layout.hxx @@ -50,7 +50,7 @@ protected: virtual sal_uInt16 getDefaultAccessibleRole() const override; - // evtl. support for screenshot context menu + // support for screenshot context menu virtual void Command(const CommandEvent& rCEvt) override; public: diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 5559833799fc..20c8d9e5751e 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -10,6 +10,7 @@ #ifndef INCLUDED_VCL_WELD_HXX #define INCLUDED_VCL_WELD_HXX +#include <basegfx/range/b2irange.hxx> #include <rtl/ustring.hxx> #include <tools/color.hxx> #include <tools/date.hxx> @@ -419,6 +420,26 @@ 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: @@ -446,6 +467,11 @@ 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; }; diff --git a/sc/source/ui/attrdlg/scdlgfact.hxx b/sc/source/ui/attrdlg/scdlgfact.hxx index e087ad7dade6..8655e6bc9ad4 100644 --- a/sc/source/ui/attrdlg/scdlgfact.hxx +++ b/sc/source/ui/attrdlg/scdlgfact.hxx @@ -21,6 +21,7 @@ #include <scabstdlg.hxx> #include <sfx2/sfxdlg.hxx> +#include <vcl/virdev.hxx> #include <corodlg.hxx> #include <condformatmgr.hxx> @@ -87,9 +88,11 @@ bool Class::selectPageByUIXMLDescription(const OString& rUIXMLDescription) \ { \ return pDlg->selectPageByUIXMLDescription(rUIXMLDescription); \ } \ -BitmapEx Class::createScreenshot() const \ +BitmapEx Class::createScreenshot() const \ { \ - return pDlg->createScreenshot(); \ + VclPtr<VirtualDevice> xDialogSurface(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); \ + pDlg->createScreenshot(*xDialogSurface); \ + return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel()); \ } \ OString Class::GetScreenshotId() const \ { \ diff --git a/solenv/sanitizers/ui/cui.suppr b/solenv/sanitizers/ui/cui.suppr index 1fb9cf484716..d417663db12c 100644 --- a/solenv/sanitizers/ui/cui.suppr +++ b/solenv/sanitizers/ui/cui.suppr @@ -248,10 +248,6 @@ cui/uiconfig/ui/paraindentspacing.ui://GtkLabel[@id='labelFT_LINEDIST'] orphan-l cui/uiconfig/ui/paraindentspacing.ui://GtkSpinButton[@id='spinED_LINEDISTPERCENT'] no-labelled-by cui/uiconfig/ui/paraindentspacing.ui://GtkSpinButton[@id='spinED_LINEDISTMETRIC'] no-labelled-by cui/uiconfig/ui/password.ui://GtkLabel[@id='label1'] orphan-label -cui/uiconfig/ui/screenshotannotationdialog.ui://GtkLabel[@id='label2'] orphan-label -cui/uiconfig/ui/screenshotannotationdialog.ui://GtkImage[@id='picture'] no-labelled-by -cui/uiconfig/ui/screenshotannotationdialog.ui://GtkLabel[@id='label1'] orphan-label -cui/uiconfig/ui/screenshotannotationdialog.ui://GtkTextView[@id='text:border'] no-labelled-by cui/uiconfig/ui/pastespecial.ui://GtkLabel[@id='label2'] orphan-label cui/uiconfig/ui/pastespecial.ui://GtkLabel[@id='source'] orphan-label cui/uiconfig/ui/paratabspage.ui://GtkSpinButton[@id='SP_TABPOS'] no-labelled-by diff --git a/test/source/screenshot_test.cxx b/test/source/screenshot_test.cxx index b2173b57bf25..e849bae672ce 100644 --- a/test/source/screenshot_test.cxx +++ b/test/source/screenshot_test.cxx @@ -19,6 +19,7 @@ #include <vcl/abstdlg.hxx> #include <vcl/pngwrite.hxx> #include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> #include <unotools/configmgr.hxx> #include <tools/stream.hxx> @@ -109,7 +110,9 @@ void ScreenshotTest::saveScreenshot(VclAbstractDialog const & rDialog) void ScreenshotTest::saveScreenshot(Dialog& rDialog) { - const BitmapEx aScreenshot(rDialog.createScreenshot()); + VclPtr<VirtualDevice> xDialogSurface(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); + rDialog.createScreenshot(*xDialogSurface); + const BitmapEx aScreenshot(xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel())); if (!aScreenshot.IsEmpty()) { diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index ac51b15cbc2d..416f81071e93 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -19,6 +19,7 @@ #include <com/sun/star/accessibility/AccessibleRelationType.hpp> #include <com/sun/star/awt/XWindow.hpp> +#include <officecfg/Office/Common.hxx> #include <salframe.hxx> #include <salinst.hxx> #include <salvd.hxx> @@ -29,12 +30,14 @@ #include <salbmp.hxx> #include <salobj.hxx> #include <salmenu.hxx> +#include <strings.hrc> #include <svdata.hxx> #include <messagedialog.hxx> #include <treeglue.hxx> #include <unotools/accessiblerelationsethelper.hxx> #include <utility> #include <tools/helpers.hxx> +#include <vcl/abstdlg.hxx> #include <vcl/builder.hxx> #include <vcl/calendar.hxx> #include <vcl/combobox.hxx> @@ -1255,6 +1258,34 @@ 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: @@ -1266,6 +1297,8 @@ private: long m_nOldEditWidthReq; // Original width request of the input field sal_Int32 m_nOldBorderWidth; // border width for expanded dialog + DECL_LINK(PopupScreenShotMenuHdl, const CommandEvent&, bool); + public: SalInstanceDialog(::Dialog* pDialog, SalInstanceBuilder* pBuilder, bool bTakeOwnership) : SalInstanceWindow(pDialog, pBuilder, bTakeOwnership) @@ -1273,6 +1306,11 @@ public: , m_nOldEditWidthReq(0) , m_nOldBorderWidth(0) { + const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get()); + if (bScreenshotMode) + { + m_xDialog->SetPopupMenuHdl(LINK(this, SalInstanceDialog, PopupScreenShotMenuHdl)); + } } virtual bool runAsync(std::shared_ptr<weld::DialogController> aOwner, const std::function<void(sal_Int32)> &rEndDialogFn) override @@ -1435,8 +1473,67 @@ 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) +{ + if (CommandEventId::ContextMenu == rCEvt.GetCommand()) + { + const Point aMenuPos(rCEvt.GetMousePosPixel()); + ScopedVclPtrInstance<PopupMenu> aMenu; + sal_uInt16 nLocalID(1); + + aMenu->InsertItem(nLocalID, VclResId(SV_BUTTONTEXT_SCREENSHOT)); + aMenu->SetHelpText(nLocalID, VclResId(SV_HELPTEXT_SCREENSHOT)); + aMenu->SetHelpId(nLocalID, "InteractiveScreenshotMode"); + aMenu->EnableItem(nLocalID); + + const sal_uInt16 nId(aMenu->Execute(m_xDialog, aMenuPos)); + + // 0 == no selection (so not usable as ID) + if (0 != nId) + { + // open screenshot annotation dialog + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + VclPtr<AbstractScreenshotAnnotationDlg> pTmp = pFact->CreateScreenshotAnnotationDlg(*this); + ScopedVclPtr<AbstractScreenshotAnnotationDlg> pDialog(pTmp); + + if (pDialog) + { + // currently just execute the dialog, no need to do + // different things for ok/cancel. This may change later, + // for that case use 'if (pDlg->Execute() == RET_OK)' + pDialog->Execute(); + } + } + + // consume event when: + // - CommandEventId::ContextMenu + // - bScreenshotMode + return true; + } + + return false; +} + class SalInstanceMessageDialog : public SalInstanceDialog, public virtual weld::MessageDialog { private: diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx index 5acc2bb8e757..679403c9efbc 100644 --- a/vcl/source/window/dialog.cxx +++ b/vcl/source/window/dialog.cxx @@ -51,6 +51,7 @@ #include <vcl/mnemonic.hxx> #include <vcl/dialog.hxx> #include <vcl/settings.hxx> +#include <vcl/virdev.hxx> #include <vcl/weld.hxx> #include <vcl/uitest/uiobject.hxx> #include <vcl/uitest/logger.hxx> @@ -350,6 +351,7 @@ struct DialogImpl long mnResult; bool mbStartedModal; VclAbstractDialog::AsyncContext maEndCtx; + Link<const CommandEvent&, bool> m_aPopupMenuHdl; Link<void*, vcl::ILibreOfficeKitNotifier*> m_aInstallLOKNotifierHdl; DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {} @@ -733,6 +735,11 @@ Size bestmaxFrameSizeForScreenSize(const Size &rScreenSize) #endif } +void Dialog::SetPopupMenuHdl(const Link<const CommandEvent&, bool>& rLink) +{ + mpDialogImpl->m_aPopupMenuHdl = rLink; +} + void Dialog::SetInstallLOKNotifierHdl(const Link<void*, vcl::ILibreOfficeKitNotifier*>& rLink) { mpDialogImpl->m_aInstallLOKNotifierHdl = rLink; @@ -1042,7 +1049,7 @@ void Dialog::ensureRepaint() } } -BitmapEx Dialog::createScreenshot() +void Dialog::createScreenshot(VirtualDevice& rOutput) { // same prerequisites as in Execute() setDeferredProperties(); @@ -1051,7 +1058,11 @@ BitmapEx Dialog::createScreenshot() ToTop(); ensureRepaint(); - return GetBitmapEx(Point(), GetOutputSizePixel()); + Point aPos; + Size aSize(GetOutputSizePixel()); + + rOutput.SetOutputSizePixel(aSize); + rOutput.DrawOutDev(aPos, aSize, aPos, aSize, *this); } short Dialog::Execute() @@ -1591,6 +1602,13 @@ void Dialog::Activate() SystemWindow::Activate(); } +void Dialog::Command(const CommandEvent& rCEvt) +{ + if (mpDialogImpl && mpDialogImpl->m_aPopupMenuHdl.Call(rCEvt)) + return; + SystemWindow::Command(rCEvt); +} + void TopLevelWindowLocker::incBusy(const weld::Widget* pIgnore) { // lock any toplevel windows from being closed until busy is over diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx index 6863a8ea4b66..609a7ca5d66b 100644 --- a/vcl/source/window/layout.cxx +++ b/vcl/source/window/layout.cxx @@ -19,8 +19,6 @@ #include <messagedialog.hxx> #include <window.h> #include <boost/multi_array.hpp> -#include <officecfg/Office/Common.hxx> -#include <vcl/abstdlg.hxx> #include <vcl/vclmedit.hxx> #include <sal/log.hxx> @@ -183,159 +181,17 @@ void VclContainer::queue_resize(StateChangedType eReason) Window::queue_resize(eReason); } - -static Button* isVisibleButtonWithText(vcl::Window* pCandidate) -{ - if (!pCandidate) - return nullptr; - - if (!pCandidate->IsVisible()) - return nullptr; - - if (pCandidate->GetText().isEmpty()) - return nullptr; - - return dynamic_cast<Button*>(pCandidate); -} - -// evtl. support for screenshot context menu +// support for screenshot context menu void VclContainer::Command(const CommandEvent& rCEvt) { - if (rCEvt.IsMouseEvent() && CommandEventId::ContextMenu == rCEvt.GetCommand()) + if (CommandEventId::ContextMenu == rCEvt.GetCommand()) { - const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get()); - - if (bScreenshotMode) + auto pParent = GetParent(); + if (pParent) { - bool bVisibleChildren(false); - vcl::Window* pChild(nullptr); - - for (pChild = GetWindow(GetWindowType::FirstChild); !bVisibleChildren && pChild; pChild = pChild->GetWindow(GetWindowType::Next)) - { - Button* pCandidate = isVisibleButtonWithText(pChild); - - if (nullptr == pCandidate) - continue; - - bVisibleChildren = true; - } - - if (bVisibleChildren) - { - static bool bAddButtonsToMenu(true); // loplugin:constvars:ignore - static bool bAddScreenshotButtonToMenu(true); // loplugin:constvars:ignore - - if (bAddButtonsToMenu || bAddScreenshotButtonToMenu) - { - const Point aMenuPos(rCEvt.GetMousePosPixel()); - ScopedVclPtrInstance<PopupMenu> aMenu; - sal_uInt16 nLocalID(1); - sal_uInt16 nScreenshotButtonID(0); - - if (bAddButtonsToMenu) - { - for (pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) - { - Button* pCandidate = isVisibleButtonWithText(pChild); - - if (nullptr == pCandidate) - continue; - - aMenu->InsertItem( - nLocalID, - pChild->GetText()); - aMenu->SetHelpText( - nLocalID, - pChild->GetHelpText()); - aMenu->SetHelpId( - nLocalID, - pChild->GetHelpId()); - aMenu->EnableItem( - nLocalID, - pChild->IsEnabled()); - nLocalID++; - } - } - - if (bAddScreenshotButtonToMenu) - { - if (nLocalID > 1) - { - aMenu->InsertSeparator(); - } - - aMenu->InsertItem( - nLocalID, - VclResId(SV_BUTTONTEXT_SCREENSHOT)); - aMenu->SetHelpText( - nLocalID, - VclResId(SV_HELPTEXT_SCREENSHOT)); - aMenu->SetHelpId( - nLocalID, - "InteractiveScreenshotMode"); - aMenu->EnableItem( - nLocalID); - nScreenshotButtonID = nLocalID; - } - - const sal_uInt16 nId(aMenu->Execute(this, aMenuPos)); - - // 0 == no selection (so not usable as ID) - if (0 != nId) - { - if (bAddButtonsToMenu && nId < nLocalID) - { - nLocalID = 1; - - for (pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next)) - { - Button* pCandidate = isVisibleButtonWithText(pChild); - - if (nullptr == pCandidate) - continue; - - if (nLocalID++ == nId) - { - // pCandidate is the selected button, trigger it - pCandidate->Click(); - break; - } - } - } - - if (bAddScreenshotButtonToMenu && nId == nScreenshotButtonID) - { - // screenshot was selected, access parent dialog (needed for - // screenshot and other data access) - Dialog* pParentDialog = GetParentDialog(); - - if (pParentDialog) - { - // open screenshot annotation dialog - VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); - VclPtr<AbstractScreenshotAnnotationDlg> pTmp = pFact->CreateScreenshotAnnotationDlg( - pParentDialog->GetFrameWeld(), - *pParentDialog); - ScopedVclPtr<AbstractScreenshotAnnotationDlg> pDialog(pTmp); - - if (pDialog) - { - // currently just execute the dialog, no need to do - // different things for ok/cancel. This may change later, - // for that case use 'if (pDlg->Execute() == RET_OK)' - pDialog->Execute(); - } - } - } - } - - // consume event when: - // - CommandEventId::ContextMenu - // - bScreenshotMode - // - bVisibleChildren - return; - } - } + CommandEvent aCEvt(rCEvt.GetMousePosPixel() + GetPosPixel(), rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData()); + pParent->Command(aCEvt); + return; } } diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 848d3671ed3b..bc5a7047915b 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -55,6 +55,7 @@ #include <comphelper/string.hxx> #include <cppuhelper/implbase.hxx> #include <cppuhelper/supportsservice.hxx> +#include <officecfg/Office/Common.hxx> #include <rtl/bootstrap.hxx> #include <svl/zforlist.hxx> #include <svl/zformat.hxx> @@ -64,6 +65,7 @@ #include <unotools/resmgr.hxx> #include <unx/gstsink.hxx> #include <vcl/ImageTree.hxx> +#include <vcl/abstdlg.hxx> #include <vcl/button.hxx> #include <vcl/event.hxx> #include <vcl/i18nhelp.hxx> @@ -75,6 +77,7 @@ #include <vcl/virdev.hxx> #include <vcl/weld.hxx> #include <vcl/wrkwin.hxx> +#include <strings.hrc> #include <window.h> #include <numeric> @@ -1809,6 +1812,8 @@ private: gulong m_nSizeAllocateSignalId; gulong m_nButtonPressSignalId; gulong m_nMotionSignalId; + gulong m_nLeaveSignalId; + gulong m_nEnterSignalId; gulong m_nButtonReleaseSignalId; gulong m_nDragMotionSignalId; gulong m_nDragDropSignalId; @@ -1950,6 +1955,31 @@ private: return true; } + static gboolean signalCrossing(GtkWidget*, GdkEventCrossing* pEvent, gpointer widget) + { + GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget); + SolarMutexGuard aGuard; + return pThis->signal_crossing(pEvent); + } + + bool signal_crossing(const GdkEventCrossing* pEvent) + { + if (!m_aMouseMotionHdl.IsSet()) + return false; + + Point aPos(pEvent->x, pEvent->y); + if (AllSettings::GetLayoutRTL()) + aPos.setX(gtk_widget_get_allocated_width(m_pWidget) - 1 - aPos.X()); + sal_uInt32 nModCode = GtkSalFrame::GetMouseModCode(pEvent->state); + sal_uInt16 nCode = m_nLastMouseButton | (nModCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)); + MouseEventModifiers eModifiers = ImplGetMouseMoveMode(nModCode); + eModifiers = eModifiers | (pEvent->type == GDK_ENTER_NOTIFY ? MouseEventModifiers::ENTERWINDOW : MouseEventModifiers::LEAVEWINDOW); + MouseEvent aMEvt(aPos, 0, eModifiers, nCode, nCode); + + m_aMouseMotionHdl.Call(aMEvt); + return true; + } + virtual void drag_started() { } @@ -2033,6 +2063,8 @@ public: , m_nSizeAllocateSignalId(0) , m_nButtonPressSignalId(0) , m_nMotionSignalId(0) + , m_nLeaveSignalId(0) + , m_nEnterSignalId(0) , m_nButtonReleaseSignalId(0) , m_nDragMotionSignalId(0) , m_nDragDropSignalId(0) @@ -2063,6 +2095,8 @@ public: { ensureEventWidget(); m_nMotionSignalId = g_signal_connect(m_pMouseEventBox, "motion-notify-event", G_CALLBACK(signalMotion), this); + m_nLeaveSignalId = g_signal_connect(m_pMouseEventBox, "leave-notify-event", G_CALLBACK(signalCrossing), this); + m_nEnterSignalId = g_signal_connect(m_pMouseEventBox, "enter-notify-event", G_CALLBACK(signalCrossing), this); weld::Widget::connect_mouse_move(rLink); } @@ -2584,6 +2618,10 @@ public: g_signal_handler_disconnect(m_pMouseEventBox, m_nButtonPressSignalId); if (m_nMotionSignalId) g_signal_handler_disconnect(m_pMouseEventBox, m_nMotionSignalId); + if (m_nLeaveSignalId) + g_signal_handler_disconnect(m_pMouseEventBox, m_nLeaveSignalId); + if (m_nEnterSignalId) + g_signal_handler_disconnect(m_pMouseEventBox, m_nEnterSignalId); if (m_nButtonReleaseSignalId) g_signal_handler_disconnect(m_pMouseEventBox, m_nButtonReleaseSignalId); if (m_nFocusInSignalId) @@ -3742,6 +3780,135 @@ private: void asyncresponse(gint ret); + static void signalActivate(GtkMenuItem*, gpointer data) + { + bool* pActivate = static_cast<bool*>(data); + *pActivate = true; + } + + bool signal_screenshot_popup_menu(GdkEventButton* pEvent) + { + GtkWidget *pMenu = gtk_menu_new(); + + GtkWidget* pMenuItem = gtk_menu_item_new_with_mnemonic(MapToGtkAccelerator(VclResId(SV_BUTTONTEXT_SCREENSHOT)).getStr()); + gtk_menu_shell_append(GTK_MENU_SHELL(pMenu), pMenuItem); + bool bActivate(false); + g_signal_connect(pMenuItem, "activate", G_CALLBACK(signalActivate), &bActivate); + gtk_widget_show(pMenuItem); + + int button, event_time; + if (pEvent) + { + button = pEvent->button; + event_time = pEvent->time; + } + else + { + button = 0; + event_time = gtk_get_current_event_time(); + } + + gtk_menu_attach_to_widget(GTK_MENU(pMenu), GTK_WIDGET(m_pDialog), nullptr); + + GMainLoop* pLoop = g_main_loop_new(nullptr, true); + gulong nSignalId = g_signal_connect_swapped(G_OBJECT(pMenu), "deactivate", G_CALLBACK(g_main_loop_quit), pLoop); + + gtk_menu_popup(GTK_MENU(pMenu), nullptr, nullptr, nullptr, nullptr, button, event_time); + + if (g_main_loop_is_running(pLoop)) + { + gdk_threads_leave(); + g_main_loop_run(pLoop); + gdk_threads_enter(); + } + + g_main_loop_unref(pLoop); + g_signal_handler_disconnect(pMenu, nSignalId); + gtk_menu_detach(GTK_MENU(pMenu)); + + if (bActivate) + { + // open screenshot annotation dialog + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + VclPtr<AbstractScreenshotAnnotationDlg> xTmp = pFact->CreateScreenshotAnnotationDlg(*this); + ScopedVclPtr<AbstractScreenshotAnnotationDlg> xDialog(xTmp); + xDialog->Execute(); + } + + return false; + } + + static gboolean signalScreenshotPopupMenu(GtkWidget*, gpointer widget) + { + GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget); + return pThis->signal_screenshot_popup_menu(nullptr); + } + + static gboolean signalScreenshotButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget) + { + GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget); + SolarMutexGuard aGuard; + return pThis->signal_screenshot_button(pEvent); + } + + bool signal_screenshot_button(GdkEventButton* pEvent) + { + if (gdk_event_triggers_context_menu(reinterpret_cast<GdkEvent*>(pEvent)) && pEvent->type == GDK_BUTTON_PRESS) + { + //if handled for context menu, stop processing + return signal_screenshot_popup_menu(pEvent); + } + 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) @@ -3756,6 +3923,12 @@ public: , m_nOldEditWidthReq(0) , m_nOldBorderWidth(0) { + const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get()); + if (bScreenshotMode) + { + g_signal_connect(m_pDialog, "popup-menu", G_CALLBACK(signalScreenshotPopupMenu), this); + g_signal_connect(m_pDialog, "button-press-event", G_CALLBACK(signalScreenshotButton), this); + } } virtual bool runAsync(std::shared_ptr<weld::DialogController> rDialogController, const std::function<void(sal_Int32)>& func) override @@ -3949,6 +4122,36 @@ public: //not implemented for the gtk variant } + virtual void draw(VirtualDevice& rOutput) override + { + 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); + } + + 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()) |