mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-05 20:46:27 +01:00
Merge pull request #74 from Ottatop/improve_api
Improve api and fix stuff
This commit is contained in:
commit
b719ad4a3c
15 changed files with 332 additions and 177 deletions
|
@ -31,6 +31,7 @@ shellexpand = "3.1.0"
|
|||
toml = "0.7.7"
|
||||
anyhow = { version = "1.0.75", features = ["backtrace"] }
|
||||
clap = { version = "4.4.2", features = ["derive"] }
|
||||
xkbcommon = "0.6.0"
|
||||
|
||||
[features]
|
||||
default = ["egl", "winit", "udev", "xwayland"]
|
||||
|
|
|
@ -18,7 +18,6 @@ require("pinnacle").setup(function(pinnacle)
|
|||
local output = pinnacle.output -- Output management
|
||||
|
||||
-- Every key supported by xkbcommon.
|
||||
-- Support for just putting in a string of a key is intended.
|
||||
local keys = input.keys
|
||||
|
||||
---@type Modifier
|
||||
|
@ -85,10 +84,12 @@ require("pinnacle").setup(function(pinnacle)
|
|||
|
||||
-- Tags ---------------------------------------------------------------------------
|
||||
|
||||
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("1", "2", "3", "4", "5")
|
||||
op:add_tags(tags)
|
||||
-- Same as tag.add(op, "1", "2", "3", "4", "5")
|
||||
tag.toggle({ name = "1", output = op })
|
||||
|
||||
|
@ -112,8 +113,11 @@ require("pinnacle").setup(function(pinnacle)
|
|||
-- })
|
||||
end)
|
||||
|
||||
---@type Layout[]
|
||||
local layouts = {
|
||||
-- Layout cycling
|
||||
|
||||
-- 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",
|
||||
|
@ -121,118 +125,29 @@ require("pinnacle").setup(function(pinnacle)
|
|||
"CornerTopRight",
|
||||
"CornerBottomLeft",
|
||||
"CornerBottomRight",
|
||||
}
|
||||
local indices = {}
|
||||
})
|
||||
|
||||
-- Layout cycling
|
||||
-- Yes, this is overly complicated and yes, I'll cook up a way to make it less so.
|
||||
input.keybind({ mod_key }, keys.space, function()
|
||||
local tags = output.get_focused():tags()
|
||||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local name = tg:name()
|
||||
if name == nil then
|
||||
return
|
||||
end
|
||||
tg:set_layout(layouts[indices[name] or 1])
|
||||
if indices[name] == nil then
|
||||
indices[name] = 2
|
||||
else
|
||||
if indices[name] + 1 > #layouts then
|
||||
indices[name] = 1
|
||||
else
|
||||
indices[name] = indices[name] + 1
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift" }, keys.space, function()
|
||||
local tags = output.get_focused():tags()
|
||||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local name = tg:name()
|
||||
if name == nil then
|
||||
return
|
||||
end
|
||||
tg:set_layout(layouts[indices[name] or #layouts])
|
||||
if indices[name] == nil then
|
||||
indices[name] = #layouts - 1
|
||||
else
|
||||
if indices[name] - 1 < 1 then
|
||||
indices[name] = #layouts
|
||||
else
|
||||
indices[name] = indices[name] - 1
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
input.keybind({ mod_key }, keys.space, layout_cycler.next)
|
||||
input.keybind({ mod_key, "Shift" }, keys.space, layout_cycler.prev)
|
||||
|
||||
input.keybind({ mod_key }, keys.KEY_1, function()
|
||||
tag.switch_to("1")
|
||||
end)
|
||||
input.keybind({ mod_key }, keys.KEY_2, function()
|
||||
tag.switch_to("2")
|
||||
end)
|
||||
input.keybind({ mod_key }, keys.KEY_3, function()
|
||||
tag.switch_to("3")
|
||||
end)
|
||||
input.keybind({ mod_key }, keys.KEY_4, function()
|
||||
tag.switch_to("4")
|
||||
end)
|
||||
input.keybind({ mod_key }, keys.KEY_5, function()
|
||||
tag.switch_to("5")
|
||||
end)
|
||||
-- Tag manipulation
|
||||
|
||||
input.keybind({ mod_key, "Shift" }, keys.KEY_1, function()
|
||||
tag.toggle("1")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift" }, keys.KEY_2, function()
|
||||
tag.toggle("2")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift" }, keys.KEY_3, function()
|
||||
tag.toggle("3")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift" }, keys.KEY_4, function()
|
||||
tag.toggle("4")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift" }, keys.KEY_5, function()
|
||||
tag.toggle("5")
|
||||
end)
|
||||
|
||||
-- I check for nil this way because I don't want stylua to take up like 80 lines on `if win ~= nil`
|
||||
input.keybind({ mod_key, "Alt" }, keys.KEY_1, function()
|
||||
local _ = window.get_focused() and window:get_focused():move_to_tag("1")
|
||||
end)
|
||||
input.keybind({ mod_key, "Alt" }, keys.KEY_2, function()
|
||||
local _ = window.get_focused() and window:get_focused():move_to_tag("2")
|
||||
end)
|
||||
input.keybind({ mod_key, "Alt" }, keys.KEY_3, function()
|
||||
local _ = window.get_focused() and window:get_focused():move_to_tag("3")
|
||||
end)
|
||||
input.keybind({ mod_key, "Alt" }, keys.KEY_4, function()
|
||||
local _ = window.get_focused() and window:get_focused():move_to_tag("4")
|
||||
end)
|
||||
input.keybind({ mod_key, "Alt" }, keys.KEY_5, function()
|
||||
local _ = window.get_focused() and window:get_focused():move_to_tag("5")
|
||||
end)
|
||||
|
||||
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_1, function()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag("1")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_2, function()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag("2")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_3, function()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag("3")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_4, function()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag("4")
|
||||
end)
|
||||
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_5, function()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag("5")
|
||||
end)
|
||||
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)
|
||||
-- mod_key + Shift + 1-5 toggles tags
|
||||
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()
|
||||
local _ = window.get_focused() and 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()
|
||||
local _ = window.get_focused() and window.get_focused():toggle_tag(tag_name)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
|
|
@ -1,12 +1,37 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
---Input management.
|
||||
---
|
||||
---This module provides utilities to set keybinds.
|
||||
---@class InputModule
|
||||
local input_module = {
|
||||
--- A table with every key provided by xkbcommon.
|
||||
keys = require("keys"),
|
||||
}
|
||||
|
||||
---Set a keybind. If called with an already existing keybind, it gets replaced.
|
||||
---
|
||||
---You must provide three arguments:
|
||||
---
|
||||
--- - `modifiers`: An array of `Modifier`s. If you don't want any, provide an empty table.
|
||||
--- - `key`: The key that will trigger `action`. You can provide three types of key:
|
||||
--- - Something from the `Keys` table in `input.keys`, which lists every xkbcommon key. The naming pattern is the xkbcommon key without the `KEY_` prefix, unless that would make it start with a number or the reserved lua keyword `function`, in which case the `KEY_` prefix is included.
|
||||
--- - A single character representing your key. This can be something like "g", "$", "~", "1", and so on.
|
||||
--- - A string of the key's name. This is the name of the xkbcommon key without the `KEY_` prefix.
|
||||
--- - `action`: The function that will be run when the keybind is pressed.
|
||||
---
|
||||
---It is important to note that `"a"` is different than `"A"`. Similarly, `keys.a` is different than `keys.A`.
|
||||
---Usually, it's best to use the non-modified key to prevent confusion and unintended behavior.
|
||||
---
|
||||
---```lua
|
||||
---input.keybind({ "Shift" }, "a", function() end) -- This is preferred
|
||||
---input.keybind({ "Shift" }, "A", function() end) -- over this
|
||||
---
|
||||
--- -- And in fact, this keybind won't work at all because it expects no modifiers,
|
||||
--- -- but you can't get "A" without using `Shift`.
|
||||
---input.keybind({}, "A", function() end)
|
||||
---```
|
||||
---
|
||||
---### Example
|
||||
---
|
||||
---```lua
|
||||
|
@ -15,15 +40,24 @@ local input_module = {
|
|||
--- process.spawn("Alacritty")
|
||||
---end)
|
||||
---```
|
||||
---@param key Keys The key for the keybind.
|
||||
---@param key Keys|string The key for the keybind.
|
||||
---@param modifiers (Modifier)[] Which modifiers need to be pressed for the keybind to trigger.
|
||||
---@param action fun() What to do.
|
||||
function input_module.keybind(modifiers, key, action)
|
||||
table.insert(CallbackTable, action)
|
||||
|
||||
local k = {}
|
||||
|
||||
if type(key) == "string" then
|
||||
k.String = key
|
||||
else
|
||||
k.Int = key
|
||||
end
|
||||
|
||||
SendMsg({
|
||||
SetKeybind = {
|
||||
modifiers = modifiers,
|
||||
key = key,
|
||||
key = k,
|
||||
callback_id = #CallbackTable,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
---@meta _
|
||||
|
||||
---@class _Msg
|
||||
---@field SetKeybind { key: Keys, modifiers: Modifier[], callback_id: integer }?
|
||||
---@field SetKeybind { key: { Int: Keys?, String: string? }, modifiers: Modifier[], callback_id: integer }?
|
||||
---@field SetMousebind { button: integer }?
|
||||
--Windows
|
||||
---@field CloseWindow { window_id: WindowId }?
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
---@diagnostic disable: redefined-local
|
||||
|
||||
---Process management.
|
||||
---
|
||||
---This module provides utilities to spawn processes and capture their output.
|
||||
---@class ProcessModule
|
||||
local process_module = {}
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
indent_type = "Spaces"
|
||||
column_width = 80
|
||||
column_width = 120
|
||||
|
|
127
api/lua/tag.lua
127
api/lua/tag.lua
|
@ -168,14 +168,9 @@ end
|
|||
---local op = output.get_by_name("DP-1")
|
||||
---
|
||||
---tag.toggle("1") -- Toggle tag 1 on the focused output
|
||||
---tag.toggle({ "1" }) -- Same as above
|
||||
---
|
||||
---tag.toggle({ "1", "DP-1" }) -- Toggle tag 1 on DP-1
|
||||
---tag.toggle({ "1", op }) -- Same as above
|
||||
---
|
||||
--- -- Verbose versions of the two above
|
||||
---tag.toggle({ name = "1", output = "DP-1" })
|
||||
---tag.toggle({ name = "1", output = op })
|
||||
---tag.toggle({ name = "1", output = "DP-1" }) -- Toggle tag 1 on "DP-1"
|
||||
---tag.toggle({ name = "1", output = op }) -- Same as above
|
||||
---
|
||||
--- -- Using a tag object
|
||||
---local t = tag.get_by_name("1")[1] -- `t` is the first tag with the name "1"
|
||||
|
@ -205,14 +200,9 @@ end
|
|||
---local op = output.get_by_name("DP-1")
|
||||
---
|
||||
---tag.switch_to("1") -- Switch to tag 1 on the focused output
|
||||
---tag.switch_to({ "1" }) -- Same as above
|
||||
---
|
||||
---tag.switch_to({ "1", "DP-1" }) -- Switch to tag 1 on DP-1
|
||||
---tag.switch_to({ "1", op }) -- Same as above
|
||||
---
|
||||
--- -- Verbose versions of the two above
|
||||
---tag.switch_to({ name = "1", output = "DP-1" })
|
||||
---tag.switch_to({ name = "1", output = op })
|
||||
---tag.switch_to({ name = "1", output = "DP-1" }) -- Switch to tag 1 on "DP-1"
|
||||
---tag.switch_to({ name = "1", output = op }) -- Same as above
|
||||
---
|
||||
--- -- Using a tag object
|
||||
---local t = tag.get_by_name("1")[1] -- `t` is the first tag with the name "1"
|
||||
|
@ -472,4 +462,113 @@ function tag_module.output(t)
|
|||
return require("output").get_for_tag(t)
|
||||
end
|
||||
|
||||
---@class LayoutCycler
|
||||
---@field next fun(output: (Output|OutputName)?) Change the first active tag on `output` to its next layout. If `output` is empty, the focused output is used.
|
||||
---@field prev fun(output: (Output|OutputName)?) Change the first active tag on `output` to its previous layout. If `output` is empty, the focused output is used.
|
||||
|
||||
---Given an array of layouts, this will create two functions; one will cycle forward the layout
|
||||
---for the provided tag, and one will cycle backward.
|
||||
---
|
||||
--- ### Example
|
||||
---```lua
|
||||
---local layout_cycler = tag.layout_cycler({ "Dwindle", "Spiral", "MasterStack" })
|
||||
---
|
||||
---layout_cycler.next() -- Go to the next layout on the first tag of the focused output
|
||||
---layout_cycler.prev() -- Go to the previous layout on the first tag of the focused output
|
||||
---
|
||||
---layout_cycler.next("DP-1") -- Do the above but on "DP-1" instead
|
||||
---layout_cycler.prev(output.get_by_name("DP-1")) -- With an output object
|
||||
---```
|
||||
---@param layouts Layout[] The available layouts.
|
||||
---@return LayoutCycler layout_cycler A table with the functions `next` and `prev`, which will cycle layouts for the given tag.
|
||||
function tag_module.layout_cycler(layouts)
|
||||
local indices = {}
|
||||
|
||||
-- Return empty functions if layouts is empty
|
||||
if #layouts == 0 then
|
||||
return {
|
||||
next = function(_) end,
|
||||
prev = function(_) end,
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
---@param output (Output|OutputName)?
|
||||
next = function(output)
|
||||
if type(output) == "string" then
|
||||
output = require("output").get_by_name(output)
|
||||
end
|
||||
|
||||
output = output or require("output").get_focused()
|
||||
|
||||
if output == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local tags = output:tags()
|
||||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local id = tg:id()
|
||||
if id == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if #layouts == 1 then
|
||||
indices[id] = 1
|
||||
elseif indices[id] == nil then
|
||||
indices[id] = 2
|
||||
else
|
||||
if indices[id] + 1 > #layouts then
|
||||
indices[id] = 1
|
||||
else
|
||||
indices[id] = indices[id] + 1
|
||||
end
|
||||
end
|
||||
|
||||
tg:set_layout(layouts[indices[id]])
|
||||
break
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---@param output (Output|OutputName)?
|
||||
prev = function(output)
|
||||
if type(output) == "string" then
|
||||
output = require("output").get_by_name(output)
|
||||
end
|
||||
|
||||
output = output or require("output").get_focused()
|
||||
|
||||
if output == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local tags = output:tags()
|
||||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local id = tg:id()
|
||||
if id == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if #layouts == 1 then
|
||||
indices[id] = 1
|
||||
elseif indices[id] == nil then
|
||||
indices[id] = #layouts - 1
|
||||
else
|
||||
if indices[id] - 1 < 1 then
|
||||
indices[id] = #layouts
|
||||
else
|
||||
indices[id] = indices[id] - 1
|
||||
end
|
||||
end
|
||||
|
||||
tg:set_layout(layouts[indices[id]])
|
||||
break
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return tag_module
|
||||
|
|
|
@ -17,11 +17,17 @@ use self::window_rules::{WindowRule, WindowRuleCondition};
|
|||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
||||
pub struct CallbackId(pub u32);
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
|
||||
pub enum KeyIntOrString {
|
||||
Int(u32),
|
||||
String(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Msg {
|
||||
// Input
|
||||
SetKeybind {
|
||||
key: u32,
|
||||
key: KeyIntOrString,
|
||||
modifiers: Vec<Modifier>,
|
||||
callback_id: CallbackId,
|
||||
},
|
||||
|
|
|
@ -72,7 +72,7 @@ use smithay::{
|
|||
backend::GlobalId, protocol::wl_surface::WlSurface, Display, DisplayHandle,
|
||||
},
|
||||
},
|
||||
utils::{Clock, DeviceFd, Logical, Monotonic, Physical, Point, Rectangle, Transform},
|
||||
utils::{Clock, DeviceFd, IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Transform},
|
||||
wayland::{
|
||||
dmabuf::{DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
|
||||
input_method::{InputMethodHandle, InputMethodSeat},
|
||||
|
@ -86,7 +86,9 @@ use smithay_drm_extras::{
|
|||
use crate::{
|
||||
api::msg::{Args, OutgoingMsg},
|
||||
render::{pointer::PointerElement, CustomRenderElements},
|
||||
state::{take_presentation_feedback, Backend, CalloopData, State, SurfaceDmabufFeedback},
|
||||
state::{
|
||||
take_presentation_feedback, Backend, CalloopData, State, SurfaceDmabufFeedback, WithState,
|
||||
},
|
||||
window::WindowElement,
|
||||
};
|
||||
|
||||
|
@ -151,14 +153,10 @@ pub fn run_udev() -> anyhow::Result<()> {
|
|||
let mut event_loop = EventLoop::try_new().unwrap();
|
||||
let mut display = Display::new().unwrap();
|
||||
|
||||
/*
|
||||
* Initialize session
|
||||
*/
|
||||
// Initialize session
|
||||
let (session, notifier) = LibSeatSession::new()?;
|
||||
|
||||
/*
|
||||
* Initialize the compositor
|
||||
*/
|
||||
// Initialize the compositor
|
||||
let primary_gpu = if let Ok(var) = std::env::var("ANVIL_DRM_DEVICE") {
|
||||
DrmNode::from_path(var).expect("Invalid drm device path")
|
||||
} else {
|
||||
|
@ -202,9 +200,7 @@ pub fn run_udev() -> anyhow::Result<()> {
|
|||
event_loop.handle(),
|
||||
)?;
|
||||
|
||||
/*
|
||||
* Initialize the udev backend
|
||||
*/
|
||||
// Initialize the udev backend
|
||||
let udev_backend = UdevBackend::new(state.seat.name())?;
|
||||
|
||||
// Create DrmNodes from already connected GPUs
|
||||
|
@ -245,9 +241,7 @@ pub fn run_udev() -> anyhow::Result<()> {
|
|||
})
|
||||
.unwrap();
|
||||
|
||||
/*
|
||||
* Initialize libinput backend
|
||||
*/
|
||||
// Initialize libinput backend
|
||||
let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<LibSeatSession>>(
|
||||
backend.session.clone().into(),
|
||||
);
|
||||
|
@ -256,9 +250,7 @@ pub fn run_udev() -> anyhow::Result<()> {
|
|||
.unwrap();
|
||||
let libinput_backend = LibinputInputBackend::new(libinput_context.clone());
|
||||
|
||||
/*
|
||||
* Bind all our objects that get driven by the event loop
|
||||
*/
|
||||
// Bind all our objects that get driven by the event loop
|
||||
let insert_ret = event_loop
|
||||
.handle()
|
||||
.insert_source(libinput_backend, move |event, _, data| {
|
||||
|
@ -1332,10 +1324,18 @@ impl State {
|
|||
return;
|
||||
};
|
||||
|
||||
let windows = self
|
||||
.focus_state
|
||||
.focus_stack
|
||||
.iter()
|
||||
.filter(|win| win.alive())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = render_surface(
|
||||
&mut self.cursor_status,
|
||||
&self.space,
|
||||
&self.windows,
|
||||
&windows,
|
||||
self.dnd_icon.as_ref(),
|
||||
&self.focus_state.focus_stack,
|
||||
surface,
|
||||
|
@ -1452,6 +1452,31 @@ fn render_surface<'a>(
|
|||
pointer_location: Point<f64, Logical>,
|
||||
clock: &Clock<Monotonic>,
|
||||
) -> Result<bool, SwapBuffersError> {
|
||||
let pending_win_count = windows
|
||||
.iter()
|
||||
.filter(|win| win.alive())
|
||||
.filter(|win| win.with_state(|state| !state.loc_request_state.is_idle()))
|
||||
.count() as u32;
|
||||
|
||||
tracing::debug!("pending_win_count is {pending_win_count}");
|
||||
|
||||
if pending_win_count > 0 {
|
||||
for win in windows.iter() {
|
||||
win.send_frame(output, clock.now(), Some(Duration::ZERO), |_, _| {
|
||||
Some(output.clone())
|
||||
});
|
||||
}
|
||||
|
||||
surface
|
||||
.compositor
|
||||
.queue_frame(None, None, None)
|
||||
.map_err(Into::<SwapBuffersError>::into)?;
|
||||
|
||||
// TODO: still draw the cursor here
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let output_render_elements = crate::render::generate_render_elements(
|
||||
space,
|
||||
windows,
|
||||
|
|
|
@ -12,7 +12,10 @@ use smithay::{
|
|||
},
|
||||
winit::{WinitError, WinitEvent, WinitGraphicsBackend},
|
||||
},
|
||||
desktop::{layer_map_for_output, utils::send_frames_surface_tree},
|
||||
desktop::{
|
||||
layer_map_for_output,
|
||||
utils::{send_frames_surface_tree, surface_primary_scanout_output},
|
||||
},
|
||||
input::pointer::CursorImageStatus,
|
||||
output::{Output, Subpixel},
|
||||
reexports::{
|
||||
|
@ -32,7 +35,7 @@ use smithay::{
|
|||
|
||||
use crate::{
|
||||
render::pointer::PointerElement,
|
||||
state::{take_presentation_feedback, Backend, CalloopData, State},
|
||||
state::{take_presentation_feedback, Backend, CalloopData, State, WithState},
|
||||
};
|
||||
|
||||
use super::BackendData;
|
||||
|
@ -232,13 +235,35 @@ pub fn run_winit() -> anyhow::Result<()> {
|
|||
|
||||
pointer_element.set_status(state.cursor_status.clone());
|
||||
|
||||
if state.pause_rendering {
|
||||
// TODO: make a pending_windows state, when pending_windows increases,
|
||||
// | pause rendering.
|
||||
// | If it goes down, push a frame, then repeat until no pending_windows are left.
|
||||
|
||||
let pending_win_count = state
|
||||
.windows
|
||||
.iter()
|
||||
.filter(|win| win.alive())
|
||||
.filter(|win| win.with_state(|state| !state.loc_request_state.is_idle()))
|
||||
.count() as u32;
|
||||
|
||||
if pending_win_count > 0 {
|
||||
for win in state.windows.iter() {
|
||||
win.send_frame(
|
||||
&output,
|
||||
state.clock.now(),
|
||||
Some(Duration::ZERO),
|
||||
surface_primary_scanout_output,
|
||||
);
|
||||
}
|
||||
|
||||
state.space.refresh();
|
||||
state.popup_manager.cleanup();
|
||||
display
|
||||
.flush_clients()
|
||||
.expect("failed to flush client buffers");
|
||||
|
||||
// TODO: still draw the cursor here
|
||||
|
||||
return TimeoutAction::ToDuration(Duration::from_millis(1));
|
||||
}
|
||||
|
||||
|
@ -248,9 +273,17 @@ pub fn run_winit() -> anyhow::Result<()> {
|
|||
|
||||
state.focus_state.fix_up_focus(&mut state.space);
|
||||
|
||||
let windows = state
|
||||
.focus_state
|
||||
.focus_stack
|
||||
.iter()
|
||||
.filter(|win| win.alive())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let output_render_elements = crate::render::generate_render_elements(
|
||||
&state.space,
|
||||
&state.windows,
|
||||
&windows,
|
||||
state.pointer_location,
|
||||
&mut state.cursor_status,
|
||||
state.dnd_icon.as_ref(),
|
||||
|
|
|
@ -333,7 +333,9 @@ impl XdgShellHandler for State {
|
|||
if !window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||
window.toggle_maximized();
|
||||
}
|
||||
// TODO: might need to update_windows here
|
||||
|
||||
let Some(output) = window.output(self) else { return };
|
||||
self.update_windows(&output);
|
||||
}
|
||||
|
||||
fn unmaximize_request(&mut self, surface: ToplevelSurface) {
|
||||
|
@ -344,6 +346,9 @@ impl XdgShellHandler for State {
|
|||
if window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||
window.toggle_maximized();
|
||||
}
|
||||
|
||||
let Some(output) = window.output(self) else { return };
|
||||
self.update_windows(&output);
|
||||
}
|
||||
|
||||
// fn minimize_request(&mut self, surface: ToplevelSurface) {
|
||||
|
|
31
src/input.rs
31
src/input.rs
|
@ -183,21 +183,30 @@ impl State {
|
|||
modifier_mask.push(Modifier::Super);
|
||||
}
|
||||
let modifier_mask = ModifierMask::from(modifier_mask);
|
||||
let raw_sym = if keysym.raw_syms().len() == 1 {
|
||||
keysym.raw_syms()[0]
|
||||
} else {
|
||||
keysyms::KEY_NoSymbol
|
||||
};
|
||||
let raw_sym = keysym.raw_syms().iter().next();
|
||||
let mod_sym = keysym.modified_sym();
|
||||
|
||||
if let Some(callback_id) = state
|
||||
let cb_id_mod = state
|
||||
.input_state
|
||||
.keybinds
|
||||
.get(&(modifier_mask, raw_sym))
|
||||
{
|
||||
return FilterResult::Intercept(KeyAction::CallCallback(*callback_id));
|
||||
} else if (modifier_mask, raw_sym) == kill_keybind {
|
||||
.get(&(modifier_mask, mod_sym));
|
||||
|
||||
let cb_id_raw = if let Some(raw_sym) = raw_sym {
|
||||
state.input_state.keybinds.get(&(modifier_mask, *raw_sym))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match (cb_id_mod, cb_id_raw) {
|
||||
(Some(cb_id), _) | (None, Some(cb_id)) => {
|
||||
return FilterResult::Intercept(KeyAction::CallCallback(*cb_id));
|
||||
}
|
||||
(None, None) => ()
|
||||
}
|
||||
|
||||
if (modifier_mask, mod_sym) == kill_keybind {
|
||||
return FilterResult::Intercept(KeyAction::Quit);
|
||||
} else if (modifier_mask, raw_sym) == reload_keybind {
|
||||
} else if (modifier_mask, mod_sym) == reload_keybind {
|
||||
return FilterResult::Intercept(KeyAction::ReloadConfig);
|
||||
} else if let mut vt @ keysyms::KEY_XF86Switch_VT_1..=keysyms::KEY_XF86Switch_VT_12 =
|
||||
keysym.modified_sym() {
|
||||
|
|
|
@ -161,24 +161,32 @@ impl State {
|
|||
//
|
||||
// This *will* cause everything to freeze for a few frames, but it shouldn't impact
|
||||
// anything meaningfully.
|
||||
self.pause_rendering = true;
|
||||
// self.pause_rendering = true;
|
||||
|
||||
// schedule on all idle
|
||||
self.schedule(
|
||||
move |_dt| {
|
||||
// tracing::debug!("Waiting for all to be idle");
|
||||
tracing::debug!("Waiting for all to be idle");
|
||||
let all_idle = pending_wins
|
||||
.iter()
|
||||
.filter(|(_, win)| win.alive())
|
||||
.all(|(_, win)| win.with_state(|state| state.loc_request_state.is_idle()));
|
||||
|
||||
let num_not_idle = pending_wins
|
||||
.iter()
|
||||
.filter(|(_, win)| win.alive())
|
||||
.filter(|(_, win)| !win.with_state(|state| state.loc_request_state.is_idle()))
|
||||
.count();
|
||||
|
||||
tracing::debug!("{num_not_idle} not idle");
|
||||
|
||||
all_idle
|
||||
},
|
||||
move |dt| {
|
||||
for (loc, win) in non_pending_wins {
|
||||
dt.state.space.map_element(win, loc, false);
|
||||
}
|
||||
dt.state.pause_rendering = false;
|
||||
// dt.state.pause_rendering = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -138,8 +138,6 @@ pub struct State {
|
|||
pub xwayland: XWayland,
|
||||
pub xwm: Option<X11Wm>,
|
||||
pub xdisplay: Option<u32>,
|
||||
|
||||
pub pause_rendering: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -359,8 +357,6 @@ impl State {
|
|||
xwayland,
|
||||
xwm: None,
|
||||
xdisplay: None,
|
||||
|
||||
pause_rendering: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ use smithay::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
api::msg::{Args, CallbackId, Msg, OutgoingMsg, Request, RequestId, RequestResponse},
|
||||
api::msg::{
|
||||
Args, CallbackId, KeyIntOrString, Msg, OutgoingMsg, Request, RequestId, RequestResponse,
|
||||
},
|
||||
tag::Tag,
|
||||
window::WindowElement,
|
||||
};
|
||||
|
@ -25,7 +27,26 @@ impl State {
|
|||
modifiers,
|
||||
callback_id,
|
||||
} => {
|
||||
tracing::info!("set keybind: {:?}, {}", modifiers, key);
|
||||
let key = match key {
|
||||
KeyIntOrString::Int(num) => num,
|
||||
KeyIntOrString::String(s) => {
|
||||
if s.chars().count() == 1 {
|
||||
let Some(ch) = s.chars().next() else { unreachable!() };
|
||||
let raw = xkbcommon::xkb::Keysym::from_char(ch).raw();
|
||||
tracing::info!("set keybind: {:?}, {:?} (raw {})", modifiers, ch, raw);
|
||||
raw
|
||||
} else {
|
||||
let raw = xkbcommon::xkb::keysym_from_name(
|
||||
&s,
|
||||
xkbcommon::xkb::KEYSYM_NO_FLAGS,
|
||||
)
|
||||
.raw();
|
||||
tracing::info!("set keybind: {:?}, {:?}", modifiers, raw);
|
||||
raw
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.input_state
|
||||
.keybinds
|
||||
.insert((modifiers.into(), key), callback_id);
|
||||
|
|
Loading…
Add table
Reference in a new issue