2023-09-26 19:40:16 +02:00
# include <stdio.h>
# include <string.h>
# include <assert.h>
# include "platform.h"
# include "render/render.h"
# include "enginestate.h"
# include "lib/types.h"
# include "lib/math.h"
# include "gui/gui.h"
# include "debug/logger.h"
# include "debug/log_viewer.h"
# include "gui/layout.h"
# include "stb_image.h"
# include <time.h>
# include <sys/utsname.h>
# include <sys/sysinfo.h>
# include <NetworkManager.h>
2023-09-27 01:42:49 +02:00
# include <libvirt/libvirt.h>
2023-09-27 23:56:31 +02:00
# include <mntent.h>
# include <sys/statvfs.h>
# include <sys/stat.h>
2023-09-26 19:40:16 +02:00
bool process_input ( ) ; // Returns true when the program needs to exit
void process_gui ( ) ;
void app_init ( ) ;
void app_deinit ( ) ;
2023-09-27 01:42:49 +02:00
struct App_Data
{
2023-09-27 23:56:31 +02:00
f64 glib_iteration_t = - 1 ;
f64 system_sample_t = - 1 ;
f64 network_sample_t = - 1 ;
f64 virt_sample_t = - 1 ;
f64 fs_sample_t = - 1 ;
2023-09-27 01:42:49 +02:00
f64 glib_iteration_delta = 0.1 ;
f64 system_sample_delta = 0.2 ;
f64 network_sample_delta = 0.2 ;
f64 virt_sample_delta = 0.5 ;
2023-09-27 23:56:31 +02:00
f64 fs_sample_delta = 1.0 ;
2023-09-28 23:30:12 +02:00
bool show_grid = false ;
2023-09-27 01:42:49 +02:00
} ;
struct System_Info
{
char hostname [ 128 ] ;
char kernel [ 128 ] ;
time_t time ;
char cached_date_string [ 128 ] ;
char cached_time_string [ 128 ] ;
s32 cpus_total ;
s32 cpus_active ;
f32 load [ 3 ] ;
s64 uptime ;
u64 ram_total ;
u64 ram_used ;
u64 ram_available ;
} ;
struct Network_Device
{
char name [ 128 ] ;
NMDeviceType type ;
NMDeviceState state ;
} ;
struct Network_Info
{
s32 device_count ;
Network_Device devices [ 32 ] ;
} ;
struct Virt_Domain
{
char name [ 128 ] ;
s32 state ;
u32 vcpus ;
f32 cpu_usage ;
u64 prev_cpuTime ;
u64 ram_total ;
u64 ram_used ;
u64 ram_available ;
} ;
struct Virt_Info
{
s32 domain_count ;
Virt_Domain domains [ 32 ] ;
} ;
2023-09-27 23:56:31 +02:00
struct FS_Entry
{
char device [ 256 ] ;
char directory [ 256 ] ;
char type [ 128 ] ;
u64 bytes_total ;
u64 bytes_available ;
} ;
struct FS_Info
{
s32 fs_count ;
FS_Entry fs [ 32 ] ;
} ;
2023-09-27 01:42:49 +02:00
System_Info system_info ;
Network_Info network_info ;
Virt_Info virt_info ;
2023-09-27 23:56:31 +02:00
FS_Info fs_info ;
2023-09-27 01:42:49 +02:00
App_Data app_data ;
2023-09-26 19:40:16 +02:00
u32 seconds_to_duration_text ( char * text , f64 seconds , bool show_millis = false )
{
u32 written = 0 ;
u32 days = seconds / ( 24 * 3600 ) ;
seconds - = days * ( 24 * 3600 ) ;
u32 hours = seconds / 3600 ;
seconds - = hours * 3600 ;
u32 minutes = seconds / 60 ;
seconds - = minutes * 60 ;
if ( days )
written + = sprintf ( text + written , " %s%dd " , ( written ? " " : " " ) , days ) ;
if ( days | | hours )
written + = sprintf ( text + written , " %s%dh " , ( written ? " " : " " ) , hours ) ;
if ( days | | hours | | minutes )
written + = sprintf ( text + written , " %s%dm " , ( written ? " " : " " ) , minutes ) ;
if ( days | | hours | | minutes | | seconds )
{
if ( show_millis )
written + = sprintf ( text + written , " %s%.3lfs " , ( written ? " " : " " ) , seconds ) ;
else
written + = sprintf ( text + written , " %s%.0lfs " , ( written ? " " : " " ) , seconds ) ;
}
return written ;
}
void load_image ( const char * filename , u8 * * data , s32 * width , s32 * height , s32 * channels )
{
stbi_set_flip_vertically_on_load ( false ) ;
* data = stbi_load ( filename , width , height , channels , 4 ) ;
}
int main ( int argc , char * argv [ ] )
{
bool status ;
LOG_INIT ( ) ;
p_init ( true ) ;
LogViewer log_viewer = LogViewer : : Init ( & global_logger ) ;
p_window_open ( ) ;
p_window_name ( ( char * ) " Server Monitor " ) ;
r_init ( ) ;
gui_init ( ) ;
log_viewer . Print_New_Messages_On_Console ( ) ;
app_init ( ) ;
f64 start = p_time ( ) ;
f64 prev_t = 0 ;
2023-09-28 10:55:40 +02:00
f32 max_render_time = 1.0 / 30.0 ;
f64 processing_start = 0 ;
2023-09-26 19:40:16 +02:00
while ( 1 )
{
// Engine
engine . time = p_time ( ) - start ;
engine . delta_t = engine . time - prev_t ;
//LOG(LOG_INFO, "Frame time: %.3lf ms FPS: %.2lf", 1000*delta_t, 1/delta_t);
r_time_update ( engine . time ) ;
2023-09-28 10:55:40 +02:00
// @Hack: @Performance: Reduced framerate to use less resources. Text rendering is highly inefficient right now. Maybe it will improve later and this will not be necessary anymore.
f64 processing_time = engine . time - processing_start ;
if ( processing_time < max_render_time )
p_wait ( maximum ( 0 , ( max_render_time - 1.02 * processing_time ) * 1000 ) ) ;
processing_start = p_time ( ) - start ;
2023-09-26 19:40:16 +02:00
// Input
bool exit = process_input ( ) ;
if ( exit )
break ;
// GUI
r_framebuffer_select ( & r_render_state . framebuffer_SCREEN ) ;
r_clear ( { 0 , 0 , 0 , 0 } ) ;
process_gui ( ) ;
log_viewer . Print_New_Messages_On_Console ( ) ;
r_swap ( ) ;
prev_t = engine . time ;
}
app_deinit ( ) ;
gui_deinit ( ) ;
p_window_close ( ) ;
LOG_DEINIT ( ) ;
p_deinit ( ) ;
return 0 ;
}
bool process_input ( )
{
// Events
Event event ;
while ( p_next_event ( & event ) )
{
gui_handle_event ( & event ) ;
switch ( event . type )
{
case EVENT_QUIT : {
return true ;
} ;
case EVENT_MOUSE_MOVE :
{
} break ;
case EVENT_KEY :
{
switch ( event . key . key_code )
{
2023-09-28 23:30:12 +02:00
case KEY_G :
case KEY_F2 : {
if ( event . key . pressed )
app_data . show_grid = ! app_data . show_grid ;
} break ;
2023-09-26 19:40:16 +02:00
default : {
// Other keys. Put default to suppress warnings
} break ;
}
} break ;
case EVENT_RESIZE :
{
//LOG(LOG_DEBUG, "New size: %u %u", signal.resize.width, signal.resize.height);
s32 width = event . resize . width ;
s32 height = event . resize . height ;
r_size_update ( width , height ) ;
global_gui_state . default_context . width = width ;
global_gui_state . default_context . height = height ;
engine . gui_scaling = minimum ( width , height ) * 0.03 ;
global_gui_state . default_context . style . font_size = engine . gui_scaling ;
global_gui_state . default_context . style . button_radius = engine . gui_scaling / 10 ;
} break ;
case EVENT_FOCUS :
{
} break ;
case EVENT_UNFOCUS :
{
} break ;
}
}
return false ;
}
2023-09-28 23:30:12 +02:00
void system_info_gui ( Gui_Layout_Grid * grid )
2023-09-26 19:40:16 +02:00
{
2023-09-28 23:30:12 +02:00
Rect r = grid - > rect_at ( { 0 , 0 } , { 4 , 4 } ) ;
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions ( v2 { 0 , 0 } , r . size , 4 , 4 , 0.2 * engine . gui_scaling ) ;
gui_window_start ( r , 0xabcdef01 ) ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
// Host date and time
2023-09-28 23:30:12 +02:00
gui_text_aligned ( layout . cell ( 1 ) , system_info . hostname , GUI_ALIGN_LEFT ) ;
gui_text_aligned ( layout . cell ( 2 ) , system_info . cached_time_string , GUI_ALIGN_CENTER ) ;
gui_text_aligned ( layout . cell ( 1 ) , system_info . cached_date_string , GUI_ALIGN_RIGHT ) ;
2023-09-26 19:40:16 +02:00
// Load, Memory, Uptime
struct sysinfo sys_info ;
sysinfo ( & sys_info ) ;
char uptime [ 128 ] = " Uptime: " ; seconds_to_duration_text ( uptime + strlen ( " Uptime: " ) , sys_info . uptime ) ;
2023-09-27 01:42:49 +02:00
char load [ 128 ] ; snprintf ( load , 128 , " Load: %.2f %.2f %.2f " , system_info . load [ 0 ] , system_info . load [ 1 ] , system_info . load [ 2 ] ) ;
char processors [ 128 ] ; snprintf ( processors , 128 , " CPUs: %d/%d " , system_info . cpus_active , system_info . cpus_total ) ;
char ram [ 128 ] ; snprintf ( ram , 128 , " RAM: %.2f/%.2f GiB " , system_info . ram_used / ( 1024.0 * 1024.0 * 1024.0 ) , system_info . ram_total / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
2023-09-26 19:40:16 +02:00
layout . row ( 2 ) ;
2023-09-28 23:30:12 +02:00
gui_text_aligned ( layout . cell ( 1 ) , processors , GUI_ALIGN_LEFT ) ;
gui_text_aligned ( layout . cell ( 1 ) , ram , GUI_ALIGN_LEFT ) ;
gui_text_aligned ( layout . cell ( 2 ) , uptime , GUI_ALIGN_RIGHT ) ;
gui_text_aligned ( layout . cell ( 1 ) , load , GUI_ALIGN_LEFT ) ;
2023-09-26 19:40:16 +02:00
gui_window_end ( ) ;
}
2023-09-28 23:30:12 +02:00
void network_gui ( Gui_Layout_Grid * grid )
2023-09-26 19:40:16 +02:00
{
2023-09-28 23:30:12 +02:00
Rect r = grid - > rect_at ( { 0 , 4 } , { 4 , 13 } ) ;
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions ( v2 { 0 , 0 } , r . size , 4 , 13 , 0.2 * engine . gui_scaling ) ;
gui_window_start ( r , 0xabcdef02 ) ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
Gui_Context * ctx = & global_gui_state . default_context ;
for ( s32 i = 0 ; i < network_info . device_count ; i + + )
2023-09-26 19:40:16 +02:00
{
2023-09-27 01:42:49 +02:00
Network_Device * device = & network_info . devices [ i ] ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
gui_button ( layout . cell ( ) , device - > name ) ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
gui_id_stack_push ( ctx , gui_id_from_pointer ( ctx , device - > name ) ) ;
switch ( device - > type )
2023-09-26 19:40:16 +02:00
{
case NM_DEVICE_TYPE_ETHERNET : gui_button ( layout . cell ( ) , " ETHERNET " ) ; break ;
case NM_DEVICE_TYPE_WIFI : gui_button ( layout . cell ( ) , " WIFI " ) ; break ;
case NM_DEVICE_TYPE_TUN : gui_button ( layout . cell ( ) , " TAP or TUN " ) ; break ;
case NM_DEVICE_TYPE_BRIDGE : gui_button ( layout . cell ( ) , " BRIDGE " ) ; break ;
case NM_DEVICE_TYPE_VLAN : gui_button ( layout . cell ( ) , " VLAN " ) ; break ;
case NM_DEVICE_TYPE_WIREGUARD : gui_button ( layout . cell ( ) , " WIREGUARD " ) ; break ;
default : gui_button ( layout . cell ( ) , " " ) ; break ;
}
2023-09-27 01:42:49 +02:00
switch ( device - > state )
2023-09-26 19:40:16 +02:00
{
case NM_DEVICE_STATE_UNKNOWN : gui_button ( layout . cell ( ) , " UNKNOWN " ) ; break ;
case NM_DEVICE_STATE_UNMANAGED : gui_button ( layout . cell ( ) , " UNMANAGED " ) ; break ;
case NM_DEVICE_STATE_UNAVAILABLE : gui_button ( layout . cell ( ) , " UNAVAILABLE " ) ; break ;
case NM_DEVICE_STATE_DISCONNECTED : gui_button ( layout . cell ( ) , " DISCONNECTED " ) ; break ;
case NM_DEVICE_STATE_PREPARE : gui_button ( layout . cell ( ) , " PREPARE " ) ; break ;
case NM_DEVICE_STATE_CONFIG : gui_button ( layout . cell ( ) , " CONFIG " ) ; break ;
case NM_DEVICE_STATE_NEED_AUTH : gui_button ( layout . cell ( ) , " NEED_AUTH " ) ; break ;
case NM_DEVICE_STATE_IP_CONFIG : gui_button ( layout . cell ( ) , " IP_CONFIG " ) ; break ;
case NM_DEVICE_STATE_IP_CHECK : gui_button ( layout . cell ( ) , " IP_CHECK " ) ; break ;
case NM_DEVICE_STATE_SECONDARIES : gui_button ( layout . cell ( ) , " SECONDARIES " ) ; break ;
case NM_DEVICE_STATE_ACTIVATED : gui_button ( layout . cell ( ) , " ACTIVATED " ) ; break ;
case NM_DEVICE_STATE_DEACTIVATING : gui_button ( layout . cell ( ) , " DEACTIVATING " ) ; break ;
case NM_DEVICE_STATE_FAILED : gui_button ( layout . cell ( ) , " FAILED " ) ; break ;
default : gui_button ( layout . cell ( ) , " " ) ; break ;
}
gui_id_stack_pop ( ctx ) ;
layout . row ( ) ;
}
gui_window_end ( ) ;
}
2023-09-28 23:30:12 +02:00
void vm_gui ( Gui_Layout_Grid * grid )
2023-09-26 19:40:16 +02:00
{
2023-09-28 23:30:12 +02:00
Rect r = grid - > rect_at ( { 0 , 17 } , { 4 , 5 } ) ;
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions ( v2 { 0 , 0 } , r . size , 4 , 5 , 0.2 * engine . gui_scaling ) ;
gui_window_start ( r , 0xabcdef03 ) ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
Gui_Context * ctx = & global_gui_state . default_context ;
Gui_Style old_style = ctx - > style ;
for ( s32 i = 0 ; i < virt_info . domain_count ; i + + )
{
Virt_Domain * domain = & virt_info . domains [ i ] ;
// Name and state
switch ( domain - > state )
{
case VIR_DOMAIN_NOSTATE :
ctx - > style . button_color = old_style . button_color ;
break ;
case VIR_DOMAIN_RUNNING :
ctx - > style . button_color = v4 { 0 , 1 , 0 , 1 } ;
break ;
case VIR_DOMAIN_BLOCKED :
case VIR_DOMAIN_SHUTOFF :
case VIR_DOMAIN_CRASHED :
ctx - > style . button_color = v4 { 1 , 0 , 0 , 1 } ;
break ;
case VIR_DOMAIN_SHUTDOWN :
ctx - > style . button_color = v4 { 0 , .6 , 0 , 1 } ;
break ;
case VIR_DOMAIN_PAUSED :
case VIR_DOMAIN_PMSUSPENDED :
ctx - > style . button_color = v4 { .7 , .7 , 0 , 1 } ;
break ;
default :
ctx - > style . button_color = old_style . button_color ;
}
gui_button ( layout . cell ( ) , domain - > name ) ;
gui_id_stack_push ( ctx , gui_id_from_pointer ( ctx , domain - > name ) ) ;
ctx - > style = old_style ;
// CPU usage
char cpu [ 128 ] ; snprintf ( cpu , 128 , " %.2f%% " , domain - > cpu_usage * 100 ) ;
gui_button ( layout . cell ( ) , cpu ) ;
2023-09-26 19:40:16 +02:00
2023-09-27 01:42:49 +02:00
char ram [ 128 ] ; snprintf ( ram , 128 , " %.2f GB " , domain - > ram_total / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
gui_button ( layout . cell ( ) , ram ) ;
char cpu_count [ 128 ] ; snprintf ( cpu_count , 128 , " %hd vCPU " , domain - > vcpus ) ;
gui_button ( layout . cell ( ) , cpu_count ) ;
gui_id_stack_pop ( ctx ) ;
layout . row ( ) ;
}
ctx - > style = old_style ;
2023-09-26 19:40:16 +02:00
gui_window_end ( ) ;
}
2023-09-27 01:42:49 +02:00
2023-09-28 23:30:12 +02:00
void fs_gui ( Gui_Layout_Grid * grid )
2023-09-27 23:56:31 +02:00
{
2023-09-28 23:30:12 +02:00
Rect r = grid - > rect_at ( { 4 , 0 } , { 2 , 22 } ) ;
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions ( v2 { 0 , 0 } , r . size , 2 , 22 , 0.2 * engine . gui_scaling ) ;
gui_window_start ( r , 0xabcdef04 ) ;
2023-09-27 23:56:31 +02:00
Gui_Context * ctx = & global_gui_state . default_context ;
for ( s32 i = 0 ; i < fs_info . fs_count ; i + + )
{
gui_id_stack_push ( ctx , gui_id_from_pointer ( ctx , fs_info . fs [ i ] . device ) ) ;
gui_button ( layout . cell ( 2 ) , fs_info . fs [ i ] . device ) ;
gui_button ( layout . cell ( 1 ) , fs_info . fs [ i ] . directory ) ;
gui_button ( layout . cell ( 1 ) , fs_info . fs [ i ] . type ) ;
char space [ 64 ] ; snprintf ( space , 64 , " %.1f/%.1f GiB " , ( f32 ) ( fs_info . fs [ i ] . bytes_total - fs_info . fs [ i ] . bytes_available ) / ( 1024 * 1024 * 1024 ) , ( f32 ) fs_info . fs [ i ] . bytes_total / ( 1024 * 1024 * 1024 ) ) ;
char percentage [ 64 ] ; snprintf ( percentage , 64 , " %.1f%% " , ( f32 ) ( fs_info . fs [ i ] . bytes_total - fs_info . fs [ i ] . bytes_available ) / fs_info . fs [ i ] . bytes_total * 100 ) ;
gui_button ( layout . cell ( 1 ) , space ) ;
gui_button ( layout . cell ( 1 ) , percentage ) ;
gui_id_stack_pop ( ctx ) ;
}
gui_window_end ( ) ;
}
2023-09-27 01:42:49 +02:00
NMClient * nmclient ;
virConnectPtr virt_connection ;
void collect_static_data ( )
{
// Hostname
struct utsname host_info ;
uname ( & host_info ) ;
system_info . hostname [ 0 ] = 0 ;
if ( host_info . nodename [ 0 ] )
strncpy ( system_info . hostname , host_info . nodename , 128 ) ;
snprintf ( system_info . kernel , 128 , " %s %s " , host_info . sysname , host_info . release ) ;
}
void collect_new_data_if_needed ( )
{
if ( engine . time - app_data . glib_iteration_t > = app_data . glib_iteration_delta )
{
g_main_context_iteration ( NULL , false ) ;
app_data . glib_iteration_t = engine . time ;
}
if ( engine . time - app_data . system_sample_t > = app_data . system_sample_delta )
{
// Clock
system_info . time = time ( NULL ) ;
struct tm * time_info = localtime ( & system_info . time ) ;
strftime ( system_info . cached_date_string , 128 , " %a %e %b %Y " , time_info ) ;
strftime ( system_info . cached_time_string , 128 , " %H:%M:%S %Z " , time_info ) ;
// CPU count
system_info . cpus_total = get_nprocs ( ) ;
system_info . cpus_active = get_nprocs_conf ( ) ;
// System info for later
struct sysinfo sys_info ;
sysinfo ( & sys_info ) ;
// Uptime
system_info . uptime = sys_info . uptime ;
// Load
system_info . load ;
for ( int i = 0 ; i < 3 ; i + + )
system_info . load [ i ] = round ( ( f32 ) sys_info . loads [ i ] / ( 1 < < SI_LOAD_SHIFT ) * 100 ) / 100 ;
// Memory
system_info . ram_total = sys_info . totalram * sys_info . mem_unit ;
system_info . ram_available = ( sys_info . freeram + sys_info . bufferram ) * sys_info . mem_unit ;
system_info . ram_used = sys_info . totalram * sys_info . mem_unit - system_info . ram_available ;
app_data . system_sample_t = engine . time ;
}
if ( engine . time - app_data . network_sample_t > = app_data . network_sample_delta )
{
const GPtrArray * devices = nm_client_get_devices ( nmclient ) ;
network_info . device_count = devices - > len ;
for ( int i = 0 ; i < devices - > len ; i + + )
{
NMDevice * device = ( NMDevice * ) devices - > pdata [ i ] ;
strncpy ( network_info . devices [ i ] . name , nm_device_get_iface ( device ) , 128 ) ;
network_info . devices [ i ] . type = nm_device_get_device_type ( device ) ;
network_info . devices [ i ] . state = nm_device_get_state ( device ) ;
}
app_data . network_sample_t = engine . time ;
}
if ( engine . time - app_data . virt_sample_t > = app_data . virt_sample_delta )
{
virDomainPtr * domains ;
virt_info . domain_count = virConnectListAllDomains ( virt_connection , & domains , 0 ) ;
for ( int i = 0 ; i < virt_info . domain_count ; i + + )
{
Virt_Domain * dom = & virt_info . domains [ i ] ;
// Name
strncpy ( dom - > name , virDomainGetName ( domains [ i ] ) , 128 ) ;
// State
virDomainInfo info ;
int res = virDomainGetInfo ( domains [ i ] , & info ) ;
dom - > state = info . state ;
// CPU
dom - > vcpus = info . nrVirtCpu ;
dom - > cpu_usage = ( info . cpuTime - dom - > prev_cpuTime ) / ( ( engine . time - app_data . virt_sample_t ) * 1e9 * dom - > vcpus ) ;
dom - > prev_cpuTime = info . cpuTime ;
dom - > ram_total = info . memory * 1024 ; // mem * 1000 or mem * 1024 ??
dom - > ram_used = dom - > ram_total ;
dom - > ram_available = 0 ;
}
p_free ( domains ) ;
app_data . virt_sample_t = engine . time ;
}
2023-09-27 23:56:31 +02:00
if ( engine . time - app_data . fs_sample_t > = app_data . fs_sample_delta )
{
FILE * file = setmntent ( " /proc/mounts " , " r " ) ;
fs_info . fs_count = 0 ;
for ( struct mntent * ent = getmntent ( file ) ; ent ! = NULL ; ent = getmntent ( file ) )
{
strncpy ( fs_info . fs [ fs_info . fs_count ] . device , ent - > mnt_fsname , 256 ) ;
strncpy ( fs_info . fs [ fs_info . fs_count ] . directory , ent - > mnt_dir , 256 ) ;
strncpy ( fs_info . fs [ fs_info . fs_count ] . type , ent - > mnt_type , 128 ) ;
fs_info . fs [ fs_info . fs_count ] . bytes_total = 0 ;
fs_info . fs [ fs_info . fs_count ] . bytes_available = 0 ;
struct stat s ;
if ( stat ( ent - > mnt_fsname , & s ) ! = 0 | | ! S_ISBLK ( s . st_mode ) )
continue ;
struct statvfs svfs ;
if ( statvfs ( ent - > mnt_dir , & svfs ) = = 0 )
{
fs_info . fs [ fs_info . fs_count ] . bytes_total = svfs . f_frsize * svfs . f_blocks ;
fs_info . fs [ fs_info . fs_count ] . bytes_available = svfs . f_frsize * svfs . f_bavail ;
}
fs_info . fs_count + + ;
}
endmntent ( file ) ;
}
2023-09-27 01:42:49 +02:00
}
2023-09-26 19:40:16 +02:00
void process_gui ( )
{
2023-09-27 01:42:49 +02:00
collect_new_data_if_needed ( ) ;
2023-09-28 23:30:12 +02:00
gui_frame_begin ( engine . time ) ;
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions ( v2 { 0 , 0 } , v2 { r_render_state . width , r_render_state . height } , 6 , 22 , 0.5 * engine . gui_scaling ) ;
2023-09-27 01:42:49 +02:00
2023-09-28 23:30:12 +02:00
system_info_gui ( & layout ) ;
network_gui ( & layout ) ;
vm_gui ( & layout ) ;
fs_gui ( & layout ) ;
gui_frame_end ( ) ;
if ( app_data . show_grid )
{
layout . cursor = { 0 , 0 } ;
while ( layout . cursor . y < layout . max_cells_count . y )
{
r_2d_immediate_rectangle_outline ( layout . cell ( ) , { 0 , 1 , 0 , 1 } ) ;
char coords [ 32 ] ; snprintf ( coords , 32 , " (%d, %d) " , layout . cursor . x - 1 , layout . cursor . y ) ;
gui_text_aligned ( layout . rect ( ) , coords , GUI_ALIGN_CENTER ) ; // abuse: used after gui_frame_end
}
}
2023-09-26 19:40:16 +02:00
}
2023-09-27 01:42:49 +02:00
void app_init ( )
{
app_data . system_sample_t = 0 ;
app_data . network_sample_t = 0 ;
app_data . virt_sample_t = 0 ;
app_data . glib_iteration_t = 0 ;
nmclient = nm_client_new ( NULL , NULL ) ;
virt_connection = virConnectOpenReadOnly ( " qemu:///system " ) ;
collect_static_data ( ) ;
}
void app_deinit ( )
{
virConnectClose ( virt_connection ) ;
}