@@ -19,6 +19,17 @@ const KIB_TO_B = 1024; // 1 KiB = 1,024 B
1919const UUID = "system-monitor-graph@rcassani" ;
2020const DESKLET_PATH = imports . ui . deskletManager . deskletMeta [ UUID ] . path ;
2121
22+ // Borrowed from battery@schorschii
23+ const UPowerInterface = `<node>
24+ <interface name="org.freedesktop.UPower.Device">
25+ <property name="TimeToEmpty" type="x" access="read" />
26+ <property name="TimeToFull" type="x" access="read" />
27+ </interface>
28+ </node>` ;
29+
30+ const UPowerProxy = Gio . DBusProxy . makeProxyWrapper ( UPowerInterface ) ;
31+ const UPowerBusName = "org.freedesktop.UPower" ;
32+
2233Gettext . bindtextdomain ( UUID , GLib . get_home_dir ( ) + "/.local/share/locale" ) ;
2334
2435function _ ( str ) {
@@ -48,6 +59,7 @@ SystemMonitorGraph.prototype = {
4859 this . settings . bindProperty ( Settings . BindingDirection . IN , "data-prefix-gpumem" , "data_prefix_gpumem" , this . on_setting_changed ) ;
4960 this . settings . bindProperty ( Settings . BindingDirection . IN , "data-prefix-network" , "data_prefix_network" , this . on_setting_changed ) ;
5061 this . settings . bindProperty ( Settings . BindingDirection . IN , "network-interface" , "network_interface" , this . on_setting_changed ) ;
62+ this . settings . bindProperty ( Settings . BindingDirection . IN , "battery-name" , "battery_name" , this . on_setting_changed ) ;
5163 this . settings . bindProperty ( Settings . BindingDirection . IN , "filesystem" , "filesystem" , this . on_setting_changed ) ;
5264 this . settings . bindProperty ( Settings . BindingDirection . IN , "filesystem-label" , "filesystem_label" , this . on_setting_changed ) ;
5365 this . settings . bindProperty ( Settings . BindingDirection . IN , "gpu-manufacturer" , "gpu_manufacturer" , this . on_setting_changed ) ;
@@ -68,6 +80,7 @@ SystemMonitorGraph.prototype = {
6880 this . settings . bindProperty ( Settings . BindingDirection . IN , "line-color-gpu" , "line_color_gpu" , this . on_setting_changed ) ;
6981 this . settings . bindProperty ( Settings . BindingDirection . IN , "line-color-network-down" , "line_color_network_down" , this . on_setting_changed ) ;
7082 this . settings . bindProperty ( Settings . BindingDirection . IN , "line-color-network-up" , "line_color_network_up" , this . on_setting_changed ) ;
83+ this . settings . bindProperty ( Settings . BindingDirection . IN , "line-color-battery" , "line_color_battery" , this . on_setting_changed ) ;
7184
7285 // initialize desklet GUI
7386 this . setupUI ( ) ;
@@ -122,6 +135,11 @@ SystemMonitorGraph.prototype = {
122135 this . net_down_speed = 0 ;
123136 this . net_up_speed = 0 ;
124137 this . net_max_scale = 1 ; // Auto-scaling for network graph
138+ // battery values
139+ this . battery_percent = NaN ;
140+ this . battery_capacity = NaN ;
141+ this . battery_status = "" ;
142+ this . battery_time = "" ;
125143
126144 // set colors
127145 switch ( this . type ) {
@@ -145,6 +163,9 @@ SystemMonitorGraph.prototype = {
145163 this . line_color_down = this . line_color_network_down ;
146164 this . line_color_up = this . line_color_network_up ;
147165 break ;
166+ case "battery" :
167+ this . line_color = this . line_color_battery ;
168+ break ;
148169 }
149170 this . first_run = false ;
150171 }
@@ -296,6 +317,18 @@ SystemMonitorGraph.prototype = {
296317 text2 = "" ;
297318 text3 = "↓ " + down_speed_formatted + " ↑ " + up_speed_formatted ;
298319 break ;
320+
321+ case "battery" :
322+ this . get_battery_use ( ) ;
323+ value = this . battery_capacity ;
324+ text1 = _ ( "Battery" ) ;
325+ text2 = this . battery_percent + "%" ;
326+ let prefix = ( this . battery_status == "Charging" ) ? "⚡ " : ( this . battery_percent <= 20 ? "🪫 " : "🔋 " ) ;
327+ text3 = ( this . battery_status == "Full" ) ? "🔋 " + _ ( "Fully charged" ) :
328+ ( this . battery_status == "Not charging" ) ? "🔌 " + _ ( "Not charging" ) :
329+ ( this . battery_status == "" || this . battery_status == "Unknown" ) ? "" :
330+ prefix + this . battery_time + _ ( " hrs" ) ;
331+ break ;
299332 }
300333
301334 // For non-network types, concatenate new value to the main values array
@@ -963,6 +996,58 @@ SystemMonitorGraph.prototype = {
963996 }
964997 GLib . free ( contents ) ;
965998 } ) ;
966- }
999+ } ,
1000+
1001+
1002+ get_battery_use : function ( ) {
1003+ // Sysfs directory for battery info
1004+ let battery_dir = "/sys/class/power_supply/" + this . battery_name + "/" ;
1005+ // D-Bus object path for the battery device in the UPower daemon
1006+ let bus_path = "/org/freedesktop/UPower/devices/battery_" + this . battery_name ;
1007+
1008+ // File capacity contains the battery charge percentage, integer number from 0 to 100
1009+ Gio . file_new_for_path ( battery_dir + "capacity" ) . load_contents_async ( null , ( file , response ) => {
1010+ try {
1011+ let [ success , contents , tag ] = file . load_contents_finish ( response ) ;
1012+ if ( success ) {
1013+ let percent = parseInt ( ByteArray . toString ( contents ) ) ;
1014+ this . battery_percent = percent >= 100 ? 100 : percent ;
1015+ this . battery_capacity = this . battery_percent / 100.0 ;
1016+ }
1017+ GLib . free ( contents ) ;
1018+ } catch ( error ) {
1019+ global . log ( 'Battery capacity file read error: ' + error . toString ( ) ) ;
1020+ }
1021+ } ) ;
1022+
1023+ // File status contains the battery charge status, string
1024+ Gio . file_new_for_path ( battery_dir + "status" ) . load_contents_async ( null , ( file , response ) => {
1025+ try {
1026+ let [ success , contents , tag ] = file . load_contents_finish ( response ) ;
1027+ if ( success ) {
1028+ this . battery_status = ByteArray . toString ( contents ) . trim ( ) ;
1029+ }
1030+ GLib . free ( contents ) ;
1031+ } catch ( error ) {
1032+ global . log ( 'Battery status file read error: ' + error . toString ( ) ) ;
1033+ }
1034+ } ) ;
1035+
1036+ try {
1037+ let upower_proxy = new UPowerProxy ( Gio . DBus . system , UPowerBusName , bus_path ) ;
1038+ let time_sec = ( this . battery_status == "Charging" ) ? upower_proxy . TimeToFull : upower_proxy . TimeToEmpty ;
1039+ this . battery_time = this . formatTime ( time_sec ) ;
1040+ } catch ( error ) {
1041+ global . log ( 'Battery time file open error: ' + error . toString ( ) ) ;
1042+ }
1043+ } ,
1044+
1045+ formatTime : function ( timeSec ) {
1046+ let totalMinutes = Math . round ( timeSec / 60 ) ;
1047+ let minutes = String ( Math . floor ( totalMinutes % 60 ) ) . padStart ( 2 , '0' ) ;
1048+ let hours = String ( Math . floor ( totalMinutes / 60 ) ) . padStart ( 2 , '0' ) ;
1049+ let result = `${ hours } :${ minutes } ` ;
1050+ return ( result == "00:00" ) ? "--:--" : result ;
1051+ }
9671052
9681053} ;
0 commit comments