ui and stuff

This commit is contained in:
Alessandro Mauri 2025-10-27 11:52:07 +01:00
parent 4def485a6d
commit 60e77cd611
5 changed files with 186 additions and 36 deletions

View File

@ -15,6 +15,6 @@
} }
}, },
"safe": true, "safe": true,
"opt": "O1", "opt": "O0",
"debug-info": "full" "debug-info": "full"
} }

View File

@ -9,7 +9,6 @@ div {
separator { separator {
bg: #fbf1c7ff; bg: #fbf1c7ff;
size: 1; size: 1;
padding: 0 5 0 5;
} }
button { button {

View File

@ -5,9 +5,17 @@ import std::os::env;
import std::core::mem::allocator; import std::core::mem::allocator;
import std::collections::object; import std::collections::object;
import std::collections::list; import std::collections::list;
import std::encoding::json;
struct ConfigFile {
Path path;
String name;
}
alias StrList = list::List{String}; alias StrList = list::List{String};
alias ConfFList = list::List{ConfigFile};
fn Path? String.to_expanded_path(&str, Allocator allocator) fn Path? String.to_expanded_path(&str, Allocator allocator)
{ {
@ -46,15 +54,15 @@ fn Path? String.to_expanded_path(&str, Allocator allocator)
}; };
} }
fn StrList get_qemu_cmdline(Allocator allocator, Object* conf) fn StrList? get_qemu_cmdline(Allocator allocator, Object* conf)
{ {
StrList cmd;
@pool() {
// parse the disk path // parse the disk path
String disk = conf.get_string("disk")!!; String disk = conf.get_string("disk")!;
Path disk_path = disk.to_expanded_path(mem)!!; Path disk_path = disk.to_expanded_path(tmem)!;
defer disk_path.free();
// compose the command line for the vm // compose the command line for the vm
StrList cmd;
cmd.init(allocator); cmd.init(allocator);
// first the executable // first the executable
@ -62,7 +70,6 @@ fn StrList get_qemu_cmdline(Allocator allocator, Object* conf)
// then the drive // then the drive
cmd.push("-drive"); cmd.push("-drive");
cmd.push(string::format(allocator, "file=%s", disk_path.str_view())); cmd.push(string::format(allocator, "file=%s", disk_path.str_view()));
//cmd.push(string::format(allocator, "file=%s,format=%s", disk_path.str_view(), disk_path.extension()))!!;
// memory // memory
cmd.push("-m"); cmd.push("-m");
cmd.push(conf.get_string("memory"))!!; cmd.push(conf.get_string("memory"))!!;
@ -80,6 +87,42 @@ fn StrList get_qemu_cmdline(Allocator allocator, Object* conf)
cmd.push(p.get_string_at(1))!!; cmd.push(p.get_string_at(1))!!;
} }
} }
};
return cmd; return cmd;
} }
fn ConfFList? get_config_list(Allocator allocator)
{
ConfFList l;
l.init(allocator);
@pool() {
// find the right config directory
Path conf_dir = env::get_config_dir(tmem).append(tmem, "simple-qemu-manager")!;
if (!file::exists(conf_dir.str_view()) || !file::is_dir(conf_dir.str_view())) {
path::mkdir(conf_dir, recursive:true)!;
return l;
}
// list all json files
PathList pl = path::ls(tmem, conf_dir)!;
foreach (fname : pl) @pool() {
if ((fname.extension() ?? "") != "json") continue;
Path fpath = conf_dir.append(tmem, fname.str_view())!;
File cf = file::open_path(fpath, "r")!;
defer (void)cf.close();
Object* c = json::parse(tmem, &cf)!;
ConfigFile e = {
.path = path::new(allocator, fpath.str_view(), fpath.env)!,
.name = string::format(allocator, "%s", c.get_string("name"))!,
};
l.push(e);
};
};
return l;
}

View File

@ -28,7 +28,7 @@ fn int main(String[] args)
Object* conf = json::parse(mem, &file)!!; Object* conf = json::parse(mem, &file)!!;
defer conf.free(); defer conf.free();
// UI initialization // ---------------------------------------------- UI initialization ---------------------------------------------- //
ArenaAllocator arena; ArenaAllocator arena;
char[] arena_mem = mem::new_array(char, 1024*1024); char[] arena_mem = mem::new_array(char, 1024*1024);
defer (void)mem::free(arena_mem); defer (void)mem::free(arena_mem);
@ -59,9 +59,9 @@ fn int main(String[] args)
ui.import_style_from_file(STYLESHEET_PATH); ui.import_style_from_file(STYLESHEET_PATH);
ren::pre(ren.win); ren::pre(ren.win);
// End UI initialization // -------------------------------------------- End UI initialization -------------------------------------------- //
StrList cmd = conf::get_qemu_cmdline(mem, conf); StrList cmd = conf::get_qemu_cmdline(mem, conf)!!;
defer cmd.free(); defer cmd.free();
String vm_name = conf.get_string("name")!!; String vm_name = conf.get_string("name")!!;
String vm_disk = conf.get_string("disk").to_expanded_path(tmem).str_view()!!; String vm_disk = conf.get_string("disk").to_expanded_path(tmem).str_view()!!;
@ -71,6 +71,11 @@ fn int main(String[] args)
SubProcess vm_proc; SubProcess vm_proc;
defer (void)vm_proc.join(); defer (void)vm_proc.join();
ConfFList conf_list = conf::get_config_list(tmem)!!;
foreach (cf : conf_list) {
io::printn(cf);
}
bool quit; bool quit;
Clock sleep_clock; Clock sleep_clock;
while (!quit) { while (!quit) {
@ -84,10 +89,23 @@ fn int main(String[] args)
if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true; if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) quit = true;
ui.@div(ugui::@grow(), ugui::@grow(), COLUMN) { ui.@div(ugui::@grow(), ugui::@grow(), COLUMN) {
ui.@div(ugui::@grow(), ugui::@fit(20)) { ui.@div(ugui::@grow(), ugui::@fit(20), ROW, LEFT) {
ui.text("Machine:")!!; ui.text("Machine:")!!;
ui.separator(ugui::@grow(), ugui::@grow())!!; ui.separator(ugui::@grow(), ugui::@grow())!!;
ui.text(vm_name)!!; ui.text(vm_name)!!;
static bool popup;
static Point popup_pos;
if (ui.button("v")!!.mouse_release) {
popup = true;
popup_pos = ui.input.mouse.pos;
}
ui.@popup(&popup, popup_pos, ugui::@fit(), ugui::@fit(), COLUMN) {
foreach (idx, c : conf_list) {
ui.text(c.name, idx)!!;
}
}!!;
}!!; }!!;
ui.hor_line()!!; ui.hor_line()!!;
ui.@div(ugui::@grow(), ugui::@grow(), COLUMN, scroll_y: true) { ui.@div(ugui::@grow(), ugui::@grow(), COLUMN, scroll_y: true) {

90
src/vm.c3 Normal file
View File

@ -0,0 +1,90 @@
import std::io;
import std::io::path;
import std::io::file;
import std::os::process;
import std::collections::object;
import std::encoding::json;
import conf;
struct VirtualMachineDesc {
Path config_path;
Object* config;
String name;
StrList cmdline;
Path disk_path;
SubProcess process;
}
fn VirtualMachineDesc? new_from_path(Allocator allocator, Path path)
{
VirtualMachineDesc desc;
desc.config_path = path::new(allocator, path.str_view(), path.env)!;
File file = file::open_path(path, "r")!;
defer (void)file.close();
desc.config = json::parse(allocator, &file)!;
desc.name = desc.config.get_string("name")!;
desc.disk_path = desc.config.get_string("disk").to_expanded_path(allocator)!;
desc.cmdline = conf::get_qemu_cmdline(allocator, desc.config)!;
return desc;
}
<* @param[&in] desc *>
fn bool VirtualMachineDesc.is_initialized(&desc)
{
return desc.config_path.str_view() != ""
&& desc.config != null
&& desc.name != ""
&& desc.disk_path.str_view() != ""
&& desc.cmdline.len() != 0;
}
<* @param[&inout] desc *>
fn void VirtualMachineDesc.free(&desc)
{
if (!desc.is_initialized()) return;
(void)desc.stop();
desc.config_path.free();
desc.config.free();
// desc.name.free() name is just a string view into desc.config
desc.disk_path.free();
desc.cmdline.free();
*desc = {};
}
<* @param[&inout] desc *>
fn void? VirtualMachineDesc.start(&desc)
{
if (!desc.is_initialized()) return;
if ((desc.process.is_running() ?? false)) return;
desc.process = process::create(desc.cmdline.array_view(), {.inherit_stdio=true, .inherit_environment=true})!;
}
<* @param[&inout] desc *>
fn void? VirtualMachineDesc.stop(&desc)
{
if (!desc.is_initialized()) return;
if (!(desc.process.is_running() ?? false)) return;
desc.process.terminate()!;
desc.process.join()!;
}
<* @param[&in] desc *>
fn bool VirtualMachineDesc.is_running(&desc)
{
if (!desc.is_initialized()) return false;
return desc.process.is_running() ?? false;
}