diff --git a/src/api/msg.rs b/src/api/msg.rs index 6fbf4d2..e17bdd9 100644 --- a/src/api/msg.rs +++ b/src/api/msg.rs @@ -7,6 +7,8 @@ // The MessagePack format for these is a one-element map where the element's key is the enum name and its // value is a map of the enum's values +use crate::window::tag::Tag; + #[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)] pub struct CallbackId(pub u32); @@ -31,6 +33,12 @@ pub enum Msg { #[serde(default)] client_id: Option, }, + MoveToTag { + tag: Tag, + }, + ToggleTag { + tag: Tag, + }, // Process management /// Spawn a program with an optional callback. diff --git a/src/main.rs b/src/main.rs index b5ce81d..a2b6fd5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,8 +12,6 @@ //! While Pinnacle is not a library, this documentation serves to guide those who want to //! contribute or learn how building something like this works. -// test - mod api; mod backend; mod cursor; @@ -22,6 +20,7 @@ mod grab; mod handlers; mod input; mod layout; +mod output; mod pointer; mod render; mod state; diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..cec9c3f --- /dev/null +++ b/src/output.rs @@ -0,0 +1,31 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// SPDX-License-Identifier: MPL-2.0 + +use std::cell::RefCell; + +use smithay::output::Output; + +use crate::window::tag::Tag; + +#[derive(Default)] +pub struct OutputState { + focused_tags: Vec, +} + +impl OutputState { + pub fn with(output: &Output, mut func: F) -> T + where + F: FnMut(&mut Self) -> T, + { + output + .user_data() + .insert_if_missing(|| RefCell::::default); + + let state = output.user_data().get::>().unwrap(); + + func(&mut state.borrow_mut()) + } +} diff --git a/src/state.rs b/src/state.rs index 25c7ee1..8dc266a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -92,8 +92,6 @@ pub struct State { pub pointer_location: Point, } -static NUM: AtomicU32 = AtomicU32::new(0); - impl State { /// Create the main [State]. /// @@ -133,6 +131,7 @@ impl State { loop_handle.insert_source(rx_channel, |msg, _, data| match msg { Event::Msg(msg) => { // TODO: move this into its own function + // TODO: no like seriously this is getting a bit unwieldy match msg { Msg::SetKeybind { key, @@ -177,28 +176,26 @@ impl State { .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) - // .stdin(if callback_id.is_some() { - // Stdio::piped() - // } else { - // // piping to null because foot won't open without a callback_id - // // otherwise - // Stdio::null() - // }) - // .stdout(if callback_id.is_some() { - // Stdio::piped() - // } else { - // Stdio::null() - // }) - // .stderr(if callback_id.is_some() { - // Stdio::piped() - // } else { - // Stdio::null() - // }) + .stdin(if callback_id.is_some() { + Stdio::piped() + } else { + // piping to null because foot won't open without a callback_id + // otherwise + Stdio::null() + }) + .stdout(if callback_id.is_some() { + Stdio::piped() + } else { + Stdio::null() + }) + .stderr(if callback_id.is_some() { + Stdio::piped() + } else { + Stdio::null() + }) .args(command) .spawn() .unwrap(); // TODO: handle unwrap - NUM.store(NUM.load(Ordering::SeqCst) + 1, Ordering::SeqCst); - tracing::info!("{} processes", NUM.load(Ordering::SeqCst)); // TODO: find a way to make this hellish code look better, deal with unwraps if let Some(callback_id) = callback_id { @@ -208,9 +205,9 @@ impl State { let stream_err = stream_out.clone(); let stream_exit = stream_out.clone(); + // TODO: make this not use 3 whole threads per process if let Some(stdout) = stdout { std::thread::spawn(move || { - // TODO: maybe find a way to make this async? let mut reader = BufReader::new(stdout); loop { let mut buf = String::new(); @@ -305,6 +302,8 @@ impl State { command, callback_id, } => todo!(), + Msg::MoveToTag { tag } => todo!(), + Msg::ToggleTag { tag } => todo!(), Msg::Quit => { data.state.loop_signal.stop(); } diff --git a/src/window.rs b/src/window.rs index d8f761d..338b056 100644 --- a/src/window.rs +++ b/src/window.rs @@ -21,12 +21,13 @@ use self::window_state::{Float, WindowState}; pub mod tag; pub mod window_state; +// TODO: maybe get rid of this and move the fn into resize_surface state because it's the only user pub trait SurfaceState: Default + 'static { - /// Access the [SurfaceState] associated with a [WlSurface]. + /// Access the [`SurfaceState`] associated with a [`WlSurface`]. /// /// # Panics /// - /// This function will panic if you use it within itself due to the use of a [RefCell]. + /// This function will panic if you use it within itself due to the use of a [`RefCell`]. fn with_state(wl_surface: &WlSurface, function: F) -> T where F: FnOnce(&mut Self) -> T, diff --git a/src/window/tag.rs b/src/window/tag.rs index 6ffeeaf..f808aaa 100644 --- a/src/window/tag.rs +++ b/src/window/tag.rs @@ -4,4 +4,25 @@ // // SPDX-License-Identifier: MPL-2.0 -pub struct Tag(u32); +use smithay::desktop::Window; + +use crate::{backend::Backend, state::State}; + +use super::window_state::WindowState; + +#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct Tag(String); + +impl Tag { + /// Returns all windows that have this tag. + pub fn windows(&self, state: &State) -> Vec { + state + .space + .elements() + .filter(|&window| { + WindowState::with_state(window, |win_state| win_state.tags.contains(self)) + }) + .cloned() + .collect() + } +} diff --git a/src/window/window_state.rs b/src/window/window_state.rs index bf0f700..4f6d76b 100644 --- a/src/window/window_state.rs +++ b/src/window/window_state.rs @@ -18,6 +18,7 @@ pub struct WindowState { pub floating: Float, /// The window's resize state. See [WindowResizeState] for more. pub resize_state: WindowResizeState, + /// What tags the window is currently on. pub tags: Vec, }