Change static callback vec to local

This commit is contained in:
Ottatop 2023-10-20 19:15:49 -05:00
parent 4e36637e19
commit 1680acc5e9
5 changed files with 184 additions and 90 deletions

View file

@ -2,9 +2,6 @@ use pinnacle_api::prelude::*;
use pinnacle_api::*;
fn main() {
// let mut num = 5;
// let test = &mut num;
pinnacle_api::connect().unwrap();
let mod_key = Modifier::Ctrl;
@ -13,65 +10,97 @@ fn main() {
process::set_env("MOZ_ENABLE_WAYLAND", "1");
input::mousebind(&[mod_key], MouseButton::Left, MouseEdge::Press, move || {
window::begin_move(MouseButton::Left);
});
let mut callback_vec = CallbackVec::new();
input::mousebind(
&[mod_key],
MouseButton::Left,
MouseEdge::Press,
move |_| {
window::begin_move(MouseButton::Left);
},
&mut callback_vec,
);
input::mousebind(
&[mod_key],
MouseButton::Right,
MouseEdge::Press,
move || {
move |_| {
window::begin_resize(MouseButton::Right);
},
&mut callback_vec,
);
input::keybind(&[mod_key, Modifier::Alt], 'q', pinnacle::quit);
input::keybind(
&[mod_key, Modifier::Alt],
'q',
|_| pinnacle::quit(),
&mut callback_vec,
);
input::keybind(&[mod_key, Modifier::Alt], 'c', move || {
if let Some(window) = window::get_focused() {
window.close();
}
});
input::keybind(
&[mod_key, Modifier::Alt],
'c',
move |_| {
if let Some(window) = window::get_focused() {
window.close();
}
},
&mut callback_vec,
);
input::keybind(&[mod_key], xkbcommon::xkb::keysyms::KEY_Return, move || {
process::spawn(vec![terminal]).unwrap();
});
input::keybind(
&[mod_key],
xkbcommon::xkb::keysyms::KEY_Return,
move |_| {
process::spawn(vec![terminal]).unwrap();
},
&mut callback_vec,
);
input::keybind(
&[mod_key, Modifier::Alt],
xkbcommon::xkb::keysyms::KEY_space,
move || {
move |_| {
if let Some(window) = window::get_focused() {
window.toggle_floating();
}
},
&mut callback_vec,
);
input::keybind(&[mod_key], 'f', move || {
if let Some(window) = window::get_focused() {
window.toggle_fullscreen();
}
});
input::keybind(
&[mod_key],
'f',
move |_| {
if let Some(window) = window::get_focused() {
window.toggle_fullscreen();
}
},
&mut callback_vec,
);
input::keybind(&[mod_key], 'm', move || {
if let Some(window) = window::get_focused() {
window.toggle_maximized();
}
});
input::keybind(
&[mod_key],
'm',
move |_| {
if let Some(window) = window::get_focused() {
window.toggle_maximized();
}
},
&mut callback_vec,
);
let tags = ["1", "2", "3", "4", "5"];
output::connect_for_all(move |output| {
tag::add(&output, tags.as_slice());
tag::get("1", Some(&output)).unwrap().toggle();
});
// let mut num = 5;
//
// input::keybind(&[mod_key], 'm', || {
// num += 1;
// });
output::connect_for_all(
move |output, _| {
tag::add(&output, tags.as_slice());
tag::get("1", Some(&output)).unwrap().toggle();
},
&mut callback_vec,
);
// let layout_cycler = tag.layout_cycler(&[
// Layout::MasterStack,
@ -89,38 +118,46 @@ fn main() {
for tag_name in tags.iter().map(|t| t.to_string()) {
let t = tag_name.clone();
input::keybind(&[mod_key], tag_name.chars().next().unwrap(), move || {
tag::get(&t, None).unwrap().switch_to();
});
input::keybind(
&[mod_key],
tag_name.chars().next().unwrap(),
move |_| {
tag::get(&t, None).unwrap().switch_to();
},
&mut callback_vec,
);
let t = tag_name.clone();
input::keybind(
&[mod_key, Modifier::Shift],
tag_name.chars().next().unwrap(),
move || {
move |_| {
tag::get(&t, None).unwrap().toggle();
},
&mut callback_vec,
);
let t = tag_name.clone();
input::keybind(
&[mod_key, Modifier::Alt],
tag_name.chars().next().unwrap(),
move || {
move |_| {
if let Some(window) = window::get_focused() {
window.move_to_tag(&tag::get(&t, None).unwrap());
}
},
&mut callback_vec,
);
let t = tag_name.clone();
input::keybind(
&[mod_key, Modifier::Shift, Modifier::Alt],
tag_name.chars().next().unwrap(),
move || {
move |_| {
if let Some(window) = window::get_focused() {
window.toggle_tag(&tag::get(&t, None).unwrap());
}
},
&mut callback_vec,
);
}
pinnacle_api::listen();
pinnacle_api::listen(callback_vec);
}

View file

@ -6,7 +6,7 @@ use xkbcommon::xkb::Keysym;
use crate::{
msg::{Args, CallbackId, KeyIntOrString, Msg},
send_msg, CALLBACK_VEC,
send_msg, CallbackVec,
};
/// Set a keybind.
@ -18,17 +18,22 @@ use crate::{
/// - [`char`]: A character of the key you want. This can be `a`, `~`, `@`, and so on.
/// - [`u32`]: The key in numeric form. You can use the keys defined in [`xkbcommon::xkb::keysyms`] for this.
/// - [`Keysym`]: The key in `Keysym` form, from [xkbcommon::xkb::Keysym].
pub fn keybind<F>(modifiers: &[Modifier], key: impl Into<KeyIntOrString>, mut action: F)
where
F: FnMut() + Send + 'static,
///
/// `action` takes in a `&mut `[`CallbackVec`] for use in the closure.
pub fn keybind<'a, F>(
modifiers: &[Modifier],
key: impl Into<KeyIntOrString>,
mut action: F,
callback_vec: &mut CallbackVec<'a>,
) where
F: FnMut(&mut CallbackVec) + 'a,
{
let args_callback = move |_: Option<Args>| {
action();
let args_callback = move |_: Option<Args>, callback_vec: &mut CallbackVec<'_>| {
action(callback_vec);
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let len = callback_vec.len();
callback_vec.push(Box::new(args_callback));
let len = callback_vec.callbacks.len();
callback_vec.callbacks.push(Box::new(args_callback));
let key = key.into();
@ -45,17 +50,23 @@ where
///
/// The mousebind can happen either on button press or release, so you must
/// specify which edge you desire.
pub fn mousebind<F>(modifiers: &[Modifier], button: MouseButton, edge: MouseEdge, mut action: F)
where
F: FnMut() + Send + 'static,
///
/// `action` takes in a `&mut `[`CallbackVec`] for use in the closure.
pub fn mousebind<'a, F>(
modifiers: &[Modifier],
button: MouseButton,
edge: MouseEdge,
mut action: F,
callback_vec: &mut CallbackVec<'a>,
) where
F: FnMut(&mut CallbackVec) + 'a,
{
let args_callback = move |_: Option<Args>| {
action();
let args_callback = move |_: Option<Args>, callback_vec: &mut CallbackVec<'_>| {
action(callback_vec);
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let len = callback_vec.len();
callback_vec.push(Box::new(args_callback));
let len = callback_vec.callbacks.len();
callback_vec.callbacks.push(Box::new(args_callback));
let msg = Msg::SetMousebind {
modifiers: modifiers.to_vec(),

View file

@ -46,8 +46,6 @@ use msg::{Args, CallbackId, IncomingMsg, Msg, Request, RequestResponse};
use crate::msg::RequestId;
static STREAM: OnceLock<Mutex<UnixStream>> = OnceLock::new();
#[allow(clippy::type_complexity)]
static CALLBACK_VEC: Mutex<Vec<Box<dyn FnMut(Option<Args>) + Send>>> = Mutex::new(Vec::new());
lazy_static::lazy_static! {
static ref UNREAD_CALLBACK_MSGS: Mutex<HashMap<CallbackId, IncomingMsg>> = Mutex::new(HashMap::new());
static ref UNREAD_REQUEST_MSGS: Mutex<HashMap<RequestId, IncomingMsg>> = Mutex::new(HashMap::new());
@ -157,7 +155,7 @@ pub fn connect() -> anyhow::Result<()> {
/// Begin listening for messages coming from Pinnacle.
///
/// This needs to be called at the very end of your `setup` function.
pub fn listen() -> Infallible {
pub fn listen(mut callback_vec: CallbackVec) -> Infallible {
loop {
let mut unread_callback_msgs = UNREAD_CALLBACK_MSGS.lock().unwrap();
@ -168,11 +166,18 @@ pub fn listen() -> Infallible {
let IncomingMsg::CallCallback { callback_id, args } = entry.remove() else {
unreachable!();
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let Some(callback) = callback_vec.get_mut(callback_id.0 as usize) else {
unreachable!();
};
callback(args);
// Take the callback out and replace it with a dummy callback
// to allow callback_vec to be used mutably below.
let mut callback = std::mem::replace(
&mut callback_vec.callbacks[callback_id.0 as usize],
Box::new(|_, _| {}),
);
callback(args, &mut callback_vec);
// Put it back.
callback_vec.callbacks[callback_id.0 as usize] = callback;
}
let incoming_msg = read_msg(None);
@ -181,11 +186,43 @@ pub fn listen() -> Infallible {
unreachable!();
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let Some(callback) = callback_vec.get_mut(callback_id.0 as usize) else {
unreachable!();
};
let mut callback = std::mem::replace(
&mut callback_vec.callbacks[callback_id.0 as usize],
Box::new(|_, _| {}),
);
callback(args);
callback(args, &mut callback_vec);
callback_vec.callbacks[callback_id.0 as usize] = callback;
}
}
/// A wrapper around a vector that holds all of your callbacks.
///
/// You will need to create this before you can start calling config functions
/// that require callbacks.
///
/// Because your callbacks can capture things, we need a non-static way to hold them.
/// That's where this struct comes in.
///
/// Every function that needs you to provide a callback will also need you to
/// provide a `&mut CallbackVec`. This will insert the callback for use in [`listen`].
///
/// Additionally, all callbacks will also take in `&mut CallbackVec`. This is so you can
/// call functions that need it inside of other callbacks.
///
/// At the end of your config, you will need to call [`listen`] to begin listening for
/// messages from Pinnacle that will call your callbacks. Here, you must in pass your
/// `CallbackVec`.
#[derive(Default)]
pub struct CallbackVec<'a> {
#[allow(clippy::type_complexity)]
pub(crate) callbacks: Vec<Box<dyn FnMut(Option<Args>, &mut CallbackVec) + 'a>>,
}
impl<'a> CallbackVec<'a> {
/// Create a new, empty `CallbackVec`.
pub fn new() -> Self {
Default::default()
}
}

View file

@ -4,7 +4,7 @@ use crate::{
msg::{Args, CallbackId, Msg, Request, RequestResponse},
request, send_msg,
tag::TagHandle,
CALLBACK_VEC,
CallbackVec,
};
/// A unique identifier for an output.
@ -58,6 +58,10 @@ pub fn get_focused() -> Option<OutputHandle> {
/// When called, `connect_for_all` will run `func` with all currently connected outputs.
/// If a new output is connected, `func` will also be called with it.
///
/// `func` takes in two parameters:
/// - `0`: An [`OutputHandle`] you can act on.
/// - `1`: A `&mut `[`CallbackVec`] for use in the closure.
///
/// This will *not* be called if it has already been called for a given connector.
/// This means turning your monitor off and on or unplugging and replugging it *to the same port*
/// won't trigger `func`. Plugging it in to a new port *will* trigger `func`.
@ -66,19 +70,18 @@ pub fn get_focused() -> Option<OutputHandle> {
/// Please note: this function will be run *after* Pinnacle processes your entire config.
/// For example, if you define tags in `func` but toggle them directly after `connect_for_all`,
/// nothing will happen as the tags haven't been added yet.
pub fn connect_for_all<F>(mut func: F)
pub fn connect_for_all<'a, F>(mut func: F, callback_vec: &mut CallbackVec<'a>)
where
F: FnMut(OutputHandle) + Send + 'static,
F: FnMut(OutputHandle, &mut CallbackVec) + 'a,
{
let args_callback = move |args: Option<Args>| {
let args_callback = move |args: Option<Args>, callback_vec: &mut CallbackVec<'_>| {
if let Some(Args::ConnectForAllOutputs { output_name }) = args {
func(OutputHandle(OutputName(output_name)));
func(OutputHandle(OutputName(output_name)), callback_vec);
}
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let len = callback_vec.len();
callback_vec.push(Box::new(args_callback));
let len = callback_vec.callbacks.len();
callback_vec.callbacks.push(Box::new(args_callback));
let msg = Msg::ConnectForAllOutputs {
callback_id: CallbackId(len as u32),

View file

@ -2,7 +2,7 @@
use crate::{
msg::{Args, CallbackId, Msg},
send_msg, CALLBACK_VEC,
send_msg, CallbackVec,
};
/// Spawn a process.
@ -26,11 +26,18 @@ pub fn spawn(command: Vec<&str>) -> anyhow::Result<()> {
/// - `1`: The process's stderr printed this line.
/// - `2`: The process exited with this code.
/// - `3`: The process exited with this message.
pub fn spawn_with_callback<F>(command: Vec<&str>, mut callback: F) -> anyhow::Result<()>
/// - `4`: A `&mut `[`CallbackVec`] for use inside the closure.
///
/// You must also pass in a mutable reference to a [`CallbackVec`] in order to store your callback.
pub fn spawn_with_callback<'a, F>(
command: Vec<&str>,
mut callback: F,
callback_vec: &mut CallbackVec<'a>,
) -> anyhow::Result<()>
where
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>) + Send + 'static,
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>, &mut CallbackVec) + 'a,
{
let args_callback = move |args: Option<Args>| {
let args_callback = move |args: Option<Args>, callback_vec: &mut CallbackVec<'_>| {
if let Some(Args::Spawn {
stdout,
stderr,
@ -38,13 +45,12 @@ where
exit_msg,
}) = args
{
callback(stdout, stderr, exit_code, exit_msg);
callback(stdout, stderr, exit_code, exit_msg, callback_vec);
}
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let len = callback_vec.len();
callback_vec.push(Box::new(args_callback));
let len = callback_vec.callbacks.len();
callback_vec.callbacks.push(Box::new(args_callback));
let msg = Msg::Spawn {
command: command.into_iter().map(|s| s.to_string()).collect(),