Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use serde::{Deserialize, Serialize};

#[non_exhaustive]
#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize)]
pub struct Graphics {
pub device: GraphicsDevice,
pub display: Display,
}

#[non_exhaustive]
#[derive(Debug, Clone, Copy, Default, strum::Display, PartialEq, Deserialize, Serialize)]
pub enum Display {
#[default]
None,
Gtk,
Sdl,
EglHeadless,
}

#[non_exhaustive]
#[derive(Debug, Clone, Copy, strum::Display, PartialEq, Deserialize, Serialize)]
pub enum GraphicsDevice {
Std { vgamem: u16 },
Qxl { vgamem: u16 },
Virtio(VirtioConfig),
None,
}

impl Default for GraphicsDevice {
fn default() -> Self {
GraphicsDevice::Std { vgamem: 16 }
}
}

#[non_exhaustive]
#[derive(Debug, Clone, Copy, Default, PartialEq, Deserialize, Serialize)]
pub struct VirtioConfig {
pub enable_3d: bool,
pub venus: bool,
}

impl Graphics {
pub fn to_qemu_arg(&self) -> Vec<String> {
let display = match self.display {
Display::None => vec!["-display".to_string(), "none".to_string()],
Display::EglHeadless => vec!["-display".to_string(), "egl-headless".to_string()],
Display::Sdl => vec!["-display".to_string(), "sdl".to_string()],
Display::Gtk => vec!["-display".to_string(), "gtk".to_string()],
};

let device = match self.device {
GraphicsDevice::Std { vgamem } => {
vec![
"-vga".to_string(),
"none".to_string(),
"-device".to_string(),
format!("VGA,vgamem_mb={}", vgamem),
]
}
GraphicsDevice::Qxl { vgamem } => {
vec![
"-vga".to_string(),
"none".to_string(),
"-device".to_string(),
format!("qxl-vga,vgamem_mb={}", vgamem),
]
}
GraphicsDevice::Virtio(config) => {
let mut arg = vec!["-vga".to_string(), "none".to_string()];

if config.enable_3d {
if config.venus {
arg.extend(vec![
"-device".to_string(),
"virtio-vga-gl,hostmem=8G,blob=true,venus=true".to_string(),
]);
} else {
arg.extend(vec![
"-device".to_string(),
"virtio-vga-gl,hostmem=8G,blob=true".to_string(),
]);
}
} else {
arg.extend(vec!["-device".to_string(), "virtio-vga".to_string()]);
}

arg
}
GraphicsDevice::None => {
vec!["-vga".to_string(), "none".to_string()]
}
};

let mut args = Vec::new();
args.extend(display);
args.extend(device);
args
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod confirmation;
pub mod event;
pub mod firmware;
pub mod fs;
pub mod graphics;
pub mod handlers;
pub mod help;
pub mod network;
Expand Down
15 changes: 3 additions & 12 deletions src/qemu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,7 @@ impl Qemu {
let vm_events_path = VM::get_events_file(vm.id);

let mut command = match vm.arch {
Arch::X86_64 => {
let mut command = Command::new("qemu-system-x86_64");
command
.arg("-device")
.arg("VGA,edid=on,xres=1920,yres=1080");

command
}
Arch::X86_64 => Command::new("qemu-system-x86_64"),
Arch::Aarch64 => {
let mut command = Command::new("qemu-system-aarch64");
command
Expand All @@ -42,8 +35,6 @@ impl Qemu {
.arg("-cpu")
.arg("max")
.arg("-device")
.arg("virtio-gpu-pci")
.arg("-device")
.arg("qemu-xhci")
.arg("-device")
.arg("usb-kbd");
Expand All @@ -58,8 +49,6 @@ impl Qemu {
.arg("-cpu")
.arg("max")
.arg("-device")
.arg("virtio-gpu-pci")
.arg("-device")
.arg("qemu-xhci")
.arg("-device")
.arg("usb-kbd");
Expand Down Expand Up @@ -93,6 +82,8 @@ impl Qemu {
command.args(fs.to_qemu_arg());
}

command.args(vm.graphics.to_qemu_arg());

command
.arg("-daemonize")
.arg("-qmp")
Expand Down
16 changes: 16 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::{
firmware,
fs::Filesystem,
get_kudu_data_dir, get_kudu_run_dir,
graphics::Graphics,
network::{Network, NetworkBackend, bridge::Bridge},
notification::{self, Notification, NotificationLevel},
os::Os::{self, TempleOS},
Expand All @@ -57,6 +58,7 @@ pub struct VM {
pub networks: Vec<Network>,
pub remote_access: Option<RemoteAccess>,
pub fs: Vec<Filesystem>,
pub graphics: Graphics,

#[serde(skip)]
pub downloading: Arc<AtomicBool>,
Expand Down Expand Up @@ -278,6 +280,7 @@ impl VM {
fs: data.fs,
state: RunState::shutdown,
remote_access: data.remote_access,
graphics: data.graphics,
};

let data = serde_json::to_string_pretty(&vm)?;
Expand Down Expand Up @@ -343,6 +346,8 @@ impl VM {

self.fs = data.fs;

self.graphics = data.graphics;

path.push("vm.json");
let mut file = File::create(&path)?;
let vm = serde_json::to_string_pretty(&self)?;
Expand Down Expand Up @@ -915,6 +920,17 @@ impl VM {
]),
Line::from(""),
]),
ListItem::from(vec![
Line::from(vec![
Span::from("Graphics").bold().fg(Color::Yellow),
Span::from(" ".repeat(9)),
Span::from(format!(
"Card: {} -- Display: {}",
self.graphics.device, self.graphics.display,
)),
]),
Line::from(""),
]),
]);

if let Some(vnc_info) = self.vnc.clone()
Expand Down
3 changes: 3 additions & 0 deletions src/vmbuilder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod access;
mod advanced;
mod fs;
mod graphics;
mod hardware;
mod overview;
mod port;
Expand All @@ -26,6 +27,7 @@ use crate::{
confirmation::cancel::CancelConfirmation,
event::Event::{self},
fs::Filesystem,
graphics::Graphics,
network::Network,
os::Os::{self},
storage::Disk,
Expand Down Expand Up @@ -67,6 +69,7 @@ pub struct VMBuildData {
pub disks: Vec<Disk>,
pub fs: Vec<Filesystem>,
pub remote_access: Option<RemoteAccess>,
pub graphics: Graphics,
}

impl VMBuilder {
Expand Down
43 changes: 39 additions & 4 deletions src/vmbuilder/advanced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
event::Event,
network,
os::Os::{ArchLinux, TempleOS},
vmbuilder::{VMBuildData, access, fs, hardware, overview, port, storage},
vmbuilder::{VMBuildData, access, fs, graphics, hardware, overview, port, storage},
};

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -28,6 +28,7 @@ pub enum Section {
Network,
PortForwarding,
RemoteAccess,
Graphics,
Summary,
}

Expand All @@ -42,6 +43,7 @@ pub struct Advanced {
pub network: network::builder::NetworkBuilder,
pub port_fowrwaring: port::PortForwarding,
pub remote_access: access::RemoteAccessBuilder,
pub graphics: graphics::GraphicsBuilder,
}

impl Default for Advanced {
Expand All @@ -65,6 +67,7 @@ impl Advanced {
network,
port_fowrwaring,
remote_access: access::RemoteAccessBuilder::new(),
graphics: graphics::GraphicsBuilder::new(),
}
}

Expand All @@ -83,6 +86,7 @@ impl Advanced {
disks: self.storage.disks(),
fs: self.fs.filesystems(),
remote_access: self.remote_access.access(),
graphics: self.graphics.build(),
}
}

Expand All @@ -98,6 +102,10 @@ impl Advanced {
self.remote_access.validate()
}

fn validate_graphics_section(&mut self) -> bool {
self.graphics.validate()
}

pub fn handle_key_events(&mut self, key_event: KeyEvent, sender: Sender<Event>) -> Result<()> {
if self.storage.new_disk_popup() {
self.storage
Expand Down Expand Up @@ -137,9 +145,15 @@ impl Advanced {
self.focused_section = Section::PortForwarding
}
Section::PortForwarding => self.focused_section = Section::RemoteAccess,

Section::RemoteAccess => {
if self.validate_remote_access() {
self.focused_section = Section::Summary
self.focused_section = Section::Graphics;
}
}
Section::Graphics => {
if self.validate_graphics_section() {
self.focused_section = Section::Summary;
}
}
Section::Summary => {
Expand Down Expand Up @@ -178,7 +192,12 @@ impl Advanced {
self.focused_section = Section::PortForwarding
}
}
Section::Summary => self.focused_section = Section::RemoteAccess,
Section::Graphics => {
if self.validate_graphics_section() {
self.focused_section = Section::RemoteAccess;
}
}
Section::Summary => self.focused_section = Section::Graphics,
},
_ => match &self.focused_section {
Section::Overview => {
Expand Down Expand Up @@ -208,6 +227,9 @@ impl Advanced {
Section::RemoteAccess => {
self.remote_access.handle_key_events(key_event);
}
Section::Graphics => {
self.graphics.handle_key_events(key_event);
}
Section::Summary => {}
},
}
Expand Down Expand Up @@ -254,6 +276,11 @@ impl Advanced {
Line::from(" Remote Access 󰢹 "),
Line::from(""),
]),
ListItem::new(vec![
Line::from(""),
Line::from(" Graphics 󰢮 "),
Line::from(""),
]),
ListItem::new(vec![
Line::from(""),
Line::from(" Summary 󱇗 "),
Expand All @@ -272,7 +299,7 @@ impl Advanced {
.direction(Direction::Vertical)
.constraints([
Constraint::Fill(1),
Constraint::Length(27),
Constraint::Length(30),
Constraint::Fill(1),
])
.split(frame.area())[1];
Expand Down Expand Up @@ -358,6 +385,10 @@ impl Advanced {
self.remote_access.render(frame, area, cancel_popup);
}

Section::Graphics => {
self.graphics.render(frame, area);
}

Section::Summary => {
let mut items = Vec::new();

Expand All @@ -368,6 +399,7 @@ impl Advanced {
items.extend(self.network.summary());
items.extend(self.port_fowrwaring.summary());
items.extend(self.remote_access.summary());
items.extend(self.graphics.summary());

let list_width = items.iter().map(|item| item.width()).max().unwrap() as u16;
let list = List::new(items);
Expand Down Expand Up @@ -524,6 +556,9 @@ impl Advanced {
])]
}
}
Section::Graphics => {
vec![Line::from(vec![Span::from("⇄").bold(), Span::from(" Nav")])]
}
Section::Summary => {
vec![Line::from(vec![
Span::from("Esc").bold(),
Expand Down
Loading
Loading