feat: display witchcraft
This commit is contained in:
@ -25,7 +25,8 @@ pub async fn startline(app: AppHandle) -> Result<(), String> {
|
||||
let hash = appd.sum_packages(p);
|
||||
liner::line_up(p, hash).await
|
||||
.map_err(|e| e.to_string())?;
|
||||
start::start(p, app_copy)
|
||||
|
||||
start::start(p, app_copy).await
|
||||
.map_err(|e| e.to_string())
|
||||
} else {
|
||||
Err("No profile".to_owned())
|
||||
@ -211,6 +212,17 @@ pub async fn write_profile_data(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_platform_capabilities() -> Result<Vec<String>, ()> {
|
||||
log::debug!("invoke: list_platform_capabilities");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
return Ok(vec!["display".to_owned()]);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
return Ok(vec!["wine".to_owned()]);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn set_cfg(
|
||||
state: State<'_, Mutex<AppData>>,
|
||||
@ -226,3 +238,32 @@ pub async fn set_cfg(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn list_displays() -> Result<Vec<(String, String)>, String> {
|
||||
use winsafe::prelude::NativeBitflag;
|
||||
|
||||
log::debug!("invoke: list_displays");
|
||||
|
||||
let mut res = Vec::new();
|
||||
for displ_dev in winsafe::EnumDisplayDevices(None, None) {
|
||||
if let Ok(displ_dev) = displ_dev {
|
||||
if displ_dev.StateFlags.has(winsafe::co::DISPLAY_DEVICE::ATTACHED_TO_DESKTOP) {
|
||||
res.push((displ_dev.DeviceName(), displ_dev.DeviceString()));
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub async fn list_displays() -> Result<Vec<String>, ()> {
|
||||
log::debug!("invoke: list_displays");
|
||||
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
93
rust/src/display.rs
Normal file
93
rust/src/display.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::profile::Profile;
|
||||
use anyhow::{Result, anyhow};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub struct DisplayInfo {
|
||||
primary: String,
|
||||
target: String,
|
||||
target_rotation: displayz::Orientation
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub async fn prepare_display(p: &Profile) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn prepare_display(p: &Profile) -> Result<Option<DisplayInfo>> {
|
||||
use displayz::{query_displays, Orientation};
|
||||
|
||||
let display_name = p.get_str("display", "default");
|
||||
let rotation = p.get_int("display-rotation", 0);
|
||||
if display_name == "default" {
|
||||
log::debug!("prepare display: skip");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let display_set = query_displays()?;
|
||||
|
||||
let primary = display_set
|
||||
.displays()
|
||||
.find(|display| display.is_primary())
|
||||
.ok_or_else(|| anyhow!("Primary display not found"))?;
|
||||
|
||||
let target = display_set
|
||||
.displays()
|
||||
.find(|display| display.name() == display_name)
|
||||
.ok_or_else(|| anyhow!("Display {} not found", display_name))?;
|
||||
|
||||
target.set_primary()?;
|
||||
let settings = target.settings()
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("Unable to query display settings"))?;
|
||||
|
||||
let res = DisplayInfo {
|
||||
primary: primary.name().to_owned(),
|
||||
target: target.name().to_owned(),
|
||||
target_rotation: settings.borrow().orientation
|
||||
};
|
||||
|
||||
match rotation {
|
||||
90 => settings.borrow_mut().orientation = Orientation::Portrait,
|
||||
270 => settings.borrow_mut().orientation = Orientation::PortraitFlipped,
|
||||
_ => ()
|
||||
};
|
||||
|
||||
display_set.apply()?;
|
||||
displayz::refresh()?;
|
||||
|
||||
log::debug!("prepare display: done");
|
||||
|
||||
Ok(Some(res))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn undo_display(info: DisplayInfo) -> Result<()> {
|
||||
use displayz::query_displays;
|
||||
|
||||
let display_set = query_displays()?;
|
||||
|
||||
let primary = display_set
|
||||
.displays()
|
||||
.find(|display| display.name() == info.primary)
|
||||
.ok_or_else(|| anyhow!("Display {} not found", info.primary))?;
|
||||
|
||||
let target = display_set
|
||||
.displays()
|
||||
.find(|display| display.name() == info.target)
|
||||
.ok_or_else(|| anyhow!("Display {} not found", info.target))?;
|
||||
|
||||
primary.set_primary()?;
|
||||
|
||||
let settings = target.settings()
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("Unable to query display settings"))?;
|
||||
settings.borrow_mut().orientation = info.target_rotation;
|
||||
|
||||
display_set.apply()?;
|
||||
displayz::refresh()?;
|
||||
|
||||
log::debug!("undo display: done");
|
||||
|
||||
Ok(())
|
||||
}
|
@ -8,6 +8,7 @@ mod start;
|
||||
mod liner;
|
||||
mod download_handler;
|
||||
mod appdata;
|
||||
mod display;
|
||||
|
||||
use closure::closure;
|
||||
use appdata::AppData;
|
||||
@ -100,6 +101,7 @@ pub async fn run(_args: Vec<String>) {
|
||||
cmd::install_package,
|
||||
cmd::delete_package,
|
||||
cmd::toggle_package,
|
||||
|
||||
cmd::list_profiles,
|
||||
cmd::init_profile,
|
||||
cmd::load_profile,
|
||||
@ -107,9 +109,13 @@ pub async fn run(_args: Vec<String>) {
|
||||
cmd::save_current_profile,
|
||||
cmd::read_profile_data,
|
||||
cmd::write_profile_data,
|
||||
|
||||
cmd::startline,
|
||||
cmd::kill,
|
||||
|
||||
cmd::list_platform_capabilities,
|
||||
cmd::set_cfg,
|
||||
cmd::list_displays,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
@ -70,7 +70,7 @@ async fn prepare_packages(p: &Profile) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn prepare_config(p: &Profile) -> Result<()> {
|
||||
async fn prepare_config(p: &Profile) -> Result<()> {
|
||||
let dir_out = p.dir();
|
||||
|
||||
let ini_in_raw = fs::read_to_string(p.data.exe_dir.join("segatools.ini")).await?;
|
||||
|
@ -1,16 +1,16 @@
|
||||
use anyhow::Result;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use tokio::process::Command;
|
||||
use tauri::{AppHandle, Emitter};
|
||||
use std::process::Stdio;
|
||||
use crate::display::{prepare_display, undo_display};
|
||||
use crate::profile::Profile;
|
||||
use crate::util;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
static CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
pub fn start(p: &Profile, app: AppHandle) -> Result<()> {
|
||||
pub async fn start(p: &Profile, app: AppHandle) -> Result<()> {
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
let ini_path = p.dir().join("segatools.ini");
|
||||
@ -20,15 +20,20 @@ pub fn start(p: &Profile, app: AppHandle) -> Result<()> {
|
||||
let mut game_builder;
|
||||
let mut amd_builder;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
let display_info;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
game_builder = Command::new(p.exe_dir.join("inject.exe"));
|
||||
game_builder = Command::new(p.data.exe_dir.join("inject.exe"));
|
||||
amd_builder = Command::new("cmd.exe");
|
||||
|
||||
display_info = prepare_display(p).await?;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let wine = p.data.wine_runtime.clone()
|
||||
.unwrap_or_else(|| PathBuf::from("/usr/bin/wine"));
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("/usr/bin/wine"));
|
||||
|
||||
game_builder = Command::new(&wine);
|
||||
amd_builder = Command::new(&wine);
|
||||
@ -134,6 +139,15 @@ pub fn start(p: &Profile, app: AppHandle) -> Result<()> {
|
||||
log::debug!("Fin");
|
||||
|
||||
_ = app.emit("launch-end", "");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(display_info) = display_info {
|
||||
if let Err(e) = undo_display(display_info).await {
|
||||
log::error!("undo display failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user