16#include <QtGui/private/qtgui-config_p.h>
17#if QT_CONFIG(directwrite3)
18#include <QtGui/private/qwindowsdirectwritefontdatabase_p.h>
21# include <QtGui/private/qwindowsfontdatabase_ft_p.h>
23#include <QtGui/private/qwindowsfontdatabase_p.h>
24#if QT_CONFIG(clipboard)
25# include "qwindowsclipboard.h"
26# if QT_CONFIG(draganddrop)
27# include "qwindowsdrag.h"
32#if QT_CONFIG(accessibility)
33# include "uiautomation/qwindowsuiaaccessibility.h"
36#include <qpa/qplatformnativeinterface.h>
37#include <qpa/qwindowsysteminterface.h>
38#if QT_CONFIG(sessionmanager)
39# include "qwindowssessionmanager.h"
41#include <QtGui/qpointingdevice.h>
42#include <QtGui/private/qguiapplication_p.h>
43#include <QtGui/private/qhighdpiscaling_p.h>
44#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
45#include <QtGui/qpa/qplatformcursor.h>
47#include <QtGui/private/qwindowsguieventdispatcher_p.h>
49#include <QtCore/qdebug.h>
50#include <QtCore/qvariant.h>
52#include <QtCore/qoperatingsystemversion.h>
53#include <QtCore/private/qfunctions_win_p.h>
54#include <QtCore/private/qcomptr_p.h>
58#if !defined(QT_NO_OPENGL)
64#if QT_CONFIG(cpp_winrt)
65# include <QtCore/private/qt_winrtbase_p.h>
66# include <winrt/Windows.UI.Notifications.h>
67# include <winrt/Windows.Data.Xml.Dom.h>
68# include <winrt/Windows.Foundation.h>
69# include <winrt/Windows.UI.ViewManagement.h>
76 Q_INIT_RESOURCE(openglblacklists);
81using namespace Qt::StringLiterals;
94#if QT_CONFIG(clipboard)
96# if QT_CONFIG(draganddrop)
105#if QT_CONFIG(accessibility)
111template <
typename IntType>
113 IntType minimumValue, IntType maximumValue, IntType *target)
115 const int valueLength = parameter.size() - option.size() - 1;
116 if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != u'=')
119 const auto valueRef = QStringView{parameter}.right(valueLength);
120 const int value = valueRef.toInt(&ok);
122 if (value >=
int(minimumValue) && value <=
int(maximumValue))
123 *target =
static_cast<IntType>(value);
125 qWarning() <<
"Value" << value <<
"for option" << option <<
"out of range"
126 << minimumValue <<
".." << maximumValue;
129 qWarning() <<
"Invalid value" << valueRef <<
"for option" << option;
134using DarkModeHandlingFlag = QNativeInterface::Private::QWindowsApplication::DarkModeHandlingFlag;
135using DarkModeHandling = QNativeInterface::Private::QWindowsApplication::DarkModeHandling;
138 int *tabletAbsoluteRange,
139 QtWindows::DpiAwareness *dpiAwareness,
140 DarkModeHandling *darkModeHandling)
142 unsigned options = 0;
143 for (
const QString ¶m : paramList) {
144 if (param.startsWith(u"fontengine=")) {
145 if (param.endsWith(u"gdi")) {
146 options |= QWindowsIntegration::FontDatabaseGDI;
147 }
else if (param.endsWith(u"freetype")) {
148 options |= QWindowsIntegration::FontDatabaseFreeType;
149 }
else if (param.endsWith(u"native")) {
150 options |= QWindowsIntegration::FontDatabaseNative;
152 }
else if (param.startsWith(u"dialogs=")) {
153 if (param.endsWith(u"xp")) {
154 options |= QWindowsIntegration::XpNativeDialogs;
155 }
else if (param.endsWith(u"none")) {
156 options |= QWindowsIntegration::NoNativeDialogs;
158 }
else if (param == u"altgr") {
159 options |= QWindowsIntegration::DetectAltGrModifier;
160 }
else if (param == u"gl=gdi") {
161 options |= QWindowsIntegration::DisableArb;
162 }
else if (param == u"nodirectwrite") {
163 options |= QWindowsIntegration::DontUseDirectWriteFonts;
164 }
else if (param == u"nocolorfonts") {
165 options |= QWindowsIntegration::DontUseColorFonts;
166 }
else if (param == u"nomousefromtouch") {
167 options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch;
168 }
else if (parseIntOption(param,
"verbose"_L1, 0, INT_MAX, &QWindowsContext::verbose)
169 || parseIntOption(param,
"tabletabsoluterange"_L1, 0, INT_MAX, tabletAbsoluteRange)
170 || parseIntOption(param,
"dpiawareness"_L1, QtWindows::DpiAwareness::Invalid,
171 QtWindows::DpiAwareness::PerMonitorVersion2, dpiAwareness)) {
172 }
else if (param == u"menus=native") {
173 options |= QWindowsIntegration::AlwaysUseNativeMenus;
174 }
else if (param == u"menus=none") {
175 options |= QWindowsIntegration::NoNativeMenus;
176 }
else if (param == u"reverse") {
177 options |= QWindowsIntegration::RtlEnabled;
178 }
else if (param == u"darkmode=0") {
179 *darkModeHandling = {};
180 }
else if (param == u"darkmode=1") {
181 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
182 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle,
false);
183 }
else if (param == u"darkmode=2") {
184 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
185 darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle);
187 qWarning() <<
"Unknown option" << param;
197 static bool dpiAwarenessSet =
false;
199 QtWindows::DpiAwareness dpiAwareness = QtWindows::DpiAwareness::PerMonitorVersion2;
201 int tabletAbsoluteRange = -1;
202 DarkModeHandling darkModeHandling = DarkModeHandlingFlag::DarkModeWindowFrames
203 | DarkModeHandlingFlag::DarkModeStyle;
204 m_options = ::parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness, &darkModeHandling);
205 q->setDarkModeHandling(darkModeHandling);
206 QWindowsFontDatabase::setFontOptions(m_options);
207 if (tabletAbsoluteRange >= 0)
210 QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
211 QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(
false);
213 if (!dpiAwarenessSet) {
214 if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
215 m_context.setProcessDpiAwareness(dpiAwareness);
216 qCDebug(lcQpaWindow) <<
"DpiAwareness=" << dpiAwareness
217 <<
"effective process DPI awareness=" << QWindowsContext::processDpiAwareness();
219 dpiAwarenessSet =
true;
222 m_context.initTouch(m_options);
223 QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);
225 m_context.initPowerNotificationHandler();
230 delete m_fontDatabase;
239 d->parseOptions(
this, paramList);
240#if QT_CONFIG(clipboard)
241 d->m_clipboard.registerViewer();
243 d->m_context.screenManager().initialize();
244 d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
249 m_instance =
nullptr;
254 auto icStrs = QPlatformInputContextFactory::requested();
255 icStrs.isEmpty() ? d->m_inputContext.reset(
new QWindowsInputContext)
256 : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
262 case ThreadedPixmaps:
266#if !QT_CONFIG(run_opengl_tests)
279 case MultipleWindows:
283 case AllGLFunctionsQueryable:
285 case SwitchableWidgetComposition:
287 case BackingStoreStaticContents:
289 case MouseCursorPositioning:
292 return QPlatformIntegration::hasCapability(cap);
300 requested.flags = window->flags();
301 requested.geometry = window->isTopLevel()
302 ? QHighDpi::toNativePixels(window->geometry(), window)
303 : QHighDpi::toNativeLocalPosition(window->geometry(), window);
304 if (!(requested.flags & Qt::FramelessWindowHint)) {
306 const QVariant customMarginsV = window->property(
"_q_windowsCustomMargins");
307 if (customMarginsV.isValid())
308 requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
312 QWindowsWindowData::create(window, requested,
313 QWindowsWindow::formatWindowTitle(window->title()));
314 qCDebug(lcQpaWindow).nospace()
315 <<
__FUNCTION__ <<
' ' << window
316 <<
"\n Requested: " << requested.geometry <<
" frame incl.="
317 << QWindowsGeometryHint::positionIncludesFrame(window)
318 <<
' ' << requested.flags
319 <<
"\n Obtained : " << obtained.geometry <<
" margins=" << obtained.fullFrameMargins
320 <<
" handle=" << obtained.hwnd <<
' ' << obtained.flags <<
'\n';
322 if (Q_UNLIKELY(!obtained.hwnd))
325 QWindowsWindow *result = createPlatformWindowHelper(window, obtained);
328 if (window->isTopLevel() && !QWindowsContext::shouldHaveNonClientDpiScaling(window))
331 if (
QWindowsMenuBar *menuBarToBeInstalled = QWindowsMenuBar::menuBarOf(window))
339 const HWND hwnd =
reinterpret_cast<HWND>(nativeHandle);
340 if (!IsWindow(hwnd)) {
341 qWarning(
"Windows QPA: Invalid foreign window ID %p.", hwnd);
345 const QRect obtainedGeometry = result->geometry();
346 QScreen *screen =
nullptr;
347 if (
const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry))
348 screen = pScreen->screen();
349 if (screen && screen != window->screen())
350 window->setScreen(screen);
351 qCDebug(lcQpaWindow) <<
"Foreign window:" << window << Qt::showbase << Qt::hex
352 << result->winId() << Qt::noshowbase << Qt::dec << obtainedGeometry << screen;
359 return new QWindowsWindow(window, data);
366#if defined(QT_OPENGL_DYNAMIC)
367 QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer();
368 switch (requestedRenderer) {
369 case QWindowsOpenGLTester::DesktopGl:
370 if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
371 if ((QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DisableRotationFlag)
372 && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
373 qCWarning(lcQpaGl,
"Unable to disable rotation.");
377 qCWarning(lcQpaGl,
"System OpenGL failed. Falling back to Software OpenGL.");
378 return QOpenGLStaticContext::create(
true);
379 case QWindowsOpenGLTester::SoftwareRasterizer:
380 if (QWindowsStaticOpenGLContext *swCtx = QOpenGLStaticContext::create(
true))
382 qCWarning(lcQpaGl,
"Software OpenGL failed. Falling back to system OpenGL.");
383 if (QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DesktopGl)
384 return QOpenGLStaticContext::create();
390 const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(requestedRenderer);
391 if (supportedRenderers.testFlag(QWindowsOpenGLTester::DisableProgramCacheFlag)
392 && !QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
393 QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache);
395 if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) {
396 if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
397 if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)
398 && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
399 qCWarning(lcQpaGl,
"Unable to disable rotation.");
404 return QOpenGLStaticContext::create(
true);
417 qCDebug(lcQpaGl) <<
__FUNCTION__ << context->format();
419 std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(context));
420 if (result->isValid())
421 return result.release();
428#if !defined(QT_OPENGL_DYNAMIC)
429 return QOpenGLContext::LibGL;
431 if (
const QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
432 return staticOpenGLContext->moduleType();
433 return QOpenGLContext::LibGL;
451 std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(ctx, window));
452 if (result->isValid()) {
453 auto *context =
new QOpenGLContext;
454 context->setShareContext(shareContext);
455 auto *contextPrivate = QOpenGLContextPrivate::get(context);
456 contextPrivate->adopt(result.release());
470 QMutexLocker lock(&d->m_staticContextLock);
471 if (d->m_staticOpenGLContext.isNull())
472 d->m_staticOpenGLContext.reset(QWindowsStaticOpenGLContext::create());
473 return d->m_staticOpenGLContext.data();
479 if (!d->m_fontDatabase) {
480#ifndef QT_NO_FREETYPE
481 if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
482 d->m_fontDatabase =
new QWindowsFontDatabaseFT;
485#if QT_CONFIG(directwrite3)
486 if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
487 d->m_fontDatabase =
new QWindowsDirectWriteFontDatabase;
490 d->m_fontDatabase =
new QWindowsFontDatabase;
492 return d->m_fontDatabase;
495#ifdef SPI_GETKEYBOARDSPEED
496static inline int keyBoardAutoRepeatRateMS()
499 if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
500 return time ? 1000 /
static_cast<
int>(time) : 500;
508 case QPlatformIntegration::CursorFlashTime:
509 if (
const unsigned timeMS = GetCaretBlinkTime())
510 return QVariant(timeMS != INFINITE ?
int(timeMS) * 2 : 0);
512#ifdef SPI_GETKEYBOARDSPEED
513 case KeyboardAutoRepeatRate:
514 return QVariant(keyBoardAutoRepeatRateMS());
516 case QPlatformIntegration::ShowIsMaximized:
517 case QPlatformIntegration::StartDragTime:
518 case QPlatformIntegration::StartDragDistance:
519 case QPlatformIntegration::KeyboardInputInterval:
520 case QPlatformIntegration::ShowIsFullScreen:
521 case QPlatformIntegration::PasswordMaskDelay:
522 case QPlatformIntegration::StartDragVelocity:
524 case QPlatformIntegration::FontSmoothingGamma:
525 return QVariant(QWindowsFontDatabase::fontSmoothingGamma());
526 case QPlatformIntegration::MouseDoubleClickInterval:
527 if (
const UINT ms = GetDoubleClickTime())
528 return QVariant(
int(ms));
530 case QPlatformIntegration::UseRtlExtensions:
531 return QVariant(d->m_context.useRTLExtensions());
535 return QPlatformIntegration::styleHint(hint);
540 return d->m_context.keyMapper();
543#if QT_CONFIG(clipboard)
544QPlatformClipboard * QWindowsIntegration::clipboard()
const
546 return &d->m_clipboard;
548# if QT_CONFIG(draganddrop)
549QPlatformDrag *QWindowsIntegration::drag()
const
558 return d->m_inputContext.data();
561#if QT_CONFIG(accessibility)
562QPlatformAccessibility *QWindowsIntegration::accessibility()
const
564 return &d->m_accessibility;
573#if QT_CONFIG(sessionmanager)
574QPlatformSessionManager *QWindowsIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
576 return new QWindowsSessionManager(id, key);
582 return new QWindowsGuiEventDispatcher;
594 return QPlatformIntegration::createPlatformTheme(name);
599 if (d->m_services.isNull())
600 d->m_services.reset(
new QWindowsServices);
602 return d->m_services.data();
613 number = qMax(0, number);
616 m_applicationBadgeNumber = number;
618 static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
620#if QT_CONFIG(cpp_winrt)
625 if (isWindows11 && qt_win_hasPackageIdentity()) {
626 using namespace winrt::Windows::UI::Notifications;
627 auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
628 badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
629 BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
641 setApplicationBadge(QImage());
645 const bool isDarkMode = QWindowsTheme::instance()->colorScheme()
646 == Qt::ColorScheme::Dark;
651#if QT_CONFIG(cpp_winrt)
654 static const auto fromUIColor = [](winrt::Windows::UI::Color &&color) {
655 return QColor(color.R, color.G, color.B, color.A);
657 using namespace winrt::Windows::UI::ViewManagement;
658 const auto settings = UISettings();
659 badgeColor = fromUIColor(settings.GetColorValue(isDarkMode ?
660 UIColorType::AccentLight2 : UIColorType::Accent));
661 textColor = fromUIColor(settings.GetColorValue(UIColorType::Background));
665 if (!badgeColor.isValid()) {
667 badgeColor = isDarkMode ? Qt::black : QColor(220, 220, 220);
668 badgeColor.setAlphaF(0.5f);
669 textColor = isDarkMode ? Qt::white : Qt::black;
672 const auto devicePixelRatio = qApp->devicePixelRatio();
674 static const QSize iconBaseSize(16, 16);
675 QImage image(iconBaseSize * devicePixelRatio,
676 QImage::Format_ARGB32_Premultiplied);
677 image.fill(Qt::transparent);
679 QPainter painter(&image);
681 QRect badgeRect = image.rect();
682 QPen badgeBorderPen = Qt::NoPen;
684 QColor badgeBorderColor = textColor;
685 badgeBorderColor.setAlphaF(0.5f);
686 badgeBorderPen = badgeBorderColor;
687 badgeRect.adjust(1, 1, -1, -1);
689 painter.setBrush(badgeColor);
690 painter.setPen(badgeBorderPen);
691 painter.setRenderHint(QPainter::Antialiasing);
692 painter.drawEllipse(badgeRect);
694 auto pixelSize = qCeil(10.5 * devicePixelRatio);
697 const bool textOverflow = number > 99;
701 QFont font = painter.font();
702 font.setPixelSize(pixelSize);
703 font.setWeight(isWindows11 ? QFont::Medium : QFont::DemiBold);
704 painter.setFont(font);
706 painter.setRenderHint(QPainter::TextAntialiasing, devicePixelRatio > 1);
707 painter.setPen(textColor);
709 auto text = textOverflow ? u"99+"_s : QString::number(number);
710 painter.translate(textOverflow ? 1 : 0, textOverflow ? 0 : -1);
711 painter.drawText(image.rect(), Qt::AlignCenter, text);
715 setApplicationBadge(image);
720 QComHelper comHelper;
722 ComPtr<ITaskbarList3> taskbarList;
723 CoCreateInstance(CLSID_TaskbarList,
nullptr,
724 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
732 const auto hIcon = image.toHICON();
737 const auto topLevelWindows = QGuiApplication::topLevelWindows();
738 for (
auto *topLevelWindow : topLevelWindows) {
739 if (!topLevelWindow->handle())
741 auto hwnd =
reinterpret_cast<HWND>(topLevelWindow->winId());
742 taskbarList->SetOverlayIcon(hwnd, hIcon, L"");
759 if (m_applicationBadgeNumber)
760 setApplicationBadge(m_applicationBadgeNumber);
764QPlatformVulkanInstance *QWindowsIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
766 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