bump product version to 6.3.0.0.beta1
[LibreOffice.git] / vcl / qt5 / Qt5Frame.cxx
blob6d19d825fa1c9cc3fc39482e85894054df54778f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
47 #include <window.h>
48 #include <vcl/layout.hxx>
49 #include <vcl/syswin.hxx>
51 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
53 #include <cairo.h>
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);
63 namespace
65 sal_Int32 screenNumber(const QScreen* pScreen)
67 const QList<QScreen*> screens = QApplication::screens();
69 sal_Int32 nScreen = 0;
70 bool bFound = false;
71 for (const QScreen* pCurScreen : screens)
73 if (pScreen == pCurScreen)
75 bFound = true;
76 break;
78 nScreen++;
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)
89 , m_bNullRegion(true)
90 , m_bGraphicsInUse(false)
91 , m_bGraphicsInvalid(false)
92 , m_ePointerStyle(PointerStyle::Arrow)
93 , m_pDragSource(nullptr)
94 , m_pDropTarget(nullptr)
95 , m_bInDrag(false)
96 , m_bDefaultSize(true)
97 , m_bDefaultPos(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;
114 m_nStyle = nStyle;
115 m_pParent = pParent;
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;
136 else
137 aWinFlags |= Qt::Window;
140 if (aWinFlags == Qt::Window)
142 QWidget* pParentWidget = nullptr;
143 if (m_pParent)
145 pParentWidget
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);
153 else
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();
173 maGeometry.nX = -1;
174 maGeometry.nY = -1;
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";
191 if (!bWayland)
192 m_aSystemData.aWindow = m_pQWidget->winId();
193 else
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";
208 if (!bWayland)
209 m_aSystemData.pPlatformName = "xcb";
210 else
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);
220 if (m_pTopLevel)
221 delete m_pTopLevel;
222 else
223 delete m_pQWidget;
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)
248 int width = 640;
249 int height = 480;
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,
254 nullptr);
257 SalGraphics* Qt5Frame::AcquireGraphics()
259 if (m_bGraphicsInUse)
260 return nullptr;
262 m_bGraphicsInUse = true;
264 if (m_bUseCairo)
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();
274 else
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)
290 (void)pSalGraph;
291 if (m_bUseCairo)
292 assert(pSalGraph == m_pOurSvpGraphics.get());
293 else
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);
302 return true;
305 bool Qt5Frame::isWindow() const
307 if (m_pTopLevel)
308 return m_pTopLevel->isWindow();
309 else
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
316 if (m_pTopLevel)
318 m_pTopLevel->setAttribute(Qt::WA_NativeWindow);
319 return m_pTopLevel->windowHandle();
321 else
323 m_pQWidget->setAttribute(Qt::WA_NativeWindow);
324 return m_pQWidget->windowHandle();
328 QScreen* Qt5Frame::screen() const
330 QWindow* const pWindow = windowHandle();
331 if (pWindow)
332 return pWindow->screen();
333 else
334 return nullptr;
337 bool Qt5Frame::isMinimized() const
339 if (m_pTopLevel)
340 return m_pTopLevel->isMinimized();
341 else
342 return m_pQWidget->isMinimized();
345 bool Qt5Frame::isMaximized() const
347 if (m_pTopLevel)
348 return m_pTopLevel->isMaximized();
349 else
350 return m_pQWidget->isMaximized();
353 void Qt5Frame::SetWindowStateImpl(Qt::WindowStates eState)
355 if (m_pTopLevel)
356 m_pTopLevel->setWindowState(eState);
357 else
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)
368 if (m_nStyle
369 & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD
370 | SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::INTRO
371 | SalFrameStyleFlags::OWNERDRAWDECORATION)
372 || !isWindow())
373 return;
375 QString appicon;
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";
389 else
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)
404 if (m_pTopLevel)
405 m_pTopLevel->setVisible(bVisible);
406 else
407 m_pQWidget->setVisible(bVisible);
410 void Qt5Frame::Show(bool bVisible, bool /*bNoActivate*/)
412 assert(m_pQWidget);
414 if (m_bDefaultSize)
415 SetDefaultSize();
417 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
418 assert(pSalInst);
419 pSalInst->RunInMainThread([this, bVisible]() { setVisible(bVisible); });
422 void Qt5Frame::SetMinClientSize(long nWidth, long nHeight)
424 if (!isChild())
426 if (m_pTopLevel)
427 m_pTopLevel->setMinimumSize(nWidth, nHeight);
428 else
429 m_pQWidget->setMinimumSize(nWidth, nHeight);
433 void Qt5Frame::SetMaxClientSize(long nWidth, long nHeight)
435 if (!isChild())
437 if (m_pTopLevel)
438 m_pTopLevel->setMaximumSize(nWidth, nHeight);
439 else
440 m_pQWidget->setMaximumSize(nWidth, nHeight);
444 void Qt5Frame::Center()
446 if (m_pParent)
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()
457 assert(isWindow());
459 Size aSize;
460 if (!m_bFullScreen)
462 const QScreen* pScreen = screen();
463 aSize = bestmaxFrameSizeForScreenSize(
464 toSize(pScreen ? pScreen->size() : QApplication::desktop()->screenGeometry(0).size()));
466 else
468 if (!m_bFullScreenSpanAll)
469 aSize = toSize(
470 QApplication::desktop()->screenGeometry(maGeometry.nDisplayScreenNumber).size());
471 else
473 int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0));
474 aSize = toSize(QApplication::screens()[nLeftScreen]->availableVirtualGeometry().size());
478 return aSize;
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))
491 return;
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);
504 else
505 pWidget->setFixedSize(nWidth, nHeight);
508 else if (m_bDefaultSize)
509 SetDefaultSize();
511 m_bDefaultSize = false;
513 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
515 if (m_pParent)
517 QRect aRect;
518 if (m_pParent->GetTopLevelWindow())
519 aRect = m_pParent->GetTopLevelWindow()->geometry();
520 else
521 aRect = m_pParent->GetQWidget()->geometry();
523 nX += aRect.x();
524 nY += aRect.y();
527 maGeometry.nX = nX;
528 maGeometry.nY = nY;
530 m_bDefaultPos = false;
531 if (m_pTopLevel)
532 m_pTopLevel->move(nX, nY);
533 else
534 m_pQWidget->move(nX, nY);
536 else if (m_bDefaultPos)
537 Center();
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)
550 if (!isWindow())
551 return;
552 QScreen* pScreen = screen();
553 if (!pScreen)
554 return;
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)
564 if (isWindow())
566 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
567 assert(pSalInst);
568 pSalInst->RunInMainThread([this, bModal]() {
569 bool wasVisible = windowHandle()->isVisible();
571 // modality change is only effective if the window is hidden
572 if (wasVisible)
574 windowHandle()->hide();
577 windowHandle()->setModality(bModal ? Qt::WindowModal : Qt::NonModal);
579 // and shown again if it was visible
580 if (wasVisible)
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))
593 return;
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)
603 if (m_pTopLevel)
605 m_pTopLevel->resize(pState->mnWidth, pState->mnHeight);
606 m_pTopLevel->move(pState->mnX, pState->mnY);
608 else
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();
621 QPoint aParentPos;
622 if (m_pParent)
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;
628 else
629 nX = aPos.x() - aParentPos.x();
630 if (pState->mnMask & WindowStateMask::Y)
631 nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
632 else
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);
646 else
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;
661 else
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;
672 return true;
675 void Qt5Frame::ShowFullScreen(bool bFullScreen, sal_Int32 nScreen)
677 // only top-level windows can go fullscreen
678 assert(m_pTopLevel);
680 if (m_bFullScreen == bFullScreen)
681 return;
683 m_bFullScreen = bFullScreen;
684 m_bFullScreenSpanAll = m_bFullScreen && (nScreen < 0);
686 // show it if it isn't shown yet
687 if (!isWindow())
688 m_pTopLevel->show();
690 if (m_bFullScreen)
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();
697 else
698 windowHandle()->showNormal();
700 else
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();
719 if (bOnTop)
720 pWidget->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
721 else
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))
730 pWidget->raise();
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();
740 if (!pWindow)
741 return;
742 if (ePointerStyle == m_ePointerStyle)
743 return;
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");
752 if (pEnv && *pEnv)
753 return;
755 if (bMouse)
756 m_pQWidget->grabMouse();
757 else
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);
781 return true;
784 // do we even need it? void Qt5Frame::Flush(const tools::Rectangle& /*rRect*/) {}
786 void Qt5Frame::SetInputContext(SalInputContext* pContext)
788 if (!pContext)
789 return;
791 if (!(pContext->mnOptions & InputContextFlags::Text))
792 return;
794 m_pQWidget->setAttribute(Qt::WA_InputMethodEnabled);
797 void Qt5Frame::EndExtTextInput(EndExtTextInputFlags /*nFlags*/)
799 Qt5Widget* pQt5Widget = static_cast<Qt5Widget*>(m_pQWidget);
800 if (pQt5Widget)
801 pQt5Widget->endExtTextInput();
804 OUString Qt5Frame::GetKeyName(sal_uInt16 nKeyCode)
806 vcl::KeyCode vclKeyCode(nKeyCode);
807 int nCode = vclKeyCode.GetCode();
808 int nRetCode = 0;
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;
816 else
818 switch (nCode)
820 case KEY_DOWN:
821 nRetCode = Qt::Key_Down;
822 break;
823 case KEY_UP:
824 nRetCode = Qt::Key_Up;
825 break;
826 case KEY_LEFT:
827 nRetCode = Qt::Key_Left;
828 break;
829 case KEY_RIGHT:
830 nRetCode = Qt::Key_Right;
831 break;
832 case KEY_HOME:
833 nRetCode = Qt::Key_Home;
834 break;
835 case KEY_END:
836 nRetCode = Qt::Key_End;
837 break;
838 case KEY_PAGEUP:
839 nRetCode = Qt::Key_PageUp;
840 break;
841 case KEY_PAGEDOWN:
842 nRetCode = Qt::Key_PageDown;
843 break;
844 case KEY_RETURN:
845 nRetCode = Qt::Key_Return;
846 break;
847 case KEY_ESCAPE:
848 nRetCode = Qt::Key_Escape;
849 break;
850 case KEY_TAB:
851 nRetCode = Qt::Key_Tab;
852 break;
853 case KEY_BACKSPACE:
854 nRetCode = Qt::Key_Backspace;
855 break;
856 case KEY_SPACE:
857 nRetCode = Qt::Key_Space;
858 break;
859 case KEY_INSERT:
860 nRetCode = Qt::Key_Insert;
861 break;
862 case KEY_DELETE:
863 nRetCode = Qt::Key_Delete;
864 break;
865 case KEY_ADD:
866 nRetCode = Qt::Key_Plus;
867 break;
868 case KEY_SUBTRACT:
869 nRetCode = Qt::Key_Minus;
870 break;
871 case KEY_MULTIPLY:
872 nRetCode = Qt::Key_Asterisk;
873 break;
874 case KEY_DIVIDE:
875 nRetCode = Qt::Key_Slash;
876 break;
877 case KEY_POINT:
878 nRetCode = Qt::Key_Period;
879 break;
880 case KEY_COMMA:
881 nRetCode = Qt::Key_Comma;
882 break;
883 case KEY_LESS:
884 nRetCode = Qt::Key_Less;
885 break;
886 case KEY_GREATER:
887 nRetCode = Qt::Key_Greater;
888 break;
889 case KEY_EQUAL:
890 nRetCode = Qt::Key_Equal;
891 break;
892 case KEY_FIND:
893 nRetCode = Qt::Key_Find;
894 break;
895 case KEY_CONTEXTMENU:
896 nRetCode = Qt::Key_Menu;
897 break;
898 case KEY_HELP:
899 nRetCode = Qt::Key_Help;
900 break;
901 case KEY_UNDO:
902 nRetCode = Qt::Key_Undo;
903 break;
904 case KEY_REPEAT:
905 nRetCode = Qt::Key_Redo;
906 break;
907 case KEY_TILDE:
908 nRetCode = Qt::Key_AsciiTilde;
909 break;
910 case KEY_QUOTELEFT:
911 nRetCode = Qt::Key_QuoteLeft;
912 break;
913 case KEY_BRACKETLEFT:
914 nRetCode = Qt::Key_BracketLeft;
915 break;
916 case KEY_BRACKETRIGHT:
917 nRetCode = Qt::Key_BracketRight;
918 break;
919 case KEY_SEMICOLON:
920 nRetCode = Qt::Key_Semicolon;
921 break;
923 // Special cases
924 case KEY_COPY:
925 nRetCode = Qt::Key_Copy;
926 break;
927 case KEY_CUT:
928 nRetCode = Qt::Key_Cut;
929 break;
930 case KEY_PASTE:
931 nRetCode = Qt::Key_Paste;
932 break;
933 case KEY_OPEN:
934 nRetCode = Qt::Key_Open;
935 break;
939 if (vclKeyCode.IsShift())
940 nRetCode += Qt::SHIFT;
941 if (vclKeyCode.IsMod1())
942 nRetCode += Qt::CTRL;
943 if (vclKeyCode.IsMod2())
944 nRetCode += Qt::ALT;
946 QKeySequence keySeq(nRetCode);
947 OUString sKeyName = toOUString(keySeq.toString());
949 return sKeyName;
952 bool Qt5Frame::MapUnicodeToKeyCode(sal_Unicode /*aUnicode*/, LanguageType /*aLangType*/,
953 vcl::KeyCode& /*rKeyCode*/)
955 // not supported yet
956 return false;
959 LanguageType Qt5Frame::GetInputLanguage()
961 // fallback
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())
973 return;
975 StyleSettings style(rSettings.GetStyleSettings());
977 // General settings
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);
995 // Foreground
996 style.SetRadioCheckTextColor(aFore);
997 style.SetLabelTextColor(aFore);
998 style.SetDialogTextColor(aFore);
999 style.SetGroupTextColor(aFore);
1001 // Text
1002 style.SetFieldTextColor(aText);
1003 style.SetFieldRolloverTextColor(aText);
1004 style.SetWindowTextColor(aText);
1005 style.SetToolTextColor(aText);
1007 // Base
1008 style.SetFieldColor(aBase);
1009 style.SetWindowColor(aBase);
1010 style.SetActiveTabColor(aBase);
1012 // Buttons
1013 style.SetButtonTextColor(aButn);
1014 style.SetButtonRolloverTextColor(aButn);
1015 style.SetButtonPressedRolloverTextColor(aButn);
1017 // Tabs
1018 style.SetTabTextColor(aButn);
1019 style.SetTabRolloverTextColor(aButn);
1020 style.SetTabHighlightTextColor(aButn);
1022 // Disable color
1023 style.SetDisableColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText)));
1025 // Background
1026 style.BatchSetBackgrounds(aBack);
1027 style.SetInactiveTabColor(aBack);
1029 // Workspace
1030 style.SetWorkspaceColor(aMid);
1032 // Selection
1033 style.SetHighlightColor(aHigh);
1034 style.SetHighlightTextColor(aHighText);
1036 // Links
1037 style.SetLinkColor(aLink);
1038 style.SetVisitedLinkColor(aVisitedLink);
1040 // Tooltip
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);
1048 // Menu
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));
1067 else
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);
1076 else
1078 style.SetMenuBarRolloverColor(aMenuBack);
1079 style.SetMenuBarRolloverTextColor(aMenuFore);
1081 style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor());
1083 // Scroll bar size
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());
1104 return aState;
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
1119 return false;
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)
1138 if (isWindow())
1140 QWindow* const pWindow = windowHandle();
1141 if (pWindow)
1143 QList<QScreen*> screens = QApplication::screens();
1144 if (static_cast<int>(nScreen) < screens.size() || m_bFullScreenSpanAll)
1146 QRect screenGeo;
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);
1156 // left-most screen
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
1166 // the new screen
1167 QWidget* const pWidget = m_pTopLevel ? m_pTopLevel : m_pQWidget;
1168 pWidget->move(screenGeo.topLeft());
1170 else
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..
1188 // Drag'n'drop foo
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);
1201 (void)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);
1215 (void)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
1242 else
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);
1249 else
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);
1259 m_bInDrag = true;
1261 else
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;
1279 else
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);
1286 else
1287 xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
1288 aEvent.Transferable = xTransferable;
1290 m_pDropTarget->fire_drop(aEvent);
1291 m_bInDrag = false;
1293 if (m_pDragSource)
1295 m_pDragSource->fire_dragEnd(m_pDropTarget->proposedDragAction());
1299 cairo_t* Qt5Frame::getCairoContext() const
1301 cairo_t* cr = nullptr;
1302 if (m_bUseCairo)
1304 cr = cairo_create(m_pSurface.get());
1305 assert(cr);
1307 return cr;
1310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */