15#include <QtGui/private/qtgui-config_p.h>
16#if QT_CONFIG(directwrite3)
17#include <QtGui/private/qwindowsdirectwritefontdatabase_p.h>
20# include <QtGui/private/qwindowsfontdatabase_ft_p.h>
22#include <QtGui/private/qwindowsfontdatabase_p.h>
23#if QT_CONFIG(clipboard)
24# include "qwindowsclipboard.h"
25# if QT_CONFIG(draganddrop)
26# include "qwindowsdrag.h"
31#if QT_CONFIG(accessibility)
32# include "uiautomation/qwindowsuiaaccessibility.h"
35#include <qpa/qplatformnativeinterface.h>
36#include <qpa/qwindowsysteminterface.h>
37#if QT_CONFIG(sessionmanager)
38# include "qwindowssessionmanager.h"
40#include <QtGui/qpointingdevice.h>
41#include <QtGui/private/qguiapplication_p.h>
42#include <QtGui/private/qhighdpiscaling_p.h>
43#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
44#include <QtGui/qpa/qplatformcursor.h>
46#include <QtGui/private/qwindowsguieventdispatcher_p.h>
48#include <QtCore/qdebug.h>
49#include <QtCore/qvariant.h>
51#include <QtCore/qoperatingsystemversion.h>
52#include <QtCore/private/qfunctions_win_p.h>
53#include <QtCore/private/qcomptr_p.h>
57#if !defined(QT_NO_OPENGL)
63#if QT_CONFIG(cpp_winrt)
64# include <QtCore/private/qt_winrtbase_p.h>
65# include <winrt/Windows.UI.Notifications.h>
66# include <winrt/Windows.Data.Xml.Dom.h>
67# include <winrt/Windows.Foundation.h>
68# include <winrt/Windows.UI.ViewManagement.h>
75 Q_INIT_RESOURCE(openglblacklists);
80using namespace Qt::StringLiterals;
93#if QT_CONFIG(clipboard)
95# if QT_CONFIG(draganddrop)
104#if QT_CONFIG(accessibility)
110template <
typename IntType>
112 IntType minimumValue, IntType maximumValue, IntType *target)
114 const int valueLength = parameter.size() - option.size() - 1;
115 if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != u'=')
118 const auto valueRef = QStringView{parameter}.right(valueLength);
119 const int value = valueRef.toInt(&ok);
121 if (value >=
int(minimumValue) && value <=
int(maximumValue))
122 *target =
static_cast<IntType>(value);
124 qWarning() <<
"Value" << value <<
"for option" << option <<
"out of range"
125 << minimumValue <<
".." << maximumValue;
128 qWarning() <<
"Invalid value" << valueRef <<
"for option" << option;
133using DarkModeHandlingFlag = QNativeInterface::Private::QWindowsApplication::DarkModeHandlingFlag;
134using DarkModeHandling = QNativeInterface::Private::QWindowsApplication::DarkModeHandling;
137 int *tabletAbsoluteRange,
138 QtWindows::DpiAwareness *dpiAwareness,
139 DarkModeHandling *darkModeHandling)
141 unsigned options = 0;
142 for (
const QString ¶m : paramList) {
143 if (param.startsWith(u"fontengine=")) {
144 if (param.endsWith(u"gdi")) {
145 options |= QWindowsIntegration::FontDatabaseGDI;
146 }
else if (param.endsWith(u"freetype")) {
147 options |= QWindowsIntegration::FontDatabaseFreeType;
148 }
else if (param.endsWith(u"native")) {
149 options |= QWindowsIntegration::FontDatabaseNative;
151 }
else if (param.startsWith(u"dialogs=")) {
152 if (param.endsWith(u"xp")) {
153 options |= QWindowsIntegration::XpNativeDialogs;
154 }
else if (param.endsWith(u"none")) {
155 options |= QWindowsIntegration::NoNativeDialogs;
157 }
else if (param == u"altgr") {
158 options |= QWindowsIntegration::DetectAltGrModifier;
159 }
else if (param == u"gl=gdi") {
160 options |= QWindowsIntegration::DisableArb;
161 }
else if (param == u"nodirectwrite") {
162 options |= QWindowsIntegration::DontUseDirectWriteFonts;
163 }
else if (param == u"nocolorfonts") {
164 options |= QWindowsIntegration::DontUseColorFonts;
165 }
else if (param == u"nomousefromtouch") {
166 options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch;
167 }
else if (parseIntOption(param,
"verbose"_L1, 0, INT_MAX, &QWindowsContext::verbose)
168 || parseIntOption(param,
"tabletabsoluterange"_L1, 0, INT_MAX, tabletAbsoluteRange)
169 || parseIntOption(param,
"dpiawareness"_L1, QtWindows::DpiAwareness::Invalid,
170 QtWindows::DpiAwareness::PerMonitorVersion2, dpiAwareness)) {
171 }
else if (param == u"menus=native") {
172 options |= QWindowsIntegration::AlwaysUseNativeMenus;
173 }
else if (param == u"menus=none") {
174 options |= QWindowsIntegration::NoNativeMenus;
175 }
else if (param == u"reverse") {
176 options |= QWindowsIntegration::RtlEnabled;
177 }
else if (param == u"darkmode=0") {
178 *darkModeHandling = {};
179 }
else if (param == u"darkmode=1") {
180 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
181 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle,
false);
182 }
else if (param == u"darkmode=2") {
183 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
184 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle);
186 qWarning() <<
"Unknown option" << param;
196 static bool dpiAwarenessSet =
false;
198 QtWindows::DpiAwareness dpiAwareness = QtWindows::DpiAwareness::PerMonitorVersion2;
200 int tabletAbsoluteRange = -1;
201 DarkModeHandling darkModeHandling = DarkModeHandlingFlag::DarkModeWindowFrames
202 | DarkModeHandlingFlag::DarkModeStyle;
203 m_options = ::parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness, &darkModeHandling);
204 q->setDarkModeHandling(darkModeHandling);
205 QWindowsFontDatabase::setFontOptions(m_options);
206 if (tabletAbsoluteRange >= 0)
209 QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
210 QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(
false);
212 if (!dpiAwarenessSet) {
213 if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
214 m_context.setProcessDpiAwareness(dpiAwareness);
215 qCDebug(lcQpaWindow) <<
"DpiAwareness=" << dpiAwareness
216 <<
"effective process DPI awareness=" << QWindowsContext::processDpiAwareness();
218 dpiAwarenessSet =
true;
221 m_context.initTouch(m_options);
222 QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);
224 m_context.initPowerNotificationHandler();
229 delete m_fontDatabase;
238 d->parseOptions(
this, paramList);
239#if QT_CONFIG(clipboard)
240 d->m_clipboard.registerViewer();
242 d->m_context.screenManager().initialize();
243 d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
248 m_instance =
nullptr;
253 auto icStrs = QPlatformInputContextFactory::requested();
254 icStrs.isEmpty() ? d->m_inputContext.reset(
new QWindowsInputContext)
255 : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
261 case ThreadedPixmaps:
265#if !QT_CONFIG(run_opengl_tests)
278 case MultipleWindows:
282 case AllGLFunctionsQueryable:
284 case SwitchableWidgetComposition:
286 case BackingStoreStaticContents:
289 return QPlatformIntegration::hasCapability(cap);
297 requested.flags = window->flags();
298 requested.geometry = window->isTopLevel()
299 ? QHighDpi::toNativePixels(window->geometry(), window)
300 : QHighDpi::toNativeLocalPosition(window->geometry(), window);
301 if (!(requested.flags & Qt::FramelessWindowHint)) {
303 const QVariant customMarginsV = window->property(
"_q_windowsCustomMargins");
304 if (customMarginsV.isValid())
305 requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
309 QWindowsWindowData::create(window, requested,
310 QWindowsWindow::formatWindowTitle(window->title()));
311 qCDebug(lcQpaWindow).nospace()
312 <<
__FUNCTION__ <<
' ' << window
313 <<
"\n Requested: " << requested.geometry <<
" frame incl.="
314 << QWindowsGeometryHint::positionIncludesFrame(window)
315 <<
' ' << requested.flags
316 <<
"\n Obtained : " << obtained.geometry <<
" margins=" << obtained.fullFrameMargins
317 <<
" handle=" << obtained.hwnd <<
' ' << obtained.flags <<
'\n';
319 if (Q_UNLIKELY(!obtained.hwnd))
322 QWindowsWindow *result = createPlatformWindowHelper(window, obtained);
325 if (window->isTopLevel() && !QWindowsContext::shouldHaveNonClientDpiScaling(window))
328 if (
QWindowsMenuBar *menuBarToBeInstalled = QWindowsMenuBar::menuBarOf(window))
336 const HWND hwnd =
reinterpret_cast<HWND>(nativeHandle);
337 if (!IsWindow(hwnd)) {
338 qWarning(
"Windows QPA: Invalid foreign window ID %p.", hwnd);
342 const QRect obtainedGeometry = result->geometry();
343 QScreen *screen =
nullptr;
344 if (
const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry))
345 screen = pScreen->screen();
346 if (screen && screen != window->screen())
347 window->setScreen(screen);
348 qCDebug(lcQpaWindow) <<
"Foreign window:" << window << Qt::showbase << Qt::hex
349 << result->winId() << Qt::noshowbase << Qt::dec << obtainedGeometry << screen;
356 return new QWindowsWindow(window, data);
363#if defined(QT_OPENGL_DYNAMIC)
364 QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer();
365 switch (requestedRenderer) {
366 case QWindowsOpenGLTester::DesktopGl:
367 if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
368 if ((QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DisableRotationFlag)
369 && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
370 qCWarning(lcQpaGl,
"Unable to disable rotation.");
374 qCWarning(lcQpaGl,
"System OpenGL failed. Falling back to Software OpenGL.");
375 return QOpenGLStaticContext::create(
true);
376 case QWindowsOpenGLTester::SoftwareRasterizer:
377 if (QWindowsStaticOpenGLContext *swCtx = QOpenGLStaticContext::create(
true))
379 qCWarning(lcQpaGl,
"Software OpenGL failed. Falling back to system OpenGL.");
380 if (QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DesktopGl)
381 return QOpenGLStaticContext::create();
387 const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(requestedRenderer);
388 if (supportedRenderers.testFlag(QWindowsOpenGLTester::DisableProgramCacheFlag)
389 && !QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
390 QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache);
392 if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) {
393 if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
394 if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)
395 && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
396 qCWarning(lcQpaGl,
"Unable to disable rotation.");
401 return QOpenGLStaticContext::create(
true);
414 qCDebug(lcQpaGl) <<
__FUNCTION__ << context->format();
416 std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(context));
417 if (result->isValid())
418 return result.release();
425#if !defined(QT_OPENGL_DYNAMIC)
426 return QOpenGLContext::LibGL;
428 if (
const QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
429 return staticOpenGLContext->moduleType();
430 return QOpenGLContext::LibGL;
448 std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(ctx, window));
449 if (result->isValid()) {
450 auto *context =
new QOpenGLContext;
451 context->setShareContext(shareContext);
452 auto *contextPrivate = QOpenGLContextPrivate::get(context);
453 contextPrivate->adopt(result.release());
467 QMutexLocker lock(&d->m_staticContextLock);
468 if (d->m_staticOpenGLContext.isNull())
469 d->m_staticOpenGLContext.reset(QWindowsStaticOpenGLContext::create());
470 return d->m_staticOpenGLContext.data();
476 if (!d->m_fontDatabase) {
477#ifndef QT_NO_FREETYPE
478 if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
479 d->m_fontDatabase =
new QWindowsFontDatabaseFT;
482#if QT_CONFIG(directwrite3)
483 if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
484 d->m_fontDatabase =
new QWindowsDirectWriteFontDatabase;
487 d->m_fontDatabase =
new QWindowsFontDatabase;
489 return d->m_fontDatabase;
492#ifdef SPI_GETKEYBOARDSPEED
493static inline int keyBoardAutoRepeatRateMS()
496 if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
497 return time ? 1000 /
static_cast<
int>(time) : 500;
505 case QPlatformIntegration::CursorFlashTime:
506 if (
const unsigned timeMS = GetCaretBlinkTime())
507 return QVariant(timeMS != INFINITE ?
int(timeMS) * 2 : 0);
509#ifdef SPI_GETKEYBOARDSPEED
510 case KeyboardAutoRepeatRate:
511 return QVariant(keyBoardAutoRepeatRateMS());
513 case QPlatformIntegration::ShowIsMaximized:
514 case QPlatformIntegration::StartDragTime:
515 case QPlatformIntegration::StartDragDistance:
516 case QPlatformIntegration::KeyboardInputInterval:
517 case QPlatformIntegration::ShowIsFullScreen:
518 case QPlatformIntegration::PasswordMaskDelay:
519 case QPlatformIntegration::StartDragVelocity:
521 case QPlatformIntegration::FontSmoothingGamma:
522 return QVariant(QWindowsFontDatabase::fontSmoothingGamma());
523 case QPlatformIntegration::MouseDoubleClickInterval:
524 if (
const UINT ms = GetDoubleClickTime())
525 return QVariant(
int(ms));
527 case QPlatformIntegration::UseRtlExtensions:
528 return QVariant(d->m_context.useRTLExtensions());
532 return QPlatformIntegration::styleHint(hint);
537 return d->m_context.keyMapper();
540#if QT_CONFIG(clipboard)
541QPlatformClipboard * QWindowsIntegration::clipboard()
const
543 return &d->m_clipboard;
545# if QT_CONFIG(draganddrop)
546QPlatformDrag *QWindowsIntegration::drag()
const
555 return d->m_inputContext.data();
558#if QT_CONFIG(accessibility)
559QPlatformAccessibility *QWindowsIntegration::accessibility()
const
561 return &d->m_accessibility;
570#if QT_CONFIG(sessionmanager)
571QPlatformSessionManager *QWindowsIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
573 return new QWindowsSessionManager(id, key);
579 return new QWindowsGuiEventDispatcher;
591 return QPlatformIntegration::createPlatformTheme(name);
596 if (d->m_services.isNull())
597 d->m_services.reset(
new QWindowsServices);
599 return d->m_services.data();
610 number = qMax(0, number);
613 m_applicationBadgeNumber = number;
615 static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
617#if QT_CONFIG(cpp_winrt)
622 if (isWindows11 && qt_win_hasPackageIdentity()) {
623 using namespace winrt::Windows::UI::Notifications;
624 auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
625 badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
626 BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
638 setApplicationBadge(QImage());
642 const bool isDarkMode = QWindowsTheme::instance()->colorScheme()
643 == Qt::ColorScheme::Dark;
648#if QT_CONFIG(cpp_winrt)
651 static const auto fromUIColor = [](winrt::Windows::UI::Color &&color) {
652 return QColor(color.R, color.G, color.B, color.A);
654 using namespace winrt::Windows::UI::ViewManagement;
655 const auto settings = UISettings();
656 badgeColor = fromUIColor(settings.GetColorValue(isDarkMode ?
657 UIColorType::AccentLight2 : UIColorType::Accent));
658 textColor = fromUIColor(settings.GetColorValue(UIColorType::Background));
662 if (!badgeColor.isValid()) {
664 badgeColor = isDarkMode ? Qt::black : QColor(220, 220, 220);
665 badgeColor.setAlphaF(0.5f);
666 textColor = isDarkMode ? Qt::white : Qt::black;
669 const auto devicePixelRatio = qApp->devicePixelRatio();
671 static const QSize iconBaseSize(16, 16);
672 QImage image(iconBaseSize * devicePixelRatio,
673 QImage::Format_ARGB32_Premultiplied);
674 image.fill(Qt::transparent);
676 QPainter painter(&image);
678 QRect badgeRect = image.rect();
679 QPen badgeBorderPen = Qt::NoPen;
681 QColor badgeBorderColor = textColor;
682 badgeBorderColor.setAlphaF(0.5f);
683 badgeBorderPen = badgeBorderColor;
684 badgeRect.adjust(1, 1, -1, -1);
686 painter.setBrush(badgeColor);
687 painter.setPen(badgeBorderPen);
688 painter.setRenderHint(QPainter::Antialiasing);
689 painter.drawEllipse(badgeRect);
691 auto pixelSize = qCeil(10.5 * devicePixelRatio);
694 const bool textOverflow = number > 99;
698 QFont font = painter.font();
699 font.setPixelSize(pixelSize);
700 font.setWeight(isWindows11 ? QFont::Medium : QFont::DemiBold);
701 painter.setFont(font);
703 painter.setRenderHint(QPainter::TextAntialiasing, devicePixelRatio > 1);
704 painter.setPen(textColor);
706 auto text = textOverflow ? u"99+"_s : QString::number(number);
707 painter.translate(textOverflow ? 1 : 0, textOverflow ? 0 : -1);
708 painter.drawText(image.rect(), Qt::AlignCenter, text);
712 setApplicationBadge(image);
717 QComHelper comHelper;
719 ComPtr<ITaskbarList3> taskbarList;
720 CoCreateInstance(CLSID_TaskbarList,
nullptr,
721 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
729 const auto hIcon = image.toHICON();
734 const auto topLevelWindows = QGuiApplication::topLevelWindows();
735 for (
auto *topLevelWindow : topLevelWindows) {
736 if (!topLevelWindow->handle())
738 auto hwnd =
reinterpret_cast<HWND>(topLevelWindow->winId());
739 taskbarList->SetOverlayIcon(hwnd, hIcon, L"");
756 if (m_applicationBadgeNumber)
757 setApplicationBadge(m_applicationBadgeNumber);
761QPlatformVulkanInstance *QWindowsIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
763 return new QWindowsVulkanInstance(instance);
Static Open GL context containing version information, extension function pointers,...
static QOpenGLStaticContext * create(bool softwareRendering=false)
Singleton container for all relevant information.
static void setTabletAbsoluteRange(int a)
Window wrapping a foreign native window.
QStringList themeNames() const override
QPlatformKeyMapper * keyMapper() const override
Accessor for the platform integration's key mapper.
static QWindowsStaticOpenGLContext * staticOpenGLContext()
void setApplicationBadge(const QImage &image)
~QWindowsIntegration() override
QOpenGLContext * createOpenGLContext(HGLRC context, HWND window, QOpenGLContext *shareContext) const override
QWindowsIntegration(const QStringList ¶mList)
void updateApplicationBadge()
QAbstractEventDispatcher * createEventDispatcher() const override
Factory function for the GUI event dispatcher.
QPlatformTheme * createPlatformTheme(const QString &name) const override
bool hasCapability(QPlatformIntegration::Capability cap) const override
QOpenGLContext::OpenGLModuleType openGLModuleType() override
Platform integration function for querying the OpenGL implementation type.
QPlatformFontDatabase * fontDatabase() const override
Accessor for the platform integration's fontdatabase.
void initialize() override
Performs initialization steps that depend on having an event dispatcher available.
void setApplicationBadge(qint64 number) override
static QWindowsIntegration * instance()
HMODULE openGLModuleHandle() const override
void beep() const override
QPlatformInputContext * inputContext() const override
Returns the platforms input context.
QPlatformServices * services() const override
QVariant styleHint(StyleHint hint) const override
QPlatformOpenGLContext * createPlatformOpenGLContext(QOpenGLContext *context) const override
Factory function for QPlatformOpenGLContext.
virtual void * moduleHandle() const =0
virtual bool supportsThreadedOpenGL() const
void setFlag(unsigned f) const
@ DisableNonClientScaling
QWindowsContext m_context
QScopedPointer< QWindowsStaticOpenGLContext > m_staticOpenGLContext
void parseOptions(QWindowsIntegration *q, const QStringList ¶mList)
~QWindowsIntegrationPrivate()
QScopedPointer< QWindowsServices > m_services
QMutex m_staticContextLock
QPlatformFontDatabase * m_fontDatabase
QScopedPointer< QPlatformInputContext > m_inputContext