Do other misc stuff

These are some horrible commit messages
This commit is contained in:
Ottatop 2023-12-14 22:00:04 -06:00
parent 93f601ca5c
commit 3427fe5d7c
9 changed files with 135 additions and 119 deletions

View file

@ -23,7 +23,6 @@ require("pinnacle").setup(function(pinnacle)
---@type Modifier
local mod_key = "Ctrl" -- This is set to `Ctrl` instead of `Super` to not conflict with your WM/DE keybinds
-- ^ Add type annotations for that sweet, sweet autocomplete
local terminal = "alacritty"
@ -43,49 +42,55 @@ require("pinnacle").setup(function(pinnacle)
-- Mousebinds --------------------------------------------------------------------
input.mousebind({"Ctrl"}, buttons.left, "Press",
function() window.begin_move(buttons.left) end)
input.mousebind({"Ctrl"}, buttons.right, "Press",
function() window.begin_resize(buttons.right) end)
input.mousebind({ "Ctrl" }, buttons.left, "Press", function()
window.begin_move(buttons.left)
end)
input.mousebind({ "Ctrl" }, buttons.right, "Press", function()
window.begin_resize(buttons.right)
end)
-- Keybinds ----------------------------------------------------------------------
-- mod_key + Alt + q quits the compositor
input.keybind({mod_key, "Alt"}, keys.q, pinnacle.quit)
input.keybind({ mod_key, "Alt" }, keys.q, pinnacle.quit)
-- mod_key + Alt + c closes the focused window
input.keybind({mod_key, "Alt"}, keys.c,
function() window.get_focused():close() end)
input.keybind({ mod_key, "Alt" }, keys.c, function()
window.get_focused():close()
end)
-- mod_key + return spawns a terminal
input.keybind({mod_key}, keys.Return, function()
input.keybind({ mod_key }, keys.Return, function()
process.spawn(terminal, function(stdout, stderr, exit_code, exit_msg)
-- do something with the output here
end)
end)
-- mod_key + Alt + Space toggle floating on the focused window
input.keybind({mod_key, "Alt"}, keys.space,
function() window.get_focused():toggle_floating() end)
input.keybind({ mod_key, "Alt" }, keys.space, function()
window.get_focused():toggle_floating()
end)
-- mod_key + f toggles fullscreen on the focused window
input.keybind({mod_key}, keys.f,
function() window.get_focused():toggle_fullscreen() end)
input.keybind({ mod_key }, keys.f, function()
window.get_focused():toggle_fullscreen()
end)
-- mod_key + m toggles maximized on the focused window
input.keybind({mod_key}, keys.m,
function() window.get_focused():toggle_maximized() end)
input.keybind({ mod_key }, keys.m, function()
window.get_focused():toggle_maximized()
end)
-- Tags ---------------------------------------------------------------------------
local tags = {"1", "2", "3", "4", "5"}
local tags = { "1", "2", "3", "4", "5" }
output.connect_for_all(function(op)
-- Add tags 1, 2, 3, 4 and 5 on all monitors, and toggle tag 1 active by default
op:add_tags(tags)
-- Same as tag.add(op, "1", "2", "3", "4", "5")
tag.toggle({name = "1", output = op})
tag.toggle({ name = "1", output = op })
-- Window rules
-- Add your own window rules here. Below is an example.
@ -112,30 +117,35 @@ require("pinnacle").setup(function(pinnacle)
-- Create a layout cycler to cycle your tag layouts. This will store which layout each tag has
-- and change to the next or previous one in the array when the respective function is called.
local layout_cycler = tag.layout_cycler({
"MasterStack", "Dwindle", "Spiral", "CornerTopLeft", "CornerTopRight",
"CornerBottomLeft", "CornerBottomRight"
"MasterStack",
"Dwindle",
"Spiral",
"CornerTopLeft",
"CornerTopRight",
"CornerBottomLeft",
"CornerBottomRight",
})
input.keybind({mod_key}, keys.space, layout_cycler.next)
input.keybind({mod_key, "Shift"}, keys.space, layout_cycler.prev)
input.keybind({ mod_key }, keys.space, layout_cycler.next)
input.keybind({ mod_key, "Shift" }, keys.space, layout_cycler.prev)
-- Tag manipulation
for _, tag_name in pairs(tags) do
-- mod_key + 1-5 switches tags
input.keybind({mod_key}, tag_name,
function() tag.switch_to(tag_name) end)
input.keybind({ mod_key }, tag_name, function()
tag.switch_to(tag_name)
end)
-- mod_key + Shift + 1-5 toggles tags
input.keybind({mod_key, "Shift"}, tag_name,
function() tag.toggle(tag_name) end)
input.keybind({ mod_key, "Shift" }, tag_name, function()
tag.toggle(tag_name)
end)
-- mod_key + Alt + 1-5 moves windows to tags
input.keybind({mod_key, "Alt"}, tag_name,
function()
input.keybind({ mod_key, "Alt" }, tag_name, function()
window:get_focused():move_to_tag(tag_name)
end)
-- mod_key + Shift + Alt + 1-5 toggles tags on windows
input.keybind({mod_key, "Shift", "Alt"}, tag_name,
function()
input.keybind({ mod_key, "Shift", "Alt" }, tag_name, function()
window.get_focused():toggle_tag(tag_name)
end)
end

View file

@ -34,6 +34,7 @@
//!
//! For an example, look at the Lua implementation in the repository.
pub mod handlers;
pub mod msg;
use std::{
@ -52,7 +53,6 @@ use sysinfo::{ProcessRefreshKind, RefreshKind, SystemExt};
use self::msg::{Msg, OutgoingMsg};
pub const DEFAULT_SOCKET_DIR: &str = "/tmp";
pub const SOCKET_NAME: &str = "pinnacle_socket";
fn handle_client(
@ -159,7 +159,8 @@ pub fn send_to_client(
stream: &mut UnixStream,
msg: &OutgoingMsg,
) -> Result<(), rmp_serde::encode::Error> {
// tracing::debug!("Sending {msg:?}");
tracing::trace!("Sending {msg:?}");
let msg = rmp_serde::to_vec_named(msg)?;
let msg_len = msg.len() as u32;
let bytes = msg_len.to_ne_bytes();
@ -201,11 +202,13 @@ impl EventSource for PinnacleSocketSource {
.process_events(readiness, token, |_readiness, listener| {
while let Ok((stream, _sock_addr)) = listener.accept() {
let sender = self.sender.clone();
let callback_stream = match stream.try_clone() {
Ok(callback_stream) => callback_stream,
Err(err) => return Err(err),
};
let callback_stream = stream.try_clone()?;
callback(callback_stream, &mut ());
// Handle the client in another thread as to not block the main one.
//
// No idea if this is even needed or if it's premature optimization.
std::thread::spawn(move || {
if let Err(err) = handle_client(stream, sender) {
tracing::error!("handle_client errored: {err}");

View file

@ -1,7 +1,7 @@
use std::ffi::OsString;
use async_process::Stdio;
use futures_lite::AsyncBufReadExt;
use futures_lite::{AsyncBufReadExt, StreamExt};
use smithay::{
desktop::space::SpaceElement,
input::keyboard::XkbConfig,
@ -11,18 +11,16 @@ use smithay::{
};
use crate::{
config::{
api::msg::{
Args, CallbackId, KeyIntOrString, Msg, OutgoingMsg, Request, RequestId, RequestResponse,
},
ConnectorSavedState,
api::msg::{
Args, CallbackId, KeyIntOrString, Msg, OutgoingMsg, Request, RequestId, RequestResponse,
},
config::ConnectorSavedState,
focus::FocusTarget,
tag::Tag,
window::WindowElement,
};
use super::{State, WithState};
use crate::state::{State, WithState};
impl State {
pub fn handle_msg(&mut self, msg: Msg) {
@ -361,10 +359,10 @@ impl State {
.stream
.as_ref()
.expect("stream doesn't exist");
let mut stream = stream.lock().expect("couldn't lock stream");
for output in self.space.outputs() {
crate::config::api::send_to_client(
&mut stream,
crate::api::send_to_client(
&mut stream.lock().expect("couldn't lock stream"),
&OutgoingMsg::CallCallback {
callback_id,
args: Some(Args::ConnectForAllOutputs {
@ -374,6 +372,7 @@ impl State {
)
.expect("Send to client failed");
}
self.config.output_callback_ids.push(callback_id);
}
Msg::SetOutputLocation { output_name, x, y } => {
@ -457,10 +456,10 @@ impl State {
let stream = self
.api_state
.stream
.as_ref()
.expect("Stream doesn't exist")
.clone();
.clone() // clone due to use of self below
.expect("Stream doesn't exist");
let mut stream = stream.lock().expect("Couldn't lock stream");
match request {
Request::GetWindows => {
let window_ids = self
@ -469,8 +468,7 @@ impl State {
.map(|win| win.with_state(|state| state.id))
.collect::<Vec<_>>();
// FIXME: figure out what to do if error
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -481,13 +479,16 @@ impl State {
}
Request::GetWindowProps { window_id } => {
let window = window_id.window(self);
let size = window
.as_ref()
.map(|win| (win.geometry().size.w, win.geometry().size.h));
let loc = window
.as_ref()
.and_then(|win| self.space.element_location(win))
.map(|loc| (loc.x, loc.y));
let (class, title) = window.as_ref().map_or((None, None), |win| match &win {
WindowElement::Wayland(_) => {
if let Some(wl_surf) = win.wl_surface() {
@ -508,17 +509,21 @@ impl State {
(Some(surface.class()), Some(surface.title()))
}
});
let focused = window.as_ref().and_then(|win| {
let output = win.output(self)?;
self.focused_window(&output).map(|foc_win| win == &foc_win)
});
let floating = window
.as_ref()
.map(|win| win.with_state(|state| state.floating_or_tiled.is_floating()));
let fullscreen_or_maximized = window
.as_ref()
.map(|win| win.with_state(|state| state.fullscreen_or_maximized));
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -541,7 +546,8 @@ impl State {
.outputs()
.map(|output| output.name())
.collect::<Vec<_>>();
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -555,38 +561,47 @@ impl State {
.space
.outputs()
.find(|output| output.name() == output_name);
let res = output.as_ref().and_then(|output| {
output.current_mode().map(|mode| (mode.size.w, mode.size.h))
});
let refresh_rate = output
.as_ref()
.and_then(|output| output.current_mode().map(|mode| mode.refresh));
let model = output
.as_ref()
.map(|output| output.physical_properties().model);
let physical_size = output.as_ref().map(|output| {
(
output.physical_properties().size.w,
output.physical_properties().size.h,
)
});
let make = output
.as_ref()
.map(|output| output.physical_properties().make);
let loc = output
.as_ref()
.map(|output| (output.current_location().x, output.current_location().y));
let focused = self
.focus_state
.focused_output
.as_ref()
.and_then(|foc_op| output.map(|op| op == foc_op));
let tag_ids = output.as_ref().map(|output| {
output.with_state(|state| {
state.tags.iter().map(|tag| tag.id()).collect::<Vec<_>>()
})
});
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -611,8 +626,8 @@ impl State {
.flat_map(|op| op.with_state(|state| state.tags.clone()))
.map(|tag| tag.id())
.collect::<Vec<_>>();
tracing::debug!("GetTags: {:?}", tag_ids);
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -623,13 +638,16 @@ impl State {
}
Request::GetTagProps { tag_id } => {
let tag = tag_id.tag(self);
let output_name = tag
.as_ref()
.and_then(|tag| tag.output(self))
.map(|output| output.name());
let active = tag.as_ref().map(|tag| tag.active());
let name = tag.as_ref().map(|tag| tag.name());
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
request_id,
@ -649,6 +667,7 @@ impl State {
let mut command = command.into_iter();
let Some(program) = command.next() else {
// TODO: notify that command was nothing
tracing::warn!("got an empty command");
return;
};
@ -690,31 +709,23 @@ impl State {
if let Some(callback_id) = callback_id {
let stdout = child.stdout.take();
let stderr = child.stderr.take();
let stream_out = self
.api_state
.stream
.as_ref()
.expect("Stream doesn't exist")
.clone();
let stream_out = self.api_state.stream.clone().expect("Stream doesn't exist");
let stream_err = stream_out.clone();
let stream_exit = stream_out.clone();
if let Some(stdout) = stdout {
let future = async move {
// TODO: use BufReader::new().lines()
let mut reader = futures_lite::io::BufReader::new(stdout);
loop {
let mut buf = String::new();
match reader.read_line(&mut buf).await {
Ok(0) => break,
Ok(_) => {
let mut stream = stream_out.lock().expect("Couldn't lock stream");
crate::config::api::send_to_client(
&mut stream,
let mut reader = futures_lite::io::BufReader::new(stdout).lines();
while let Some(line) = reader.next().await {
match line {
Ok(line) => {
crate::api::send_to_client(
&mut stream_out.lock().expect("Couldn't lock stream"),
&OutgoingMsg::CallCallback {
callback_id,
args: Some(Args::Spawn {
stdout: Some(buf.trim_end_matches('\n').to_string()),
stdout: Some(line),
stderr: None,
exit_code: None,
exit_msg: None,
@ -723,10 +734,8 @@ impl State {
)
.expect("Send to client failed"); // TODO: notify instead of crash
}
Err(err) => {
tracing::warn!("child read err: {err}");
break;
}
// TODO: possibly break on err?
Err(err) => tracing::warn!("read err: {err}"),
}
}
};
@ -736,22 +745,20 @@ impl State {
tracing::error!("Failed to schedule future: {err}");
}
}
if let Some(stderr) = stderr {
let future = async move {
let mut reader = futures_lite::io::BufReader::new(stderr);
loop {
let mut buf = String::new();
match reader.read_line(&mut buf).await {
Ok(0) => break,
Ok(_) => {
let mut stream = stream_err.lock().expect("Couldn't lock stream");
crate::config::api::send_to_client(
&mut stream,
let mut reader = futures_lite::io::BufReader::new(stderr).lines();
while let Some(line) = reader.next().await {
match line {
Ok(line) => {
crate::api::send_to_client(
&mut stream_err.lock().expect("Couldn't lock stream"),
&OutgoingMsg::CallCallback {
callback_id,
args: Some(Args::Spawn {
stdout: None,
stderr: Some(buf.trim_end_matches('\n').to_string()),
stderr: Some(line),
exit_code: None,
exit_msg: None,
}),
@ -759,13 +766,11 @@ impl State {
)
.expect("Send to client failed"); // TODO: notify instead of crash
}
Err(err) => {
tracing::warn!("child read err: {err}");
break;
}
Err(err) => tracing::warn!("read err: {err}"),
}
}
};
if let Err(err) = self.async_scheduler.schedule(future) {
tracing::error!("Failed to schedule future: {err}");
}
@ -774,9 +779,8 @@ impl State {
let future = async move {
match child.status().await {
Ok(exit_status) => {
let mut stream = stream_exit.lock().expect("Couldn't lock stream");
crate::config::api::send_to_client(
&mut stream,
crate::api::send_to_client(
&mut stream_exit.lock().expect("Couldn't lock stream"),
&OutgoingMsg::CallCallback {
callback_id,
args: Some(Args::Spawn {
@ -794,6 +798,7 @@ impl State {
}
}
};
if let Err(err) = self.async_scheduler.schedule(future) {
tracing::error!("Failed to schedule future: {err}");
}

View file

@ -74,11 +74,9 @@ use smithay_drm_extras::{
};
use crate::{
api::msg::{Args, OutgoingMsg},
backend::Backend,
config::{
api::msg::{Args, OutgoingMsg},
ConnectorSavedState,
},
config::ConnectorSavedState,
output::OutputName,
render::{pointer::PointerElement, take_presentation_feedback},
state::{CalloopData, State, SurfaceDmabufFeedback, WithState},
@ -1015,10 +1013,10 @@ impl State {
.api_state
.stream
.as_ref()
.expect("Stream doesn't exist");
let mut stream = stream.lock().expect("Couldn't lock stream");
.expect("stream doesn't exist");
let mut stream = stream.lock().expect("couldn't lock stream");
for callback_id in dt.state.config.output_callback_ids.iter() {
crate::config::api::send_to_client(
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::CallCallback {
callback_id: *callback_id,

View file

@ -1,7 +1,5 @@
pub mod api;
use crate::{
config::api::{msg::ModifierMask, PinnacleSocketSource},
api::{msg::ModifierMask, PinnacleSocketSource},
output::OutputName,
tag::Tag,
window::rules::{WindowRule, WindowRuleCondition},
@ -19,7 +17,7 @@ use smithay::{
};
use toml::Table;
use api::msg::Modifier;
use crate::api::msg::{CallbackId, Modifier};
use xkbcommon::xkb::Keysym;
use crate::{
@ -27,7 +25,7 @@ use crate::{
tag::TagId,
};
use self::api::msg::CallbackId;
const DEFAULT_SOCKET_DIR: &str = "/tmp";
#[derive(serde::Deserialize, Debug)]
pub struct Metaconfig {
@ -226,7 +224,7 @@ impl State {
crate::XDG_BASE_DIRS
.get_runtime_directory()
.cloned()
.unwrap_or(PathBuf::from(crate::config::api::DEFAULT_SOCKET_DIR))
.unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR))
};
let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir)

View file

@ -5,7 +5,7 @@ pub mod libinput;
use std::collections::HashMap;
use crate::{
config::api::msg::{CallbackId, Modifier, ModifierMask, MouseEdge, OutgoingMsg},
api::msg::{CallbackId, Modifier, ModifierMask, MouseEdge, OutgoingMsg},
focus::FocusTarget,
state::WithState,
window::WindowElement,
@ -244,7 +244,7 @@ impl State {
match action {
Some(KeyAction::CallCallback(callback_id)) => {
if let Some(stream) = self.api_state.stream.as_ref() {
if let Err(err) = crate::config::api::send_to_client(
if let Err(err) = crate::api::send_to_client(
&mut stream.lock().expect("Could not lock stream mutex"),
&OutgoingMsg::CallCallback {
callback_id,
@ -295,10 +295,9 @@ impl State {
.mousebinds
.get(&(modifier_mask, button, edge))
{
if let Some(stream) = self.api_state.stream.clone() {
let mut stream = stream.lock().expect("failed to lock api stream");
crate::config::api::send_to_client(
&mut stream,
if let Some(stream) = self.api_state.stream.as_ref() {
crate::api::send_to_client(
&mut stream.lock().expect("failed to lock api stream"),
&OutgoingMsg::CallCallback {
callback_id,
args: None,

View file

@ -16,6 +16,7 @@ use tracing_appender::rolling::Rotation;
use tracing_subscriber::{fmt::writer::MakeWriterExt, EnvFilter};
use xdg::BaseDirectories;
mod api;
mod backend;
mod config;
mod cursor;

View file

@ -1,15 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
mod api_handlers;
use std::{cell::RefCell, sync::Arc, time::Duration};
use crate::{
api::{msg::Msg, ApiState},
backend::Backend,
config::{
api::{msg::Msg, ApiState},
Config,
},
config::Config,
cursor::Cursor,
focus::FocusState,
grab::resize_grab::ResizeSurfaceState,
@ -77,8 +73,11 @@ pub struct State {
pub primary_selection_state: PrimarySelectionState,
pub layer_shell_state: WlrLayerShellState,
/// The state of key and mousebinds along with libinput settings
pub input_state: InputState,
/// The state holding stuff dealing with the api, like the stream
pub api_state: ApiState,
/// Keeps track of the focus stack and focused output
pub focus_state: FocusState,
pub popup_manager: PopupManager,
@ -87,12 +86,15 @@ pub struct State {
pub pointer_location: Point<f64, Logical>,
pub dnd_icon: Option<WlSurface>,
/// The main window vec
pub windows: Vec<WindowElement>,
pub config: Config,
/// A scheduler for futures
pub async_scheduler: Scheduler<()>,
// xwayland stuff
pub xwayland: XWayland,
pub xwm: Option<X11Wm>,
pub xdisplay: Option<u32>,