diff --git a/debian/control b/debian/control index ee4da77bfe910d2307b93c3a8590b8e64fe937b8..b07eb906311624fdfcccac69fa7e3a3ca0764b6e 100644 --- a/debian/control +++ b/debian/control @@ -39,6 +39,7 @@ Build-Depends: valac, # for the plugins libecal2.0-dev, + libqrcodegen-dev, evolution-data-server-dev, universal-ctags, # to run the tests @@ -75,6 +76,7 @@ Depends: gnome-shell-common, gsettings-desktop-schemas (>= 47), libcap2-bin, + libqrcodegen1, phoc (>= 0.45.0), phosh-common (= ${source:Version}), Recommends: diff --git a/plugins/wifi-hotspot-quick-setting/meson.build b/plugins/wifi-hotspot-quick-setting/meson.build index af9d0d741db5fd746cd09192ee1efd82e8ec281b..2b7f556cf2cf367f29ab669cb14411afc862db2c 100644 --- a/plugins/wifi-hotspot-quick-setting/meson.build +++ b/plugins/wifi-hotspot-quick-setting/meson.build @@ -1,5 +1,7 @@ name = 'wifi-hotspot-quick-setting' +qrcodegen_dep = dependency('qrcodegen') + wifi_hotspot_quick_setting_resources = gnome.compile_resources( 'phosh-plugin-wifi-hotspot-quick-setting-resources', 'phosh-plugin-wifi-hotspot-quick-setting.gresources.xml', @@ -9,6 +11,7 @@ wifi_hotspot_quick_setting_resources = gnome.compile_resources( wifi_hotspot_quick_setting_plugin_sources = files( 'phosh-plugin-wifi-hotspot-quick-setting.c', 'wifi-hotspot-quick-setting.c', + 'wifi-hotspot-status-page.c', ) phosh_wifi_hotspot_quick_setting_plugin = shared_module( @@ -16,7 +19,7 @@ phosh_wifi_hotspot_quick_setting_plugin = shared_module( wifi_hotspot_quick_setting_plugin_sources, wifi_hotspot_quick_setting_resources, c_args: ['-DG_LOG_DOMAIN="phosh-plugin-@0@"'.format(name), '-DPLUGIN_NAME="@0@"'.format(name)], - dependencies: plugin_dep, + dependencies: [plugin_dep, qrcodegen_dep], install: true, install_dir: plugins_dir, ) diff --git a/plugins/wifi-hotspot-quick-setting/phosh-plugin-wifi-hotspot-quick-setting.gresources.xml b/plugins/wifi-hotspot-quick-setting/phosh-plugin-wifi-hotspot-quick-setting.gresources.xml index 67e1eadc8284c48f08e87fa25421da5d224b10c1..17c1e57873d9a3922dca253969cc2bc6e42b84e9 100644 --- a/plugins/wifi-hotspot-quick-setting/phosh-plugin-wifi-hotspot-quick-setting.gresources.xml +++ b/plugins/wifi-hotspot-quick-setting/phosh-plugin-wifi-hotspot-quick-setting.gresources.xml @@ -1,8 +1,10 @@ + status-page.ui qs.ui icons/network-wireless-hotspot-disabled-symbolic.svg icons/network-wireless-hotspot-acquiring-symbolic.svg + style.css diff --git a/plugins/wifi-hotspot-quick-setting/qs.ui b/plugins/wifi-hotspot-quick-setting/qs.ui index 8e677cab1c747600ceefaf9f73ba61dd85e8ee6b..039c272547ac2a4d767a6025cde7329dbef35c87 100644 --- a/plugins/wifi-hotspot-quick-setting/qs.ui +++ b/plugins/wifi-hotspot-quick-setting/qs.ui @@ -3,10 +3,12 @@ 1 16 + diff --git a/plugins/wifi-hotspot-quick-setting/status-page.ui b/plugins/wifi-hotspot-quick-setting/status-page.ui new file mode 100644 index 0000000000000000000000000000000000000000..28de75ce648f10dd795446c4c8192595e7fbaf93 --- /dev/null +++ b/plugins/wifi-hotspot-quick-setting/status-page.ui @@ -0,0 +1,77 @@ + + + + + + 1 + crossfade + 0 + + + 1 + turn_on_btn + + + empty_state + + + + + 1 + vertical + 6 + + + 1 + 128 + + + + + 1 + entry + center + 0.5 + 0 + password + 0 + view-reveal-symbolic + + + + + + + hotspot_enabled + + + + + 1 + center + Turn On + 0 + + + + 1 + 1 + 0 + panel.launch-panel + "wifi" + + + 1 + end + Wi-Fi Settings + + + + diff --git a/plugins/wifi-hotspot-quick-setting/style.css b/plugins/wifi-hotspot-quick-setting/style.css new file mode 100644 index 0000000000000000000000000000000000000000..71b0459d7a872b021c6bcb855eaca50f94ed524c --- /dev/null +++ b/plugins/wifi-hotspot-quick-setting/style.css @@ -0,0 +1,4 @@ +phosh-wifi-hotspot-status-page #entry { + font-size: 1.25rem; + font-weight: bold; +} diff --git a/plugins/wifi-hotspot-quick-setting/wifi-hotspot-quick-setting.c b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-quick-setting.c index 356195814645300a27989a9816017547ee1655c1..f11a99fefe64f5029eba4cb4217459f15816d027 100644 --- a/plugins/wifi-hotspot-quick-setting/wifi-hotspot-quick-setting.c +++ b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-quick-setting.c @@ -7,6 +7,7 @@ */ #include "wifi-hotspot-quick-setting.h" +#include "wifi-hotspot-status-page.h" #include "plugin-shell.h" #include @@ -100,6 +101,8 @@ phosh_wifi_hotspot_quick_setting_class_init (PhoshWifiHotspotQuickSettingClass * { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + g_type_ensure (PHOSH_TYPE_WIFI_HOTSPOT_STATUS_PAGE); + gtk_widget_class_set_template_from_resource (widget_class, "/mobi/phosh/plugins/wifi-hotspot-quick-setting/qs.ui"); @@ -112,10 +115,18 @@ phosh_wifi_hotspot_quick_setting_class_init (PhoshWifiHotspotQuickSettingClass * static void phosh_wifi_hotspot_quick_setting_init (PhoshWifiHotspotQuickSetting *self) { + g_autoptr (GtkCssProvider) css_provider = NULL; PhoshShell *shell = phosh_shell_get_default (); gtk_widget_init_template (GTK_WIDGET (self)); + css_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (css_provider, + "/mobi/phosh/plugins/wifi-hotspot-quick-setting/style.css"); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/mobi/phosh/plugins/wifi-hotspot-quick-setting/icons"); diff --git a/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.c b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.c new file mode 100644 index 0000000000000000000000000000000000000000..675b5e274475e3fda9e4ff4386d15fa9762f4c1d --- /dev/null +++ b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.c @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Arun Mani J + */ + +#include "plugin-shell.h" +#include "status-page-placeholder.h" +#include "wifi-hotspot-status-page.h" + +#include + +#define QR_CODE_SIZE 128 + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (cairo_t, cairo_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (cairo_surface_t, cairo_surface_destroy) + +/** + * PhoshWifiHotspotStatusPage: + * + * A status-page to show password of Wi-Fi hotspot. + * + * The code to display QR is taken from GNOME Control Center. + */ + +struct _PhoshWifiHotspotStatusPage { + PhoshStatusPage parent; + + GtkEntry *entry; + GtkImage *image; + PhoshStatusPagePlaceholder *placeholder; + GtkStack *stack; + GtkButton *turn_on_btn; + + GCancellable *cancel; + PhoshWifiManager *wifi; +}; + +G_DEFINE_TYPE (PhoshWifiHotspotStatusPage, phosh_wifi_hotspot_status_page, PHOSH_TYPE_STATUS_PAGE); + + +static cairo_surface_t * +qr_from_text (const char *text, int size, int scale) +{ + uint8_t qr_code[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; + uint8_t temp_buf[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; + g_autoptr (cairo_t) cr = NULL; + cairo_surface_t *surface; + int pixel_size, qr_size, padding; + gboolean success = FALSE; + + g_return_val_if_fail (size > 0, NULL); + g_return_val_if_fail (scale > 0, NULL); + + success = qrcodegen_encodeText (text, + temp_buf, + qr_code, + qrcodegen_Ecc_LOW, + qrcodegen_VERSION_MIN, + qrcodegen_VERSION_MAX, + qrcodegen_Mask_AUTO, + FALSE); + + if (!success) + return NULL; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, size * scale, size * scale); + cairo_surface_set_device_scale (surface, scale, scale); + cr = cairo_create (surface); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + /* Draw white background */ + cairo_set_source_rgba (cr, 1, 1, 1, 1); + cairo_rectangle (cr, 0, 0, size * scale, size * scale); + cairo_fill (cr); + + qr_size = qrcodegen_getSize (qr_code); + pixel_size = MAX (1, size / (qr_size)); + padding = (size - qr_size * pixel_size) / 2; + + /* If subpixel size is big and margin is pretty small, + * increase the margin */ + if (pixel_size > 4 && padding < 12) { + pixel_size--; + padding = (size - qr_size * pixel_size) / 2; + } + + /* Now draw the black QR code pixels */ + cairo_set_source_rgba (cr, 0, 0, 0, 1); + for (int row = 0; row < qr_size; row++) { + for (int column = 0; column < qr_size; column++) { + if (qrcodegen_getModule (qr_code, row, column)) { + cairo_rectangle (cr, + column * pixel_size + padding, + row * pixel_size + padding, + pixel_size, pixel_size); + cairo_fill (cr); + } + } + } + + return surface; +} + + +static char * +escape_string (const char *str, gboolean quote) +{ + GString *string; + const char *next; + + if (!str) + return NULL; + + string = g_string_new (""); + if (quote) + g_string_append_c (string, '"'); + + while ((next = strpbrk (str, "\\;,:\""))) { + g_string_append_len (string, str, next - str); + g_string_append_c (string, '\\'); + g_string_append_c (string, *next); + str = next + 1; + } + + g_string_append (string, str); + if (quote) + g_string_append_c (string, '"'); + + return g_string_free (string, FALSE); +} + + +static const char * +get_connection_security_type (NMConnection *c) +{ + NMSettingWirelessSecurity *setting; + const char *key_mgmt; + + g_return_val_if_fail (c, "nopass"); + + setting = nm_connection_get_setting_wireless_security (c); + + if (!setting) + return "nopass"; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting); + + /* No IEEE 802.1x */ + if (g_strcmp0 (key_mgmt, "none") == 0) + return "WEP"; + + if (g_strcmp0 (key_mgmt, "wpa-psk") == 0) + return "WPA"; + + if (g_strcmp0 (key_mgmt, "sae") == 0) + return "SAE"; + + return "nopass"; +} + + +static char * +get_wifi_password (NMConnection *c) +{ + NMSettingWirelessSecurity *setting; + const char *sec_type, *password; + int wep_index; + + sec_type = get_connection_security_type (c); + setting = nm_connection_get_setting_wireless_security (c); + + if (g_str_equal (sec_type, "nopass")) + return NULL; + + if (g_str_equal (sec_type, "WEP")) { + wep_index = nm_setting_wireless_security_get_wep_tx_keyidx (setting); + password = nm_setting_wireless_security_get_wep_key (setting, wep_index); + } else { + password = nm_setting_wireless_security_get_psk (setting); + } + + return g_strdup (password); +} + + +/* Generate a string representing the connection + * An example generated text: + * WIFI:S:ssid;T:WPA;P:my-valid-pass;H:true; + * Where, + * S = ssid, T = security, P = password, H = hidden (Optional) + * + * See https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11 + */ +static char * +get_qr_string_for_connection (NMConnection *c) +{ + NMSettingWireless *setting; + g_autofree char *ssid_text = NULL; + g_autofree char *escaped_ssid = NULL; + g_autofree char *password_str = NULL; + g_autofree char *escaped_password = NULL; + GString *string; + GBytes *ssid; + gboolean hidden; + + setting = nm_connection_get_setting_wireless (c); + ssid = nm_setting_wireless_get_ssid (setting); + + if (!ssid) + return NULL; + + string = g_string_new ("WIFI:S:"); + + /* SSID */ + ssid_text = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), + g_bytes_get_size (ssid)); + escaped_ssid = escape_string (ssid_text, FALSE); + g_string_append (string, escaped_ssid); + g_string_append_c (string, ';'); + + /* Security type */ + g_string_append (string, "T:"); + g_string_append (string, get_connection_security_type (c)); + g_string_append_c (string, ';'); + + /* Password */ + g_string_append (string, "P:"); + password_str = get_wifi_password (c); + escaped_password = escape_string (password_str, FALSE); + if (escaped_password) + g_string_append (string, escaped_password); + g_string_append_c (string, ';'); + + /* WiFi Hidden */ + hidden = nm_setting_wireless_get_hidden (setting); + if (hidden) + g_string_append (string, "H:true"); + g_string_append_c (string, ';'); + + return g_string_free (string, FALSE); +} + + +static void +on_secrets_ready (GObject *object, GAsyncResult *result, gpointer data) +{ + PhoshWifiHotspotStatusPage *self = data; + NMConnection *conn = NM_CONNECTION (object); + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) variant = NULL; + g_autofree char *cnx_str = NULL; + g_autofree char *password = NULL; + g_autoptr (cairo_surface_t) surface = NULL; + int scale; + + variant = nm_remote_connection_get_secrets_finish (NM_REMOTE_CONNECTION (conn), result, &error); + if (variant == NULL) { + g_warning ("Unable to fetch secrets: %s", error->message); + gtk_image_set_from_icon_name (self->image, "face-sad-symbolic", -1); + gtk_entry_set_text (self->entry, ""); + return; + } + if (!nm_connection_update_secrets (conn, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + variant, + &error)) { + g_warning ("Unable to set secrets: %s", error->message); + gtk_image_set_from_icon_name (self->image, "face-sad-symbolic", -1); + gtk_entry_set_text (self->entry, ""); + return; + } + + cnx_str = get_qr_string_for_connection (conn); + scale = gtk_widget_get_scale_factor (GTK_WIDGET (self->image)); + surface = qr_from_text (cnx_str, QR_CODE_SIZE, scale); + password = get_wifi_password (conn); + gtk_image_set_from_surface (self->image, surface); + gtk_entry_set_text (self->entry, password); + nm_connection_clear_secrets (conn); +} + + +static void +setup_hotspot_page (PhoshWifiHotspotStatusPage *self) +{ + NMActiveConnection *conn = phosh_wifi_manager_get_active_connection (self->wifi); + NMRemoteConnection *remote = nm_active_connection_get_connection (conn); + + nm_remote_connection_get_secrets_async (NM_REMOTE_CONNECTION (remote), + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + self->cancel, + on_secrets_ready, + self); +} + + +static void +on_wifi_notify (PhoshWifiHotspotStatusPage *self) +{ + gboolean wifi_absent = !phosh_wifi_manager_get_present (self->wifi); + gboolean wifi_disabled = !phosh_wifi_manager_get_enabled (self->wifi); + gboolean hotspot_disabled = !phosh_wifi_manager_is_hotspot_master (self->wifi); + const char *icon_name; + + if (wifi_absent) + icon_name = "network-wireless-hardware-disabled-symbolic"; + else if (wifi_disabled) + icon_name = "network-wireless-disabled-symbolic"; + else + icon_name = "network-wireless-hotspot-disabled-symbolic"; + + phosh_status_page_placeholder_set_icon_name (self->placeholder, icon_name); + gtk_widget_set_visible (GTK_WIDGET (self->turn_on_btn), !wifi_absent); + + if (hotspot_disabled) { + gtk_stack_set_visible_child_name (self->stack, "empty_state"); + } else { + gtk_stack_set_visible_child_name (self->stack, "hotspot_enabled"); + setup_hotspot_page (self); + } +} + + +static void +on_icon_press (PhoshWifiHotspotStatusPage *self) +{ + gboolean visibility = gtk_entry_get_visibility (self->entry); + const char *icon_name; + + if (visibility) + icon_name = "view-reveal-symbolic"; + else + icon_name = "view-conceal-symbolic"; + + gtk_entry_set_visibility (self->entry, !visibility); + gtk_entry_set_icon_from_icon_name (self->entry, GTK_ENTRY_ICON_SECONDARY, icon_name); +} + + +static void +on_turn_on_clicked (PhoshWifiHotspotStatusPage *self) +{ + gboolean wifi_disabled = !phosh_wifi_manager_get_enabled (self->wifi); + + if (wifi_disabled) + phosh_wifi_manager_set_enabled (self->wifi, TRUE); + else + phosh_wifi_manager_set_hotspot_master (self->wifi, TRUE); +} + + +static void +phosh_wifi_hotspot_status_page_dispose (GObject *object) +{ + PhoshWifiHotspotStatusPage *self = PHOSH_WIFI_HOTSPOT_STATUS_PAGE (object); + + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + + if (self->wifi) + g_signal_handlers_disconnect_by_data (self->wifi, self); + + G_OBJECT_CLASS (phosh_wifi_hotspot_status_page_parent_class)->dispose (object); +} + + +static void +phosh_wifi_hotspot_status_page_class_init (PhoshWifiHotspotStatusPageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = phosh_wifi_hotspot_status_page_dispose; + + gtk_widget_class_set_template_from_resource (widget_class, + "/mobi/phosh/plugins/wifi-hotspot-quick-setting/status-page.ui"); + + gtk_widget_class_bind_template_child (widget_class, PhoshWifiHotspotStatusPage, entry); + gtk_widget_class_bind_template_child (widget_class, PhoshWifiHotspotStatusPage, image); + gtk_widget_class_bind_template_child (widget_class, PhoshWifiHotspotStatusPage, placeholder); + gtk_widget_class_bind_template_child (widget_class, PhoshWifiHotspotStatusPage, stack); + gtk_widget_class_bind_template_child (widget_class, PhoshWifiHotspotStatusPage, turn_on_btn); + gtk_widget_class_bind_template_callback (widget_class, on_turn_on_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_icon_press); + + gtk_widget_class_set_css_name (widget_class, "phosh-wifi-hotspot-status-page"); +} + + +static void +phosh_wifi_hotspot_status_page_init (PhoshWifiHotspotStatusPage *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->cancel = g_cancellable_new (); + self->wifi = phosh_shell_get_wifi_manager (phosh_shell_get_default ()); + + g_return_if_fail (PHOSH_IS_WIFI_MANAGER (self->wifi)); + + g_object_connect (self->wifi, + "swapped-object-signal::notify::present", + G_CALLBACK (on_wifi_notify), self, + "swapped-object-signal::notify::enabled", + G_CALLBACK (on_wifi_notify), self, + "swapped-object-signal::notify::is-hotspot-master", + G_CALLBACK (on_wifi_notify), self, + NULL); +} + + +GtkWidget * +phosh_wifi_hotspot_status_page_new (void) +{ + return g_object_new (PHOSH_TYPE_WIFI_HOTSPOT_STATUS_PAGE, NULL); +} diff --git a/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.h b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.h new file mode 100644 index 0000000000000000000000000000000000000000..21fadc49734479cdbab3a94071e9e11dd0f4c018 --- /dev/null +++ b/plugins/wifi-hotspot-quick-setting/wifi-hotspot-status-page.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 Phosh.mobi e.V. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "status-page.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_WIFI_HOTSPOT_STATUS_PAGE phosh_wifi_hotspot_status_page_get_type () + +G_DECLARE_FINAL_TYPE (PhoshWifiHotspotStatusPage, phosh_wifi_hotspot_status_page, PHOSH, + WIFI_HOTSPOT_STATUS_PAGE, PhoshStatusPage) + +GtkWidget *phosh_wifi_hotspot_status_page_new (void); + +G_END_DECLS diff --git a/po/POTFILES.in b/po/POTFILES.in index ff029886b5a81b00ec82c148176b71dca7c030c4..5c2da31330beb9211b5381e8345c39e9ea66a108 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -141,4 +141,5 @@ plugins/upcoming-events/prefs/upcoming-events-prefs.ui plugins/scaling-quick-setting/qs.ui plugins/scaling-quick-setting/scale-row.c plugins/scaling-quick-setting/scaling-quick-setting.c +plugins/wifi-hotspot-quick-setting/status-page.ui plugins/wifi-hotspot-quick-setting/wifi-hotspot-quick-setting.c diff --git a/src/phosh-exported-symbols.txt.in b/src/phosh-exported-symbols.txt.in index 9ba715e2d71a467bd339e0bb88effa6394555425..7dd1bb69e0dc60f983d2265f73995977cab9dc31 100644 --- a/src/phosh-exported-symbols.txt.in +++ b/src/phosh-exported-symbols.txt.in @@ -41,9 +41,13 @@ # Wi-Fi Hotspot plugin wants Wi-Fi Manager phosh_shell_get_wifi_manager; + phosh_wifi_manager_get_type; + phosh_wifi_manager_get_active_connection; phosh_wifi_manager_get_enabled; + phosh_wifi_manager_get_present; phosh_wifi_manager_get_state; phosh_wifi_manager_is_hotspot_master; + phosh_wifi_manager_set_enabled; phosh_wifi_manager_set_hotspot_master; # Mobile Data wants WWan Manager diff --git a/src/wifi-manager.c b/src/wifi-manager.c index a2b9f87a2c5d5533cd08fb7d061e3948e023eed2..c3d5203dcd5bc7c16b9290b1a400096bf88c5243 100644 --- a/src/wifi-manager.c +++ b/src/wifi-manager.c @@ -1404,3 +1404,12 @@ phosh_wifi_manager_get_state (PhoshWifiManager *self) return self->state; } + + +NMActiveConnection * +phosh_wifi_manager_get_active_connection (PhoshWifiManager *self) +{ + g_return_val_if_fail (PHOSH_IS_WIFI_MANAGER (self), NULL); + + return self->active; +} diff --git a/src/wifi-manager.h b/src/wifi-manager.h index 6b6c2d4a2fed65df775ae9cb943035feff255eef..a3c42e224a04f4543d19eeb6f525dff01e38212a 100644 --- a/src/wifi-manager.h +++ b/src/wifi-manager.h @@ -32,5 +32,6 @@ void phosh_wifi_manager_connect_network (PhoshWifiManager *self, void phosh_wifi_manager_request_scan (PhoshWifiManager *self); gboolean phosh_wifi_manager_get_scanning (PhoshWifiManager *self); NMActiveConnectionState phosh_wifi_manager_get_state (PhoshWifiManager *self); +NMActiveConnection *phosh_wifi_manager_get_active_connection (PhoshWifiManager *self); G_END_DECLS