sorry about monster commit

This commit is contained in:
galister
2025-09-20 15:28:23 +09:00
parent c6a32f4109
commit cfb733de09
32 changed files with 1208 additions and 289 deletions

View File

@@ -0,0 +1,160 @@
use std::{
cell::RefCell,
io::BufReader,
process::{Child, ChildStdout},
};
use wgui::{
event::{self, EventCallback, EventListenerCollection, EventListenerKind, ListenerHandleVec},
parser::CustomAttribsInfoOwned,
};
use crate::{
backend::{common::OverlaySelector, overlay::OverlayID, task::TaskType, wayvr::WayVRAction},
config::{save_layout, AStrSetExt},
state::AppState,
};
use super::helper::read_label_from_pipe;
pub(super) fn setup_custom_button<S>(
attribs: &CustomAttribsInfoOwned,
listeners: &mut EventListenerCollection<AppState, S>,
listener_handles: &mut ListenerHandleVec,
app: &AppState,
) {
const EVENTS: [(&str, EventListenerKind); 2] = [
("press", EventListenerKind::MousePress),
("release", EventListenerKind::MouseRelease),
];
for (name, kind) in EVENTS.iter() {
let Some(action) = attribs.get_value(name) else {
continue;
};
let mut args = action.split_whitespace();
let Some(command) = args.next() else {
continue;
};
let callback: EventCallback<AppState, S> = match command {
"::DashToggle" => Box::new(move |_common, _data, app, _| {
app.tasks
.enqueue(TaskType::WayVR(WayVRAction::ToggleDashboard));
Ok(())
}),
"::OverlayToggle" => {
let Some(selector) = args.next() else {
log::warn!("Missing argument for {}", command);
continue;
};
let selector = selector
.parse::<usize>()
.map(|id| OverlaySelector::Id(OverlayID { 0: id }))
.unwrap_or_else(|_| OverlaySelector::Name(selector.into()));
Box::new(move |_common, _data, app, _| {
app.tasks.enqueue(TaskType::Overlay(
selector.clone(),
Box::new(|app, o| {
o.want_visible = !o.want_visible;
if o.recenter {
o.show_hide = o.want_visible;
o.reset(app, false);
}
let mut state_dirty = false;
if !o.want_visible {
state_dirty |=
app.session.config.show_screens.arc_rm(o.name.as_ref());
} else if o.want_visible {
state_dirty |=
app.session.config.show_screens.arc_set(o.name.clone());
}
if state_dirty {
match save_layout(&app.session.config) {
Ok(()) => log::debug!("Saved state"),
Err(e) => {
log::error!("Failed to save state: {e:?}");
}
}
}
}),
));
Ok(())
})
}
"::WatchHide" => todo!(),
"::WatchSwapHand" => todo!(),
"::EditToggle" => return,
"::OscSend" => return,
// shell
_ => todo!(),
};
listeners.register(listener_handles, attribs.widget_id, *kind, callback);
}
}
struct ShellButtonMutableState {
child: Option<Child>,
reader: Option<BufReader<ChildStdout>>,
}
struct ShellButtonState {
exec: String,
mut_state: RefCell<ShellButtonMutableState>,
carry_over: RefCell<Option<String>>,
}
fn shell_on_action(
state: &ShellButtonState,
common: &mut event::CallbackDataCommon,
data: &mut event::CallbackData,
) {
let mut mut_state = state.mut_state.borrow_mut();
}
fn shell_on_tick(
state: &ShellButtonState,
common: &mut event::CallbackDataCommon,
data: &mut event::CallbackData,
) {
let mut mut_state = state.mut_state.borrow_mut();
if let Some(mut child) = mut_state.child.take() {
match child.try_wait() {
// not exited yet
Ok(None) => {
if let Some(text) = mut_state.reader.as_mut().and_then(|r| {
read_label_from_pipe("child process", r, &mut *state.carry_over.borrow_mut())
}) {
//TODO update label
}
mut_state.child = Some(child);
}
// exited successfully
Ok(Some(code)) if code.success() => {
if let Some(text) = mut_state.reader.as_mut().and_then(|r| {
read_label_from_pipe("child process", r, &mut *state.carry_over.borrow_mut())
}) {
//TODO update label
}
mut_state.child = None;
}
// exited with failure
Ok(Some(code)) => {
mut_state.child = None;
log::warn!("Label process exited with code {}", code);
}
// lost
Err(_) => {
mut_state.child = None;
log::warn!("Label child process lost.");
}
}
}
}