Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
ximper-shell-notification-center
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
ximper-shell-notification-center
Commits
dd0798ae
Verified
Commit
dd0798ae
authored
Mar 26, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
quick-settings: add WiFi and VPN tiles with NetworkManager integration
parent
56d36009
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1230 additions
and
2 deletions
+1230
-2
quick-settings.scss
data/style/widgets/quick-settings.scss
+10
-1
POTFILES
po/POTFILES
+2
-0
ru.po
po/ru.po
+40
-0
config.json.in
src/config.json.in
+2
-0
configSchema.json
src/configSchema.json
+1
-1
networkManagerProxy.vala
...trolCenter/widgets/quickSettings/networkManagerProxy.vala
+190
-0
quickSettings.vala
src/controlCenter/widgets/quickSettings/quickSettings.vala
+6
-0
vpnTile.vala
src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
+379
-0
wifiTile.vala
src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
+597
-0
meson.build
src/meson.build
+3
-0
No files found.
data/style/widgets/quick-settings.scss
View file @
dd0798ae
...
@@ -62,8 +62,17 @@
...
@@ -62,8 +62,17 @@
.quick-settings-submenu
{
.quick-settings-submenu
{
border-radius
:
var
(
--
border-radius
);
border-radius
:
var
(
--
border-radius
);
margin
:
5px
0
;
margin
:
5px
0
;
padding
:
4px
;
padding
:
4px
0
;
background
:
var
(
--
dialog-bg-color
);
background
:
var
(
--
dialog-bg-color
);
border
:
1px
solid
var
(
--
border-color
);
border
:
1px
solid
var
(
--
border-color
);
box-shadow
:
0px
0px
10px
var
(
--
headerbar-shade-color
);
box-shadow
:
0px
0px
10px
var
(
--
headerbar-shade-color
);
button
{
margin
:
2px
4px
;
}
separator
{
margin-top
:
4px
;
margin-bottom
:
4px
;
}
}
}
po/POTFILES
View file @
dd0798ae
...
@@ -11,4 +11,6 @@ src/controlCenter/widgets/quickSettings/tiles/powerProfilesTile.vala
...
@@ -11,4 +11,6 @@ src/controlCenter/widgets/quickSettings/tiles/powerProfilesTile.vala
src/controlCenter/widgets/quickSettings/tiles/commandTile.vala
src/controlCenter/widgets/quickSettings/tiles/commandTile.vala
src/controlCenter/widgets/quickSettings/tiles/caffeineTile.vala
src/controlCenter/widgets/quickSettings/tiles/caffeineTile.vala
src/controlCenter/widgets/quickSettings/tiles/nightLightTile.vala
src/controlCenter/widgets/quickSettings/tiles/nightLightTile.vala
src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
data/ui/notifications_widget.blp
data/ui/notifications_widget.blp
po/ru.po
View file @
dd0798ae
...
@@ -118,3 +118,43 @@ msgstr "Баланс"
...
@@ -118,3 +118,43 @@ msgstr "Баланс"
#: src/controlCenter/widgets/quickSettings/tiles/powerProfilesTile.vala:99
#: src/controlCenter/widgets/quickSettings/tiles/powerProfilesTile.vala:99
msgid "Power Saver"
msgid "Power Saver"
msgstr "Энергосбережение"
msgstr "Энергосбережение"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Wi-Fi"
msgstr "Wi-Fi"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Disabled"
msgstr "Отключён"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Not Connected"
msgstr "Не подключён"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Connecting…"
msgstr "Подключение…"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Password"
msgstr "Пароль"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Connect"
msgstr "Подключить"
#: src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
msgid "Network Settings"
msgstr "Настройки сети"
#: src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
msgid "VPN"
msgstr "VPN"
#: src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
msgid "Disconnected"
msgstr "Отключён"
#: src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
msgid "VPN Settings"
msgstr "Настройки VPN"
src/config.json.in
View file @
dd0798ae
...
@@ -37,6 +37,8 @@
...
@@ -37,6 +37,8 @@
"widget-config": {
"widget-config": {
"quick-settings": {
"quick-settings": {
"tiles": [
"tiles": [
{ "type": "wifi" },
{ "type": "vpn" },
{ "type": "power-profiles" },
{ "type": "power-profiles" },
{ "type": "dnd" },
{ "type": "dnd" },
{ "type": "dark-mode" },
{ "type": "dark-mode" },
...
...
src/configSchema.json
View file @
dd0798ae
...
@@ -459,7 +459,7 @@
...
@@ -459,7 +459,7 @@
"type"
:
{
"type"
:
{
"type"
:
"string"
,
"type"
:
"string"
,
"description"
:
"The tile type"
,
"description"
:
"The tile type"
,
"enum"
:
[
"dnd"
,
"dark-mode"
,
"power-profiles"
,
"caffeine"
,
"night-light"
,
"command"
]
"enum"
:
[
"dnd"
,
"dark-mode"
,
"power-profiles"
,
"caffeine"
,
"night-light"
,
"command"
,
"wifi"
,
"vpn"
]
},
},
"label"
:
{
"label"
:
{
"type"
:
"string"
,
"type"
:
"string"
,
...
...
src/controlCenter/widgets/quickSettings/networkManagerProxy.vala
0 → 100644
View file @
dd0798ae
namespace
XimperShellNotificationCenter.Widgets
{
[
DBus
(
name
=
"org.freedesktop.NetworkManager"
)]
public
interface
NMDBus
:
Object
{
public
abstract
bool
wireless_enabled
{
get
;
set
;
}
public
abstract
ObjectPath
[]
devices
{
owned
get
;
}
public
abstract
ObjectPath
[]
active_connections
{
owned
get
;
}
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.Device"
)]
public
interface
NMDeviceDBus
:
Object
{
public
abstract
uint
device_type
{
get
;
}
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.Device.Wireless"
)]
public
interface
NMWirelessDBus
:
Object
{
public
abstract
ObjectPath
active_access_point
{
owned
get
;
}
public
abstract
ObjectPath
[]
get_all_access_points
()
throws
GLib
.
Error
;
public
abstract
void
request_scan
(
HashTable
<
string
,
Variant
>
options
)
throws
GLib
.
Error
;
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.AccessPoint"
)]
public
interface
NMAccessPointDBus
:
Object
{
public
abstract
uint8
[]
ssid
{
owned
get
;
}
public
abstract
uint8
strength
{
get
;
}
public
abstract
uint
wpa_flags
{
get
;
}
public
abstract
uint
rsn_flags
{
get
;
}
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.Connection.Active"
)]
public
interface
NMActiveConnDBus
:
Object
{
public
abstract
bool
vpn
{
get
;
}
public
abstract
uint
state
{
get
;
}
public
abstract
ObjectPath
connection
{
owned
get
;
}
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.Settings"
)]
public
interface
NMSettingsDBus
:
Object
{
public
abstract
ObjectPath
[]
list_connections
()
throws
GLib
.
Error
;
}
[
DBus
(
name
=
"org.freedesktop.NetworkManager.Settings.Connection"
)]
public
interface
NMSettingsConnDBus
:
Object
{
public
abstract
HashTable
<
string
,
HashTable
<
string
,
Variant
>>
get_settings
()
throws
GLib
.
Error
;
}
public
class
NetworkManagerProxy
:
Object
{
public
signal
void
state_changed
();
private
NMDBus
?
nm
=
null
;
private
DBusProxy
?
nm_raw
=
null
;
private
bool
_available
=
false
;
private
bool
_has_wifi
=
false
;
private
static
NetworkManagerProxy
?
_instance
=
null
;
public
static
NetworkManagerProxy
get_instance
()
{
if
(
_instance
==
null
)
{
_instance
=
new
NetworkManagerProxy
();
}
return
_instance
;
}
public
bool
available
{
get
{
return
_available
;
}
}
public
bool
has_wifi
{
get
{
return
_has_wifi
;
}
}
private
NetworkManagerProxy
()
{
connect_dbus
.
begin
();
}
private
async
void
connect_dbus
()
{
try
{
nm
=
yield
Bus
.
get_proxy
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
"/org/freedesktop/NetworkManager"
);
nm_raw
=
nm
as
DBusProxy
;
_available
=
true
;
nm_raw
.
g_properties_changed
.
connect
(
on_props_changed
);
yield
detect_wifi
();
}
catch
(
Error
e
)
{
warning
(
"NetworkManager not available: %s"
,
e
.
message
);
}
}
private
void
on_props_changed
(
Variant
changed
,
string
[]
invalidated
)
{
state_changed
();
}
private
async
void
detect_wifi
()
{
if
(
nm
==
null
)
return
;
try
{
foreach
(
var
dev_path
in
nm
.
devices
)
{
var
dev
=
yield
Bus
.
get_proxy
<
NMDeviceDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
dev_path
);
if
(
dev
.
device_type
==
2
)
{
_has_wifi
=
true
;
return
;
}
}
}
catch
(
Error
e
)
{
warning
(
"Failed to detect WiFi: %s"
,
e
.
message
);
}
}
public
bool
get_wireless_enabled
()
{
if
(
nm
==
null
)
return
false
;
return
nm
.
wireless_enabled
;
}
public
void
set_wireless_enabled
(
bool
val
)
{
if
(
nm
==
null
)
return
;
nm
.
wireless_enabled
=
val
;
}
public
async
ObjectPath
?
get_wifi_device
()
{
if
(
nm
==
null
)
return
null
;
try
{
foreach
(
var
dev_path
in
nm
.
devices
)
{
var
dev
=
yield
Bus
.
get_proxy
<
NMDeviceDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
dev_path
);
if
(
dev
.
device_type
==
2
)
{
return
dev_path
;
}
}
}
catch
(
Error
e
)
{
warning
(
"get_wifi_device: %s"
,
e
.
message
);
}
return
null
;
}
public
unowned
NMDBus
?
get_nm
()
{
return
nm
;
}
public
async
Variant
?
call_nm
(
string
method
,
Variant
?
args
)
throws
GLib
.
Error
{
var
proxy
=
yield
new
DBusProxy
.
for_bus
(
BusType
.
SYSTEM
,
DBusProxyFlags
.
NONE
,
null
,
"org.freedesktop.NetworkManager"
,
"/org/freedesktop/NetworkManager"
,
"org.freedesktop.NetworkManager"
,
null
);
return
yield
proxy
.
call
(
method
,
args
,
DBusCallFlags
.
NONE
,
30000
,
null
);
}
public
static
string
ssid_to_string
(
uint8
[]
ssid
)
{
return
(
string
)
ssid
;
}
public
static
string
get_signal_icon
(
uint8
strength
)
{
if
(
strength
>=
80
)
{
return
"network-wireless-signal-excellent-symbolic"
;
}
else
if
(
strength
>=
60
)
{
return
"network-wireless-signal-good-symbolic"
;
}
else
if
(
strength
>=
40
)
{
return
"network-wireless-signal-ok-symbolic"
;
}
else
if
(
strength
>=
20
)
{
return
"network-wireless-signal-weak-symbolic"
;
}
return
"network-wireless-signal-none-symbolic"
;
}
}
}
src/controlCenter/widgets/quickSettings/quickSettings.vala
View file @
dd0798ae
...
@@ -28,6 +28,12 @@ namespace XimperShellNotificationCenter.Widgets {
...
@@ -28,6 +28,12 @@ namespace XimperShellNotificationCenter.Widgets {
case
"night-light"
:
case
"night-light"
:
tile
=
new
NightLightTile
(
cfg
);
tile
=
new
NightLightTile
(
cfg
);
break
;
break
;
case
"wifi"
:
tile
=
new
WifiTile
(
cfg
);
break
;
case
"vpn"
:
tile
=
new
VpnTile
(
cfg
);
break
;
default
:
default
:
warning
(
"Unknown quick-settings tile: %s"
,
warning
(
"Unknown quick-settings tile: %s"
,
type_id
);
type_id
);
...
...
src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
0 → 100644
View file @
dd0798ae
namespace
XimperShellNotificationCenter.Widgets
{
private
struct
VpnInfo
{
string
name
;
ObjectPath
conn_path
;
bool
is_active
;
ObjectPath
?
active_path
;
}
public
class
VpnTile
:
QuickSettingsTile
{
private
NetworkManagerProxy
nm_proxy
;
private
Gee
.
ArrayList
<
VpnInfo
?>
vpn_list
=
new
Gee
.
ArrayList
<
VpnInfo
?>
();
private
uint
sync_timeout
=
0
;
private
Gtk
.
Box
?
current_submenu
=
null
;
private
bool
updating_submenu
=
false
;
private
bool
connecting
=
false
;
public
VpnTile
(
Json
.
Object
?
cfg
)
{
base
(
"network-vpn-symbolic"
,
_
(
"VPN"
));
setup_arrow
();
nm_proxy
=
NetworkManagerProxy
.
get_instance
();
nm_proxy
.
state_changed
.
connect
(
schedule_sync
);
}
public
override
bool
is_available
()
{
return
nm_proxy
.
available
;
}
public
override
void
on_toggle
()
{
toggle_vpn
.
begin
();
}
public
override
void
on_cc_visibility_change
(
bool
visible
)
{
if
(
visible
)
{
sync_state
.
begin
();
}
else
{
current_submenu
=
null
;
connecting
=
false
;
}
}
private
void
schedule_sync
()
{
if
(
sync_timeout
!=
0
)
{
Source
.
remove
(
sync_timeout
);
}
sync_timeout
=
Timeout
.
add
(
500
,
()
=>
{
sync_timeout
=
0
;
on_debounced_update
.
begin
();
return
Source
.
REMOVE
;
});
}
private
async
void
on_debounced_update
()
{
bool
was_active
=
active
;
yield
sync_state
();
if
(
was_active
!=
active
)
{
connecting
=
false
;
refresh_submenu
.
begin
();
}
else
if
(!
connecting
)
{
refresh_submenu
.
begin
();
}
}
private
async
void
sync_state
()
{
yield
load_vpn_list
();
bool
any_active
=
false
;
string
?
active_name
=
null
;
foreach
(
var
vpn
in
vpn_list
)
{
if
(
vpn
.
is_active
)
{
any_active
=
true
;
active_name
=
vpn
.
name
;
break
;
}
}
active
=
any_active
;
if
(
any_active
&&
active_name
!=
null
)
{
icon
.
set_from_icon_name
(
"network-vpn-symbolic"
);
set_subtitle
(
active_name
);
}
else
{
icon
.
set_from_icon_name
(
"network-vpn-symbolic"
);
set_subtitle
(
_
(
"Disconnected"
));
}
}
private
async
void
load_vpn_list
()
{
var
new_list
=
new
Gee
.
ArrayList
<
VpnInfo
?>
();
var
seen
=
new
Gee
.
HashSet
<
string
>
();
// Get active VPN connections
var
active_vpns
=
new
Gee
.
HashMap
<
string
,
ObjectPath
>
();
try
{
var
nm
=
nm_proxy
.
get_nm
();
if
(
nm
!=
null
)
{
foreach
(
var
ac_path
in
nm
.
active_connections
)
{
try
{
var
ac
=
yield
Bus
.
get_proxy
<
NMActiveConnDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
ac_path
);
if
(
ac
.
vpn
&&
ac
.
state
==
2
)
{
active_vpns
.
set
(
(
string
)
ac
.
connection
,
ac_path
);
}
}
catch
(
Error
e
)
{
continue
;
}
}
}
}
catch
(
Error
e
)
{}
// Get saved VPN connections
try
{
var
settings
=
yield
Bus
.
get_proxy
<
NMSettingsDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
"/org/freedesktop/NetworkManager/"
+
"Settings"
);
foreach
(
var
conn_path
in
settings
.
list_connections
())
{
try
{
var
conn
=
yield
Bus
.
get_proxy
<
NMSettingsConnDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
conn_path
);
var
s
=
conn
.
get_settings
();
var
conn_s
=
s
.
lookup
(
"connection"
);
if
(
conn_s
==
null
)
continue
;
var
type_var
=
conn_s
.
lookup
(
"type"
);
if
(
type_var
==
null
||
type_var
.
get_string
()
!=
"vpn"
)
{
continue
;
}
var
id_var
=
conn_s
.
lookup
(
"id"
);
string
name
=
id_var
!=
null
?
id_var
.
get_string
()
:
"VPN"
;
string
key
=
(
string
)
conn_path
;
if
(
seen
.
contains
(
key
))
continue
;
seen
.
add
(
key
);
bool
is_act
=
active_vpns
.
has_key
(
key
);
ObjectPath
?
act_path
=
is_act
?
active_vpns
.
get
(
key
)
:
null
;
new_list
.
add
(
VpnInfo
()
{
name
=
name
,
conn_path
=
conn_path
,
is_active
=
is_act
,
active_path
=
act_path
,
});
}
catch
(
Error
e
)
{
continue
;
}
}
}
catch
(
Error
e
)
{
warning
(
"load_vpn_list: %s"
,
e
.
message
);
}
vpn_list
=
new_list
;
}
private
async
void
toggle_vpn
()
{
// Find first active VPN to deactivate
foreach
(
var
vpn
in
vpn_list
)
{
if
(
vpn
.
is_active
&&
vpn
.
active_path
!=
null
)
{
yield
deactivate_vpn
(
vpn
.
active_path
);
return
;
}
}
// No active VPN — activate first in list
if
(
vpn_list
.
size
>
0
)
{
yield
activate_vpn
(
vpn_list
.
get
(
0
).
conn_path
);
}
}
private
async
void
activate_vpn
(
ObjectPath
conn_path
)
{
try
{
yield
nm_proxy
.
call_nm
(
"ActivateConnection"
,
new
Variant
(
"(ooo)"
,
conn_path
,
new
ObjectPath
(
"/"
),
new
ObjectPath
(
"/"
)));
}
catch
(
Error
e
)
{
warning
(
"activate_vpn: %s"
,
e
.
message
);
}
}
private
async
void
deactivate_vpn
(
ObjectPath
active_path
)
{
try
{
yield
nm_proxy
.
call_nm
(
"DeactivateConnection"
,
new
Variant
(
"(o)"
,
active_path
));
}
catch
(
Error
e
)
{
warning
(
"deactivate_vpn: %s"
,
e
.
message
);
}
}
private
async
void
deactivate_by_conn
(
ObjectPath
conn_path
)
{
try
{
var
nm
=
nm_proxy
.
get_nm
();
if
(
nm
==
null
)
return
;
foreach
(
var
ac_path
in
nm
.
active_connections
)
{
try
{
var
ac
=
yield
Bus
.
get_proxy
<
NMActiveConnDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
ac_path
);
if
(
ac
.
vpn
&&
(
string
)
ac
.
connection
==
(
string
)
conn_path
)
{
yield
deactivate_vpn
(
ac_path
);
return
;
}
}
catch
(
Error
e
)
{
continue
;
}
}
}
catch
(
Error
e
)
{
warning
(
"deactivate_by_conn: %s"
,
e
.
message
);
}
}
// Submenu
public
override
Gtk
.
Widget
?
create_submenu
()
{
var
box
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
VERTICAL
,
0
);
box
.
add_css_class
(
"quick-settings-submenu"
);
current_submenu
=
box
;
refresh_submenu
.
begin
();
return
box
;
}
private
async
void
refresh_submenu
()
{
if
(
current_submenu
==
null
)
return
;
if
(
updating_submenu
)
return
;
updating_submenu
=
true
;
yield
load_vpn_list
();
if
(
current_submenu
!=
null
)
{
for
(
var
child
=
current_submenu
.
get_first_child
();
child
!=
null
;)
{
var
next
=
child
.
get_next_sibling
();
current_submenu
.
remove
(
child
);
child
=
next
;
}
build_vpn_list
(
current_submenu
);
}
updating_submenu
=
false
;
}
private
void
build_vpn_list
(
Gtk
.
Box
box
)
{
foreach
(
var
vpn
in
vpn_list
)
{
var
row
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
8
);
row
.
add_css_class
(
"submenu-row"
);
var
row_icon
=
new
Gtk
.
Image
.
from_icon_name
(
"network-vpn-symbolic"
);
var
row_label
=
new
Gtk
.
Label
(
vpn
.
name
);
row_label
.
set_ellipsize
(
Pango
.
EllipsizeMode
.
END
);
row_label
.
set_hexpand
(
true
);
row_label
.
set_halign
(
Gtk
.
Align
.
START
);
var
vpn_switch
=
new
Gtk
.
Switch
();
vpn_switch
.
set_valign
(
Gtk
.
Align
.
CENTER
);
vpn_switch
.
set_active
(
vpn
.
is_active
);
ObjectPath
conn_path
=
vpn
.
conn_path
;
// Connect AFTER initial set_active
Idle
.
add_once
(()
=>
{
vpn_switch
.
state_set
.
connect
((
state
)
=>
{
connecting
=
true
;
if
(
state
)
{
activate_vpn
.
begin
(
conn_path
);
}
else
{
deactivate_by_conn
.
begin
(
conn_path
);
}
return
true
;
});
});
row
.
append
(
row_icon
);
row
.
append
(
row_label
);
row
.
append
(
vpn_switch
);
var
btn
=
new
Gtk
.
Button
();
btn
.
set_child
(
row
);
btn
.
add_css_class
(
"flat"
);
btn
.
clicked
.
connect
(()
=>
{
vpn_switch
.
set_active
(
!
vpn_switch
.
active
);
});
box
.
append
(
btn
);
}
// Settings button
build_settings_button
(
box
);
}
private
void
build_settings_button
(
Gtk
.
Box
box
)
{
string
?
cmd
=
get_settings_command
();
if
(
cmd
==
null
)
return
;
if
(
vpn_list
.
size
>
0
)
{
box
.
append
(
new
Gtk
.
Separator
(
Gtk
.
Orientation
.
HORIZONTAL
));
}
var
row
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
8
);
row
.
add_css_class
(
"submenu-row"
);
row
.
append
(
new
Gtk
.
Image
.
from_icon_name
(
"emblem-system-symbolic"
));
var
label
=
new
Gtk
.
Label
(
_
(
"VPN Settings"
));
label
.
set_hexpand
(
true
);
label
.
set_halign
(
Gtk
.
Align
.
START
);
row
.
append
(
label
);
var
btn
=
new
Gtk
.
Button
();
btn
.
set_child
(
row
);
btn
.
add_css_class
(
"flat"
);
btn
.
clicked
.
connect
(()
=>
{
try
{
Process
.
spawn_command_line_async
(
cmd
);
ximper_shell_notification_center_daemon
.
set_visibility
(
false
);
}
catch
(
Error
e
)
{
warning
(
"Settings: %s"
,
e
.
message
);
}
});
box
.
append
(
btn
);
}
private
static
string
?
get_settings_command
()
{
try
{
string
output
;
Process
.
spawn_command_line_sync
(
"which nm-connection-editor"
,
out
output
,
null
,
null
);
if
(
output
.
strip
().
length
>
0
)
{
return
"nm-connection-editor"
;
}
}
catch
(
SpawnError
e
)
{}
return
null
;
}
}
}
src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
0 → 100644
View file @
dd0798ae
namespace
XimperShellNotificationCenter.Widgets
{
private
struct
ApInfo
{
string
ssid
;
uint8
strength
;
bool
secured
;
bool
is_active
;
ObjectPath
ap_path
;
bool
has_saved
;
ObjectPath
?
saved_path
;
}
public
class
WifiTile
:
QuickSettingsTile
{
private
NetworkManagerProxy
nm_proxy
;
private
ObjectPath
?
wifi_dev_path
=
null
;
private
string
?
active_ssid
=
null
;
private
uint8
active_strength
=
0
;
private
Gee
.
HashSet
<
string
>
?
saved_ssids
=
null
;
private
Gee
.
HashMap
<
string
,
ObjectPath
>
?
saved_map
=
null
;
private
uint
sync_timeout
=
0
;
private
Gtk
.
Box
?
current_submenu
=
null
;
private
bool
connecting
=
false
;
private
bool
updating_submenu
=
false
;
public
WifiTile
(
Json
.
Object
?
cfg
)
{
base
(
"network-wireless-offline-symbolic"
,
_
(
"Wi-Fi"
));
setup_arrow
();
nm_proxy
=
NetworkManagerProxy
.
get_instance
();
nm_proxy
.
state_changed
.
connect
(
schedule_sync
);
init_wifi
.
begin
();
}
private
void
schedule_sync
()
{
if
(
sync_timeout
!=
0
)
{
Source
.
remove
(
sync_timeout
);
}
sync_timeout
=
Timeout
.
add
(
1000
,
()
=>
{
sync_timeout
=
0
;
on_debounced_update
.
begin
();
return
Source
.
REMOVE
;
});
}
private
async
void
on_debounced_update
()
{
string
?
old_ssid
=
active_ssid
;
yield
sync_state
();
if
(
old_ssid
!=
active_ssid
)
{
connecting
=
false
;
refresh_submenu
.
begin
();
}
else
if
(!
connecting
)
{
refresh_submenu
.
begin
();
}
}
private
async
void
init_wifi
()
{
wifi_dev_path
=
yield
nm_proxy
.
get_wifi_device
();
yield
sync_state
();
}
public
override
bool
is_available
()
{
return
nm_proxy
.
available
&&
nm_proxy
.
has_wifi
;
}
public
override
void
on_toggle
()
{
nm_proxy
.
set_wireless_enabled
(
!
nm_proxy
.
get_wireless_enabled
());
}
public
override
void
on_cc_visibility_change
(
bool
visible
)
{
if
(
visible
)
{
sync_state
.
begin
();
scan
.
begin
();
}
else
{
current_submenu
=
null
;
connecting
=
false
;
}
}
private
async
void
sync_state
()
{
if
(
wifi_dev_path
==
null
&&
nm_proxy
.
available
)
{
wifi_dev_path
=
yield
nm_proxy
.
get_wifi_device
();
}
bool
enabled
=
nm_proxy
.
get_wireless_enabled
();
active
=
enabled
;
if
(!
enabled
)
{
icon
.
set_from_icon_name
(
"network-wireless-disabled-symbolic"
);
set_subtitle
(
_
(
"Disabled"
));
active_ssid
=
null
;
return
;
}
active_ssid
=
null
;
active_strength
=
0
;
if
(
wifi_dev_path
!=
null
)
{
try
{
var
wireless
=
yield
Bus
.
get_proxy
<
NMWirelessDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
wifi_dev_path
);
ObjectPath
ap_path
=
wireless
.
active_access_point
;
if
(
ap_path
!=
null
&&
ap_path
!=
"/"
&&
ap_path
!=
""
)
{
var
ap
=
yield
Bus
.
get_proxy
<
NMAccessPointDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
ap_path
);
active_ssid
=
NetworkManagerProxy
.
ssid_to_string
(
ap
.
ssid
);
active_strength
=
ap
.
strength
;
}
}
catch
(
Error
e
)
{}
}
if
(
active_ssid
!=
null
&&
active_ssid
.
length
>
0
)
{
icon
.
set_from_icon_name
(
NetworkManagerProxy
.
get_signal_icon
(
active_strength
));
set_subtitle
(
active_ssid
);
connecting
=
false
;
}
else
if
(!
connecting
)
{
icon
.
set_from_icon_name
(
"network-wireless-offline-symbolic"
);
set_subtitle
(
_
(
"Not Connected"
));
}
}
private
async
void
scan
()
{
if
(
wifi_dev_path
==
null
)
return
;
try
{
var
wireless
=
yield
Bus
.
get_proxy
<
NMWirelessDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
wifi_dev_path
);
wireless
.
request_scan
(
new
HashTable
<
string
,
Variant
>
(
str_hash
,
str_equal
));
}
catch
(
Error
e
)
{}
}
private
async
ApInfo
[]
get_access_points
()
{
ApInfo
[]
result
=
{};
if
(
wifi_dev_path
==
null
)
return
result
;
yield
load_saved_connections
();
try
{
var
wireless
=
yield
Bus
.
get_proxy
<
NMWirelessDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
wifi_dev_path
);
var
ap_paths
=
wireless
.
get_all_access_points
();
var
best
=
new
Gee
.
HashMap
<
string
,
ApInfo
?>
();
foreach
(
var
ap_path
in
ap_paths
)
{
try
{
var
ap
=
yield
Bus
.
get_proxy
<
NMAccessPointDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
ap_path
);
string
ssid
=
NetworkManagerProxy
.
ssid_to_string
(
ap
.
ssid
);
if
(
ssid
==
null
||
ssid
.
length
==
0
)
{
continue
;
}
bool
secured
=
ap
.
wpa_flags
!=
0
||
ap
.
rsn_flags
!=
0
;
bool
is_act
=
active_ssid
!=
null
&&
ssid
==
active_ssid
;
bool
has_saved
=
saved_ssids
!=
null
&&
saved_ssids
.
contains
(
ssid
);
ObjectPath
?
sp
=
has_saved
&&
saved_map
!=
null
?
saved_map
.
get
(
ssid
)
:
null
;
var
info
=
ApInfo
()
{
ssid
=
ssid
,
strength
=
ap
.
strength
,
secured
=
secured
,
is_active
=
is_act
,
ap_path
=
ap_path
,
has_saved
=
has_saved
,
saved_path
=
sp
,
};
if
(!
best
.
has_key
(
ssid
)
||
best
.
get
(
ssid
).
strength
<
ap
.
strength
)
{
best
.
set
(
ssid
,
info
);
}
}
catch
(
Error
e
)
{
continue
;
}
}
var
sorted
=
new
Gee
.
ArrayList
<
ApInfo
?>
();
foreach
(
var
v
in
best
.
values
)
{
sorted
.
add
(
v
);
}
sorted
.
sort
((
a
,
b
)
=>
{
if
(
a
.
is_active
!=
b
.
is_active
)
{
return
a
.
is_active
?
-
1
:
1
;
}
return
(
int
)
b
.
strength
-
(
int
)
a
.
strength
;
});
foreach
(
var
info
in
sorted
)
{
result
+=
info
;
}
}
catch
(
Error
e
)
{
warning
(
"get_access_points: %s"
,
e
.
message
);
}
return
result
;
}
private
async
void
load_saved_connections
()
{
saved_ssids
=
new
Gee
.
HashSet
<
string
>
();
saved_map
=
new
Gee
.
HashMap
<
string
,
ObjectPath
>
();
try
{
var
settings
=
yield
Bus
.
get_proxy
<
NMSettingsDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
"/org/freedesktop/NetworkManager/"
+
"Settings"
);
foreach
(
var
conn_path
in
settings
.
list_connections
())
{
try
{
var
conn
=
yield
Bus
.
get_proxy
<
NMSettingsConnDBus
>
(
BusType
.
SYSTEM
,
"org.freedesktop.NetworkManager"
,
conn_path
);
var
s
=
conn
.
get_settings
();
var
wifi_s
=
s
.
lookup
(
"802-11-wireless"
);
if
(
wifi_s
==
null
)
continue
;
var
ssid_var
=
wifi_s
.
lookup
(
"ssid"
);
if
(
ssid_var
==
null
)
continue
;
string
ssid
=
NetworkManagerProxy
.
ssid_to_string
(
ssid_var
.
get_data_as_bytes
()
.
get_data
());
if
(
ssid
.
length
>
0
)
{
saved_ssids
.
add
(
ssid
);
saved_map
.
set
(
ssid
,
conn_path
);
}
}
catch
(
Error
e
)
{
continue
;
}
}
}
catch
(
Error
e
)
{
warning
(
"load_saved: %s"
,
e
.
message
);
}
}
// Submenu
public
override
Gtk
.
Widget
?
create_submenu
()
{
if
(!
nm_proxy
.
get_wireless_enabled
())
{
current_submenu
=
null
;
return
null
;
}
var
box
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
VERTICAL
,
0
);
box
.
add_css_class
(
"quick-settings-submenu"
);
current_submenu
=
box
;
refresh_submenu
.
begin
();
return
box
;
}
private
async
void
refresh_submenu
()
{
if
(
current_submenu
==
null
)
return
;
if
(
updating_submenu
)
return
;
updating_submenu
=
true
;
var
aps
=
yield
get_access_points
();
if
(
current_submenu
!=
null
)
{
for
(
var
child
=
current_submenu
.
get_first_child
();
child
!=
null
;)
{
var
next
=
child
.
get_next_sibling
();
current_submenu
.
remove
(
child
);
child
=
next
;
}
build_ap_list
(
current_submenu
,
aps
);
}
updating_submenu
=
false
;
}
private
void
build_ap_list
(
Gtk
.
Box
box
,
ApInfo
[]
aps
)
{
foreach
(
var
ap
in
aps
)
{
var
row
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
8
);
row
.
add_css_class
(
"submenu-row"
);
var
row_icon
=
new
Gtk
.
Image
.
from_icon_name
(
NetworkManagerProxy
.
get_signal_icon
(
ap
.
strength
));
var
row_label
=
new
Gtk
.
Label
(
ap
.
ssid
);
row_label
.
set_ellipsize
(
Pango
.
EllipsizeMode
.
END
);
row_label
.
set_hexpand
(
true
);
row_label
.
set_halign
(
Gtk
.
Align
.
START
);
var
status_stack
=
new
Gtk
.
Stack
();
status_stack
.
set_transition_type
(
Gtk
.
StackTransitionType
.
CROSSFADE
);
var
check_img
=
new
Gtk
.
Image
.
from_icon_name
(
"object-select-symbolic"
);
var
lock_img
=
new
Gtk
.
Image
.
from_icon_name
(
"network-wireless-encrypted-symbolic"
);
var
spinner
=
new
Gtk
.
Spinner
();
var
empty
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
0
);
status_stack
.
add_named
(
check_img
,
"check"
);
status_stack
.
add_named
(
lock_img
,
"lock"
);
status_stack
.
add_named
(
spinner
,
"spinner"
);
status_stack
.
add_named
(
empty
,
"empty"
);
if
(
ap
.
is_active
)
{
status_stack
.
set_visible_child_name
(
"check"
);
}
else
if
(
ap
.
secured
&&
!
ap
.
has_saved
)
{
status_stack
.
set_visible_child_name
(
"lock"
);
}
else
{
status_stack
.
set_visible_child_name
(
"empty"
);
}
row
.
append
(
row_icon
);
row
.
append
(
row_label
);
row
.
append
(
status_stack
);
var
item_box
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
VERTICAL
,
0
);
var
btn
=
new
Gtk
.
Button
();
btn
.
set_child
(
row
);
btn
.
add_css_class
(
"flat"
);
item_box
.
append
(
btn
);
if
(
ap
.
secured
&&
!
ap
.
has_saved
&&
!
ap
.
is_active
)
{
build_password_row
(
item_box
,
btn
,
status_stack
,
spinner
,
ap
);
}
else
if
(!
ap
.
is_active
)
{
build_connect_handler
(
btn
,
status_stack
,
spinner
,
ap
);
}
box
.
append
(
item_box
);
}
// Settings button
build_settings_button
(
box
);
}
private
void
build_password_row
(
Gtk
.
Box
item_box
,
Gtk
.
Button
btn
,
Gtk
.
Stack
status_stack
,
Gtk
.
Spinner
spinner
,
ApInfo
ap
)
{
var
pwd_revealer
=
new
Gtk
.
Revealer
();
pwd_revealer
.
set_transition_type
(
Gtk
.
RevealerTransitionType
.
SLIDE_DOWN
);
pwd_revealer
.
set_transition_duration
(
150
);
var
pwd_box
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
4
);
pwd_box
.
set_margin_start
(
8
);
pwd_box
.
set_margin_end
(
8
);
pwd_box
.
set_margin_bottom
(
4
);
var
pwd_entry
=
new
Gtk
.
PasswordEntry
();
pwd_entry
.
set_hexpand
(
true
);
pwd_entry
.
placeholder_text
=
_
(
"Password"
);
pwd_entry
.
set_show_peek_icon
(
true
);
var
connect_btn
=
new
Gtk
.
Button
.
with_label
(
_
(
"Connect"
));
connect_btn
.
set_sensitive
(
false
);
pwd_entry
.
notify
[
"text"
].
connect
(()
=>
{
connect_btn
.
set_sensitive
(
pwd_entry
.
get_text
().
strip
().
length
>=
8
);
});
pwd_box
.
append
(
pwd_entry
);
pwd_box
.
append
(
connect_btn
);
pwd_revealer
.
set_child
(
pwd_box
);
item_box
.
append
(
pwd_revealer
);
btn
.
clicked
.
connect
(()
=>
{
pwd_revealer
.
set_reveal_child
(
!
pwd_revealer
.
get_reveal_child
());
if
(
pwd_revealer
.
get_reveal_child
())
{
pwd_entry
.
grab_focus
();
}
});
string
ssid
=
ap
.
ssid
;
connect_btn
.
clicked
.
connect
(()
=>
{
string
pwd
=
pwd_entry
.
get_text
().
strip
();
if
(
pwd
.
length
>
0
)
{
pwd_revealer
.
set_reveal_child
(
false
);
start_connecting
(
status_stack
,
spinner
);
connect_new
.
begin
(
ssid
,
pwd
);
}
});
pwd_entry
.
activate
.
connect
(()
=>
{
connect_btn
.
clicked
();
});
}
private
void
build_connect_handler
(
Gtk
.
Button
btn
,
Gtk
.
Stack
status_stack
,
Gtk
.
Spinner
spinner
,
ApInfo
ap
)
{
ObjectPath
?
sp
=
ap
.
saved_path
;
ObjectPath
ap_path
=
ap
.
ap_path
;
string
ssid
=
ap
.
ssid
;
bool
secured
=
ap
.
secured
;
btn
.
clicked
.
connect
(()
=>
{
start_connecting
(
status_stack
,
spinner
);
if
(
sp
!=
null
)
{
activate_saved
.
begin
(
sp
,
ap_path
);
}
else
if
(!
secured
)
{
connect_new
.
begin
(
ssid
,
""
);
}
});
}
private
void
start_connecting
(
Gtk
.
Stack
stack
,
Gtk
.
Spinner
spinner
)
{
stack
.
set_visible_child_name
(
"spinner"
);
spinner
.
start
();
connecting
=
true
;
set_subtitle
(
_
(
"Connecting\u2026"
));
}
private
void
build_settings_button
(
Gtk
.
Box
box
)
{
string
?
cmd
=
get_settings_command
();
if
(
cmd
==
null
)
return
;
box
.
append
(
new
Gtk
.
Separator
(
Gtk
.
Orientation
.
HORIZONTAL
));
var
row
=
new
Gtk
.
Box
(
Gtk
.
Orientation
.
HORIZONTAL
,
8
);
row
.
add_css_class
(
"submenu-row"
);
row
.
append
(
new
Gtk
.
Image
.
from_icon_name
(
"emblem-system-symbolic"
));
var
label
=
new
Gtk
.
Label
(
_
(
"Network Settings"
));
label
.
set_hexpand
(
true
);
label
.
set_halign
(
Gtk
.
Align
.
START
);
row
.
append
(
label
);
var
btn
=
new
Gtk
.
Button
();
btn
.
set_child
(
row
);
btn
.
add_css_class
(
"flat"
);
btn
.
clicked
.
connect
(()
=>
{
try
{
Process
.
spawn_command_line_async
(
cmd
);
ximper_shell_notification_center_daemon
.
set_visibility
(
false
);
}
catch
(
Error
e
)
{
warning
(
"Settings: %s"
,
e
.
message
);
}
});
box
.
append
(
btn
);
}
private
static
string
?
get_settings_command
()
{
try
{
string
output
;
Process
.
spawn_command_line_sync
(
"which nm-connection-editor"
,
out
output
,
null
,
null
);
if
(
output
.
strip
().
length
>
0
)
{
return
"nm-connection-editor"
;
}
}
catch
(
SpawnError
e
)
{}
return
null
;
}
// Connection methods
private
async
void
activate_saved
(
ObjectPath
conn_path
,
ObjectPath
ap_path
)
{
if
(
wifi_dev_path
==
null
)
return
;
try
{
yield
nm_proxy
.
call_nm
(
"ActivateConnection"
,
new
Variant
(
"(ooo)"
,
conn_path
,
wifi_dev_path
,
ap_path
));
}
catch
(
Error
e
)
{
warning
(
"activate_saved: %s"
,
e
.
message
);
connecting
=
false
;
}
}
private
async
void
connect_new
(
string
ssid
,
string
psk
)
{
if
(
wifi_dev_path
==
null
)
return
;
try
{
yield
nm_proxy
.
call_nm
(
"AddAndActivateConnection"
,
new
Variant
(
"(a{sa{sv}}oo)"
,
build_wifi_settings
(
ssid
,
psk
),
wifi_dev_path
,
new
ObjectPath
(
"/"
)));
}
catch
(
Error
e
)
{
warning
(
"connect_new: %s"
,
e
.
message
);
connecting
=
false
;
}
}
private
HashTable
<
string
,
HashTable
<
string
,
Variant
>>
build_wifi_settings
(
string
ssid
,
string
psk
)
{
var
result
=
new
HashTable
<
string
,
HashTable
<
string
,
Variant
>>
(
str_hash
,
str_equal
);
var
conn
=
new
HashTable
<
string
,
Variant
>
(
str_hash
,
str_equal
);
conn
.
insert
(
"type"
,
new
Variant
.
string
(
"802-11-wireless"
));
conn
.
insert
(
"id"
,
new
Variant
.
string
(
ssid
));
string
user
=
Environment
.
get_user_name
();
var
perms
=
new
VariantBuilder
(
new
VariantType
(
"as"
));
perms
.
add
(
"s"
,
"user:%s:"
.
printf
(
user
));
conn
.
insert
(
"permissions"
,
perms
.
end
());
result
.
insert
(
"connection"
,
conn
);
var
wifi
=
new
HashTable
<
string
,
Variant
>
(
str_hash
,
str_equal
);
var
ssid_builder
=
new
VariantBuilder
(
new
VariantType
(
"ay"
));
for
(
int
i
=
0
;
i
<
ssid
.
data
.
length
;
i
++)
{
ssid_builder
.
add
(
"y"
,
ssid
.
data
[
i
]);
}
wifi
.
insert
(
"ssid"
,
ssid_builder
.
end
());
result
.
insert
(
"802-11-wireless"
,
wifi
);
if
(
psk
.
length
>
0
)
{
var
sec
=
new
HashTable
<
string
,
Variant
>
(
str_hash
,
str_equal
);
sec
.
insert
(
"key-mgmt"
,
new
Variant
.
string
(
"wpa-psk"
));
sec
.
insert
(
"psk"
,
new
Variant
.
string
(
psk
));
result
.
insert
(
"802-11-wireless-security"
,
sec
);
}
return
result
;
}
}
}
src/meson.build
View file @
dd0798ae
...
@@ -52,6 +52,9 @@ widget_sources = [
...
@@ -52,6 +52,9 @@ widget_sources = [
'controlCenter/widgets/quickSettings/tiles/commandTile.vala',
'controlCenter/widgets/quickSettings/tiles/commandTile.vala',
'controlCenter/widgets/quickSettings/tiles/caffeineTile.vala',
'controlCenter/widgets/quickSettings/tiles/caffeineTile.vala',
'controlCenter/widgets/quickSettings/tiles/nightLightTile.vala',
'controlCenter/widgets/quickSettings/tiles/nightLightTile.vala',
'controlCenter/widgets/quickSettings/networkManagerProxy.vala',
'controlCenter/widgets/quickSettings/tiles/wifiTile.vala',
'controlCenter/widgets/quickSettings/tiles/vpnTile.vala',
]
]
app_sources = [
app_sources = [
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment