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>
This commit is contained in:
@@ -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
|
||||
|
||||
+1
-17
@@ -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())
|
||||
|
||||
@@ -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 )
|
||||
|
||||
+32
-25
@@ -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() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,\
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: */
|
||||
|
||||
@@ -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>
|
||||
+215
-178
@@ -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,6 +3554,60 @@ public:
|
||||
g_signal_handler_unblock(m_pWidget, m_nToplevelFocusChangedSignalId);
|
||||
}
|
||||
|
||||
virtual void draw(VirtualDevice& rOutput) override
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
if (!bAlreadyRealized)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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_pWindow));
|
||||
|
||||
#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
|
||||
|
||||
cairo_translate(cr, -aOffset.X(), -aOffset.Y());
|
||||
|
||||
gtk_widget_draw(GTK_WIDGET(m_pWindow), cr);
|
||||
|
||||
cairo_destroy(cr);
|
||||
|
||||
if (!bAlreadyVisible)
|
||||
gtk_widget_hide(GTK_WIDGET(m_pWindow));
|
||||
if (!bAlreadyRealized)
|
||||
gtk_widget_unrealize(GTK_WIDGET(m_pWindow));
|
||||
}
|
||||
|
||||
virtual weld::ScreenShotCollection collect_screenshot_data() override
|
||||
{
|
||||
weld::ScreenShotCollection aRet;
|
||||
|
||||
gtk_container_foreach(GTK_CONTAINER(m_pWindow), do_collect_screenshot_data, &aRet);
|
||||
|
||||
return aRet;
|
||||
}
|
||||
|
||||
virtual ~GtkInstanceWindow() override
|
||||
{
|
||||
if (m_nToplevelFocusChangedSignalId)
|
||||
@@ -3443,79 +3617,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
class GtkInstanceDialog;
|
||||
|
||||
struct DialogRunner
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user