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 <Qt5Tools.hxx>
31 #include <Qt5Widget.hxx>
33 #include <QtCore/QMimeData>
34 #include <QtCore/QPoint>
35 #include <QtCore/QSize>
36 #include <QtGui/QIcon>
37 #include <QtGui/QWindow>
38 #include <QtGui/QScreen>
39 #include <QtWidgets/QStyle>
40 #include <QtWidgets/QToolTip>
41 #include <QtWidgets/QApplication>
42 #include <QtWidgets/QDesktopWidget>
43 #include <QtWidgets/QMenuBar>
44 #include <QtWidgets/QMainWindow>
46 #include <saldatabasic.hxx>
48 #include <vcl/layout.hxx>
49 #include <vcl/syswin.hxx>
51 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
54 #include <headless/svpgdi.hxx>
56 static void SvpDamageHandler(void* handle
, sal_Int32 nExtentsX
, sal_Int32 nExtentsY
,
57 sal_Int32 nExtentsWidth
, sal_Int32 nExtentsHeight
)
59 Qt5Frame
* pThis
= static_cast<Qt5Frame
*>(handle
);
60 pThis
->Damage(nExtentsX
, nExtentsY
, nExtentsWidth
, nExtentsHeight
);
65 sal_Int32
screenNumber(const QScreen
* pScreen
)
67 const QList
<QScreen
*> screens
= QApplication::screens();
69 sal_Int32 nScreen
= 0;
71 for (const QScreen
* pCurScreen
: screens
)
73 if (pScreen
== pCurScreen
)
81 return bFound
? nScreen
: -1;
85 Qt5Frame::Qt5Frame(Qt5Frame
* pParent
, SalFrameStyleFlags nStyle
, bool bUseCairo
)
86 : m_pTopLevel(nullptr)
87 , m_bUseCairo(bUseCairo
)
88 , m_pSvpGraphics(nullptr)
90 , m_bGraphicsInUse(false)
91 , m_bGraphicsInvalid(false)
92 , m_ePointerStyle(PointerStyle::Arrow
)
93 , m_pDragSource(nullptr)
94 , m_pDropTarget(nullptr)
96 , m_bDefaultSize(true)
98 , m_bFullScreen(false)
99 , m_bFullScreenSpanAll(false)
101 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
102 pInst
->insertFrame(this);
104 m_aDamageHandler
.handle
= this;
105 m_aDamageHandler
.damaged
= ::SvpDamageHandler
;
107 if (nStyle
& SalFrameStyleFlags::DEFAULT
) // ensure default style
109 nStyle
|= SalFrameStyleFlags::MOVEABLE
| SalFrameStyleFlags::SIZEABLE
110 | SalFrameStyleFlags::CLOSEABLE
;
111 nStyle
&= ~SalFrameStyleFlags::FLOAT
;
117 Qt::WindowFlags aWinFlags
;
118 if (!(nStyle
& SalFrameStyleFlags::SYSTEMCHILD
))
120 if (nStyle
& SalFrameStyleFlags::INTRO
)
121 aWinFlags
|= Qt::SplashScreen
;
122 // floating toolbars are frameless tool windows
123 // + they must be able to receive keyboard focus
124 else if ((nStyle
& SalFrameStyleFlags::FLOAT
)
125 && (nStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
))
126 aWinFlags
|= Qt::Tool
| Qt::FramelessWindowHint
;
127 else if (nStyle
& (SalFrameStyleFlags::FLOAT
| SalFrameStyleFlags::TOOLTIP
))
128 aWinFlags
|= Qt::ToolTip
;
129 else if ((nStyle
& SalFrameStyleFlags::FLOAT
)
130 && !(nStyle
& SalFrameStyleFlags::OWNERDRAWDECORATION
))
131 aWinFlags
|= Qt::Popup
;
132 else if (nStyle
& SalFrameStyleFlags::DIALOG
&& pParent
)
133 aWinFlags
|= Qt::Dialog
;
134 else if (nStyle
& SalFrameStyleFlags::TOOLWINDOW
)
135 aWinFlags
|= Qt::Tool
;
137 aWinFlags
|= Qt::Window
;
140 if (aWinFlags
== Qt::Window
)
142 QWidget
* pParentWidget
= nullptr;
146 = (m_pParent
->m_pTopLevel
) ? m_pParent
->m_pTopLevel
: m_pParent
->m_pQWidget
;
149 m_pTopLevel
= new Qt5MainWindow(*this, pParentWidget
, aWinFlags
);
150 m_pQWidget
= new Qt5Widget(*this, aWinFlags
);
151 m_pTopLevel
->setCentralWidget(m_pQWidget
);
154 m_pQWidget
= new Qt5Widget(*this, aWinFlags
);
156 connect(this, &Qt5Frame::tooltipRequest
, static_cast<Qt5Widget
*>(m_pQWidget
),
157 &Qt5Widget::showTooltip
);
159 if (pParent
&& !(pParent
->m_nStyle
& SalFrameStyleFlags::PLUG
))
161 QWindow
* pParentWindow
= pParent
->GetQWidget()->window()->windowHandle();
162 QWindow
* pChildWindow
= (m_pTopLevel
? m_pTopLevel
->window()->windowHandle()
163 : m_pQWidget
->window()->windowHandle());
164 if (pParentWindow
&& pChildWindow
&& (pParentWindow
!= pChildWindow
))
165 pChildWindow
->setTransientParent(pParentWindow
);
168 // fake an initial geometry, gets updated via configure event or SetPosSize
169 if (m_bDefaultPos
|| m_bDefaultSize
)
171 maGeometry
.nDisplayScreenNumber
= 0;
172 Size aDefSize
= CalcDefaultSize();
175 maGeometry
.nWidth
= aDefSize
.Width();
176 maGeometry
.nHeight
= aDefSize
.Height();
177 maGeometry
.nTopDecoration
= 0;
178 maGeometry
.nBottomDecoration
= 0;
179 maGeometry
.nLeftDecoration
= 0;
180 maGeometry
.nRightDecoration
= 0;
183 m_aSystemData
.nSize
= sizeof(SystemEnvData
);
185 // Calling 'QWidget::winId()' implicitly enables native windows to be used
186 // rather than "alien widgets" that are unknown to the windowing system,
187 // s. https://doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets
188 // Avoid this on Wayland due to problems with missing 'mouseMoveEvent's,
189 // s. tdf#122293/QTBUG-75766
190 const bool bWayland
= QGuiApplication::platformName() == "wayland";
192 m_aSystemData
.aWindow
= m_pQWidget
->winId();
195 // TODO implement as needed for Wayland,
196 // s.a. commit c0d4f3ad3307c which did this for gtk3
197 // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface();
198 // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr);
199 // m_aSystemData.aWindow = reinterpret_cast<unsigned long>(
200 // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle()));
203 m_aSystemData
.aShellWindow
= reinterpret_cast<sal_IntPtr
>(this);
204 //m_aSystemData.pSalFrame = this;
205 //m_aSystemData.pWidget = m_pQWidget;
206 //m_aSystemData.nScreen = m_nXScreen.getXScreen();
207 m_aSystemData
.pToolkit
= "qt5";
209 m_aSystemData
.pPlatformName
= "xcb";
211 m_aSystemData
.pPlatformName
= "wayland";
213 SetIcon(SV_ICON_ID_OFFICE
);
216 Qt5Frame::~Qt5Frame()
218 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
219 pInst
->eraseFrame(this);
224 m_aSystemData
.aShellWindow
= 0;
227 void Qt5Frame::Damage(sal_Int32 nExtentsX
, sal_Int32 nExtentsY
, sal_Int32 nExtentsWidth
,
228 sal_Int32 nExtentsHeight
) const
230 m_pQWidget
->update(nExtentsX
, nExtentsY
, nExtentsWidth
, nExtentsHeight
);
233 void Qt5Frame::TriggerPaintEvent()
235 QSize
aSize(m_pQWidget
->size());
236 SalPaintEvent
aPaintEvt(0, 0, aSize
.width(), aSize
.height(), true);
237 CallCallback(SalEvent::Paint
, &aPaintEvt
);
240 void Qt5Frame::TriggerPaintEvent(QRect aRect
)
242 SalPaintEvent
aPaintEvt(aRect
.x(), aRect
.y(), aRect
.width(), aRect
.height(), true);
243 CallCallback(SalEvent::Paint
, &aPaintEvt
);
246 void Qt5Frame::InitQt5SvpGraphics(Qt5SvpGraphics
* pQt5SvpGraphics
)
250 m_pSvpGraphics
= pQt5SvpGraphics
;
251 m_pSurface
.reset(cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
));
252 m_pSvpGraphics
->setSurface(m_pSurface
.get(), basegfx::B2IVector(width
, height
));
253 cairo_surface_set_user_data(m_pSurface
.get(), Qt5SvpGraphics::getDamageKey(), &m_aDamageHandler
,
257 SalGraphics
* Qt5Frame::AcquireGraphics()
259 if (m_bGraphicsInUse
)
262 m_bGraphicsInUse
= true;
266 if (!m_pOurSvpGraphics
.get() || m_bGraphicsInvalid
)
268 m_pOurSvpGraphics
.reset(new Qt5SvpGraphics(m_pQWidget
));
269 InitQt5SvpGraphics(m_pOurSvpGraphics
.get());
270 m_bGraphicsInvalid
= false;
272 return m_pOurSvpGraphics
.get();
276 if (!m_pQt5Graphics
.get() || m_bGraphicsInvalid
)
278 m_pQt5Graphics
.reset(new Qt5Graphics(this));
279 m_pQImage
.reset(new QImage(m_pQWidget
->size(), Qt5_DefaultFormat32
));
280 m_pQImage
->fill(Qt::transparent
);
281 m_pQt5Graphics
->ChangeQImage(m_pQImage
.get());
282 m_bGraphicsInvalid
= false;
284 return m_pQt5Graphics
.get();
288 void Qt5Frame::ReleaseGraphics(SalGraphics
* pSalGraph
)
292 assert(pSalGraph
== m_pOurSvpGraphics
.get());
294 assert(pSalGraph
== m_pQt5Graphics
.get());
295 m_bGraphicsInUse
= false;
298 bool Qt5Frame::PostEvent(std::unique_ptr
<ImplSVEvent
> pData
)
300 Qt5Instance
* pInst
= static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
);
301 pInst
->PostEvent(this, pData
.release(), SalEvent::UserEvent
);
305 bool Qt5Frame::isWindow() const
308 return m_pTopLevel
->isWindow();
310 return m_pQWidget
->isWindow();
313 QWindow
* Qt5Frame::windowHandle() const
315 // set attribute 'Qt::WA_NativeWindow' first to make sure a window handle actually exists
318 m_pTopLevel
->setAttribute(Qt::WA_NativeWindow
);
319 return m_pTopLevel
->windowHandle();
323 m_pQWidget
->setAttribute(Qt::WA_NativeWindow
);
324 return m_pQWidget
->windowHandle();
328 QScreen
* Qt5Frame::screen() const
330 QWindow
* const pWindow
= windowHandle();
332 return pWindow
->screen();
337 bool Qt5Frame::isMinimized() const
340 return m_pTopLevel
->isMinimized();
342 return m_pQWidget
->isMinimized();
345 bool Qt5Frame::isMaximized() const
348 return m_pTopLevel
->isMaximized();
350 return m_pQWidget
->isMaximized();
353 void Qt5Frame::SetWindowStateImpl(Qt::WindowStates eState
)
356 m_pTopLevel
->setWindowState(eState
);
358 m_pQWidget
->setWindowState(eState
);
361 void Qt5Frame::SetTitle(const OUString
& rTitle
)
363 m_pQWidget
->window()->setWindowTitle(toQString(rTitle
));
366 void Qt5Frame::SetIcon(sal_uInt16 nIcon
)
369 & (SalFrameStyleFlags::PLUG
| SalFrameStyleFlags::SYSTEMCHILD
370 | SalFrameStyleFlags::FLOAT
| SalFrameStyleFlags::INTRO
371 | SalFrameStyleFlags::OWNERDRAWDECORATION
)
377 if (nIcon
== SV_ICON_ID_TEXT
)
378 appicon
= "libreoffice-writer";
379 else if (nIcon
== SV_ICON_ID_SPREADSHEET
)
380 appicon
= "libreoffice-calc";
381 else if (nIcon
== SV_ICON_ID_DRAWING
)
382 appicon
= "libreoffice-draw";
383 else if (nIcon
== SV_ICON_ID_PRESENTATION
)
384 appicon
= "libreoffice-impress";
385 else if (nIcon
== SV_ICON_ID_DATABASE
)
386 appicon
= "libreoffice-base";
387 else if (nIcon
== SV_ICON_ID_FORMULA
)
388 appicon
= "libreoffice-math";
390 appicon
= "libreoffice-startcenter";
392 QIcon aIcon
= QIcon::fromTheme(appicon
);
393 m_pQWidget
->window()->setWindowIcon(aIcon
);
396 void Qt5Frame::SetMenu(SalMenu
* pMenu
) { m_pSalMenu
= static_cast<Qt5Menu
*>(pMenu
); }
398 void Qt5Frame::DrawMenuBar() { /* not needed */}
400 void Qt5Frame::SetExtendedFrameStyle(SalExtStyle
/*nExtStyle*/) { /* not needed */}
402 void Qt5Frame::setVisible(bool bVisible
)
405 m_pTopLevel
->setVisible(bVisible
);
407 m_pQWidget
->setVisible(bVisible
);
410 void Qt5Frame::Show(bool bVisible
, bool /*bNoActivate*/)
417 auto* pSalInst(static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
));
419 pSalInst
->RunInMainThread([this, bVisible
]() { setVisible(bVisible
); });
422 void Qt5Frame::SetMinClientSize(long nWidth
, long nHeight
)
427 m_pTopLevel
->setMinimumSize(nWidth
, nHeight
);
429 m_pQWidget
->setMinimumSize(nWidth
, nHeight
);
433 void Qt5Frame::SetMaxClientSize(long nWidth
, long nHeight
)
438 m_pTopLevel
->setMaximumSize(nWidth
, nHeight
);
440 m_pQWidget
->setMaximumSize(nWidth
, nHeight
);
444 void Qt5Frame::Center()
448 QWidget
* pWindow
= m_pParent
->GetQWidget()->window();
449 QWidget
* const pWidget
= m_pTopLevel
? m_pTopLevel
: m_pQWidget
;
450 pWidget
->move(pWindow
->frameGeometry().topLeft() + pWindow
->rect().center()
451 - pWidget
->rect().center());
455 Size
Qt5Frame::CalcDefaultSize()
462 const QScreen
* pScreen
= screen();
463 aSize
= bestmaxFrameSizeForScreenSize(
464 toSize(pScreen
? pScreen
->size() : QApplication::desktop()->screenGeometry(0).size()));
468 if (!m_bFullScreenSpanAll
)
470 QApplication::desktop()->screenGeometry(maGeometry
.nDisplayScreenNumber
).size());
473 int nLeftScreen
= QApplication::desktop()->screenNumber(QPoint(0, 0));
474 aSize
= toSize(QApplication::screens()[nLeftScreen
]->availableVirtualGeometry().size());
481 void Qt5Frame::SetDefaultSize()
483 Size aDefSize
= CalcDefaultSize();
484 SetPosSize(0, 0, aDefSize
.Width(), aDefSize
.Height(),
485 SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
);
488 void Qt5Frame::SetPosSize(long nX
, long nY
, long nWidth
, long nHeight
, sal_uInt16 nFlags
)
490 if (!isWindow() || isChild(true, false))
493 if ((nFlags
& (SAL_FRAME_POSSIZE_WIDTH
| SAL_FRAME_POSSIZE_HEIGHT
))
494 && (nWidth
> 0 && nHeight
> 0) // sometimes stupid things happen
497 m_bDefaultSize
= false;
498 if (isChild(false) || !m_pQWidget
->isMaximized())
500 QWidget
* const pWidget
= m_pTopLevel
? m_pTopLevel
: m_pQWidget
;
502 if (m_nStyle
& SalFrameStyleFlags::SIZEABLE
)
503 pWidget
->resize(nWidth
, nHeight
);
505 pWidget
->setFixedSize(nWidth
, nHeight
);
508 else if (m_bDefaultSize
)
511 m_bDefaultSize
= false;
513 if (nFlags
& (SAL_FRAME_POSSIZE_X
| SAL_FRAME_POSSIZE_Y
))
518 if (m_pParent
->GetTopLevelWindow())
519 aRect
= m_pParent
->GetTopLevelWindow()->geometry();
521 aRect
= m_pParent
->GetQWidget()->geometry();
530 m_bDefaultPos
= false;
532 m_pTopLevel
->move(nX
, nY
);
534 m_pQWidget
->move(nX
, nY
);
536 else if (m_bDefaultPos
)
539 m_bDefaultPos
= false;
542 void Qt5Frame::GetClientSize(long& rWidth
, long& rHeight
)
544 rWidth
= m_pQWidget
->width();
545 rHeight
= m_pQWidget
->height();
548 void Qt5Frame::GetWorkArea(tools::Rectangle
& rRect
)
552 QScreen
* pScreen
= screen();
556 QSize aSize
= pScreen
->availableVirtualSize();
557 rRect
= tools::Rectangle(0, 0, aSize
.width(), aSize
.height());
560 SalFrame
* Qt5Frame::GetParent() const { return m_pParent
; }
562 void Qt5Frame::SetModal(bool bModal
)
566 auto* pSalInst(static_cast<Qt5Instance
*>(GetSalData()->m_pInstance
));
568 pSalInst
->RunInMainThread([this, bModal
]() {
569 bool wasVisible
= windowHandle()->isVisible();
571 // modality change is only effective if the window is hidden
574 windowHandle()->hide();
577 windowHandle()->setModality(bModal
? Qt::WindowModal
: Qt::NonModal
);
579 // and shown again if it was visible
582 windowHandle()->show();
588 bool Qt5Frame::GetModal() const { return isWindow() && windowHandle()->isModal(); }
590 void Qt5Frame::SetWindowState(const SalFrameState
* pState
)
592 if (!isWindow() || !pState
|| isChild(true, false))
595 const WindowStateMask nMaxGeometryMask
596 = WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
| WindowStateMask::Height
597 | WindowStateMask::MaximizedX
| WindowStateMask::MaximizedY
598 | WindowStateMask::MaximizedWidth
| WindowStateMask::MaximizedHeight
;
600 if ((pState
->mnMask
& WindowStateMask::State
) && (pState
->mnState
& WindowStateState::Maximized
)
601 && !isMaximized() && (pState
->mnMask
& nMaxGeometryMask
) == nMaxGeometryMask
)
605 m_pTopLevel
->resize(pState
->mnWidth
, pState
->mnHeight
);
606 m_pTopLevel
->move(pState
->mnX
, pState
->mnY
);
610 m_pQWidget
->resize(pState
->mnWidth
, pState
->mnHeight
);
611 m_pQWidget
->move(pState
->mnX
, pState
->mnY
);
613 SetWindowStateImpl(Qt::WindowMaximized
);
615 else if (pState
->mnMask
616 & (WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
617 | WindowStateMask::Height
))
619 sal_uInt16 nPosSizeFlags
= 0;
620 QPoint aPos
= m_pQWidget
->pos();
623 aParentPos
= m_pParent
->GetQWidget()->window()->pos();
624 long nX
= pState
->mnX
- aParentPos
.x();
625 long nY
= pState
->mnY
- aParentPos
.y();
626 if (pState
->mnMask
& WindowStateMask::X
)
627 nPosSizeFlags
|= SAL_FRAME_POSSIZE_X
;
629 nX
= aPos
.x() - aParentPos
.x();
630 if (pState
->mnMask
& WindowStateMask::Y
)
631 nPosSizeFlags
|= SAL_FRAME_POSSIZE_Y
;
633 nY
= aPos
.y() - aParentPos
.y();
634 if (pState
->mnMask
& WindowStateMask::Width
)
635 nPosSizeFlags
|= SAL_FRAME_POSSIZE_WIDTH
;
636 if (pState
->mnMask
& WindowStateMask::Height
)
637 nPosSizeFlags
|= SAL_FRAME_POSSIZE_HEIGHT
;
638 SetPosSize(nX
, nY
, pState
->mnWidth
, pState
->mnHeight
, nPosSizeFlags
);
640 else if (pState
->mnMask
& WindowStateMask::State
&& !isChild())
642 if (pState
->mnState
& WindowStateState::Maximized
)
643 SetWindowStateImpl(Qt::WindowMaximized
);
644 else if (pState
->mnState
& WindowStateState::Minimized
)
645 SetWindowStateImpl(Qt::WindowMinimized
);
647 SetWindowStateImpl(Qt::WindowNoState
);
651 bool Qt5Frame::GetWindowState(SalFrameState
* pState
)
653 pState
->mnState
= WindowStateState::Normal
;
654 pState
->mnMask
= WindowStateMask::State
;
655 if (isMinimized() /*|| !windowHandle()*/)
656 pState
->mnState
|= WindowStateState::Minimized
;
657 else if (isMaximized())
659 pState
->mnState
|= WindowStateState::Maximized
;
663 QRect rect
= m_pTopLevel
? m_pTopLevel
->geometry() : m_pQWidget
->geometry();
664 pState
->mnX
= rect
.x();
665 pState
->mnY
= rect
.y();
666 pState
->mnWidth
= rect
.width();
667 pState
->mnHeight
= rect
.height();
668 pState
->mnMask
|= WindowStateMask::X
| WindowStateMask::Y
| WindowStateMask::Width
669 | WindowStateMask::Height
;
675 void Qt5Frame::ShowFullScreen(bool bFullScreen
, sal_Int32 nScreen
)
677 // only top-level windows can go fullscreen
680 if (m_bFullScreen
== bFullScreen
)
683 m_bFullScreen
= bFullScreen
;
684 m_bFullScreenSpanAll
= m_bFullScreen
&& (nScreen
< 0);
686 // show it if it isn't shown yet
692 m_aRestoreGeometry
= m_pTopLevel
->geometry();
693 m_nRestoreScreen
= maGeometry
.nDisplayScreenNumber
;
694 SetScreenNumber(m_bFullScreenSpanAll
? m_nRestoreScreen
: nScreen
);
695 if (!m_bFullScreenSpanAll
)
696 windowHandle()->showFullScreen();
698 windowHandle()->showNormal();
702 SetScreenNumber(m_nRestoreScreen
);
703 windowHandle()->showNormal();
704 m_pTopLevel
->setGeometry(m_aRestoreGeometry
);
708 void Qt5Frame::StartPresentation(bool)
710 // meh - so there's no Qt platform independent solution - defer to
711 // KDE5 impl. For everyone else:
712 // https://forum.qt.io/topic/38504/solved-qdialog-in-fullscreen-disable-os-screensaver
715 void Qt5Frame::SetAlwaysOnTop(bool bOnTop
)
717 QWidget
* const pWidget
= m_pTopLevel
? m_pTopLevel
: m_pQWidget
;
718 const Qt::WindowFlags flags
= pWidget
->windowFlags();
720 pWidget
->setWindowFlags(flags
| Qt::CustomizeWindowHint
| Qt::WindowStaysOnTopHint
);
722 pWidget
->setWindowFlags(flags
& ~(Qt::CustomizeWindowHint
| Qt::WindowStaysOnTopHint
));
725 void Qt5Frame::ToTop(SalFrameToTop nFlags
)
727 QWidget
* const pWidget
= m_pTopLevel
? m_pTopLevel
: m_pQWidget
;
729 if (isWindow() && !(nFlags
& SalFrameToTop::GrabFocusOnly
))
731 if ((nFlags
& SalFrameToTop::RestoreWhenMin
) || (nFlags
& SalFrameToTop::ForegroundTask
))
732 pWidget
->activateWindow();
733 else if ((nFlags
& SalFrameToTop::GrabFocus
) || (nFlags
& SalFrameToTop::GrabFocusOnly
))
734 m_pQWidget
->setFocus();
737 void Qt5Frame::SetPointer(PointerStyle ePointerStyle
)
739 QWindow
* pWindow
= m_pQWidget
->window()->windowHandle();
742 if (ePointerStyle
== m_ePointerStyle
)
744 m_ePointerStyle
= ePointerStyle
;
746 pWindow
->setCursor(static_cast<Qt5Data
*>(GetSalData())->getCursor(ePointerStyle
));
749 void Qt5Frame::CaptureMouse(bool bMouse
)
751 static const char* pEnv
= getenv("SAL_NO_MOUSEGRABS");
756 m_pQWidget
->grabMouse();
758 m_pQWidget
->releaseMouse();
761 void Qt5Frame::SetPointerPos(long nX
, long nY
)
763 // some cursor already exists (and it has m_ePointerStyle shape)
764 // so here we just reposition it
765 QCursor::setPos(m_pQWidget
->mapToGlobal(QPoint(nX
, nY
)));
768 void Qt5Frame::Flush()
770 // was: QGuiApplication::sync();
771 // but FIXME it causes too many issues, figure out sth better
773 // unclear if we need to also flush cairo surface - gtk3 backend
774 // does not do it. QPainter in Qt5Widget::paintEvent() is
775 // destroyed, so that state should be safely flushed.
778 bool Qt5Frame::ShowTooltip(const OUString
& rText
, const tools::Rectangle
& /*rHelpArea*/)
780 emit
tooltipRequest(rText
);
784 // do we even need it? void Qt5Frame::Flush(const tools::Rectangle& /*rRect*/) {}
786 void Qt5Frame::SetInputContext(SalInputContext
* pContext
)
791 if (!(pContext
->mnOptions
& InputContextFlags::Text
))
794 m_pQWidget
->setAttribute(Qt::WA_InputMethodEnabled
);
797 void Qt5Frame::EndExtTextInput(EndExtTextInputFlags
/*nFlags*/)
799 Qt5Widget
* pQt5Widget
= static_cast<Qt5Widget
*>(m_pQWidget
);
801 pQt5Widget
->endExtTextInput();
804 OUString
Qt5Frame::GetKeyName(sal_uInt16 nKeyCode
)
806 vcl::KeyCode
vclKeyCode(nKeyCode
);
807 int nCode
= vclKeyCode
.GetCode();
810 if (nCode
>= KEY_0
&& nCode
<= KEY_9
)
811 nRetCode
= (nCode
- KEY_0
) + Qt::Key_0
;
812 else if (nCode
>= KEY_A
&& nCode
<= KEY_Z
)
813 nRetCode
= (nCode
- KEY_A
) + Qt::Key_A
;
814 else if (nCode
>= KEY_F1
&& nCode
<= KEY_F26
)
815 nRetCode
= (nCode
- KEY_F1
) + Qt::Key_F1
;
821 nRetCode
= Qt::Key_Down
;
824 nRetCode
= Qt::Key_Up
;
827 nRetCode
= Qt::Key_Left
;
830 nRetCode
= Qt::Key_Right
;
833 nRetCode
= Qt::Key_Home
;
836 nRetCode
= Qt::Key_End
;
839 nRetCode
= Qt::Key_PageUp
;
842 nRetCode
= Qt::Key_PageDown
;
845 nRetCode
= Qt::Key_Return
;
848 nRetCode
= Qt::Key_Escape
;
851 nRetCode
= Qt::Key_Tab
;
854 nRetCode
= Qt::Key_Backspace
;
857 nRetCode
= Qt::Key_Space
;
860 nRetCode
= Qt::Key_Insert
;
863 nRetCode
= Qt::Key_Delete
;
866 nRetCode
= Qt::Key_Plus
;
869 nRetCode
= Qt::Key_Minus
;
872 nRetCode
= Qt::Key_Asterisk
;
875 nRetCode
= Qt::Key_Slash
;
878 nRetCode
= Qt::Key_Period
;
881 nRetCode
= Qt::Key_Comma
;
884 nRetCode
= Qt::Key_Less
;
887 nRetCode
= Qt::Key_Greater
;
890 nRetCode
= Qt::Key_Equal
;
893 nRetCode
= Qt::Key_Find
;
895 case KEY_CONTEXTMENU
:
896 nRetCode
= Qt::Key_Menu
;
899 nRetCode
= Qt::Key_Help
;
902 nRetCode
= Qt::Key_Undo
;
905 nRetCode
= Qt::Key_Redo
;
908 nRetCode
= Qt::Key_AsciiTilde
;
911 nRetCode
= Qt::Key_QuoteLeft
;
913 case KEY_BRACKETLEFT
:
914 nRetCode
= Qt::Key_BracketLeft
;
916 case KEY_BRACKETRIGHT
:
917 nRetCode
= Qt::Key_BracketRight
;
920 nRetCode
= Qt::Key_Semicolon
;
925 nRetCode
= Qt::Key_Copy
;
928 nRetCode
= Qt::Key_Cut
;
931 nRetCode
= Qt::Key_Paste
;
934 nRetCode
= Qt::Key_Open
;
939 if (vclKeyCode
.IsShift())
940 nRetCode
+= Qt::SHIFT
;
941 if (vclKeyCode
.IsMod1())
942 nRetCode
+= Qt::CTRL
;
943 if (vclKeyCode
.IsMod2())
946 QKeySequence
keySeq(nRetCode
);
947 OUString sKeyName
= toOUString(keySeq
.toString());
952 bool Qt5Frame::MapUnicodeToKeyCode(sal_Unicode
/*aUnicode*/, LanguageType
/*aLangType*/,
953 vcl::KeyCode
& /*rKeyCode*/)
959 LanguageType
Qt5Frame::GetInputLanguage()
962 return LANGUAGE_DONTKNOW
;
965 static Color
toColor(const QColor
& rColor
)
967 return Color(rColor
.red(), rColor
.green(), rColor
.blue());
970 void Qt5Frame::UpdateSettings(AllSettings
& rSettings
)
972 if (Qt5Data::noNativeControls())
975 StyleSettings
style(rSettings
.GetStyleSettings());
978 QPalette pal
= QApplication::palette();
980 style
.SetToolbarIconSize(ToolbarIconSize::Large
);
982 Color aFore
= toColor(pal
.color(QPalette::Active
, QPalette::WindowText
));
983 Color aBack
= toColor(pal
.color(QPalette::Active
, QPalette::Window
));
984 Color aText
= toColor(pal
.color(QPalette::Active
, QPalette::Text
));
985 Color aBase
= toColor(pal
.color(QPalette::Active
, QPalette::Base
));
986 Color aButn
= toColor(pal
.color(QPalette::Active
, QPalette::ButtonText
));
987 Color aMid
= toColor(pal
.color(QPalette::Active
, QPalette::Mid
));
988 Color aHigh
= toColor(pal
.color(QPalette::Active
, QPalette::Highlight
));
989 Color aHighText
= toColor(pal
.color(QPalette::Active
, QPalette::HighlightedText
));
990 Color aLink
= toColor(pal
.color(QPalette::Active
, QPalette::Link
));
991 Color aVisitedLink
= toColor(pal
.color(QPalette::Active
, QPalette::LinkVisited
));
993 style
.SetSkipDisabledInMenus(true);
996 style
.SetRadioCheckTextColor(aFore
);
997 style
.SetLabelTextColor(aFore
);
998 style
.SetDialogTextColor(aFore
);
999 style
.SetGroupTextColor(aFore
);
1002 style
.SetFieldTextColor(aText
);
1003 style
.SetFieldRolloverTextColor(aText
);
1004 style
.SetWindowTextColor(aText
);
1005 style
.SetToolTextColor(aText
);
1008 style
.SetFieldColor(aBase
);
1009 style
.SetWindowColor(aBase
);
1010 style
.SetActiveTabColor(aBase
);
1013 style
.SetButtonTextColor(aButn
);
1014 style
.SetButtonRolloverTextColor(aButn
);
1015 style
.SetButtonPressedRolloverTextColor(aButn
);
1018 style
.SetTabTextColor(aButn
);
1019 style
.SetTabRolloverTextColor(aButn
);
1020 style
.SetTabHighlightTextColor(aButn
);
1023 style
.SetDisableColor(toColor(pal
.color(QPalette::Disabled
, QPalette::WindowText
)));
1026 style
.BatchSetBackgrounds(aBack
);
1027 style
.SetInactiveTabColor(aBack
);
1030 style
.SetWorkspaceColor(aMid
);
1033 style
.SetHighlightColor(aHigh
);
1034 style
.SetHighlightTextColor(aHighText
);
1037 style
.SetLinkColor(aLink
);
1038 style
.SetVisitedLinkColor(aVisitedLink
);
1041 style
.SetHelpColor(toColor(QToolTip::palette().color(QPalette::Active
, QPalette::ToolTipBase
)));
1042 style
.SetHelpTextColor(
1043 toColor(QToolTip::palette().color(QPalette::Active
, QPalette::ToolTipText
)));
1045 const int flash_time
= QApplication::cursorFlashTime();
1046 style
.SetCursorBlinkTime(flash_time
!= 0 ? flash_time
/ 2 : STYLE_CURSOR_NOBLINKTIME
);
1049 std::unique_ptr
<QMenuBar
> pMenuBar
= std::make_unique
<QMenuBar
>();
1050 QPalette qMenuCG
= pMenuBar
->palette();
1052 // Menu text and background color, theme specific
1053 Color aMenuFore
= toColor(qMenuCG
.color(QPalette::WindowText
));
1054 Color aMenuBack
= toColor(qMenuCG
.color(QPalette::Window
));
1056 style
.SetMenuTextColor(aMenuFore
);
1057 style
.SetMenuBarTextColor(style
.GetPersonaMenuBarTextColor().get_value_or(aMenuFore
));
1058 style
.SetMenuColor(aMenuBack
);
1059 style
.SetMenuBarColor(aMenuBack
);
1060 style
.SetMenuHighlightColor(toColor(qMenuCG
.color(QPalette::Highlight
)));
1061 style
.SetMenuHighlightTextColor(toColor(qMenuCG
.color(QPalette::HighlightedText
)));
1063 // set special menubar highlight text color
1064 if (QApplication::style()->inherits("HighContrastStyle"))
1065 ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
1066 = toColor(qMenuCG
.color(QPalette::HighlightedText
));
1068 ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
= aMenuFore
;
1070 // set menubar rollover color
1071 if (pMenuBar
->style()->styleHint(QStyle::SH_MenuBar_MouseTracking
))
1073 style
.SetMenuBarRolloverColor(toColor(qMenuCG
.color(QPalette::Highlight
)));
1074 style
.SetMenuBarRolloverTextColor(ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
);
1078 style
.SetMenuBarRolloverColor(aMenuBack
);
1079 style
.SetMenuBarRolloverTextColor(aMenuFore
);
1081 style
.SetMenuBarHighlightTextColor(style
.GetMenuHighlightTextColor());
1084 style
.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent
));
1085 style
.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin
));
1087 // These colors are used for the ruler text and marks
1088 style
.SetShadowColor(toColor(pal
.color(QPalette::Disabled
, QPalette::WindowText
)));
1089 style
.SetDarkShadowColor(toColor(pal
.color(QPalette::Inactive
, QPalette::WindowText
)));
1091 m_bGraphicsInvalid
= true;
1092 rSettings
.SetStyleSettings(style
);
1095 void Qt5Frame::Beep() { QApplication::beep(); }
1097 SalFrame::SalPointerState
Qt5Frame::GetPointerState()
1099 SalPointerState aState
;
1100 QPoint pos
= QCursor::pos();
1101 aState
.maPos
= Point(pos
.x(), pos
.y());
1102 aState
.mnState
= GetMouseModCode(QGuiApplication::mouseButtons())
1103 | GetKeyModCode(QGuiApplication::keyboardModifiers());
1107 KeyIndicatorState
Qt5Frame::GetIndicatorState() { return KeyIndicatorState(); }
1109 void Qt5Frame::SimulateKeyPress(sal_uInt16 nKeyCode
)
1111 SAL_WARN("vcl.kde5", "missing simulate keypress " << nKeyCode
);
1114 void Qt5Frame::SetParent(SalFrame
* pNewParent
) { m_pParent
= static_cast<Qt5Frame
*>(pNewParent
); }
1116 bool Qt5Frame::SetPluginParent(SystemParentData
* /*pNewParent*/)
1118 //FIXME: no SetPluginParent impl. for kde5
1122 void Qt5Frame::ResetClipRegion() { m_bNullRegion
= true; }
1124 void Qt5Frame::BeginSetClipRegion(sal_uInt32
)
1126 m_aRegion
= QRegion(QRect(QPoint(0, 0), m_pQWidget
->size()));
1129 void Qt5Frame::UnionClipRegion(long nX
, long nY
, long nWidth
, long nHeight
)
1131 m_aRegion
= m_aRegion
.united(QRegion(nX
, nY
, nWidth
, nHeight
));
1134 void Qt5Frame::EndSetClipRegion() { m_bNullRegion
= false; }
1136 void Qt5Frame::SetScreenNumber(unsigned int nScreen
)
1140 QWindow
* const pWindow
= windowHandle();
1143 QList
<QScreen
*> screens
= QApplication::screens();
1144 if (static_cast<int>(nScreen
) < screens
.size() || m_bFullScreenSpanAll
)
1148 if (!m_bFullScreenSpanAll
)
1150 screenGeo
= QApplication::desktop()->screenGeometry(nScreen
);
1151 pWindow
->setScreen(QApplication::screens()[nScreen
]);
1153 else // special case: fullscreen over all available screens
1155 assert(m_bFullScreen
);
1157 int nLeftScreen
= QApplication::desktop()->screenNumber(QPoint(0, 0));
1158 // entire virtual desktop
1159 screenGeo
= QApplication::screens()[nLeftScreen
]->availableVirtualGeometry();
1160 pWindow
->setScreen(QApplication::screens()[nLeftScreen
]);
1161 pWindow
->setGeometry(screenGeo
);
1162 nScreen
= nLeftScreen
;
1165 // setScreen by itself has no effect, explicitly move the widget to
1167 QWidget
* const pWidget
= m_pTopLevel
? m_pTopLevel
: m_pQWidget
;
1168 pWidget
->move(screenGeo
.topLeft());
1172 // index outta bounds, use primary screen
1173 QScreen
* primaryScreen
= QApplication::primaryScreen();
1174 pWindow
->setScreen(primaryScreen
);
1175 nScreen
= static_cast<sal_uInt32
>(screenNumber(primaryScreen
));
1178 maGeometry
.nDisplayScreenNumber
= nScreen
;
1183 void Qt5Frame::SetApplicationID(const OUString
&)
1185 // So the hope is that QGuiApplication deals with this properly..
1190 Qt5DragSource
* Qt5DragSource::m_ActiveDragSource
;
1192 void Qt5Frame::registerDragSource(Qt5DragSource
* pDragSource
)
1194 assert(!m_pDragSource
);
1195 m_pDragSource
= pDragSource
;
1198 void Qt5Frame::deregisterDragSource(Qt5DragSource
const* pDragSource
)
1200 assert(m_pDragSource
== pDragSource
);
1202 m_pDragSource
= nullptr;
1205 void Qt5Frame::registerDropTarget(Qt5DropTarget
* pDropTarget
)
1207 assert(!m_pDropTarget
);
1208 m_pDropTarget
= pDropTarget
;
1209 m_pQWidget
->setAcceptDrops(true);
1212 void Qt5Frame::deregisterDropTarget(Qt5DropTarget
const* pDropTarget
)
1214 assert(m_pDropTarget
== pDropTarget
);
1216 m_pDropTarget
= nullptr;
1219 void Qt5Frame::draggingStarted(const int x
, const int y
, Qt::DropActions eActions
,
1220 Qt::KeyboardModifiers eKeyMod
, const QMimeData
* pQMimeData
)
1222 assert(m_pDropTarget
);
1224 sal_Int8 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_MOVE
;
1225 if ((eKeyMod
& Qt::ShiftModifier
) && !(eKeyMod
& Qt::ControlModifier
))
1226 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_MOVE
;
1227 else if ((eKeyMod
& Qt::ControlModifier
) && !(eKeyMod
& Qt::ShiftModifier
))
1228 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_COPY
;
1229 else if ((eKeyMod
& Qt::ShiftModifier
) && (eKeyMod
& Qt::ControlModifier
))
1230 nUserDropAction
= css::datatransfer::dnd::DNDConstants::ACTION_LINK
;
1232 css::datatransfer::dnd::DropTargetDragEnterEvent aEvent
;
1233 aEvent
.Source
= static_cast<css::datatransfer::dnd::XDropTarget
*>(m_pDropTarget
);
1234 aEvent
.Context
= static_cast<css::datatransfer::dnd::XDropTargetDragContext
*>(m_pDropTarget
);
1235 aEvent
.LocationX
= x
;
1236 aEvent
.LocationY
= y
;
1238 // system drop action if neither Shift nor Control is held
1239 if (!(eKeyMod
& (Qt::ShiftModifier
| Qt::ControlModifier
)))
1240 aEvent
.DropAction
= getPreferredDropAction(eActions
);
1241 // otherwise user-preferred action
1243 aEvent
.DropAction
= nUserDropAction
;
1244 aEvent
.SourceActions
= toVclDropActions(eActions
);
1246 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
;
1247 if (!pQMimeData
->hasFormat(sInternalMimeType
))
1248 xTransferable
= new Qt5DnDTransferable(pQMimeData
);
1250 xTransferable
= Qt5DragSource::m_ActiveDragSource
->GetTransferable();
1252 if (!m_bInDrag
&& xTransferable
.is())
1254 css::uno::Sequence
<css::datatransfer::DataFlavor
> aFormats
1255 = xTransferable
->getTransferDataFlavors();
1256 aEvent
.SupportedDataFlavors
= aFormats
;
1258 m_pDropTarget
->fire_dragEnter(aEvent
);
1262 m_pDropTarget
->fire_dragOver(aEvent
);
1265 void Qt5Frame::dropping(const int x
, const int y
, Qt::KeyboardModifiers eKeyMod
,
1266 const QMimeData
* pQMimeData
)
1268 assert(m_pDropTarget
);
1270 css::datatransfer::dnd::DropTargetDropEvent aEvent
;
1271 aEvent
.Source
= static_cast<css::datatransfer::dnd::XDropTarget
*>(m_pDropTarget
);
1272 aEvent
.Context
= static_cast<css::datatransfer::dnd::XDropTargetDropContext
*>(m_pDropTarget
);
1273 aEvent
.LocationX
= x
;
1274 aEvent
.LocationY
= y
;
1276 if (!(eKeyMod
& (Qt::ShiftModifier
| Qt::ControlModifier
)))
1277 aEvent
.DropAction
= m_pDropTarget
->proposedDragAction()
1278 | css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT
;
1280 aEvent
.DropAction
= m_pDropTarget
->proposedDragAction();
1281 aEvent
.SourceActions
= css::datatransfer::dnd::DNDConstants::ACTION_MOVE
;
1283 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
;
1284 if (!pQMimeData
->hasFormat(sInternalMimeType
))
1285 xTransferable
= new Qt5DnDTransferable(pQMimeData
);
1287 xTransferable
= Qt5DragSource::m_ActiveDragSource
->GetTransferable();
1288 aEvent
.Transferable
= xTransferable
;
1290 m_pDropTarget
->fire_drop(aEvent
);
1295 m_pDragSource
->fire_dragEnd(m_pDropTarget
->proposedDragAction());
1299 cairo_t
* Qt5Frame::getCairoContext() const
1301 cairo_t
* cr
= nullptr;
1304 cr
= cairo_create(m_pSurface
.get());
1310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */