diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.vala.in | 6 | ||||
-rw-r--r-- | src/meson.build | 66 | ||||
-rw-r--r-- | src/network.vala | 201 | ||||
-rw-r--r-- | src/vpn.vala | 1 | ||||
-rw-r--r-- | src/wifi.vala | 137 | ||||
-rw-r--r-- | src/wired.vala | 75 |
6 files changed, 486 insertions, 0 deletions
diff --git a/src/config.vala.in b/src/config.vala.in new file mode 100644 index 0000000..dbec0f3 --- /dev/null +++ b/src/config.vala.in @@ -0,0 +1,6 @@ +namespace AstalNetwork { + public const int MAJOR_VERSION = @MAJOR_VERSION@; + public const int MINOR_VERSION = @MINOR_VERSION@; + public const int MICRO_VERSION = @MICRO_VERSION@; + public const string VERSION = "@VERSION@"; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..c8138fb --- /dev/null +++ b/src/meson.build @@ -0,0 +1,66 @@ +version_split = meson.project_version().split('.') +api_version = version_split[0] + '.' + version_split[1] +gir = 'AstalNetwork-' + api_version + '.gir' +typelib = 'AstalNetwork-' + api_version + '.typelib' + +config = configure_file( + input: 'config.vala.in', + output: 'config.vala', + configuration: { + 'VERSION': meson.project_version(), + 'MAJOR_VERSION': version_split[0], + 'MINOR_VERSION': version_split[1], + 'MICRO_VERSION': version_split[2], + }, +) + +deps = [ + dependency('glib-2.0'), + dependency('gobject-2.0'), + dependency('libnm') +] + +sources = [ + config, + 'network.vala', + 'wifi.vala', + 'wired.vala', + 'wired.vala', +] + +lib = library( + meson.project_name(), + sources, + dependencies: deps, + vala_header: meson.project_name() + '.h', + vala_vapi: meson.project_name() + '-' + api_version + '.vapi', + vala_gir: gir, + version: meson.project_version(), + install: true, + install_dir: [true, true, true, true], +) + +import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', +) + +custom_target( + typelib, + command: [ + find_program('g-ir-compiler'), + '--output', '@OUTPUT@', + '--shared-library', get_option('prefix') / get_option('libdir') / '@PLAINNAME@', + meson.current_build_dir() / gir, + ], + input: lib, + output: typelib, + depends: lib, + install: true, + install_dir: get_option('libdir') / 'girepository-1.0', +) diff --git a/src/network.vala b/src/network.vala new file mode 100644 index 0000000..53b3139 --- /dev/null +++ b/src/network.vala @@ -0,0 +1,201 @@ +namespace AstalNetwork { + public Network get_default() { + return Network.get_default(); + } +} + +public class AstalNetwork.Network : Object { + private static Network instance; + public static Network get_default() { + if (instance == null) + instance = new Network(); + + return instance; + } + + public NM.Client client { get; private set; } + + public Wifi wifi { get; private set; } + public Wired wired { get; private set; } + public Primary primary { get; private set; } + + public Connectivity connectivity { + get { return (Connectivity)client.connectivity; } + } + + public State state { + get { return (State)client.state; } + } + + construct { + try { + client = new NM.Client(); + wifi = new Wifi((NM.DeviceWifi)get_device(NM.DeviceType.WIFI), client); + wired = new Wired((NM.DeviceEthernet)get_device(NM.DeviceType.ETHERNET), client); + + sync(); + client.notify["primary-connection"].connect(sync); + client.notify["activating-connection"].connect(sync); + + client.notify["state"].connect(() => notify_property("state")); + client.notify["connectivity"].connect(() => notify_property("connectivity")); + } catch (Error err) { + critical(err.message); + } + } + + private NM.Device get_device(NM.DeviceType t) { + var valid = new GenericArray<NM.Device>(); + foreach (var device in client.get_devices()) { + if (device.device_type == t) + valid.add(device); + } + + foreach (var device in valid) { + if (device.active_connection != null) + return device; + } + + return valid.get(0); + } + + private void sync() { + var ac = client.get_primary_connection(); + + if (ac == null) + ac = client.get_activating_connection(); + + if (ac != null) + primary = Primary.from_connection_type(ac.type); + else + primary = Primary.UNKNOWN; + } +} + +public enum AstalNetwork.Primary { + UNKNOWN, + WIRED, + WIFI; + + public string to_string() { + switch (this) { + case WIFI: return "wifi"; + case WIRED: return "wired"; + default: return "unknown"; + } + } + + public static Primary from_connection_type(string type) { + switch (type) { + case "802-11-wireless": return Primary.WIFI; + case "802-3-ethernet": return Primary.WIRED; + default: return Primary.UNKNOWN; + } + } +} + +// alias for NM.State +public enum AstalNetwork.State { + UNKNOWN, + ASLEEP, + DISCONNECTED, + DISCONNECTING, + CONNECTING, + CONNECTED_LOCAL, + CONNECTED_SITE, + CONNECTED_GLOBAL; + + public string to_string() { + switch (this) { + case ASLEEP: return "asleep"; + case DISCONNECTED: return "disconnected"; + case DISCONNECTING: return "disconnecting"; + case CONNECTING: return "connecting"; + case CONNECTED_LOCAL: return "connected_local"; + case CONNECTED_SITE: return "connected_site"; + case CONNECTED_GLOBAL: return "connected_global"; + default: return "unknown"; + } + } +} + + +// alias for NM.ConnectivityState +public enum AstalNetwork.Connectivity { + UNKNOWN, + NONE, + PORTAL, + LIMITED, + FULL; + + public string to_string() { + switch (this) { + case NONE: return "none"; + case PORTAL: return "portal"; + case LIMITED: return "limited"; + case FULL: return "full"; + default: return "unknown"; + } + } +} + +// alias for NM.DeviceState +public enum AstalNetwork.DeviceState { + UNKNOWN, + UNMANAGED, + UNAVAILABLE, + DISCONNECTED, + PREPARE, + CONFIG, + NEED_AUTH, + IP_CONFIG, + IP_CHECK, + SECONDARIES, + ACTIVATED, + DEACTIVATING, + FAILED; + + public string to_string() { + switch (this) { + case UNMANAGED: return "unmanaged"; + case UNAVAILABLE: return "unavailable"; + case DISCONNECTED: return "disconnected"; + case PREPARE: return "prepare"; + case CONFIG: return "config"; + case NEED_AUTH: return "need_auth"; + case IP_CONFIG: return "ip_config"; + case IP_CHECK: return "ip_check"; + case SECONDARIES: return "secondaries"; + case ACTIVATED: return "activated"; + case DEACTIVATING: return "deactivating"; + case FAILED: return "failed"; + default: return "unknown"; + } + + } +} + +public enum AstalNetwork.Internet { + CONNECTED, + CONNECTING, + DISCONNECTED; + + public static Internet from_device(NM.Device device) { + if (device == null || device.active_connection == null) + return DISCONNECTED; + + switch (device.active_connection.state) { + case NM.ActiveConnectionState.ACTIVATED: return CONNECTED; + case NM.ActiveConnectionState.ACTIVATING: return CONNECTING; + default: return DISCONNECTED; + } + } + + public string to_string() { + switch (this) { + case CONNECTED: return "connected"; + case CONNECTING: return "connecting"; + default: return "disconnected"; + } + } +} diff --git a/src/vpn.vala b/src/vpn.vala new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/vpn.vala @@ -0,0 +1 @@ + diff --git a/src/wifi.vala b/src/wifi.vala new file mode 100644 index 0000000..8412a09 --- /dev/null +++ b/src/wifi.vala @@ -0,0 +1,137 @@ +public class AstalNetwork.Wifi : Object { + private const string ICON_EXCELLENT = "network-wireless-signal-excellent-symbolic"; + private const string ICON_OK = "network-wireless-signal-ok-symbolic"; + private const string ICON_GOOD = "network-wireless-signal-good-symbolic"; + private const string ICON_WEAK = "network-wireless-signal-weak-symbolic"; + private const string ICON_NONE = "network-wireless-signal-none-symbolic"; + private const string ICON_ACQUIRING = "network-wireless-acquiring-symbolic"; + private const string ICON_CONNECTED = "network-wireless-connected-symbolic"; + private const string ICON_DISABLED = "network-wireless-disabled-symbolic"; + private const string ICON_OFFLINE = "network-wireless-offline-symbolic"; + private const string ICON_NO_ROUTE = "network-wireless-no-route-symbolic"; + + private NM.Client client; + public NM.DeviceWifi device { get; private set; } + + public NM.ActiveConnection? connection; + private ulong connection_handler = 0; + + public NM.AccessPoint? access_point; + private ulong ap_handler = 0; + + internal Wifi(NM.DeviceWifi device, NM.Client client) { + this.device = device; + this.client = client; + + on_active_connection(); + device.notify["active-connection"].connect(on_active_connection); + + on_active_access_point(); + device.notify["active-access-point"].connect(on_active_access_point); + + state = (DeviceState)device.state; + device.access_point_added.connect(() => notify_property("access-points")); + device.access_point_removed.connect(() => notify_property("access-points")); + client.notify["wireless-enabled"].connect(() => notify_property("enabled")); + device.state_changed.connect((n, o, r) => { + state_changed(n, o, r); + state = (DeviceState)n; + }); + + device.notify.connect(() => { icon_name = _icon(); }); + client.notify.connect(() => { icon_name = _icon(); }); + icon_name = _icon(); + } + + public signal void state_changed( + DeviceState new_state, + DeviceState old_state, + NM.DeviceStateReason reaseon + ); + + private void on_active_connection() { + if (connection_handler > 0 && connection != null) { + connection.disconnect(connection_handler); + connection_handler = 0; + connection = null; + } + + connection = device.active_connection; + if (connection != null) { + connection_handler = connection.notify["state"].connect(() => { + internet = Internet.from_device(device); + }); + } + } + + private void on_active_access_point_notify() { + bandwidth = access_point.bandwidth; + frequency = access_point.frequency; + strength = access_point.strength; + ssid = access_point.ssid; + } + + private void on_active_access_point() { + if (ap_handler > 0 && access_point != null) { + access_point.disconnect(ap_handler); + ap_handler = 0; + access_point = null; + } + + access_point = device.active_access_point; + if (access_point != null) { + on_active_access_point_notify(); + ap_handler = access_point.notify.connect(on_active_access_point_notify); + } + } + + public bool enabled { + get { return client.wireless_enabled; } + set { client.wireless_enabled = value; } + } + + public GenericArray<NM.AccessPoint> access_points { + get { return device.access_points; } + } + + public Internet internet { get; private set; } + public uint bandwidth { get; private set; } + public Bytes ssid { get; private set; } + public uint8 strength { get; private set; } + public uint frequency { get; private set; } + public DeviceState state { get; private set; } + public string icon_name { get; private set; } + + private string _icon() { + var full = client.connectivity == NM.ConnectivityState.FULL; + + if (!enabled) return ICON_DISABLED; + + if (internet == Internet.CONNECTED) { + if (!full) return ICON_NO_ROUTE; + + if (strength >= 80) return ICON_EXCELLENT; + if (strength >= 60) return ICON_GOOD; + if (strength >= 40) return ICON_OK; + if (strength >= 20) return ICON_WEAK; + if (strength >= 0) return ICON_NONE; + + return ICON_CONNECTED; + } + + if (internet == Internet.CONNECTING) { + return ICON_ACQUIRING; + } + + return ICON_OFFLINE; + } +} + +namespace AstalNetwork { + public string ssid_to_string(Bytes? bytes) { + if (bytes == null) + return ""; + + return (string)NM.Utils.ssid_to_utf8(bytes.get_data()); + } +} diff --git a/src/wired.vala b/src/wired.vala new file mode 100644 index 0000000..4ff505f --- /dev/null +++ b/src/wired.vala @@ -0,0 +1,75 @@ +public class AstalNetwork.Wired : Object { + private const string ICON_CONNECTED = "network-wired-symbolic"; + private const string ICON_DISCONNECTED = "network-wired-disconnected-symbolic"; + private const string ICON_ACQUIRING = "network-wired-acquiring-symbolic"; + private const string ICON_NO_ROUTE = "network-wired-no-route-symbolic"; + + private NM.Client client; + public NM.DeviceEthernet device { get; construct set; } + + public NM.ActiveConnection connection; + private ulong connection_handler = 0; + + internal Wired(NM.DeviceEthernet device, NM.Client client) { + this.device = device; + this.client = client; + + speed = device.speed; + state = (DeviceState)device.state; + icon_name = _icon(); + + device.notify.connect((pspec) => { + if (pspec.name == "speed") { + speed = device.speed; + } + if (pspec.name == "state") { + state = (DeviceState)device.state; + } + if (pspec.name == "active-connection") { + on_active_connection(); + } + icon_name = _icon(); + }); + + client.notify.connect(() => { icon_name = _icon(); }); + + on_active_connection(); + icon_name = _icon(); + } + + private void on_active_connection() { + if (connection_handler > 0 && connection != null) { + connection.disconnect(connection_handler); + connection_handler = 0; + connection = null; + } + + connection = device.active_connection; + if (connection != null) { + connection_handler = connection.notify["state"].connect(() => { + internet = Internet.from_device(device); + }); + } + } + + public uint speed { get; private set; } + public Internet internet { get; private set; } + public DeviceState state { get; private set; } + public string icon_name { get; private set; } + + private string _icon() { + var full = client.connectivity == NM.ConnectivityState.FULL; + + if (internet == Internet.CONNECTING) { + return ICON_ACQUIRING; + } + + if (internet == Internet.CONNECTED) { + if (!full) return ICON_NO_ROUTE; + + return ICON_CONNECTED; + } + + return ICON_DISCONNECTED; + } +} |