summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2019-10-07 16:43:59 +0100
committerCaolán McNamara <caolanm@redhat.com>2019-10-08 16:31:21 +0200
commit64fc5986607eaba5db627c546cb1321f00abc501 (patch)
tree9016569f3c8c3da8e744db3daeadd8e39714f739 /vcl
parent1c68ab312c5473ce642f75fc35a1edd6be187489 (diff)
implement gtk dialog screenshotting
Change-Id: If4e570f775bd1e29dfb75cb7e5dd9d9dfc35e654 Reviewed-on: https://gerrit.libreoffice.org/80416 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/app/salvtables.cxx97
-rw-r--r--vcl/source/window/dialog.cxx22
-rw-r--r--vcl/source/window/layout.cxx158
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx203
4 files changed, 327 insertions, 153 deletions
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())