/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
Qt::WindowFlags aWinFlags(Qt::Widget); if (!(nStyle & SalFrameStyleFlags::SYSTEMCHILD))
{ if (nStyle & SalFrameStyleFlags::INTRO)
aWinFlags = Qt::SplashScreen; // floating toolbars are frameless tool windows // + they must be able to receive keyboard focus elseif ((nStyle & SalFrameStyleFlags::FLOAT)
&& (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION))
aWinFlags = Qt::Tool | Qt::FramelessWindowHint; elseif (nStyle & SalFrameStyleFlags::TOOLTIP)
aWinFlags = Qt::ToolTip; // Can't use Qt::Popup, because it grabs the input focus and generates a focus-out event, // instantly auto-closing the LO's editable ComboBox popup. // On X11, the alternative Qt::Window | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint // seems to work well enough, but at least on Wayland and WASM, this results in problems. // So while using Qt::ToolTip, the popups are wrongly advertised via accessibility, at least // the GUI seems to work on all platforms... what a mess. elseif (isPopup())
aWinFlags = Qt::ToolTip | Qt::FramelessWindowHint; elseif (nStyle & SalFrameStyleFlags::TOOLWINDOW)
aWinFlags = Qt::Tool; // top level windows can't be transient in Qt, so make them dialogs, if they have a parent. At least // the plasma shell relies on this setting to skip dialogs in the window list. And Qt Xcb will just // set transient for the types Dialog, Sheet, Tool, SplashScreen, ToolTip, Drawer and Popup. elseif (nStyle & SalFrameStyleFlags::DIALOG || m_pParent)
aWinFlags = Qt::Dialog; else
aWinFlags = Qt::Window;
}
if (aWinFlags == Qt::Window)
{
m_pTopLevel = new QtMainWindow(*this, aWinFlags);
m_pQWidget = new QtWidget(*this);
m_pTopLevel->setCentralWidget(m_pQWidget);
m_pTopLevel->setFocusProxy(m_pQWidget);
} else
{
m_pQWidget = new QtWidget(*this, aWinFlags); // from Qt's POV the popup window doesn't have the input focus, so we must force tooltips... if (isPopup())
m_pQWidget->setAttribute(Qt::WA_AlwaysShowToolTips);
}
if (QGuiApplication::platformName() == "wayland" && m_pQWidget->window()->isVisible())
{ // Qt currently doesn't provide API to directly set the app_id for a single // window/toplevel on Wayland, but the one set for the application is picked up // on hide/show, so do that. // An alternative would be to use private Qt API and low-level wayland API to set the // app_id directly, s. discussion in QTBUG-77182. const QString sOrigDesktopFileName = QGuiApplication::desktopFileName();
QGuiApplication::setDesktopFileName(appicon);
m_pQWidget->window()->hide();
m_pQWidget->window()->show();
QGuiApplication::setDesktopFileName(sOrigDesktopFileName);
}
}
void QtFrame::SetMenu(SalMenu*) {}
void QtFrame::SetExtendedFrameStyle(SalExtStyle /*nExtStyle*/) { /* not needed */}
// modality change is only effective if the window is hidden if (bWasVisible)
{
pChild->hide(); if (QGuiApplication::platformName() == "xcb")
{
SAL_WARN("vcl.qt", "SetModal called after Show - apply delay"); // tdf#152979 give QXcbConnection some time to avoid // "qt.qpa.xcb: internal error: void QXcbWindow::setNetWmStateOnUnmappedWindow() called on mapped window"
QThread::msleep(100);
}
}
if (bMouse)
m_pQWidget->grabMouse(); else
m_pQWidget->releaseMouse();
}
void QtFrame::SetPointerPos(tools::Long nX, tools::Long nY)
{ // some cursor already exists (and it has m_ePointerStyle shape) // so here we just reposition it
QCursor::setPos(m_pQWidget->mapToGlobal(QPoint(nX, nY) / devicePixelRatioF()));
}
void QtFrame::Flush()
{ // was: QGuiApplication::sync(); // but FIXME it causes too many issues, figure out sth better
// unclear if we need to also flush cairo surface - gtk3 backend // does not do it. QPainter in QtWidget::paintEvent() is // destroyed, so that state should be safely flushed.
}
// General settings
QPalette pal = QApplication::palette();
style.SetToolbarIconSize(ToolbarIconSize::Large);
Color aFore = toColor(pal.color(QPalette::Active, QPalette::WindowText));
Color aBack = toColor(pal.color(QPalette::Active, QPalette::Window));
Color aText = toColor(pal.color(QPalette::Active, QPalette::Text));
Color aBase = toColor(pal.color(QPalette::Active, QPalette::Base));
Color aButn = toColor(pal.color(QPalette::Active, QPalette::ButtonText));
Color aMid = toColor(pal.color(QPalette::Active, QPalette::Mid));
Color aHigh = toColor(pal.color(QPalette::Active, QPalette::Highlight));
Color aHighText = toColor(pal.color(QPalette::Active, QPalette::HighlightedText));
Color aLink = toColor(pal.color(QPalette::Active, QPalette::Link));
Color aVisitedLink = toColor(pal.color(QPalette::Active, QPalette::LinkVisited));
// Menu
std::unique_ptr<QMenuBar> pMenuBar = std::make_unique<QMenuBar>();
QPalette qMenuCG = pMenuBar->palette();
// Menu text and background color, theme specific
Color aMenuFore = toColor(qMenuCG.color(QPalette::WindowText));
Color aMenuBack = toColor(qMenuCG.color(QPalette::Window));
// set special menubar highlight text color if (QApplication::style()->inherits("HighContrastStyle"))
ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor
= toColor(qMenuCG.color(QPalette::HighlightedText)); else
ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;
// set menubar rollover color if (pMenuBar->style()->styleHint(QStyle::SH_MenuBar_MouseTracking))
{
style.SetMenuBarRolloverColor(toColor(qMenuCG.color(QPalette::Highlight)));
style.SetMenuBarRolloverTextColor(
ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor);
} else
{
style.SetMenuBarRolloverColor(aMenuBack);
style.SetMenuBarRolloverTextColor(aMenuFore);
}
style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor());
// Scroll bar size
style.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent));
style.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin));
// These colors are used for the ruler text and marks
style.SetShadowColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText)));
style.SetDarkShadowColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));
// match native QComboBox behavior of putting text cursor to end of text // without text selection when combobox entry is selected
style.SetComboBoxTextSelectionMode(ComboBoxTextSelectionMode::CursorToEnd);
// don't set QWidget parents; this breaks popups on Wayland, like the LO ComboBox or ColorPicker! void QtFrame::SetParent(SalFrame* pNewParent) { m_pParent = static_cast<QtFrame*>(pNewParent); }
void QtFrame::SetPluginParent(SystemParentData* /*pNewParent*/)
{ //FIXME: no SetPluginParent impl. for qt5
}
void QtFrame::SetScreenNumber(unsignedint nScreen)
{ if (!isWindow()) return;
QWindow* const pWindow = windowHandle(); if (!pWindow) return;
QList<QScreen*> screens = QApplication::screens(); if (static_cast<int>(nScreen) >= screens.size() && !m_bFullScreenSpanAll)
{
SAL_WARN("vcl.qt", "Ignoring request to set invalid screen number"); return;
}
QRect screenGeo;
if (!m_bFullScreenSpanAll)
{
screenGeo = QGuiApplication::screens().at(nScreen)->geometry();
pWindow->setScreen(QApplication::screens().at(nScreen));
} else// special case: fullscreen over all available screens
{
assert(m_bFullScreen); // left-most screen
QScreen* pScreen = QGuiApplication::screenAt(QPoint(0, 0)); // entire virtual desktop
screenGeo = pScreen->availableVirtualGeometry();
pWindow->setScreen(pScreen);
pWindow->setGeometry(screenGeo);
}
// setScreen by itself has no effect, explicitly move the widget to // the new screen
GetQtInstance().EmscriptenLightweightRunInMainThread(
[ child = asChild(), topLeft = screenGeo.topLeft() ] { child->move(topLeft); });
}
void QtFrame::ResolveWindowHandle(SystemEnvData& rData) const
{ if (!rData.pWidget) return;
assert(rData.platform != SystemEnvData::Platform::Invalid); // Calling QWidget::winId() implicitly enables native windows to be used instead // of "alien widgets" that don't have a native widget associated with them, // s. https://doc.qt.io/qt-6/qwidget.html#native-widgets-vs-alien-widgets // Avoid native widgets with Qt 5 on Wayland and with Qt 6 altogether as they // cause unresponsive UI, s. tdf#122293/QTBUG-75766 and tdf#160565 // (for qt5 xcb, they're needed for video playback) if (rData.platform != SystemEnvData::Platform::Wayland
&& QLibraryInfo::version().majorVersion() < 6)
{
rData.SetWindowHandle(static_cast<QWidget*>(rData.pWidget)->winId());
}
}
static sal_Int8 lcl_getUserDropAction(const QDropEvent* pEvent, const sal_Int8 nSourceActions, const QMimeData* pMimeData)
{ // we completely ignore all proposals by the Qt event, as they don't // match at all with the preferred LO DnD actions. // check the key modifiers to detect a user-overridden DnD action #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const Qt::KeyboardModifiers eKeyMod = pEvent->modifiers(); #else const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers(); #endif
sal_Int8 nUserDropAction = 0; if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; elseif ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY; elseif ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK;
nUserDropAction &= nSourceActions;
// select the default DnD action, if there isn't a user preference if (0 == nUserDropAction)
{ // default LO internal action is move, but default external action is copy
nUserDropAction = qobject_cast<const QtMimeData*>(pMimeData)
? css::datatransfer::dnd::DNDConstants::ACTION_MOVE
: css::datatransfer::dnd::DNDConstants::ACTION_COPY;
nUserDropAction &= nSourceActions;
// if the default doesn't match any allowed source action, fall back to the // preferred of all allowed source actions if (0 == nUserDropAction)
nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions));
// this is "our" preference, but actually we would even prefer any default, // if there is any
nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT;
} return nUserDropAction;
}
// ask the drop target to accept our drop action if (!m_bInDrag)
{
aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors();
m_pDropTarget->fire_dragEnter(aEvent);
m_bInDrag = true;
} else
m_pDropTarget->fire_dragOver(aEvent);
// the drop target accepted our drop action => inform Qt if (m_pDropTarget->proposedDropAction() != 0)
{
pEvent->setDropAction(getPreferredDropAction(m_pDropTarget->proposedDropAction()));
pEvent->accept();
} else// or maybe someone else likes it?
pEvent->ignore();
}
// inform the drag source of the drag-origin frame of the drop result if (pEvent->source())
{
QtWidget* pWidget = qobject_cast<QtWidget*>(pEvent->source());
assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself if (pWidget)
pWidget->frame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful);
}
// the drop target accepted our drop action => inform Qt if (bDropSuccessful)
{
pEvent->setDropAction(getPreferredDropAction(nDropAction));
pEvent->accept();
} else// or maybe someone else likes it?
pEvent->ignore();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.