Commit 7a9a7bf3 authored by Volker Krause's avatar Volker Krause
Browse files

Add Flatpak portal network monitor support

parent 06b6bab5
......@@ -24,6 +24,7 @@ else()
)
qt5_add_dbus_interface(solidextras_srcs org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml brightnesscontroldbusinterface)
qt5_add_dbus_interface(solidextras_srcs org.freedesktop.ScreenSaver.xml screensaverdbusinterface)
qt5_add_dbus_interface(solidextras_srcs org.freedesktop.portal.NetworkMonitor.xml portalnetworkmonitor)
endif()
add_library(SolidExtras ${solidextras_srcs})
......
......@@ -6,24 +6,105 @@
#include "config-solid-extras.h"
#include "networkstatus.h"
#include "portalnetworkmonitor.h"
#ifdef HAVE_NM
#include <NetworkManagerQt/Manager>
#endif
#include <QCoreApplication>
#include <QDebug>
namespace SolidExtras {
class PortalNetworkMonitor : public QObject
{
Q_OBJECT
public:
static bool hasPortal();
static NetworkStatus::State connectivity() { return instance()->m_connected; }
static NetworkStatus::State metered() { return instance()->m_metered; }
static PortalNetworkMonitor* instance();
Q_SIGNALS:
void connectivityChanged();
void meteredChanged();
private:
PortalNetworkMonitor(QObject *parent = nullptr);
void asyncUpdate();
org::freedesktop::portal::NetworkMonitor m_iface;
NetworkStatus::State m_connected = NetworkStatus::Unknown;
NetworkStatus::State m_metered = NetworkStatus::Unknown;
};
}
using namespace SolidExtras;
PortalNetworkMonitor::PortalNetworkMonitor(QObject *parent)
: QObject(parent)
, m_iface(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QDBusConnection::sessionBus())
{
connect(&m_iface, &org::freedesktop::portal::NetworkMonitor::changed, this, &PortalNetworkMonitor::asyncUpdate);
if (m_iface.isValid()) {
asyncUpdate();
}
}
PortalNetworkMonitor* PortalNetworkMonitor::instance()
{
static PortalNetworkMonitor *s_instance = new PortalNetworkMonitor(QCoreApplication::instance());
return s_instance;
}
bool SolidExtras::PortalNetworkMonitor::hasPortal()
{
return instance()->m_iface.isValid();
}
void PortalNetworkMonitor::asyncUpdate()
{
auto connectivityPendingReply = m_iface.GetConnectivity();
auto connectivityWatcher = new QDBusPendingCallWatcher(connectivityPendingReply, this);
connect(connectivityWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) {
const QDBusPendingReply<unsigned int> reply(*watcher);
if (reply.isValid() && ((reply.value() == 4) != (m_connected == NetworkStatus::Yes) || m_connected == NetworkStatus::Unknown)) {
m_connected = (reply.value() == 4) ? NetworkStatus::Yes : NetworkStatus::No;
emit connectivityChanged();
}
});
auto meteredPendingReply = m_iface.GetMetered();
auto meteredWatcher = new QDBusPendingCallWatcher(meteredPendingReply, this);
connect(meteredWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) {
const QDBusPendingReply<bool> reply(*watcher);
if (reply.isValid() && (reply.value() != (m_metered == NetworkStatus::Yes) || m_metered == NetworkStatus::Unknown)) {
m_metered = reply.value() ? NetworkStatus::Yes : NetworkStatus::No;
emit meteredChanged();
}
});
}
NetworkStatus::NetworkStatus(QObject *parent)
: QObject(parent)
{
qDebug() << "has portal:" << PortalNetworkMonitor::hasPortal();
connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::connectivityChanged, this, &NetworkStatus::connectivityChanged);
connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::meteredChanged, this, &NetworkStatus::meteredChanged);
#ifdef HAVE_NM
connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::connectivityChanged);
connect(NetworkManager::notifier(), &NetworkManager::Notifier::meteredChanged, this, &NetworkStatus::meteredChanged);
if (!PortalNetworkMonitor::hasPortal()) {
connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::connectivityChanged);
connect(NetworkManager::notifier(), &NetworkManager::Notifier::meteredChanged, this, &NetworkStatus::meteredChanged);
}
#endif
}
NetworkStatus::State NetworkStatus::connectivity() const
{
if (PortalNetworkMonitor::hasPortal()) {
return PortalNetworkMonitor::connectivity();
}
#ifdef HAVE_NM
switch (NetworkManager::connectivity()) {
case NetworkManager::UnknownConnectivity:
......@@ -42,6 +123,9 @@ NetworkStatus::State NetworkStatus::connectivity() const
NetworkStatus::State NetworkStatus::metered() const
{
if (PortalNetworkMonitor::hasPortal()) {
return PortalNetworkMonitor::metered();
}
#ifdef HAVE_NM
switch (NetworkManager::metered()) {
case NetworkManager::Device::UnknownStatus:
......@@ -57,3 +141,5 @@ NetworkStatus::State NetworkStatus::metered() const
#endif
return NetworkStatus::Unknown;
}
#include "networkstatus_dbus.moc"
<?xml version="1.0"?>
<!--
SPDX-FileCopyrightText: 2016 Red Hat Inc.
SPDX-FileContributor: Matthias Clasen <mclasen@redhat.com>
SPDX-License-Identifier: LGPL-2.0-or-later
-->
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<!--
org.freedesktop.portal.NetworkMonitor:
@short_description: Network monitoring portal
The NetworkMonitor interface provides network status information
to sandboxed applications. It is not a portal in the strict sense,
since it does not involve user interaction. Applications are
expected to use this interface indirectly, via a library API
such as the GLib GNetworkMonitor interface.
This documentation describes version 3 of this interface.
-->
<interface name="org.freedesktop.portal.NetworkMonitor">
<!--
changed:
Emitted when the network configuration changes.
-->
<signal name="changed"/>
<!--
GetAvailable:
@available: whether the network is available
Returns whether the network is considered available.
That is, whether the system as a default route for
at least one of IPv4 or IPv6.
This method was added in version 2 to replace
the available property.
-->
<method name="GetAvailable">
<arg type='b' name='available' direction='out'/>
</method>
<!--
GetMetered:
@metered: whether the network is metered
Returns whether the network is considered metered.
That is, whether the system as traffic flowing through
the default connection that is subject ot limitations
by service providers.
This method was added in version 2 to replace
the metered property.
-->
<method name="GetMetered">
<arg type='b' name='metered' direction='out'/>
</method>
<!--
GetConnectivity:
@connectivity: the level of connectivity
Returns more detailed information about the host's network
connectivity. The meaning of the value is:
<simplelist>
<member>1: Local only. The host is not configured with a route to the internet.</member>
<member>2: Limited connectivity. The host is connected to a network, but can't reach the full internet.</member>
<member>3: Captive portal. The host is behind a captive portal and cannot reach the full internet.</member>
<member>4: Full network. The host connected to a network, and can reach the full internet.</member>
</simplelist>
This method was added in version 2 to replace
the connectivity property.
-->
<method name="GetConnectivity">
<arg type='u' name='connectivity' direction='out'/>
</method>
<!--
GetStatus:
@status: a dictionary with the current values
Returns the three values all at once.
The following results get returned via @status:
<variablelist>
<varlistentry>
<term>available b</term>
<listitem><para>
Whether the network is available.
</para></listitem>
</varlistentry>
<varlistentry>
<term>metered b</term>
<listitem><para>
Whether the network is metered.
</para></listitem>
</varlistentry>
<varlistentry>
<term>connectivity u</term>
<listitem><para>
The level of connectivity.
</para></listitem>
</varlistentry>
</variablelist>
This method was added in version 3 to avoid multiple round-trips.
-->
<method name="GetStatus">
<arg type='a{sv}' name='status' direction='out'/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap" />
</method>
<!--
CanReach:
@hostname: the hostname to reach
@port: the port to reach
@reachable: Whether the hostname:port was reachable
Returns whether the given hostname is believed to be reachable.
This method was added in version 3.
-->
<method name="CanReach">
<arg type='s' name='hostname' direction='in'/>
<arg type='u' name='port' direction='in'/>
<arg type='b' name='reachable' direction='out'/>
</method>
<property name="version" type="u" access="read"/>
</interface>
</node>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment