diff options
author | Caolán McNamara <caolanm@redhat.com> | 2019-10-07 16:43:59 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2019-10-08 16:31:21 +0200 |
commit | 64fc5986607eaba5db627c546cb1321f00abc501 (patch) | |
tree | 9016569f3c8c3da8e744db3daeadd8e39714f739 /vcl | |
parent | 1c68ab312c5473ce642f75fc35a1edd6be187489 (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.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 |
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()) |