File indexing completed on 2024-05-05 03:56:27
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org> 0003 * SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "tabletmodewatcher.h" 0009 #include <QCoreApplication> 0010 0011 #if defined(KIRIGAMI_ENABLE_DBUS) 0012 #include "settings_interface.h" 0013 #include <QDBusConnection> 0014 #endif 0015 0016 using namespace Qt::Literals::StringLiterals; 0017 0018 // TODO: All the dbus stuff should be conditional, optional win32 support 0019 0020 namespace Kirigami 0021 { 0022 namespace Platform 0023 { 0024 0025 class TabletModeWatcherSingleton 0026 { 0027 public: 0028 TabletModeWatcher self; 0029 }; 0030 0031 Q_GLOBAL_STATIC(TabletModeWatcherSingleton, privateTabletModeWatcherSelf) 0032 0033 class TabletModeWatcherPrivate 0034 { 0035 static constexpr auto PORTAL_GROUP = "org.kde.TabletMode"_L1; 0036 static constexpr auto KEY_AVAILABLE = "available"_L1; 0037 static constexpr auto KEY_ENABLED = "enabled"_L1; 0038 0039 public: 0040 TabletModeWatcherPrivate(TabletModeWatcher *watcher) 0041 : q(watcher) 0042 { 0043 // Called here to avoid collisions with application event types so we should use 0044 // registerEventType for generating the event types. 0045 TabletModeChangedEvent::type = QEvent::Type(QEvent::registerEventType()); 0046 #if !defined(KIRIGAMI_ENABLE_DBUS) && (defined(Q_OS_ANDROID) || defined(Q_OS_IOS)) 0047 isTabletModeAvailable = true; 0048 isTabletMode = true; 0049 #elif defined(KIRIGAMI_ENABLE_DBUS) 0050 // Mostly for debug purposes and for platforms which are always mobile, 0051 // such as Plasma Mobile 0052 if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE") || qEnvironmentVariableIsSet("KDE_KIRIGAMI_TABLET_MODE")) { 0053 /* clang-format off */ 0054 isTabletMode = 0055 (QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("1") 0056 || QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("true")) 0057 || (QString::fromLatin1(qgetenv("KDE_KIRIGAMI_TABLET_MODE")) == QStringLiteral("1") 0058 || QString::fromLatin1(qgetenv("KDE_KIRIGAMI_TABLET_MODE")) == QStringLiteral("true")); 0059 /* clang-format on */ 0060 isTabletModeAvailable = isTabletMode; 0061 } else { 0062 qDBusRegisterMetaType<VariantMapMap>(); 0063 auto portal = new OrgFreedesktopPortalSettingsInterface(u"org.freedesktop.portal.Desktop"_s, 0064 u"/org/freedesktop/portal/desktop"_s, 0065 QDBusConnection::sessionBus(), 0066 q); 0067 0068 QObject::connect(portal, 0069 &OrgFreedesktopPortalSettingsInterface::SettingChanged, 0070 q, 0071 [this](const QString &group, const QString &key, const QDBusVariant &value) { 0072 if (group != PORTAL_GROUP) { 0073 return; 0074 } 0075 if (key == KEY_AVAILABLE) { 0076 Q_EMIT q->tabletModeAvailableChanged(value.variant().toBool()); 0077 } else if (key == KEY_ENABLED) { 0078 setIsTablet(value.variant().toBool()); 0079 } 0080 }); 0081 0082 const auto reply = portal->ReadAll({PORTAL_GROUP}); 0083 auto watcher = new QDBusPendingCallWatcher(reply, q); 0084 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, q, [this, watcher]() { 0085 watcher->deleteLater(); 0086 QDBusPendingReply<VariantMapMap> reply = *watcher; 0087 const auto properties = reply.value().value(PORTAL_GROUP); 0088 Q_EMIT q->tabletModeAvailableChanged(properties[KEY_AVAILABLE].toBool()); 0089 setIsTablet(properties[KEY_ENABLED].toBool()); 0090 }); 0091 } 0092 // TODO: case for Windows 0093 #endif 0094 } 0095 ~TabletModeWatcherPrivate(){}; 0096 void setIsTablet(bool tablet); 0097 0098 TabletModeWatcher *q; 0099 QList<QObject *> watchers; 0100 bool isTabletModeAvailable = false; 0101 bool isTabletMode = false; 0102 }; 0103 0104 void TabletModeWatcherPrivate::setIsTablet(bool tablet) 0105 { 0106 if (isTabletMode == tablet) { 0107 return; 0108 } 0109 0110 isTabletMode = tablet; 0111 TabletModeChangedEvent event{tablet}; 0112 Q_EMIT q->tabletModeChanged(tablet); 0113 for (auto *w : watchers) { 0114 QCoreApplication::sendEvent(w, &event); 0115 } 0116 } 0117 0118 TabletModeWatcher::TabletModeWatcher(QObject *parent) 0119 : QObject(parent) 0120 , d(new TabletModeWatcherPrivate(this)) 0121 { 0122 } 0123 0124 TabletModeWatcher::~TabletModeWatcher() 0125 { 0126 delete d; 0127 } 0128 0129 TabletModeWatcher *TabletModeWatcher::self() 0130 { 0131 return &privateTabletModeWatcherSelf()->self; 0132 } 0133 0134 bool TabletModeWatcher::isTabletModeAvailable() const 0135 { 0136 return d->isTabletModeAvailable; 0137 } 0138 0139 bool TabletModeWatcher::isTabletMode() const 0140 { 0141 return d->isTabletMode; 0142 } 0143 0144 void TabletModeWatcher::addWatcher(QObject *watcher) 0145 { 0146 d->watchers.append(watcher); 0147 } 0148 0149 void TabletModeWatcher::removeWatcher(QObject *watcher) 0150 { 0151 d->watchers.removeAll(watcher); 0152 } 0153 0154 } 0155 } 0156 0157 #include "moc_tabletmodewatcher.cpp"