mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-30 20:34:49 +01:00
Add output location setting
This commit is contained in:
parent
f9a32af4dc
commit
f99c8b886d
8 changed files with 177 additions and 39 deletions
|
@ -121,6 +121,28 @@ function output_module.tags(op) end
|
||||||
---@see Output.add_tags
|
---@see Output.add_tags
|
||||||
function output_module.add_tags(op, ...) end
|
function output_module.add_tags(op, ...) end
|
||||||
|
|
||||||
|
---Set the specified output's location.
|
||||||
|
---
|
||||||
|
---@usage
|
||||||
|
----- Assuming DP-1 is 2560x1440 and DP-2 is 1920x1080...
|
||||||
|
---local dp1 = output.get_by_name("DP-1")
|
||||||
|
---local dp2 = output.get_by_name("DP-2")
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the left of DP-1, top borders aligned
|
||||||
|
---output.set_loc(dp1, { x = 1920, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = 0, y = 0 })
|
||||||
|
---
|
||||||
|
----- Do the same as above, with a different origin
|
||||||
|
---output.set_loc(dp1, { x = 0, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = -1920, y = 0 })
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the right of DP-1, bottom borders aligned
|
||||||
|
---output.set_loc(dp1, { x = 0, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = 2560, y = 1440 - 1080 })
|
||||||
|
---@tparam Output op
|
||||||
|
---@tparam table loc A table of the form `{ x: integer?, y: integer? }`
|
||||||
|
function output_module.set_loc(op, loc) end
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
---The output object.
|
---The output object.
|
||||||
|
@ -176,3 +198,24 @@ function output:physical_size() end
|
||||||
---@treturn boolean|nil
|
---@treturn boolean|nil
|
||||||
---@see OutputModule.focused
|
---@see OutputModule.focused
|
||||||
function output:focused() end
|
function output:focused() end
|
||||||
|
|
||||||
|
---Set this output's location.
|
||||||
|
---
|
||||||
|
---@usage
|
||||||
|
--- -- Assuming DP-1 is 2560x1440 and DP-2 is 1920x1080...
|
||||||
|
---local dp1 = output.get_by_name("DP-1")
|
||||||
|
---local dp2 = output.get_by_name("DP-2")
|
||||||
|
---
|
||||||
|
--- -- Place DP-2 to the left of DP-1, top borders aligned
|
||||||
|
---dp1:set_loc({ x = 1920, y = 0 })
|
||||||
|
---dp2:set_loc({ x = 0, y = 0 })
|
||||||
|
---
|
||||||
|
--- -- Do the same as above, with a different origin
|
||||||
|
---dp1:set_loc({ x = 0, y = 0 })
|
||||||
|
---dp2:set_loc({ x = -1920, y = 0 })
|
||||||
|
---
|
||||||
|
--- -- Place DP-2 to the right of DP-1, bottom borders aligned
|
||||||
|
---dp1:set_loc({ x = 0, y = 0 })
|
||||||
|
---dp2:set_loc({ x = 2560, y = 1440 - 1080 })
|
||||||
|
---@tparam table loc A table of the form `{ x: integer?, y: integer? }`
|
||||||
|
function output:set_loc(loc) end
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
---@field SetLayout { tag_id: TagId, layout: Layout }?
|
---@field SetLayout { tag_id: TagId, layout: Layout }?
|
||||||
--Outputs
|
--Outputs
|
||||||
---@field ConnectForAllOutputs { callback_id: integer }?
|
---@field ConnectForAllOutputs { callback_id: integer }?
|
||||||
|
---@field SetOutputLocation { output_name: OutputName, x: integer?, y: integer? }?
|
||||||
|
|
||||||
---@alias Msg _Msg | "Quit"
|
---@alias Msg _Msg | "Quit"
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,31 @@ function output:focused()
|
||||||
return output_module.focused(self)
|
return output_module.focused(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Set this output's location.
|
||||||
|
---
|
||||||
|
---### Examples
|
||||||
|
---```lua
|
||||||
|
----- Assuming DP-1 is 2560x1440 and DP-2 is 1920x1080...
|
||||||
|
---local dp1 = output.get_by_name("DP-1")
|
||||||
|
---local dp2 = output.get_by_name("DP-2")
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the left of DP-1, top borders aligned
|
||||||
|
---dp1:set_loc({ x = 1920, y = 0 })
|
||||||
|
---dp2:set_loc({ x = 0, y = 0 })
|
||||||
|
---
|
||||||
|
----- Do the same as above, with a different origin
|
||||||
|
---dp1:set_loc({ x = 0, y = 0 })
|
||||||
|
---dp2:set_loc({ x = -1920, y = 0 })
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the right of DP-1, bottom borders aligned
|
||||||
|
---dp1:set_loc({ x = 0, y = 0 })
|
||||||
|
---dp2:set_loc({ x = 2560, y = 1440 - 1080 })
|
||||||
|
---```
|
||||||
|
---@param loc { x: integer?, y: integer? }
|
||||||
|
function output:set_loc(loc)
|
||||||
|
return output_module.set_loc(self, loc)
|
||||||
|
end
|
||||||
|
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
---Get an output by its name.
|
---Get an output by its name.
|
||||||
|
@ -104,7 +129,7 @@ end
|
||||||
---### Example
|
---### Example
|
||||||
---```lua
|
---```lua
|
||||||
---local monitor = output.get_by_name("DP-1")
|
---local monitor = output.get_by_name("DP-1")
|
||||||
---print(monitor.name) -- should print `DP-1`
|
---print(monitor:name()) -- should print `DP-1`
|
||||||
---```
|
---```
|
||||||
---@param name string The name of the output.
|
---@param name string The name of the output.
|
||||||
---@return Output|nil output The output, or nil if none have the provided name.
|
---@return Output|nil output The output, or nil if none have the provided name.
|
||||||
|
@ -240,6 +265,8 @@ function output_module.get_for_tag(tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---------Fully-qualified functions
|
||||||
|
|
||||||
---Get the specified output's make.
|
---Get the specified output's make.
|
||||||
---@param op Output
|
---@param op Output
|
||||||
---@return string|nil
|
---@return string|nil
|
||||||
|
@ -369,4 +396,36 @@ function output_module.add_tags(op, ...)
|
||||||
require("tag").add(op, ...)
|
require("tag").add(op, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Set the specified output's location.
|
||||||
|
---
|
||||||
|
---### Examples
|
||||||
|
---```lua
|
||||||
|
----- Assuming DP-1 is 2560x1440 and DP-2 is 1920x1080...
|
||||||
|
---local dp1 = output.get_by_name("DP-1")
|
||||||
|
---local dp2 = output.get_by_name("DP-2")
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the left of DP-1, top borders aligned
|
||||||
|
---output.set_loc(dp1, { x = 1920, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = 0, y = 0 })
|
||||||
|
---
|
||||||
|
----- Do the same as above, with a different origin
|
||||||
|
---output.set_loc(dp1, { x = 0, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = -1920, y = 0 })
|
||||||
|
---
|
||||||
|
----- Place DP-2 to the right of DP-1, bottom borders aligned
|
||||||
|
---output.set_loc(dp1, { x = 0, y = 0 })
|
||||||
|
---output.set_loc(dp2, { x = 2560, y = 1440 - 1080 })
|
||||||
|
---```
|
||||||
|
---@param op Output
|
||||||
|
---@param loc { x: integer?, y: integer? }
|
||||||
|
function output_module.set_loc(op, loc)
|
||||||
|
SendMsg({
|
||||||
|
SetOutputLocation = {
|
||||||
|
output_name = op:name(),
|
||||||
|
x = loc.x,
|
||||||
|
y = loc.y,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
return output_module
|
return output_module
|
||||||
|
|
|
@ -66,10 +66,20 @@ require("pinnacle").setup(function(pinnacle)
|
||||||
|
|
||||||
-- Just testing stuff
|
-- Just testing stuff
|
||||||
input.keybind({ mod_key }, keys.h, function()
|
input.keybind({ mod_key }, keys.h, function()
|
||||||
local win = window.get_focused()
|
local dp2 = output.get_by_name("DP-2")
|
||||||
if win ~= nil then
|
local dp3 = output.get_by_name("DP-3")
|
||||||
win:set_size({ w = 500, h = 500 })
|
output.set_loc(dp2, { x = 1920, y = 0 })
|
||||||
end
|
output.set_loc(dp3, { x = 0, y = 1440 - 1080 })
|
||||||
|
local dp2loc = dp2:loc()
|
||||||
|
local dp3loc = dp3:loc()
|
||||||
|
|
||||||
|
print("dp2: " .. dp2loc.x .. ", " .. dp2loc.y)
|
||||||
|
print("dp3: " .. dp3loc.x .. ", " .. dp3loc.y)
|
||||||
|
|
||||||
|
-- local win = window.get_focused()
|
||||||
|
-- if win ~= nil then
|
||||||
|
-- win:set_size({ w = 500, h = 500 })
|
||||||
|
-- end
|
||||||
|
|
||||||
-- local wins = window.get_all()
|
-- local wins = window.get_all()
|
||||||
-- for _, win in pairs(wins) do
|
-- for _, win in pairs(wins) do
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// The MessagePack format for these is a one-element map where the element's key is the enum name and its
|
// The MessagePack format for these is a one-element map where the element's key is the enum name and its
|
||||||
// value is a map of the enum's values
|
// value is a map of the enum's values
|
||||||
|
|
||||||
use crate::{layout::Layout, tag::TagId, window::window_state::WindowId};
|
use crate::{layout::Layout, output::OutputName, tag::TagId, window::window_state::WindowId};
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
||||||
pub struct CallbackId(pub u32);
|
pub struct CallbackId(pub u32);
|
||||||
|
@ -68,6 +68,13 @@ pub enum Msg {
|
||||||
ConnectForAllOutputs {
|
ConnectForAllOutputs {
|
||||||
callback_id: CallbackId,
|
callback_id: CallbackId,
|
||||||
},
|
},
|
||||||
|
SetOutputLocation {
|
||||||
|
output_name: OutputName,
|
||||||
|
#[serde(default)]
|
||||||
|
x: Option<i32>,
|
||||||
|
#[serde(default)]
|
||||||
|
y: Option<i32>,
|
||||||
|
},
|
||||||
|
|
||||||
// Process management
|
// Process management
|
||||||
/// Spawn a program with an optional callback.
|
/// Spawn a program with an optional callback.
|
||||||
|
|
49
src/input.rs
49
src/input.rs
|
@ -440,6 +440,7 @@ impl State<UdevData> {
|
||||||
// InputEvent::DeviceRemoved { device } => todo!(),
|
// InputEvent::DeviceRemoved { device } => todo!(),
|
||||||
InputEvent::Keyboard { event } => self.keyboard::<B>(event),
|
InputEvent::Keyboard { event } => self.keyboard::<B>(event),
|
||||||
InputEvent::PointerMotion { event } => self.pointer_motion::<B>(event),
|
InputEvent::PointerMotion { event } => self.pointer_motion::<B>(event),
|
||||||
|
// currently does not seem to use absolute
|
||||||
InputEvent::PointerMotionAbsolute { event } => self.pointer_motion_absolute::<B>(event),
|
InputEvent::PointerMotionAbsolute { event } => self.pointer_motion_absolute::<B>(event),
|
||||||
InputEvent::PointerButton { event } => self.pointer_button::<B>(event),
|
InputEvent::PointerButton { event } => self.pointer_button::<B>(event),
|
||||||
InputEvent::PointerAxis { event } => self.pointer_axis::<B>(event),
|
InputEvent::PointerAxis { event } => self.pointer_axis::<B>(event),
|
||||||
|
@ -557,38 +558,26 @@ impl State<UdevData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (pos_x, pos_y) = pos.into();
|
let (pos_x, pos_y) = pos.into();
|
||||||
let max_x = self.space.outputs().fold(0, |acc, o| {
|
|
||||||
acc + self
|
let nearest_points = self.space.outputs().map(|op| {
|
||||||
|
let size = self
|
||||||
.space
|
.space
|
||||||
.output_geometry(o)
|
.output_geometry(op)
|
||||||
.expect("Output geometry doesn't exist")
|
.expect("called output_geometry on unmapped output")
|
||||||
.size
|
.size;
|
||||||
.w
|
let loc = op.current_location();
|
||||||
});
|
let pos_x = pos_x.clamp(loc.x as f64, (loc.x + size.w) as f64);
|
||||||
let clamped_x = pos_x.clamp(0.0, max_x as f64);
|
let pos_y = pos_y.clamp(loc.y as f64, (loc.y + size.h) as f64);
|
||||||
let max_y = self
|
(pos_x, pos_y)
|
||||||
.space
|
|
||||||
.outputs()
|
|
||||||
.find(|o| {
|
|
||||||
let geo = self
|
|
||||||
.space
|
|
||||||
.output_geometry(o)
|
|
||||||
.expect("Output geometry doesn't exist");
|
|
||||||
geo.contains((clamped_x as i32, 0))
|
|
||||||
})
|
|
||||||
.map(|o| {
|
|
||||||
self.space
|
|
||||||
.output_geometry(o)
|
|
||||||
.expect("Output geometry doesn't exist")
|
|
||||||
.size
|
|
||||||
.h
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(max_y) = max_y {
|
let nearest_point = nearest_points.min_by(|(x1, y1), (x2, y2)| {
|
||||||
let clamped_y = pos_y.clamp(0.0, max_y as f64);
|
f64::total_cmp(
|
||||||
(clamped_x, clamped_y).into()
|
&((pos_x - x1).powi(2) + (pos_y - y1).powi(2)).sqrt(),
|
||||||
} else {
|
&((pos_x - x2).powi(2) + (pos_y - y2).powi(2)).sqrt(),
|
||||||
(clamped_x, pos_y).into()
|
)
|
||||||
}
|
});
|
||||||
|
|
||||||
|
nearest_point.map(|point| point.into()).unwrap_or(pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,26 @@ use std::cell::RefCell;
|
||||||
|
|
||||||
use smithay::output::Output;
|
use smithay::output::Output;
|
||||||
|
|
||||||
use crate::{state::WithState, tag::Tag};
|
use crate::{
|
||||||
|
backend::Backend,
|
||||||
|
state::{State, WithState},
|
||||||
|
tag::Tag,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||||
pub struct OutputName(pub String);
|
pub struct OutputName(pub String);
|
||||||
|
|
||||||
|
impl OutputName {
|
||||||
|
/// Get the output with this name.
|
||||||
|
pub fn output<B: Backend>(&self, state: &State<B>) -> Option<Output> {
|
||||||
|
state
|
||||||
|
.space
|
||||||
|
.outputs()
|
||||||
|
.find(|output| output.name() == self.0)
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct OutputState {
|
pub struct OutputState {
|
||||||
pub tags: Vec<Tag>,
|
pub tags: Vec<Tag>,
|
||||||
|
|
14
src/state.rs
14
src/state.rs
|
@ -272,6 +272,20 @@ impl<B: Backend> State<B> {
|
||||||
}
|
}
|
||||||
self.output_callback_ids.push(callback_id);
|
self.output_callback_ids.push(callback_id);
|
||||||
}
|
}
|
||||||
|
Msg::SetOutputLocation { output_name, x, y } => {
|
||||||
|
let Some(output) = output_name.output(self) else { return };
|
||||||
|
let mut loc = output.current_location();
|
||||||
|
if let Some(x) = x {
|
||||||
|
loc.x = x;
|
||||||
|
}
|
||||||
|
if let Some(y) = y {
|
||||||
|
loc.y = y;
|
||||||
|
}
|
||||||
|
output.change_current_state(None, None, None, Some(loc));
|
||||||
|
self.space.map_output(&output, loc);
|
||||||
|
tracing::debug!("mapping output {} to {loc:?}", output.name());
|
||||||
|
self.re_layout(&output);
|
||||||
|
}
|
||||||
|
|
||||||
Msg::Quit => {
|
Msg::Quit => {
|
||||||
self.loop_signal.stop();
|
self.loop_signal.stop();
|
||||||
|
|
Loading…
Add table
Reference in a new issue