1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <Qt5Frame.hxx>
21 #include <Qt5Frame.moc>
23 #include <Qt5Data.hxx>
24 #include <Qt5DragAndDrop.hxx>
25 #include <Qt5Graphics.hxx>
26 #include <Qt5Instance.hxx>
27 #include <Qt5MainWindow.hxx>
28 #include <Qt5Menu.hxx>
29 #include <Qt5SvpGraphics.hxx>
30 #include <Qt5System.hxx>
31 #include <Qt5Tools.hxx>
32 #include <Qt5Transferable.hxx>
33 #include <Qt5Widget.hxx>
35 #include <QtCore/QMimeData>
36 #include <QtCore/QPoint>
37 #include <QtCore/QSize>
38 #include <QtCore/QThread>
39 #include <QtCore/QVersionNumber>
40 #include <QtGui/QDragMoveEvent>
41 #include <QtGui/QDropEvent>
42 #include <QtGui/QIcon>
43 #include <QtGui/QWindow>
44 #include <QtGui/QScreen>
45 #include <QtWidgets/QStyle>
46 #include <QtWidgets/QToolTip>
47 #include <QtWidgets/QApplication>
48 #include <QtWidgets/QDesktopWidget>
49 #include <QtWidgets/QMenuBar>
50 #include <QtWidgets/QMainWindow>
53 #include <QtX11Extras/QX11Info>
54 #include <xcb/xproto.h>
55 #if QT5_HAVE_XCB_ICCCM
56 #include <xcb/xcb_icccm.h>
60 #include <saldatabasic.hxx>
62 #include <vcl/layout.hxx>
63 #include <vcl/syswin.hxx>
65 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
68 #include <headless/svpgdi.hxx>
70 #if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM
71 static bool g_bNeedsWmHintsWindowGroup
= true;
72 static xcb_atom_t g_aXcbClientLeaderAtom
= 0;
75 static void SvpDamageHandler(void* handle
, sal_Int32 nExtentsX
, sal_Int32 nExtentsY
,
76 sal_Int32 nExtentsWidth
, sal_Int32 nExtentsHeight
)
78 Qt5Frame
* pThis
= static_cast<Qt5Frame
*>(handle
);
79 pThis
->Damage(nExtentsX
, nExtentsY
, nExtentsWidth
, nExtentsHeight
);
84 sal_Int32
screenNumber(const QScreen
* pScreen
)
86 const QList
<QScreen
*> screens
= QApplication::screens();
88 sal_Int32 nScreen
= 0;
90 for (const QScreen
* pCurScreen
: screens
)
92 if (pScreen
== pCurScreen
)
100 return bFound
? nScreen
: -1;
104 Qt5Frame::Qt5Frame(Qt5Frame
* pParent
, SalFrameStyleFlags nStyle
, bool bUseCairo
)
105 : m_pTopLevel(nullptr)
106 , m_bUseCairo(bUseCairo
)
107 , m_bNullRegion(true)
108 , m_bGraphicsInUse(false)
109 , m_ePointerStyle(PointerStyle::Arrow
)
110 , m_pDragSource(nullptr)
111 , m_pDropTarget(nullptr)
113 , m_bDefaultSize(true)
114 , m_bDefaultPos(true)
115 , m_bFullScreen(false)
116 , m_bFullScreenSpanAll(false)
118 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
119 pInst
->insertFrame(this);
121 m_aDamageHandler
.handle
= this;
122 m_aDamageHandler
.damaged
= ::SvpDamageHandler
;
124 if (nStyle
& SalFrameStyleFlags::DEFAULT
) // ensure default style
126 nStyle
|= SalFrameStyleFlags::MOVEABLE
| SalFrameStyleFlags::SIZEABLE
127 | SalFrameStyleFlags::CLOSEABLE
;
128 nStyle
&= ~SalFrameStyleFlags::FLOAT
;
134 Qt::WindowFlags aWinFlags
;
135 if (!(nStyle
& SalFrameStyleFlags::SYSTEMCHILD
))
137 if (nStyle
& SalFrameStyleFlags::INTRO
)
138 aWinFlags
|= Qt::SplashScreen
;
139 // floating toolbars are frameless tool windows
140 // + they must be able to receive keyboard focus
141 else if ((nStyle
& SalFrameStyleFlags::FLOAT
)
142 && (nStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
))
143 aWinFlags
|= Qt::Tool
| Qt::FramelessWindowHint
;
144 else if (nStyle
& (SalFrameStyleFlags::FLOAT
| SalFrameStyleFlags::TOOLTIP
))
145 aWinFlags
|= Qt::ToolTip
;
146 else if ((nStyle
& SalFrameStyleFlags::FLOAT
)
147 && !(nStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
))
148 aWinFlags
|= Qt::Popup
;
149 else if (nStyle
& SalFrameStyleFlags::TOOLWINDOW
)
150 aWinFlags
|= Qt::Tool
;
151 // top level windows can't be transient in Qt, so make them dialogs, if they have a parent. At least
152 // the plasma shell relies on this setting to skip dialogs in the window list. And Qt Xcb will just
153 // set transient for the types Dialog, Sheet, Tool, SplashScreen, ToolTip, Drawer and Popup.
154 else if (nStyle
& SalFrameStyleFlags::DIALOG
|| m_pParent
)
155 aWinFlags
|= Qt::Dialog
;
157 aWinFlags
|= Qt::Window
;
160 if (aWinFlags
== Qt::Window
)
162 m_pTopLevel
= new Qt5MainWindow(*this, aWinFlags
);
163 m_pQWidget
= new Qt5Widget(*this, aWinFlags
);
164 m_pTopLevel
->setCentralWidget(m_pQWidget
);
165 m_pTopLevel
->setFocusProxy(m_pQWidget
);
168 m_pQWidget
= new Qt5Widget(*this, aWinFlags
);
170 if (pParent
&& !(pParent
->m_nStyle
& SalFrameStyleFlags::PLUG
))
172 QWindow
* pParentWindow
= pParent
->GetQWidget()->window()->windowHandle();
173 QWindow
* pChildWindow
= asChild()->window()->windowHandle();
174 if (pParentWindow
&& pChildWindow
&& (pParentWindow
!= pChildWindow
))
175 pChildWindow
->setTransientParent(pParentWindow
);
178 // Calling 'QWidget::winId()' implicitly enables native windows to be used
179 // rather than "alien widgets" that are unknown to the windowing system,
180 // s. https://doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets
181 // Avoid this on Wayland due to problems with missing 'mouseMoveEvent's,
182 // s. tdf#122293/QTBUG-75766
183 const bool bWayland
= QGuiApplication::platformName() == "wayland";
185 m_aSystemData
.SetWindowHandle(m_pQWidget
->winId());
188 // TODO implement as needed for Wayland,
189 // s.a. commit c0d4f3ad3307c which did this for gtk3
190 // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface();
191 // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr);
192 // m_aSystemData.aWindow = reinterpret_cast<unsigned long>(
193 // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle()));
196 m_aSystemData
.aShellWindow
= reinterpret_cast<sal_IntPtr
>(this);
197 //m_aSystemData.pSalFrame = this;
198 m_aSystemData
.pWidget
= m_pQWidget
;
199 //m_aSystemData.nScreen = m_nXScreen.getXScreen();
200 m_aSystemData
.toolkit
= SystemEnvData::Toolkit::Qt5
;
202 m_aSystemData
.platform
= SystemEnvData::Platform::Xcb
;
204 m_aSystemData
.platform
= SystemEnvData::Platform::Wayland
;
206 SetIcon(SV_ICON_ID_OFFICE
);
208 fixICCCMwindowGroup();
211 void Qt5Frame::fixICCCMwindowGroup()
213 #if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM
214 // older Qt5 just sets WM_CLIENT_LEADER, but not the XCB_ICCCM_WM_HINT_WINDOW_GROUP
215 // see Qt commit 0de4b326d8 ("xcb: fix issue with dialogs hidden by other windows")
216 // or QTBUG-46626. So LO has to set this itself to help some WMs.
217 if (!g_bNeedsWmHintsWindowGroup
)
219 g_bNeedsWmHintsWindowGroup
= false;
221 if (QGuiApplication::platformName() != "xcb")
223 if (QVersionNumber::fromString(qVersion()) >= QVersionNumber(5, 12))
226 xcb_connection_t
* conn
= QX11Info::connection();
227 xcb_window_t win
= asChild()->winId();
229 xcb_icccm_wm_hints_t hints
;
231 xcb_get_property_cookie_t prop_cookie
= xcb_icccm_get_wm_hints_unchecked(conn
, win
);
232 if (!xcb_icccm_get_wm_hints_reply(conn
, prop_cookie
, &hints
, nullptr))
235 if (hints
.flags
& XCB_ICCCM_WM_HINT_WINDOW_GROUP
)
238 if (g_aXcbClientLeaderAtom
== 0)
240 const char* const leader_name
= "WM_CLIENT_LEADER\0";
241 xcb_intern_atom_cookie_t atom_cookie
242 = xcb_intern_atom(conn
, 1, strlen(leader_name
), leader_name
);
243 xcb_intern_atom_reply_t
* atom_reply
= xcb_intern_atom_reply(conn
, atom_cookie
, nullptr);
246 g_aXcbClientLeaderAtom
= atom_reply
->atom
;
250 g_bNeedsWmHintsWindowGroup
= true;
252 prop_cookie
= xcb_get_property(conn
, 0, win
, g_aXcbClientLeaderAtom
, XCB_ATOM_WINDOW
, 0, 1);
253 xcb_get_property_reply_t
* prop_reply
= xcb_get_property_reply(conn
, prop_cookie
, nullptr);
257 if (xcb_get_property_value_length(prop_reply
) != 4)
263 xcb_window_t leader
= *static_cast<xcb_window_t
*>(xcb_get_property_value(prop_reply
));
266 hints
.flags
|= XCB_ICCCM_WM_HINT_WINDOW_GROUP
;
267 hints
.window_group
= leader
;
268 xcb_icccm_set_wm_hints(conn
, win
, &hints
);
270 (void)this; // avoid loplugin:staticmethods
274 Qt5Frame::~Qt5Frame()
276 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
277 pInst
->eraseFrame(this);
279 m_aSystemData
.aShellWindow
= 0;
282 void Qt5Frame::Damage(sal_Int32 nExtentsX
, sal_Int32 nExtentsY
, sal_Int32 nExtentsWidth
,
283 sal_Int32 nExtentsHeight
) const
285 m_pQWidget
->update(scaledQRect(QRect(nExtentsX
, nExtentsY
, nExtentsWidth
, nExtentsHeight
),
286 1 / devicePixelRatioF()));
289 SalGraphics
* Qt5Frame::AcquireGraphics()
291 if (m_bGraphicsInUse
)
294 m_bGraphicsInUse
= true;
300 QSize aSize
= m_pQWidget
->size() * devicePixelRatioF();
301 m_pSvpGraphics
.reset(new Qt5SvpGraphics(this));
303 cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, aSize
.width(), aSize
.height()));
304 m_pSvpGraphics
->setSurface(m_pSurface
.get(),
305 basegfx::B2IVector(aSize
.width(), aSize
.height()));
306 cairo_surface_set_user_data(m_pSurface
.get(), Qt5SvpGraphics::getDamageKey(),
307 &m_aDamageHandler
, nullptr);
309 return m_pSvpGraphics
.get();
315 m_pQt5Graphics
.reset(new Qt5Graphics(this));
317 new QImage(m_pQWidget
->size() * devicePixelRatioF(), Qt5_DefaultFormat32
));
318 m_pQImage
->fill(Qt::transparent
);
319 m_pQt5Graphics
->ChangeQImage(m_pQImage
.get());
321 return m_pQt5Graphics
.get();
325 void Qt5Frame::ReleaseGraphics(SalGraphics
* pSalGraph
)
329 assert(pSalGraph
== m_pSvpGraphics
.get());
331 assert(pSalGraph
== m_pQt5Graphics
.get());
332 m_bGraphicsInUse
= false;
335 bool Qt5Frame::PostEvent(std::unique_ptr
<ImplSVEvent
> pData
)
337 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
338 pInst
->PostEvent(this, pData
.release(), SalEvent::UserEvent
);
342 QWidget
* Qt5Frame::asChild() const { return m_pTopLevel
? m_pTopLevel
: m_pQWidget
; }
344 qreal
Qt5Frame::devicePixelRatioF() const { return asChild()->devicePixelRatioF(); }
346 bool Qt5Frame::isWindow() const { return asChild()->isWindow(); }
348 QWindow
* Qt5Frame::windowHandle() const
350 // set attribute 'Qt::WA_NativeWindow' first to make sure a window handle actually exists
351 QWidget
* pChild
= asChild();
352 pChild
->setAttribute(Qt::WA_NativeWindow
);
353 return pChild
->windowHandle();
356 QScreen
* Qt5Frame::screen() const
358 QWindow
* const pWindow
= windowHandle();
359 return pWindow
? pWindow
->screen() : nullptr;
362 bool Qt5Frame::isMinimized() const { return asChild()->isMinimized(); }
364 bool Qt5Frame::isMaximized() const { return asChild()->isMaximized(); }
366 void Qt5Frame::SetWindowStateImpl(Qt::WindowStates eState
)
368 return asChild()->setWindowState(eState
);
371 void Qt5Frame::SetTitle(const OUString
& rTitle
)
373 m_pQWidget
->window()->setWindowTitle(toQString(rTitle
));
376 void Qt5Frame::SetIcon(sal_uInt16 nIcon
)
379 & (SalFrameStyleFlags::PLUG
| SalFrameStyleFlags::SYSTEMCHILD
380 | SalFrameStyleFlags::FLOAT
| SalFrameStyleFlags::INTRO
381 | SalFrameStyleFlags::OWNERDRAWDECORATION
)
387 if (nIcon
== SV_ICON_ID_TEXT
)
388 appicon
= "libreoffice-writer";
389 else if (nIcon
== SV_ICON_ID_SPREADSHEET
)
390 appicon
= "libreoffice-calc";
391 else if (nIcon
== SV_ICON_ID_DRAWING
)
392 appicon
= "libreoffice-draw";
393 else if (nIcon
== SV_ICON_ID_PRESENTATION
)
394 appicon
= "libreoffice-impress";
395 else if (nIcon
== SV_ICON_ID_DATABASE
)
396 appicon
= "libreoffice-base";
397 else if (nIcon
== SV_ICON_ID_FORMULA
)
398 appicon
= "libreoffice-math";
400 appicon
= "libreoffice-startcenter";
402 QIcon aIcon
= QIcon::fromTheme(appicon
);
403 m_pQWidget
->window()->setWindowIcon(aIcon
);
406 void Qt5Frame::SetMenu(SalMenu
*) {}
408 void Qt5Frame::DrawMenuBar() { /* not needed */}
410 void Qt5Frame::SetExtendedFrameStyle(SalExtStyle
/*nExtStyle*/) { /* not needed */}
412 void Qt5Frame::Show(bool bVisible
, bool /*bNoActivate*/)
419 auto* pSalInst(static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
));
421 pSalInst
->RunInMainThread([this, bVisible
]() { asChild()->setVisible(bVisible
); });
424 void Qt5Frame::SetMinClientSize(tools::Long nWidth
, tools::Long nHeight
)
428 const qreal fRatio
= devicePixelRatioF();
429 asChild()->setMinimumSize(round(nWidth
/ fRatio
), round(nHeight
/ fRatio
));
433 void Qt5Frame::SetMaxClientSize(tools::Long nWidth
, tools::Long nHeight
)
437 const qreal fRatio
= devicePixelRatioF();
438 asChild()->setMaximumSize(round(nWidth
/ fRatio
), round(nHeight
/ fRatio
));
442 void Qt5Frame::SetDefaultPos()
450 const qreal fRatio
= devicePixelRatioF();
451 QWidget
* const pWindow
= m_pParent
->GetQWidget()->window();
452 QWidget
* const pWidget
= asChild();
453 QPoint aPos
= pWindow
->rect().center() - pWidget
->rect().center();
454 SetPosSize(round(aPos
.x() * fRatio
), round(aPos
.y() * fRatio
), 0, 0,
455 SAL_FRAME_POSSIZE_X
| SAL_FRAME_POSSIZE_Y
);
456 assert(!m_bDefaultPos
);
459 m_bDefaultPos
= false;
462 Size
Qt5Frame::CalcDefaultSize()
469 const QScreen
* pScreen
= screen();
470 SAL_WNODEPRECATED_DECLARATIONS_PUSH
471 aSize
= bestmaxFrameSizeForScreenSize(
472 toSize(pScreen
? pScreen
->size() : QApplication::desktop()->screenGeometry(0).size()));
473 SAL_WNODEPRECATED_DECLARATIONS_POP
477 if (!m_bFullScreenSpanAll
)
479 SAL_WNODEPRECATED_DECLARATIONS_PUSH
481 QApplication::desktop()->screenGeometry(maGeometry
.nDisplayScreenNumber
).size());
482 SAL_WNODEPRECATED_DECLARATIONS_POP
486 SAL_WNODEPRECATED_DECLARATIONS_PUSH
487 int nLeftScreen
= QApplication::desktop()->screenNumber(QPoint(0, 0));
488 SAL_WNODEPRECATED_DECLARATIONS_POP
489 aSize
= toSize(QApplication::screens()[nLeftScreen
]->availableVirtualGeometry().size());
496 void Qt5Frame::SetDefaultSize()
501 Size aDefSize
= CalcDefaultSize();
502 SetPosSize(0, 0, aDefSize
.Width(), aDefSize
.Height(),
503 SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
);
504 assert(!m_bDefaultSize
);
507 void Qt5Frame::SetPosSize(tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
,
510 if (!isWindow() || isChild(true, false))
513 if (nFlags
& (SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
))
515 if (isChild(false) || !m_pQWidget
->isMaximized())
517 if (!(nFlags
& SAL_FRAME_POSSIZE_WIDTH
))
518 nWidth
= maGeometry
.nWidth
;
519 else if (!(nFlags
& SAL_FRAME_POSSIZE_HEIGHT
))
520 nHeight
= maGeometry
.nHeight
;
522 if (nWidth
> 0 && nHeight
> 0)
524 m_bDefaultSize
= false;
525 const int nNewWidth
= round(nWidth
/ devicePixelRatioF());
526 const int nNewHeight
= round(nHeight
/ devicePixelRatioF());
527 if (m_nStyle
& SalFrameStyleFlags::SIZEABLE
)
528 asChild()->resize(nNewWidth
, nNewHeight
);
530 asChild()->setFixedSize(nNewWidth
, nNewHeight
);
533 // assume the resize happened
534 // needed for calculations and will eventually be corrected by events
536 maGeometry
.nWidth
= nWidth
;
538 maGeometry
.nHeight
= nHeight
;
542 if (!(nFlags
& (SAL_FRAME_POSSIZE_X
| SAL_FRAME_POSSIZE_Y
)))
547 const SalFrameGeometry
& aParentGeometry
= m_pParent
->maGeometry
;
548 if (QGuiApplication::isRightToLeft())
549 nX
= aParentGeometry
.nX
+ aParentGeometry
.nWidth
- nX
- maGeometry
.nWidth
- 1;
551 nX
+= aParentGeometry
.nX
;
552 nY
+= aParentGeometry
.nY
;
554 Qt5MainWindow
* pTopLevel
= m_pParent
->GetTopLevelWindow();
555 if (pTopLevel
&& pTopLevel
->menuBar() && pTopLevel
->menuBar()->isVisible())
556 nY
+= round(pTopLevel
->menuBar()->geometry().height() * devicePixelRatioF());
559 if (!(nFlags
& SAL_FRAME_POSSIZE_X
))
561 else if (!(nFlags
& SAL_FRAME_POSSIZE_Y
))
564 // assume the reposition happened
565 // needed for calculations and will eventually be corrected by events later
569 m_bDefaultPos
= false;
570 asChild()->move(round(nX
/ devicePixelRatioF()), round(nY
/ devicePixelRatioF()));
573 void Qt5Frame::GetClientSize(tools::Long
& rWidth
, tools::Long
& rHeight
)
575 rWidth
= round(m_pQWidget
->width() * devicePixelRatioF());
576 rHeight
= round(m_pQWidget
->height() * devicePixelRatioF());
579 void Qt5Frame::GetWorkArea(tools::Rectangle
& rRect
)
583 QScreen
* pScreen
= screen();
587 QSize aSize
= pScreen
->availableVirtualSize() * devicePixelRatioF();
588 rRect
= tools::Rectangle(0, 0, aSize
.width(), aSize
.height());
591 SalFrame
* Qt5Frame::GetParent() const { return m_pParent
; }
593 void Qt5Frame::SetModal(bool bModal
)
598 auto* pSalInst(static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
));
600 pSalInst
->RunInMainThread([this, bModal
]() {
602 QWidget
* const pChild
= asChild();
603 const bool bWasVisible
= pChild
->isVisible();
605 // modality change is only effective if the window is hidden
609 pChild
->setWindowModality(bModal
? Qt::WindowModal
: Qt::NonModal
);
616 bool Qt5Frame::GetModal() const { return isWindow() && windowHandle()->isModal(); }
618 void Qt5Frame::SetWindowState(const SalFrameState
* pState
)
620 if (!isWindow() || !pState
|| isChild(true, false))
623 const WindowStateMask nMaxGeometryMask
624 = WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
| WindowStateMask::Height
625 | WindowStateMask::MaximizedX
| WindowStateMask::MaximizedY
626 | WindowStateMask::MaximizedWidth
| WindowStateMask::MaximizedHeight
;
628 if ((pState
->mnMask
& WindowStateMask::State
) && (pState
->mnState
& WindowStateState::Maximized
)
629 && !isMaximized() && (pState
->mnMask
& nMaxGeometryMask
) == nMaxGeometryMask
)
631 const qreal fRatio
= devicePixelRatioF();
632 QWidget
* const pChild
= asChild();
633 pChild
->resize(ceil(pState
->mnWidth
/ fRatio
), ceil(pState
->mnHeight
/ fRatio
));
634 pChild
->move(ceil(pState
->mnX
/ fRatio
), ceil(pState
->mnY
/ fRatio
));
635 SetWindowStateImpl(Qt::WindowMaximized
);
637 else if (pState
->mnMask
638 & (WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
639 | WindowStateMask::Height
))
641 sal_uInt16 nPosSizeFlags
= 0;
642 if (pState
->mnMask
& WindowStateMask::X
)
643 nPosSizeFlags
|= SAL_FRAME_POSSIZE_X
;
644 if (pState
->mnMask
& WindowStateMask::Y
)
645 nPosSizeFlags
|= SAL_FRAME_POSSIZE_Y
;
646 if (pState
->mnMask
& WindowStateMask::Width
)
647 nPosSizeFlags
|= SAL_FRAME_POSSIZE_WIDTH
;
648 if (pState
->mnMask
& WindowStateMask::Height
)
649 nPosSizeFlags
|= SAL_FRAME_POSSIZE_HEIGHT
;
650 SetPosSize(pState
->mnX
, pState
->mnY
, pState
->mnWidth
, pState
->mnHeight
, nPosSizeFlags
);
652 else if (pState
->mnMask
& WindowStateMask::State
&& !isChild())
654 if (pState
->mnState
& WindowStateState::Maximized
)
655 SetWindowStateImpl(Qt::WindowMaximized
);
656 else if (pState
->mnState
& WindowStateState::Minimized
)
657 SetWindowStateImpl(Qt::WindowMinimized
);
659 SetWindowStateImpl(Qt::WindowNoState
);
663 bool Qt5Frame::GetWindowState(SalFrameState
* pState
)
665 pState
->mnState
= WindowStateState::Normal
;
666 pState
->mnMask
= WindowStateMask::State
;
667 if (isMinimized() /*|| !windowHandle()*/)
668 pState
->mnState
|= WindowStateState::Minimized
;
669 else if (isMaximized())
671 pState
->mnState
|= WindowStateState::Maximized
;
675 // geometry() is the drawable area, which is wanted here
676 QRect rect
= scaledQRect(asChild()->geometry(), devicePixelRatioF());
677 pState
->mnX
= rect
.x();
678 pState
->mnY
= rect
.y();
679 pState
->mnWidth
= rect
.width();
680 pState
->mnHeight
= rect
.height();
681 pState
->mnMask
|= WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
682 | WindowStateMask::Height
;
688 void Qt5Frame::ShowFullScreen(bool bFullScreen
, sal_Int32 nScreen
)
690 // only top-level windows can go fullscreen
693 if (m_bFullScreen
== bFullScreen
)
696 m_bFullScreen
= bFullScreen
;
697 m_bFullScreenSpanAll
= m_bFullScreen
&& (nScreen
< 0);
699 // show it if it isn't shown yet
705 m_aRestoreGeometry
= m_pTopLevel
->geometry();
706 m_nRestoreScreen
= maGeometry
.nDisplayScreenNumber
;
707 SetScreenNumber(m_bFullScreenSpanAll
? m_nRestoreScreen
: nScreen
);
708 if (!m_bFullScreenSpanAll
)
709 windowHandle()->showFullScreen();
711 windowHandle()->showNormal();
715 SetScreenNumber(m_nRestoreScreen
);
716 windowHandle()->showNormal();
717 m_pTopLevel
->setGeometry(m_aRestoreGeometry
);
721 void Qt5Frame::StartPresentation(bool bStart
)
723 // meh - so there's no Qt platform independent solution
724 // https://forum.qt.io/topic/38504/solved-qdialog-in-fullscreen-disable-os-screensaver
726 std::optional
<unsigned int> aRootWindow
;
727 std::optional
<Display
*> aDisplay
;
729 if (QX11Info::isPlatformX11())
731 aRootWindow
= QX11Info::appRootWindow();
732 aDisplay
= QX11Info::display();
735 m_ScreenSaverInhibitor
.inhibit(bStart
, "presentation", QX11Info::isPlatformX11(), aRootWindow
,
742 void Qt5Frame::SetAlwaysOnTop(bool bOnTop
)
744 QWidget
* const pWidget
= asChild();
745 const Qt::WindowFlags flags
= pWidget
->windowFlags();
747 pWidget
->setWindowFlags(flags
| Qt::CustomizeWindowHint
| Qt::WindowStaysOnTopHint
);
749 pWidget
->setWindowFlags(flags
& ~(Qt::CustomizeWindowHint
| Qt::WindowStaysOnTopHint
));
752 void Qt5Frame::ToTop(SalFrameToTop nFlags
)
754 QWidget
* const pWidget
= asChild();
755 if (isWindow() && !(nFlags
& SalFrameToTop::GrabFocusOnly
))
757 if ((nFlags
& SalFrameToTop::RestoreWhenMin
) || (nFlags
& SalFrameToTop::ForegroundTask
))
758 pWidget
->activateWindow();
759 else if ((nFlags
& SalFrameToTop::GrabFocus
) || (nFlags
& SalFrameToTop::GrabFocusOnly
))
761 pWidget
->activateWindow();
766 void Qt5Frame::SetPointer(PointerStyle ePointerStyle
)
768 QWindow
* pWindow
= m_pQWidget
->window()->windowHandle();
771 if (ePointerStyle
== m_ePointerStyle
)
773 m_ePointerStyle
= ePointerStyle
;
775 pWindow
->setCursor(static_cast<Qt5Data
*>(GetSalData())->getCursor(ePointerStyle
));
778 void Qt5Frame::CaptureMouse(bool bMouse
)
780 static const char* pEnv
= getenv("SAL_NO_MOUSEGRABS");
785 m_pQWidget
->grabMouse();
787 m_pQWidget
->releaseMouse();
790 void Qt5Frame::SetPointerPos(tools::Long nX
, tools::Long nY
)
792 // some cursor already exists (and it has m_ePointerStyle shape)
793 // so here we just reposition it
794 QCursor::setPos(m_pQWidget
->mapToGlobal(QPoint(nX
, nY
)));
797 void Qt5Frame::Flush()
799 // was: QGuiApplication::sync();
800 // but FIXME it causes too many issues, figure out sth better
802 // unclear if we need to also flush cairo surface - gtk3 backend
803 // does not do it. QPainter in Qt5Widget::paintEvent() is
804 // destroyed, so that state should be safely flushed.
807 bool Qt5Frame::ShowTooltip(const OUString
& rText
, const tools::Rectangle
& rHelpArea
)
809 QRect
aHelpArea(toQRect(rHelpArea
));
810 if (QGuiApplication::isRightToLeft())
811 aHelpArea
.moveLeft(maGeometry
.nWidth
- aHelpArea
.width() - aHelpArea
.left() - 1);
812 QToolTip::showText(QCursor::pos(), toQString(rText
), m_pQWidget
, aHelpArea
);
816 void Qt5Frame::SetInputContext(SalInputContext
* pContext
)
821 if (!(pContext
->mnOptions
& InputContextFlags::Text
))
824 m_pQWidget
->setAttribute(Qt::WA_InputMethodEnabled
);
827 void Qt5Frame::EndExtTextInput(EndExtTextInputFlags
/*nFlags*/)
829 Qt5Widget
* pQt5Widget
= static_cast<Qt5Widget
*>(m_pQWidget
);
831 pQt5Widget
->endExtTextInput();
834 OUString
Qt5Frame::GetKeyName(sal_uInt16 nKeyCode
)
836 vcl::KeyCode
vclKeyCode(nKeyCode
);
837 int nCode
= vclKeyCode
.GetCode();
840 if (nCode
>= KEY_0
&& nCode
<= KEY_9
)
841 nRetCode
= (nCode
- KEY_0
) + Qt::Key_0
;
842 else if (nCode
>= KEY_A
&& nCode
<= KEY_Z
)
843 nRetCode
= (nCode
- KEY_A
) + Qt::Key_A
;
844 else if (nCode
>= KEY_F1
&& nCode
<= KEY_F26
)
845 nRetCode
= (nCode
- KEY_F1
) + Qt::Key_F1
;
851 nRetCode
= Qt::Key_Down
;
854 nRetCode
= Qt::Key_Up
;
857 nRetCode
= Qt::Key_Left
;
860 nRetCode
= Qt::Key_Right
;
863 nRetCode
= Qt::Key_Home
;
866 nRetCode
= Qt::Key_End
;
869 nRetCode
= Qt::Key_PageUp
;
872 nRetCode
= Qt::Key_PageDown
;
875 nRetCode
= Qt::Key_Return
;
878 nRetCode
= Qt::Key_Escape
;
881 nRetCode
= Qt::Key_Tab
;
884 nRetCode
= Qt::Key_Backspace
;
887 nRetCode
= Qt::Key_Space
;
890 nRetCode
= Qt::Key_Insert
;
893 nRetCode
= Qt::Key_Delete
;
896 nRetCode
= Qt::Key_Plus
;
899 nRetCode
= Qt::Key_Minus
;
902 nRetCode
= Qt::Key_Asterisk
;
905 nRetCode
= Qt::Key_Slash
;
908 nRetCode
= Qt::Key_Period
;
911 nRetCode
= Qt::Key_Comma
;
914 nRetCode
= Qt::Key_Less
;
917 nRetCode
= Qt::Key_Greater
;
920 nRetCode
= Qt::Key_Equal
;
923 nRetCode
= Qt::Key_Find
;
925 case KEY_CONTEXTMENU
:
926 nRetCode
= Qt::Key_Menu
;
929 nRetCode
= Qt::Key_Help
;
932 nRetCode
= Qt::Key_Undo
;
935 nRetCode
= Qt::Key_Redo
;
938 nRetCode
= Qt::Key_AsciiTilde
;
941 nRetCode
= Qt::Key_QuoteLeft
;
943 case KEY_BRACKETLEFT
:
944 nRetCode
= Qt::Key_BracketLeft
;
946 case KEY_BRACKETRIGHT
:
947 nRetCode
= Qt::Key_BracketRight
;
950 nRetCode
= Qt::Key_Semicolon
;
955 nRetCode
= Qt::Key_Copy
;
958 nRetCode
= Qt::Key_Cut
;
961 nRetCode
= Qt::Key_Paste
;
964 nRetCode
= Qt::Key_Open
;
969 if (vclKeyCode
.IsShift())
970 nRetCode
+= Qt::SHIFT
;
971 if (vclKeyCode
.IsMod1())
972 nRetCode
+= Qt::CTRL
;
973 if (vclKeyCode
.IsMod2())
976 QKeySequence
keySeq(nRetCode
);
977 OUString sKeyName
= toOUString(keySeq
.toString());
982 bool Qt5Frame::MapUnicodeToKeyCode(sal_Unicode
/*aUnicode*/, LanguageType
/*aLangType*/,
983 vcl::KeyCode
& /*rKeyCode*/)
989 LanguageType
Qt5Frame::GetInputLanguage()
992 return LANGUAGE_DONTKNOW
;
995 static Color
toColor(const QColor
& rColor
)
997 return Color(rColor
.red(), rColor
.green(), rColor
.blue());
1000 void Qt5Frame::UpdateSettings(AllSettings
& rSettings
)
1002 if (Qt5Data::noNativeControls())
1005 StyleSettings
style(rSettings
.GetStyleSettings());
1008 QPalette pal
= QApplication::palette();
1010 style
.SetToolbarIconSize(ToolbarIconSize::Large
);
1012 Color aFore
= toColor(pal
.color(QPalette::Active
, QPalette::WindowText
));
1013 Color aBack
= toColor(pal
.color(QPalette::Active
, QPalette::Window
));
1014 Color aText
= toColor(pal
.color(QPalette::Active
, QPalette::Text
));
1015 Color aBase
= toColor(pal
.color(QPalette::Active
, QPalette::Base
));
1016 Color aButn
= toColor(pal
.color(QPalette::Active
, QPalette::ButtonText
));
1017 Color aMid
= toColor(pal
.color(QPalette::Active
, QPalette::Mid
));
1018 Color aHigh
= toColor(pal
.color(QPalette::Active
, QPalette::Highlight
));
1019 Color aHighText
= toColor(pal
.color(QPalette::Active
, QPalette::HighlightedText
));
1020 Color aLink
= toColor(pal
.color(QPalette::Active
, QPalette::Link
));
1021 Color aVisitedLink
= toColor(pal
.color(QPalette::Active
, QPalette::LinkVisited
));
1023 style
.SetSkipDisabledInMenus(true);
1026 style
.SetRadioCheckTextColor(aFore
);
1027 style
.SetLabelTextColor(aFore
);
1028 style
.SetDialogTextColor(aFore
);
1029 style
.SetGroupTextColor(aFore
);
1032 style
.SetFieldTextColor(aText
);
1033 style
.SetFieldRolloverTextColor(aText
);
1034 style
.SetWindowTextColor(aText
);
1035 style
.SetToolTextColor(aText
);
1038 style
.SetFieldColor(aBase
);
1039 style
.SetWindowColor(aBase
);
1040 style
.SetActiveTabColor(aBase
);
1041 style
.SetAlternatingRowColor(toColor(pal
.color(QPalette::Active
, QPalette::AlternateBase
)));
1044 style
.SetDefaultButtonTextColor(aButn
);
1045 style
.SetButtonTextColor(aButn
);
1046 style
.SetDefaultActionButtonTextColor(aButn
);
1047 style
.SetActionButtonTextColor(aButn
);
1048 style
.SetFlatButtonTextColor(aButn
);
1049 style
.SetDefaultButtonRolloverTextColor(aButn
);
1050 style
.SetButtonRolloverTextColor(aButn
);
1051 style
.SetDefaultActionButtonRolloverTextColor(aButn
);
1052 style
.SetActionButtonRolloverTextColor(aButn
);
1053 style
.SetFlatButtonRolloverTextColor(aButn
);
1054 style
.SetDefaultButtonPressedRolloverTextColor(aButn
);
1055 style
.SetButtonPressedRolloverTextColor(aButn
);
1056 style
.SetDefaultActionButtonPressedRolloverTextColor(aButn
);
1057 style
.SetActionButtonPressedRolloverTextColor(aButn
);
1058 style
.SetFlatButtonPressedRolloverTextColor(aButn
);
1061 style
.SetTabTextColor(aButn
);
1062 style
.SetTabRolloverTextColor(aButn
);
1063 style
.SetTabHighlightTextColor(aButn
);
1066 style
.SetDisableColor(toColor(pal
.color(QPalette::Disabled
, QPalette::WindowText
)));
1069 style
.BatchSetBackgrounds(aBack
);
1070 style
.SetInactiveTabColor(aBack
);
1073 style
.SetWorkspaceColor(aMid
);
1076 style
.SetHighlightColor(aHigh
);
1077 style
.SetHighlightTextColor(aHighText
);
1078 style
.SetActiveColor(aHigh
);
1079 style
.SetActiveTextColor(aHighText
);
1082 style
.SetLinkColor(aLink
);
1083 style
.SetVisitedLinkColor(aVisitedLink
);
1086 style
.SetHelpColor(toColor(QToolTip::palette().color(QPalette::Active
, QPalette::ToolTipBase
)));
1087 style
.SetHelpTextColor(
1088 toColor(QToolTip::palette().color(QPalette::Active
, QPalette::ToolTipText
)));
1090 const int flash_time
= QApplication::cursorFlashTime();
1091 style
.SetCursorBlinkTime(flash_time
!= 0 ? flash_time
/ 2 : STYLE_CURSOR_NOBLINKTIME
);
1094 std::unique_ptr
<QMenuBar
> pMenuBar
= std::make_unique
<QMenuBar
>();
1095 QPalette qMenuCG
= pMenuBar
->palette();
1097 // Menu text and background color, theme specific
1098 Color aMenuFore
= toColor(qMenuCG
.color(QPalette::WindowText
));
1099 Color aMenuBack
= toColor(qMenuCG
.color(QPalette::Window
));
1101 style
.SetMenuTextColor(aMenuFore
);
1102 style
.SetMenuBarTextColor(style
.GetPersonaMenuBarTextColor().value_or(aMenuFore
));
1103 style
.SetMenuColor(aMenuBack
);
1104 style
.SetMenuBarColor(aMenuBack
);
1105 style
.SetMenuHighlightColor(toColor(qMenuCG
.color(QPalette::Highlight
)));
1106 style
.SetMenuHighlightTextColor(toColor(qMenuCG
.color(QPalette::HighlightedText
)));
1108 // set special menubar highlight text color
1109 if (QApplication::style()->inherits("HighContrastStyle"))
1110 ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
1111 = toColor(qMenuCG
.color(QPalette::HighlightedText
));
1113 ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
= aMenuFore
;
1115 // set menubar rollover color
1116 if (pMenuBar
->style()->styleHint(QStyle::SH_MenuBar_MouseTracking
))
1118 style
.SetMenuBarRolloverColor(toColor(qMenuCG
.color(QPalette::Highlight
)));
1119 style
.SetMenuBarRolloverTextColor(ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
);
1123 style
.SetMenuBarRolloverColor(aMenuBack
);
1124 style
.SetMenuBarRolloverTextColor(aMenuFore
);
1126 style
.SetMenuBarHighlightTextColor(style
.GetMenuHighlightTextColor());
1129 style
.SetPreferredIconTheme(toOUString(QIcon::themeName()));
1132 style
.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent
));
1133 style
.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin
));
1135 // These colors are used for the ruler text and marks
1136 style
.SetShadowColor(toColor(pal
.color(QPalette::Disabled
, QPalette::WindowText
)));
1137 style
.SetDarkShadowColor(toColor(pal
.color(QPalette::Inactive
, QPalette::WindowText
)));
1139 rSettings
.SetStyleSettings(style
);
1142 void Qt5Frame::Beep() { QApplication::beep(); }
1144 SalFrame::SalPointerState
Qt5Frame::GetPointerState()
1146 SalPointerState aState
;
1147 aState
.maPos
= toPoint(QCursor::pos() * devicePixelRatioF());
1148 aState
.maPos
.Move(-maGeometry
.nX
, -maGeometry
.nY
);
1149 aState
.mnState
= GetMouseModCode(QGuiApplication::mouseButtons())
1150 | GetKeyModCode(QGuiApplication::keyboardModifiers());
1154 KeyIndicatorState
Qt5Frame::GetIndicatorState() { return KeyIndicatorState(); }
1156 void Qt5Frame::SimulateKeyPress(sal_uInt16 nKeyCode
)
1158 SAL_WARN("vcl.qt5", "missing simulate keypress " << nKeyCode
);
1161 void Qt5Frame::SetParent(SalFrame
* pNewParent
) { m_pParent
= static_cast<Qt5Frame
*>(pNewParent
); }
1163 bool Qt5Frame::SetPluginParent(SystemParentData
* /*pNewParent*/)
1165 //FIXME: no SetPluginParent impl. for qt5
1169 void Qt5Frame::ResetClipRegion() { m_bNullRegion
= true; }
1171 void Qt5Frame::BeginSetClipRegion(sal_uInt32
)
1173 m_aRegion
= QRegion(QRect(QPoint(0, 0), m_pQWidget
->size()));
1176 void Qt5Frame::UnionClipRegion(tools::Long nX
, tools::Long nY
, tools::Long nWidth
,
1177 tools::Long nHeight
)
1180 = m_aRegion
.united(scaledQRect(QRect(nX
, nY
, nWidth
, nHeight
), 1 / devicePixelRatioF()));
1183 void Qt5Frame::EndSetClipRegion() { m_bNullRegion
= false; }
1185 void Qt5Frame::SetScreenNumber(unsigned int nScreen
)
1190 QWindow
* const pWindow
= windowHandle();
1194 QList
<QScreen
*> screens
= QApplication::screens();
1195 if (static_cast<int>(nScreen
) < screens
.size() || m_bFullScreenSpanAll
)
1199 if (!m_bFullScreenSpanAll
)
1201 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1202 screenGeo
= QApplication::desktop()->screenGeometry(nScreen
);
1203 SAL_WNODEPRECATED_DECLARATIONS_POP
1204 pWindow
->setScreen(QApplication::screens()[nScreen
]);
1206 else // special case: fullscreen over all available screens
1208 assert(m_bFullScreen
);
1210 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1211 int nLeftScreen
= QApplication::desktop()->screenNumber(QPoint(0, 0));
1212 SAL_WNODEPRECATED_DECLARATIONS_POP
1213 // entire virtual desktop
1214 screenGeo
= QApplication::screens()[nLeftScreen
]->availableVirtualGeometry();
1215 pWindow
->setScreen(QApplication::screens()[nLeftScreen
]);
1216 pWindow
->setGeometry(screenGeo
);
1217 nScreen
= nLeftScreen
;
1220 // setScreen by itself has no effect, explicitly move the widget to
1222 asChild()->move(screenGeo
.topLeft());
1226 // index outta bounds, use primary screen
1227 QScreen
* primaryScreen
= QApplication::primaryScreen();
1228 pWindow
->setScreen(primaryScreen
);
1229 nScreen
= static_cast<sal_uInt32
>(screenNumber(primaryScreen
));
1232 maGeometry
.nDisplayScreenNumber
= nScreen
;
1235 void Qt5Frame::SetApplicationID(const OUString
& rWMClass
)
1238 if (QGuiApplication::platformName() != "xcb" || !m_pTopLevel
)
1241 OString aResClass
= OUStringToOString(rWMClass
, RTL_TEXTENCODING_ASCII_US
);
1242 const char* pResClass
1243 = !aResClass
.isEmpty() ? aResClass
.getStr() : SalGenericSystem::getFrameClassName();
1244 OString aResName
= SalGenericSystem::getFrameResName();
1246 // the WM_CLASS data consists of two concatenated cstrings, including the terminating '\0' chars
1247 const uint32_t data_len
= aResName
.getLength() + 1 + strlen(pResClass
) + 1;
1248 char* data
= new char[data_len
];
1249 memcpy(data
, aResName
.getStr(), aResName
.getLength() + 1);
1250 memcpy(data
+ aResName
.getLength() + 1, pResClass
, strlen(pResClass
) + 1);
1252 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE
, m_pTopLevel
->winId(),
1253 XCB_ATOM_WM_CLASS
, XCB_ATOM_STRING
, 8, data_len
, data
);
1262 void Qt5Frame::registerDragSource(Qt5DragSource
* pDragSource
)
1264 assert(!m_pDragSource
);
1265 m_pDragSource
= pDragSource
;
1268 void Qt5Frame::deregisterDragSource(Qt5DragSource
const* pDragSource
)
1270 assert(m_pDragSource
== pDragSource
);
1272 m_pDragSource
= nullptr;
1275 void Qt5Frame::registerDropTarget(Qt5DropTarget
* pDropTarget
)
1277 assert(!m_pDropTarget
);
1278 m_pDropTarget
= pDropTarget
;
1279 m_pQWidget
->setAcceptDrops(true);
1282 void Qt5Frame::deregisterDropTarget(Qt5DropTarget
const* pDropTarget
)
1284 assert(m_pDropTarget
== pDropTarget
);
1286 m_pDropTarget
= nullptr;
1289 static css::uno::Reference
<css::datatransfer::XTransferable
>
1290 lcl_getXTransferable(const QMimeData
* pMimeData
)
1292 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
;
1293 const Qt5MimeData
* pQt5MimeData
= dynamic_cast<const Qt5MimeData
*>(pMimeData
);
1295 xTransferable
= new Qt5DnDTransferable(pMimeData
);
1297 xTransferable
= pQt5MimeData
->xTransferable();
1298 return xTransferable
;
1301 static sal_Int8
lcl_getUserDropAction(const QDropEvent
* pEvent
, const sal_Int8 nSourceActions
,
1302 const QMimeData
* pMimeData
)
1304 // we completely ignore all proposals by the Qt event, as they don't
1305 // match at all with the preferred LO DnD actions.
1307 // check the key modifiers to detect a user-overridden DnD action
1308 const Qt::KeyboardModifiers eKeyMod
= pEvent
->keyboardModifiers();
1309 sal_Int8 nUserDropAction
= 0;
1310 if ((eKeyMod
& Qt::ShiftModifier
) && !(eKeyMod
& Qt::ControlModifier
))
1311 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_MOVE
;
1312 else if ((eKeyMod
& Qt::ControlModifier
) && !(eKeyMod
& Qt::ShiftModifier
))
1313 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_COPY
;
1314 else if ((eKeyMod
& Qt::ShiftModifier
) && (eKeyMod
& Qt::ControlModifier
))
1315 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_LINK
;
1316 nUserDropAction
&= nSourceActions
;
1318 // select the default DnD action, if there isn't a user preference
1319 if (0 == nUserDropAction
)
1321 // default LO internal action is move, but default external action is copy
1322 nUserDropAction
= dynamic_cast<const Qt5MimeData
*>(pMimeData
)
1323 ? css::datatransfer::dnd::DNDConstants::ACTION_MOVE
1324 : css::datatransfer::dnd::DNDConstants::ACTION_COPY
;
1325 nUserDropAction
&= nSourceActions
;
1327 // if the default doesn't match any allowed source action, fall back to the
1328 // preferred of all allowed source actions
1329 if (0 == nUserDropAction
)
1330 nUserDropAction
= toVclDropAction(getPreferredDropAction(nSourceActions
));
1332 // this is "our" preference, but actually we would even prefer any default,
1334 nUserDropAction
|= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT
;
1336 return nUserDropAction
;
1339 void Qt5Frame::handleDragMove(QDragMoveEvent
* pEvent
)
1341 assert(m_pDropTarget
);
1343 // prepare our suggested drop action for the drop target
1344 const sal_Int8 nSourceActions
= toVclDropActions(pEvent
->possibleActions());
1345 const QMimeData
* pMimeData
= pEvent
->mimeData();
1346 const sal_Int8 nUserDropAction
= lcl_getUserDropAction(pEvent
, nSourceActions
, pMimeData
);
1347 const Point aPos
= toPoint(pEvent
->pos() * devicePixelRatioF());
1349 css::datatransfer::dnd::DropTargetDragEnterEvent aEvent
;
1350 aEvent
.Source
= static_cast<css::datatransfer::dnd::XDropTarget
*>(m_pDropTarget
);
1351 aEvent
.Context
= static_cast<css::datatransfer::dnd::XDropTargetDragContext
*>(m_pDropTarget
);
1352 aEvent
.LocationX
= aPos
.X();
1353 aEvent
.LocationY
= aPos
.Y();
1354 aEvent
.DropAction
= nUserDropAction
;
1355 aEvent
.SourceActions
= nSourceActions
;
1357 // ask the drop target to accept our drop action
1360 aEvent
.SupportedDataFlavors
= lcl_getXTransferable(pMimeData
)->getTransferDataFlavors();
1361 m_pDropTarget
->fire_dragEnter(aEvent
);
1365 m_pDropTarget
->fire_dragOver(aEvent
);
1367 // the drop target accepted our drop action => inform Qt
1368 if (m_pDropTarget
->proposedDropAction() != 0)
1370 pEvent
->setDropAction(getPreferredDropAction(m_pDropTarget
->proposedDropAction()));
1373 else // or maybe someone else likes it?
1377 void Qt5Frame::handleDrop(QDropEvent
* pEvent
)
1379 assert(m_pDropTarget
);
1381 // prepare our suggested drop action for the drop target
1382 const sal_Int8 nSourceActions
= toVclDropActions(pEvent
->possibleActions());
1383 const sal_Int8 nUserDropAction
1384 = lcl_getUserDropAction(pEvent
, nSourceActions
, pEvent
->mimeData());
1385 const Point aPos
= toPoint(pEvent
->pos() * devicePixelRatioF());
1387 css::datatransfer::dnd::DropTargetDropEvent aEvent
;
1388 aEvent
.Source
= static_cast<css::datatransfer::dnd::XDropTarget
*>(m_pDropTarget
);
1389 aEvent
.Context
= static_cast<css::datatransfer::dnd::XDropTargetDropContext
*>(m_pDropTarget
);
1390 aEvent
.LocationX
= aPos
.X();
1391 aEvent
.LocationY
= aPos
.Y();
1392 aEvent
.SourceActions
= nSourceActions
;
1393 aEvent
.DropAction
= nUserDropAction
;
1394 aEvent
.Transferable
= lcl_getXTransferable(pEvent
->mimeData());
1396 // ask the drop target to accept our drop action
1397 m_pDropTarget
->fire_drop(aEvent
);
1400 const bool bDropSuccessful
= m_pDropTarget
->dropSuccessful();
1401 const sal_Int8 nDropAction
= m_pDropTarget
->proposedDropAction();
1403 // inform the drag source of the drag-origin frame of the drop result
1404 if (pEvent
->source())
1406 Qt5Widget
* pWidget
= dynamic_cast<Qt5Widget
*>(pEvent
->source());
1407 assert(pWidget
); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself
1409 pWidget
->frame().m_pDragSource
->fire_dragEnd(nDropAction
, bDropSuccessful
);
1412 // the drop target accepted our drop action => inform Qt
1413 if (bDropSuccessful
)
1415 pEvent
->setDropAction(getPreferredDropAction(nDropAction
));
1418 else // or maybe someone else likes it?
1422 void Qt5Frame::handleDragLeave()
1424 css::datatransfer::dnd::DropTargetEvent aEvent
;
1425 aEvent
.Source
= static_cast<css::datatransfer::dnd::XDropTarget
*>(m_pDropTarget
);
1426 m_pDropTarget
->fire_dragExit(aEvent
);
1430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */