Update README

This commit is contained in:
Ottatop 2024-06-17 18:45:36 -05:00
parent 853a2a23f7
commit 2c52839d3e
4 changed files with 385 additions and 11 deletions

View file

@ -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)
for Wayland.
### What is Snowcap?
You will see references to Snowcap throughout this README. [Snowcap](https://github.com/pinnacle-comp/snowcap) is the
very, *very* WIP widget system for Pinnacle. Currently it's only being used for the builtin quit prompt and keybind overlay.
Pinnacle comes integrated with [Snowcap](https://github.com/pinnacle-comp/snowcap), a
very, *very* WIP widget system. 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.
> [!NOTE]
> Only the Rust API has implemented Snowcap integration currently. Lua support soon™
### Features
- Tag system
- 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
# For a Lua configuration
just install run -- -c "./api/lua/examples/default"
just install run -- -c ./api/lua/examples/default
# 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,
run the one in the following directory:
When running without compiled Snowcap integration,
use the following directories instead:
```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
@ -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.
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.
## 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.
# 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).
| Binding | Action |
|----------------------------------------------|------------------------------------|

View 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",
}

View 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)

View 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"