File indexing completed on 2025-02-02 05:02:43
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "config-solid-extras.h" 0008 #include "networkstatus.h" 0009 #include "portalnetworkmonitor.h" 0010 0011 #if HAVE_NM 0012 #include <NetworkManagerQt/Manager> 0013 #endif 0014 0015 #include <QCoreApplication> 0016 #include <QDebug> 0017 0018 namespace SolidExtras { 0019 class PortalNetworkMonitor : public QObject 0020 { 0021 Q_OBJECT 0022 public: 0023 static bool hasPortal(); 0024 static NetworkStatus::State connectivity() { return instance()->m_connected; } 0025 static NetworkStatus::State metered() { return instance()->m_metered; } 0026 static PortalNetworkMonitor* instance(); 0027 0028 Q_SIGNALS: 0029 void connectivityChanged(); 0030 void meteredChanged(); 0031 0032 private: 0033 PortalNetworkMonitor(QObject *parent = nullptr); 0034 void asyncUpdate(); 0035 org::freedesktop::portal::NetworkMonitor m_iface; 0036 NetworkStatus::State m_connected = NetworkStatus::Unknown; 0037 NetworkStatus::State m_metered = NetworkStatus::Unknown; 0038 }; 0039 } 0040 0041 using namespace SolidExtras; 0042 0043 PortalNetworkMonitor::PortalNetworkMonitor(QObject *parent) 0044 : QObject(parent) 0045 , m_iface(QLatin1StringView("org.freedesktop.portal.Desktop"), QLatin1StringView("/org/freedesktop/portal/desktop"), QDBusConnection::sessionBus()) 0046 { 0047 connect(&m_iface, &org::freedesktop::portal::NetworkMonitor::changed, this, &PortalNetworkMonitor::asyncUpdate); 0048 if (m_iface.isValid()) { 0049 asyncUpdate(); 0050 } 0051 } 0052 0053 PortalNetworkMonitor* PortalNetworkMonitor::instance() 0054 { 0055 static PortalNetworkMonitor *s_instance = new PortalNetworkMonitor(QCoreApplication::instance()); 0056 return s_instance; 0057 } 0058 0059 bool SolidExtras::PortalNetworkMonitor::hasPortal() 0060 { 0061 return instance()->m_iface.isValid(); 0062 } 0063 0064 void PortalNetworkMonitor::asyncUpdate() 0065 { 0066 auto connectivityPendingReply = m_iface.GetConnectivity(); 0067 auto connectivityWatcher = new QDBusPendingCallWatcher(connectivityPendingReply, this); 0068 connect(connectivityWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) { 0069 const QDBusPendingReply<unsigned int> reply(*watcher); 0070 if (reply.isValid() && ((reply.value() == 4) != (m_connected == NetworkStatus::Yes) || m_connected == NetworkStatus::Unknown)) { 0071 m_connected = (reply.value() == 4) ? NetworkStatus::Yes : NetworkStatus::No; 0072 Q_EMIT connectivityChanged(); 0073 } 0074 }); 0075 0076 auto meteredPendingReply = m_iface.GetMetered(); 0077 auto meteredWatcher = new QDBusPendingCallWatcher(meteredPendingReply, this); 0078 connect(meteredWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) { 0079 const QDBusPendingReply<bool> reply(*watcher); 0080 if (reply.isValid() && (reply.value() != (m_metered == NetworkStatus::Yes) || m_metered == NetworkStatus::Unknown)) { 0081 m_metered = reply.value() ? NetworkStatus::Yes : NetworkStatus::No; 0082 Q_EMIT meteredChanged(); 0083 } 0084 }); 0085 } 0086 0087 0088 NetworkStatus::NetworkStatus(QObject *parent) 0089 : QObject(parent) 0090 { 0091 qDebug() << "has portal:" << PortalNetworkMonitor::hasPortal(); 0092 connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::connectivityChanged, this, &NetworkStatus::connectivityChanged); 0093 connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::meteredChanged, this, &NetworkStatus::meteredChanged); 0094 0095 #if HAVE_NM 0096 if (!PortalNetworkMonitor::hasPortal()) { 0097 connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::connectivityChanged); 0098 connect(NetworkManager::notifier(), &NetworkManager::Notifier::meteredChanged, this, &NetworkStatus::meteredChanged); 0099 } 0100 #endif 0101 } 0102 0103 NetworkStatus::State NetworkStatus::connectivity() const 0104 { 0105 if (PortalNetworkMonitor::hasPortal()) { 0106 return PortalNetworkMonitor::connectivity(); 0107 } 0108 #if HAVE_NM 0109 switch (NetworkManager::connectivity()) { 0110 case NetworkManager::UnknownConnectivity: 0111 return Unknown; 0112 case NetworkManager::NoConnectivity: 0113 case NetworkManager::Portal: 0114 case NetworkManager::Limited: 0115 return No; 0116 case NetworkManager::Full: 0117 return Yes; 0118 } 0119 Q_UNREACHABLE(); 0120 #endif 0121 return NetworkStatus::Unknown; 0122 } 0123 0124 NetworkStatus::State NetworkStatus::metered() const 0125 { 0126 if (PortalNetworkMonitor::hasPortal()) { 0127 return PortalNetworkMonitor::metered(); 0128 } 0129 #if HAVE_NM 0130 switch (NetworkManager::metered()) { 0131 case NetworkManager::Device::UnknownStatus: 0132 return Unknown; 0133 case NetworkManager::Device::GuessYes: 0134 case NetworkManager::Device::Yes: 0135 return Yes; 0136 case NetworkManager::Device::GuessNo: 0137 case NetworkManager::Device::No: 0138 return No; 0139 } 0140 Q_UNREACHABLE(); 0141 #endif 0142 return NetworkStatus::Unknown; 0143 } 0144 0145 #include "networkstatus_dbus.moc"