mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-13 08:01:05 +01:00
Add quit function to api, update README and example_config
This commit is contained in:
parent
c46159c77a
commit
8c054e17ba
8 changed files with 121 additions and 131 deletions
18
README.md
18
README.md
|
@ -77,7 +77,7 @@ It is *highly* recommended to use the [Lua language server](https://github.com/L
|
|||
Install the [Lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) plugin, then go into its settings and add the absolute(?) path to the [`api/lua`](api/lua) directory to Workspace: Library.
|
||||
|
||||
#### For Neovim:
|
||||
Pass
|
||||
Pass this table into your Lua language server settings:
|
||||
```lua
|
||||
Lua = {
|
||||
workspace = {
|
||||
|
@ -87,28 +87,18 @@ Lua = {
|
|||
}
|
||||
}
|
||||
```
|
||||
into your Lua language server settings.
|
||||
|
||||
Doc website soon:tm:
|
||||
|
||||
## Controls
|
||||
The following controls are currently hardcoded:
|
||||
|
||||
- `Esc`: Stop Pinnacle
|
||||
- `Ctrl + Left Mouse`: Move a window
|
||||
- `Ctrl + Right Mouse`: Resize a window
|
||||
|
||||
The following controls are set in the [`example_config`](api/lua/example_config.lua):
|
||||
- `Ctrl + Alt + C`: Close the currently focused window
|
||||
- `Ctrl + Alt + Space`: Toggle "floating" for the currently focused window
|
||||
- `Ctrl + Return`: Open Alacritty
|
||||
- `Ctrl + 1`: Open Kitty
|
||||
- `Ctrl + 2`: Open Foot
|
||||
- `Ctrl + 3`: Open Nautilus
|
||||
|
||||
"Floating" is in quotes because while windows do currently tile themselves, tiled ones can still be moved just like a floating window. Toggling to and from floating will retile all tiled windows.
|
||||
|
||||
The only layout currently is a master stack with the master on the left side.
|
||||
You can find the rest of the controls in the [`example_config`](api/lua/example_config.lua).
|
||||
|
||||
## A Small Note
|
||||
This is currently just a summer project I'm working on, but I hope that I can work on it enough that it becomes somewhat usable! If development slows down during the rest of the year, it's because :star:university:star:.
|
||||
|
||||
Also the only layout is kinda wonk right now if you close all but one window
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
require("pinnacle").setup(function(pinnacle)
|
||||
local input = pinnacle.input
|
||||
local client = pinnacle.client
|
||||
local keys = pinnacle.keys
|
||||
local process = pinnacle.process
|
||||
local input = pinnacle.input --Key and mouse binds
|
||||
local client = pinnacle.client --Window management
|
||||
local process = pinnacle.process -- Process spawning
|
||||
|
||||
input.keybind({ "Alt", "Ctrl" }, keys.c, client.close_window)
|
||||
-- Every key supported by xkbcommon.
|
||||
-- Support for just putting in a string of a key is intended.
|
||||
local keys = input.keys
|
||||
|
||||
-- Keybinds ----------------------------------------------------------------------
|
||||
input.keybind({ "Ctrl", "Alt" }, keys.c, client.close_window)
|
||||
|
||||
-- NOTE: In tiled mode you can still move stuff around as if it's floating. Actual tiling is TODO
|
||||
input.keybind({ "Ctrl", "Alt" }, keys.space, client.toggle_floating)
|
||||
|
||||
input.keybind({ "Ctrl" }, keys.Return, function()
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
local M = {}
|
||||
local M = {
|
||||
keys = require("keys"),
|
||||
}
|
||||
|
||||
---Set a keybind. If called on an already existing keybind, it gets replaced.
|
||||
---@param key Keys The key for the keybind. NOTE: uppercase and lowercase characters are considered different.
|
||||
|
|
|
@ -43,10 +43,14 @@ end
|
|||
local pinnacle = {
|
||||
input = require("input"),
|
||||
client = require("client"),
|
||||
keys = require("keys"),
|
||||
process = require("process"),
|
||||
}
|
||||
|
||||
---Quit Pinnacle.
|
||||
function pinnacle.quit()
|
||||
SendMsg("Quit")
|
||||
end
|
||||
|
||||
---Configure Pinnacle. You should put mostly eveything into the config_func to avoid invalid state.
|
||||
---The function takes one argument: the Pinnacle table, which is how you'll access all of the available config options.
|
||||
---@param config_func fun(pinnacle: Pinnacle)
|
||||
|
|
|
@ -66,7 +66,6 @@ impl PinnacleSocketSource {
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn send_to_client(
|
||||
stream: &mut UnixStream,
|
||||
msg: &OutgoingMsg,
|
||||
|
|
|
@ -41,6 +41,10 @@ pub enum Msg {
|
|||
#[serde(default)]
|
||||
callback_id: Option<CallbackId>,
|
||||
},
|
||||
|
||||
// Pinnacle management
|
||||
/// Quit the compositor.
|
||||
Quit,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
|
48
src/input.rs
48
src/input.rs
|
@ -228,17 +228,6 @@ impl<B: Backend> State<B> {
|
|||
{
|
||||
return FilterResult::Intercept(*callback_id);
|
||||
}
|
||||
match keysym.modified_sym() {
|
||||
keysyms::KEY_L => return FilterResult::Intercept(100),
|
||||
keysyms::KEY_K => return FilterResult::Intercept(200),
|
||||
keysyms::KEY_J => return FilterResult::Intercept(300),
|
||||
keysyms::KEY_H => return FilterResult::Intercept(400),
|
||||
keysyms::KEY_Escape => {
|
||||
state.loop_signal.stop();
|
||||
return FilterResult::Intercept(0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if keysym.modified_sym() == keysyms::KEY_Control_L {
|
||||
|
@ -259,34 +248,19 @@ impl<B: Backend> State<B> {
|
|||
|
||||
self.move_mode = move_mode;
|
||||
|
||||
let program = match action {
|
||||
Some(100) => "alacritty",
|
||||
Some(200) => "nautilus",
|
||||
Some(300) => "kitty",
|
||||
Some(400) => "foot",
|
||||
Some(callback_id) => {
|
||||
if let Some(stream) = self.api_state.stream.as_mut() {
|
||||
if let Err(err) = crate::api::send_to_client(
|
||||
&mut self.api_state.stream.as_ref().unwrap().lock().unwrap(),
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id: CallbackId(callback_id),
|
||||
args: None,
|
||||
},
|
||||
) {
|
||||
// TODO: print error
|
||||
}
|
||||
if let Some(callback_id) = action {
|
||||
if let Some(stream) = self.api_state.stream.as_ref() {
|
||||
if let Err(err) = crate::api::send_to_client(
|
||||
&mut stream.lock().unwrap(),
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id: CallbackId(callback_id),
|
||||
args: None,
|
||||
},
|
||||
) {
|
||||
// TODO: print error
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
None => return,
|
||||
};
|
||||
|
||||
tracing::info!("Spawning {}", program);
|
||||
std::process::Command::new(program)
|
||||
.env("WAYLAND_DISPLAY", self.socket_name.clone())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
155
src/state.rs
155
src/state.rs
|
@ -118,6 +118,7 @@ impl<B: Backend> State<B> {
|
|||
let (tx_channel, rx_channel) = calloop::channel::channel::<Msg>();
|
||||
loop_handle.insert_source(rx_channel, |msg, _, data| match msg {
|
||||
Event::Msg(msg) => {
|
||||
// TODO: move this into its own function
|
||||
match msg {
|
||||
Msg::SetKeybind {
|
||||
key,
|
||||
|
@ -162,6 +163,8 @@ impl<B: Backend> State<B> {
|
|||
.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() {
|
||||
|
@ -180,81 +183,84 @@ impl<B: Backend> State<B> {
|
|||
|
||||
// TODO: find a way to make this hellish code look better, deal with unwraps
|
||||
if let Some(callback_id) = callback_id {
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
let stderr = child.stderr.take().unwrap();
|
||||
let stream = data.state.api_state.stream.as_ref().unwrap().clone();
|
||||
// data.state
|
||||
// .api_state
|
||||
// .stream
|
||||
// .replace(stream.try_clone().unwrap());
|
||||
let stream2 = stream.clone();
|
||||
let stream3 = stream.clone();
|
||||
std::thread::spawn(move || {
|
||||
// TODO: maybe make this not a thread?
|
||||
let mut reader = BufReader::new(stdout);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
match reader.read_line(&mut buf) {
|
||||
Ok(0) => break, // EOF
|
||||
Ok(_) => {
|
||||
let mut stream = stream.lock().unwrap();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id,
|
||||
args: Some(Args::Spawn {
|
||||
stdout: Some(
|
||||
buf.trim_end_matches('\n').to_string(),
|
||||
),
|
||||
stderr: None,
|
||||
exit_code: None,
|
||||
exit_msg: None,
|
||||
}),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("child read err: {err}");
|
||||
break;
|
||||
let stdout = child.stdout.take();
|
||||
let stderr = child.stderr.take();
|
||||
let stream_out = data.state.api_state.stream.as_ref().unwrap().clone();
|
||||
let stream_err = stream_out.clone();
|
||||
let stream_exit = stream_out.clone();
|
||||
|
||||
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();
|
||||
match reader.read_line(&mut buf) {
|
||||
Ok(0) => break, // stream closed
|
||||
Ok(_) => {
|
||||
let mut stream = stream_out.lock().unwrap();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id,
|
||||
args: Some(Args::Spawn {
|
||||
stdout: Some(
|
||||
buf.trim_end_matches('\n')
|
||||
.to_string(),
|
||||
),
|
||||
stderr: None,
|
||||
exit_code: None,
|
||||
exit_msg: None,
|
||||
}),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("child read err: {err}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
let mut reader = BufReader::new(stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
match reader.read_line(&mut buf) {
|
||||
Ok(0) => break, // EOF
|
||||
Ok(_) => {
|
||||
let mut stream = stream2.lock().unwrap();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id,
|
||||
args: Some(Args::Spawn {
|
||||
stdout: None,
|
||||
stderr: Some(
|
||||
buf.trim_end_matches('\n').to_string(),
|
||||
),
|
||||
exit_code: None,
|
||||
exit_msg: None,
|
||||
}),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("child read err: {err}");
|
||||
break;
|
||||
});
|
||||
}
|
||||
if let Some(stderr) = stderr {
|
||||
std::thread::spawn(move || {
|
||||
let mut reader = BufReader::new(stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
match reader.read_line(&mut buf) {
|
||||
Ok(0) => break, // stream closed
|
||||
Ok(_) => {
|
||||
let mut stream = stream_err.lock().unwrap();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::CallCallback {
|
||||
callback_id,
|
||||
args: Some(Args::Spawn {
|
||||
stdout: None,
|
||||
stderr: Some(
|
||||
buf.trim_end_matches('\n')
|
||||
.to_string(),
|
||||
),
|
||||
exit_code: None,
|
||||
exit_msg: None,
|
||||
}),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("child read err: {err}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
std::thread::spawn(move || match child.wait() {
|
||||
Ok(exit_status) => {
|
||||
let mut stream = stream3.lock().unwrap();
|
||||
let mut stream = stream_exit.lock().unwrap();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::CallCallback {
|
||||
|
@ -275,9 +281,14 @@ impl<B: Backend> State<B> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add the rest
|
||||
_ => (),
|
||||
Msg::SpawnShell {
|
||||
shell,
|
||||
command,
|
||||
callback_id,
|
||||
} => todo!(),
|
||||
Msg::Quit => {
|
||||
data.state.loop_signal.stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
Event::Closed => todo!(),
|
||||
|
|
Loading…
Reference in a new issue