mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Update README
This commit is contained in:
parent
853a2a23f7
commit
2c52839d3e
4 changed files with 385 additions and 11 deletions
26
README.md
26
README.md
|
@ -35,14 +35,10 @@ Pinnacle is a Wayland compositor built in Rust using [Smithay](https://github.co
|
||||||
It's my attempt at creating something like [AwesomeWM](https://github.com/awesomeWM/awesome)
|
It's my attempt at creating something like [AwesomeWM](https://github.com/awesomeWM/awesome)
|
||||||
for Wayland.
|
for Wayland.
|
||||||
|
|
||||||
### What is Snowcap?
|
Pinnacle comes integrated with [Snowcap](https://github.com/pinnacle-comp/snowcap), a
|
||||||
You will see references to Snowcap throughout this README. [Snowcap](https://github.com/pinnacle-comp/snowcap) is the
|
very, *very* WIP widget system. Currently it's only being used for the builtin quit prompt and keybind overlay.
|
||||||
very, *very* WIP widget system for Pinnacle. Currently it's only being used for the builtin quit prompt and keybind overlay.
|
|
||||||
In the future, Snowcap will be used for everything Awesome uses its widget system for: a taskbar, system tray, etc.
|
In the future, Snowcap will be used for everything Awesome uses its widget system for: a taskbar, system tray, etc.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Only the Rust API has implemented Snowcap integration currently. Lua support soon™️
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Tag system
|
- Tag system
|
||||||
- Customizable layouts, including most of the ones from Awesome
|
- Customizable layouts, including most of the ones from Awesome
|
||||||
|
@ -170,16 +166,20 @@ the Lua or Rust default configs standalone, run one of the following in the crat
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# For a Lua configuration
|
# For a Lua configuration
|
||||||
just install run -- -c "./api/lua/examples/default"
|
just install run -- -c ./api/lua/examples/default
|
||||||
|
|
||||||
# For a Rust configuration
|
# For a Rust configuration
|
||||||
cargo run -- -c "./api/rust/examples/default_config"
|
cargo run -- -c ./api/rust/examples/default_config
|
||||||
```
|
```
|
||||||
|
|
||||||
When running the default Rust config standalone without compiled Snowcap integration,
|
When running without compiled Snowcap integration,
|
||||||
run the one in the following directory:
|
use the following directories instead:
|
||||||
```sh
|
```sh
|
||||||
cargo run -- -c "./api/rust/examples/default_config_no_snowcap"
|
# Lua
|
||||||
|
just install run -- -c ./api/lua/examples/default_no_snowcap
|
||||||
|
|
||||||
|
# Rust
|
||||||
|
cargo run -- -c ./api/rust/examples/default_config_no_snowcap
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom configuration
|
## Custom configuration
|
||||||
|
@ -200,6 +200,8 @@ It will then generate a config at that directory. If Lua is chosen and there are
|
||||||
files in the directory, the generator will prompt to rename them to a backup before continuing.
|
files in the directory, the generator will prompt to rename them to a backup before continuing.
|
||||||
If Rust is chosen, the directory must be manually emptied to continue.
|
If Rust is chosen, the directory must be manually emptied to continue.
|
||||||
|
|
||||||
|
Note that this currently copies default configs *with* Snowcap integration.
|
||||||
|
|
||||||
Run `cargo run -- config gen --help` for information on the command.
|
Run `cargo run -- config gen --help` for information on the command.
|
||||||
|
|
||||||
## More on configuration
|
## More on configuration
|
||||||
|
@ -252,6 +254,8 @@ Rust: https://pinnacle-comp.github.io/rust-reference/main.</b>
|
||||||
> Documentation for other branches can be reached by replacing `main` with the branch you want.
|
> Documentation for other branches can be reached by replacing `main` with the branch you want.
|
||||||
|
|
||||||
# Controls
|
# Controls
|
||||||
|
> Yes, ctrl is a bad mod key I know, this will be changed to Awesome keybinds soon
|
||||||
|
|
||||||
The following are the default controls in the [`default_config`](api/rust/examples/default_config/main.rs).
|
The following are the default controls in the [`default_config`](api/rust/examples/default_config/main.rs).
|
||||||
| Binding | Action |
|
| Binding | Action |
|
||||||
|----------------------------------------------|------------------------------------|
|
|----------------------------------------------|------------------------------------|
|
||||||
|
|
10
api/lua/examples/default_no_snowcap/.luarc.json
Normal file
10
api/lua/examples/default_no_snowcap/.luarc.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||||
|
"workspace.library": [
|
||||||
|
"~/.luarocks/share/lua/5.4/pinnacle.lua",
|
||||||
|
"~/.luarocks/share/lua/5.4/pinnacle",
|
||||||
|
"~/.luarocks/share/lua/5.4/snowcap.lua",
|
||||||
|
"~/.luarocks/share/lua/5.4/snowcap"
|
||||||
|
],
|
||||||
|
"runtime.version": "Lua 5.4",
|
||||||
|
}
|
314
api/lua/examples/default_no_snowcap/default_config.lua
Normal file
314
api/lua/examples/default_no_snowcap/default_config.lua
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
-- neovim users be like
|
||||||
|
require("pinnacle").setup(function(Pinnacle)
|
||||||
|
local Input = Pinnacle.input
|
||||||
|
local Process = Pinnacle.process
|
||||||
|
local Output = Pinnacle.output
|
||||||
|
local Tag = Pinnacle.tag
|
||||||
|
local Window = Pinnacle.window
|
||||||
|
local Layout = Pinnacle.layout
|
||||||
|
local Util = Pinnacle.util
|
||||||
|
|
||||||
|
local key = Input.key
|
||||||
|
|
||||||
|
---@type Modifier
|
||||||
|
local mod_key = "ctrl"
|
||||||
|
|
||||||
|
local terminal = "alacritty"
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
-- Mousebinds --
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Input.mousebind({ mod_key }, "btn_left", "press", function()
|
||||||
|
Window.begin_move("btn_left")
|
||||||
|
end)
|
||||||
|
|
||||||
|
Input.mousebind({ mod_key }, "btn_right", "press", function()
|
||||||
|
Window.begin_resize("btn_right")
|
||||||
|
end)
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
-- Keybinds --
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
-- mod_key + alt + q = Quit Pinnacle
|
||||||
|
Input.keybind({ mod_key, "alt" }, "q", function()
|
||||||
|
Pinnacle.quit()
|
||||||
|
end, {
|
||||||
|
group = "Compositor",
|
||||||
|
description = "Quit Pinnacle",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + alt + r = Reload config
|
||||||
|
Input.keybind({ mod_key, "alt" }, "r", function()
|
||||||
|
Pinnacle.reload_config()
|
||||||
|
end, {
|
||||||
|
group = "Compositor",
|
||||||
|
description = "Reload the config",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + alt + c = Close window
|
||||||
|
Input.keybind({ mod_key, "alt" }, "c", function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:close()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Window",
|
||||||
|
description = "Close the focused window",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + alt + Return = Spawn `terminal`
|
||||||
|
Input.keybind({ mod_key }, key.Return, function()
|
||||||
|
Process.spawn(terminal)
|
||||||
|
end, {
|
||||||
|
group = "Process",
|
||||||
|
description = "Spawn `alacritty`",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + alt + space = Toggle floating
|
||||||
|
Input.keybind({ mod_key, "alt" }, key.space, function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:toggle_floating()
|
||||||
|
focused:raise()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Window",
|
||||||
|
description = "Toggle floating on the focused window",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + f = Toggle fullscreen
|
||||||
|
Input.keybind({ mod_key }, "f", function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:toggle_fullscreen()
|
||||||
|
focused:raise()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Window",
|
||||||
|
description = "Toggle fullscreen on the focused window",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + m = Toggle maximized
|
||||||
|
Input.keybind({ mod_key }, "m", function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:toggle_maximized()
|
||||||
|
focused:raise()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Window",
|
||||||
|
description = "Toggle maximized on the focused window",
|
||||||
|
})
|
||||||
|
|
||||||
|
----------------------
|
||||||
|
-- Tags and Outputs --
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
local tag_names = { "1", "2", "3", "4", "5" }
|
||||||
|
|
||||||
|
-- Setup outputs.
|
||||||
|
--
|
||||||
|
-- `Output.setup` allows you to declare things like mode, scale, and tags for outputs.
|
||||||
|
-- Here we give all outputs tags 1 through 5.
|
||||||
|
Output.setup({
|
||||||
|
-- "*" matches all outputs
|
||||||
|
["*"] = { tags = tag_names },
|
||||||
|
})
|
||||||
|
|
||||||
|
-- If you want to declare output locations as well, you can use `Output.setup_locs`.
|
||||||
|
-- This will additionally allow you to recalculate output locations on signals like
|
||||||
|
-- output connect, disconnect, and resize.
|
||||||
|
--
|
||||||
|
-- Read the admittedly scuffed docs for more.
|
||||||
|
|
||||||
|
-- Tag keybinds
|
||||||
|
for _, tag_name in ipairs(tag_names) do
|
||||||
|
-- nil-safety: tags are guaranteed to be on the outputs due to connect_for_all above
|
||||||
|
|
||||||
|
-- mod_key + 1-5 = Switch to tags 1-5
|
||||||
|
Input.keybind({ mod_key }, tag_name, function()
|
||||||
|
Tag.get(tag_name):switch_to()
|
||||||
|
end, {
|
||||||
|
group = "Tag",
|
||||||
|
description = "Switch to tag " .. tag_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + shift + 1-5 = Toggle tags 1-5
|
||||||
|
Input.keybind({ mod_key, "shift" }, tag_name, function()
|
||||||
|
Tag.get(tag_name):toggle_active()
|
||||||
|
end, {
|
||||||
|
group = "Tag",
|
||||||
|
description = "Toggle tag " .. tag_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + alt + 1-5 = Move window to tags 1-5
|
||||||
|
Input.keybind({ mod_key, "alt" }, tag_name, function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:move_to_tag(Tag.get(tag_name) --[[@as TagHandle]])
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Tag",
|
||||||
|
description = "Move the focused window to tag " .. tag_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + shift + alt + 1-5 = Toggle tags 1-5 on window
|
||||||
|
Input.keybind({ mod_key, "shift", "alt" }, tag_name, function()
|
||||||
|
local focused = Window.get_focused()
|
||||||
|
if focused then
|
||||||
|
focused:toggle_tag(Tag.get(tag_name) --[[@as TagHandle]])
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Tag",
|
||||||
|
description = "Toggle tag " .. tag_name .. " on the focused window",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
-- Layouts --
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
-- Pinnacle does not manage layouts compositor-side.
|
||||||
|
-- Instead, it delegates computation of layouts to your config,
|
||||||
|
-- which provides an interface to calculate the size and location of
|
||||||
|
-- windows that the compositor will use to position windows.
|
||||||
|
--
|
||||||
|
-- If you're familiar with River's layout generators, you'll understand the system here
|
||||||
|
-- a bit better.
|
||||||
|
--
|
||||||
|
-- The Lua API provides two layout system abstractions:
|
||||||
|
-- 1. Layout managers, and
|
||||||
|
-- 2. Layout generators.
|
||||||
|
--
|
||||||
|
-- ### Layout Managers ###
|
||||||
|
-- A layout manager is a table that contains a `get_active` function
|
||||||
|
-- that returns some layout generator.
|
||||||
|
-- A manager is meant to keep track of and choose various layout generators
|
||||||
|
-- across your usage of the compositor.
|
||||||
|
--
|
||||||
|
-- ### Layout generators ###
|
||||||
|
-- A layout generator is a table that holds some state as well as
|
||||||
|
-- the `layout` function, which takes in layout arguments and computes
|
||||||
|
-- an array of geometries that will determine the size and position
|
||||||
|
-- of windows being laid out.
|
||||||
|
--
|
||||||
|
-- There is one built-in layout manager and five built-in layout generators,
|
||||||
|
-- as shown below.
|
||||||
|
--
|
||||||
|
-- Additionally, this system is designed to be user-extensible;
|
||||||
|
-- you are free to create your own layout managers and generators for
|
||||||
|
-- maximum customizability! Docs for doing so are in the works, so sit tight.
|
||||||
|
|
||||||
|
-- Create a cycling layout manager. This provides methods to cycle
|
||||||
|
-- between the given layout generators below.
|
||||||
|
local layout_manager = Layout.new_cycling_manager({
|
||||||
|
-- `Layout.builtins` contains functions that create various layout generators.
|
||||||
|
-- Each of these has settings that can be overridden by passing in a table with
|
||||||
|
-- overriding options.
|
||||||
|
Layout.builtins.master_stack(),
|
||||||
|
Layout.builtins.master_stack({ master_side = "right" }),
|
||||||
|
Layout.builtins.master_stack({ master_side = "top" }),
|
||||||
|
Layout.builtins.master_stack({ master_side = "bottom" }),
|
||||||
|
Layout.builtins.dwindle(),
|
||||||
|
Layout.builtins.spiral(),
|
||||||
|
Layout.builtins.corner(),
|
||||||
|
Layout.builtins.corner({ corner_loc = "top_right" }),
|
||||||
|
Layout.builtins.corner({ corner_loc = "bottom_left" }),
|
||||||
|
Layout.builtins.corner({ corner_loc = "bottom_right" }),
|
||||||
|
Layout.builtins.fair(),
|
||||||
|
Layout.builtins.fair({ direction = "horizontal" }),
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Set the cycling layout manager as the layout manager that will be used.
|
||||||
|
-- This then allows you to call `Layout.request_layout` to manually layout windows.
|
||||||
|
Layout.set_manager(layout_manager)
|
||||||
|
|
||||||
|
-- mod_key + space = Cycle forward one layout on the focused output
|
||||||
|
--
|
||||||
|
-- Yes, this is a bit verbose for my liking.
|
||||||
|
-- You need to cycle the layout on the first active tag
|
||||||
|
-- because that is the one that decides which layout is used.
|
||||||
|
Input.keybind({ mod_key }, key.space, function()
|
||||||
|
local focused_op = Output.get_focused()
|
||||||
|
if focused_op then
|
||||||
|
local tags = focused_op:tags() or {}
|
||||||
|
local tag = nil
|
||||||
|
|
||||||
|
---@type (fun(): (boolean|nil))[]
|
||||||
|
local tag_actives = {}
|
||||||
|
for i, t in ipairs(tags) do
|
||||||
|
tag_actives[i] = function()
|
||||||
|
return t:active()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We are batching API calls here for better performance
|
||||||
|
tag_actives = Util.batch(tag_actives)
|
||||||
|
|
||||||
|
for i, active in ipairs(tag_actives) do
|
||||||
|
if active then
|
||||||
|
tag = tags[i]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if tag then
|
||||||
|
layout_manager:cycle_layout_forward(tag)
|
||||||
|
Layout.request_layout(focused_op)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Layout",
|
||||||
|
description = "Cycle the layout forward on the first active tag",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- mod_key + shift + space = Cycle backward one layout on the focused output
|
||||||
|
Input.keybind({ mod_key, "shift" }, key.space, function()
|
||||||
|
local focused_op = Output.get_focused()
|
||||||
|
if focused_op then
|
||||||
|
local tags = focused_op:tags() or {}
|
||||||
|
local tag = nil
|
||||||
|
|
||||||
|
---@type (fun(): (boolean|nil))[]
|
||||||
|
local tag_actives = {}
|
||||||
|
for i, t in ipairs(tags) do
|
||||||
|
tag_actives[i] = function()
|
||||||
|
return t:active()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tag_actives = Util.batch(tag_actives)
|
||||||
|
|
||||||
|
for i, active in ipairs(tag_actives) do
|
||||||
|
if active then
|
||||||
|
tag = tags[i]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if tag then
|
||||||
|
layout_manager:cycle_layout_backward(tag)
|
||||||
|
Layout.request_layout(focused_op)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
group = "Layout",
|
||||||
|
description = "Cycle the layout backward on the first active tag",
|
||||||
|
})
|
||||||
|
|
||||||
|
Input.set_libinput_settings({
|
||||||
|
tap = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Enable sloppy focus
|
||||||
|
Window.connect_signal({
|
||||||
|
pointer_enter = function(window)
|
||||||
|
window:set_focused(true)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Spawning should happen after you add tags, as Pinnacle currently doesn't render windows without tags.
|
||||||
|
Process.spawn_once(terminal)
|
||||||
|
end)
|
46
api/lua/examples/default_no_snowcap/metaconfig.toml
Normal file
46
api/lua/examples/default_no_snowcap/metaconfig.toml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# This metaconfig.toml file dictates what config Pinnacle will run.
|
||||||
|
#
|
||||||
|
# When running Pinnacle, the compositor will look in the following directories for a metaconfig.toml file,
|
||||||
|
# in order from top to bottom:
|
||||||
|
# $PINNACLE_CONFIG_DIR
|
||||||
|
# $XDG_CONFIG_HOME/pinnacle/
|
||||||
|
# ~/.config/pinnacle/
|
||||||
|
#
|
||||||
|
# When Pinnacle finds a metaconfig.toml file, it will execute the command provided to `command`.
|
||||||
|
# To use a Rust config, this should be changed to something like ["cargo", "run"].
|
||||||
|
#
|
||||||
|
# Because configuration is done using an external process, if it ever crashes, you lose all of your keybinds.
|
||||||
|
# The compositor will load the default config if that happens, but in the event that you don't have
|
||||||
|
# the necessary dependencies for it to run, you may get softlocked.
|
||||||
|
# In order prevent you from getting stuck in the compositor, you must define keybinds to reload your config
|
||||||
|
# and kill Pinnacle.
|
||||||
|
#
|
||||||
|
# More details on each setting can be found below.
|
||||||
|
|
||||||
|
# The command Pinnacle will run on startup and when you reload your config.
|
||||||
|
# Paths are relative to the directory the metaconfig.toml file is in.
|
||||||
|
# This must be an array.
|
||||||
|
command = ["lua", "default_config.lua"]
|
||||||
|
|
||||||
|
### Keybinds ###
|
||||||
|
# Each keybind takes in a table with two fields: `modifiers` and `key`.
|
||||||
|
# - `modifiers` can be one of "Ctrl", "Alt", "Shift", or "Super".
|
||||||
|
# - `key` can be a string of any lowercase letter, number,
|
||||||
|
# "numN" where N is a number for numpad keys, or "esc"/"escape".
|
||||||
|
# Support for any xkbcommon key is planned for a future update.
|
||||||
|
|
||||||
|
# The keybind that will reload your config.
|
||||||
|
reload_keybind = { modifiers = ["Ctrl", "Alt"], key = "r" }
|
||||||
|
# The keybind that will kill Pinnacle.
|
||||||
|
kill_keybind = { modifiers = ["Ctrl", "Alt", "Shift"], key = "escape" }
|
||||||
|
|
||||||
|
### Socket directory ###
|
||||||
|
# Pinnacle will open a Unix socket at `$XDG_RUNTIME_DIR` by default, falling back to `/tmp` if it doesn't exist.
|
||||||
|
# If you want/need to change this, use the `socket_dir` setting set to the directory of your choosing.
|
||||||
|
#
|
||||||
|
# socket_dir = "/your/dir/here/"
|
||||||
|
|
||||||
|
### Environment Variables ###
|
||||||
|
# If you need to spawn your config with any environment variables, list them here.
|
||||||
|
[envs]
|
||||||
|
# key = "value"
|
Loading…
Reference in a new issue