mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-17 18:11:30 +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
|
||||
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.
|
||||
|
@ -176,3 +198,24 @@ function output:physical_size() end
|
|||
---@treturn boolean|nil
|
||||
---@see OutputModule.focused
|
||||
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 }?
|
||||
--Outputs
|
||||
---@field ConnectForAllOutputs { callback_id: integer }?
|
||||
---@field SetOutputLocation { output_name: OutputName, x: integer?, y: integer? }?
|
||||
|
||||
---@alias Msg _Msg | "Quit"
|
||||
|
||||
|
|
|
@ -93,6 +93,31 @@ function output:focused()
|
|||
return output_module.focused(self)
|
||||
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.
|
||||
|
@ -104,7 +129,7 @@ end
|
|||
---### Example
|
||||
---```lua
|
||||
---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.
|
||||
---@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
|
||||
|
||||
---------Fully-qualified functions
|
||||
|
||||
---Get the specified output's make.
|
||||
---@param op Output
|
||||
---@return string|nil
|
||||
|
@ -369,4 +396,36 @@ function output_module.add_tags(op, ...)
|
|||
require("tag").add(op, ...)
|
||||
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
|
||||
|
|
|
@ -66,10 +66,20 @@ require("pinnacle").setup(function(pinnacle)
|
|||
|
||||
-- Just testing stuff
|
||||
input.keybind({ mod_key }, keys.h, function()
|
||||
local win = window.get_focused()
|
||||
if win ~= nil then
|
||||
win:set_size({ w = 500, h = 500 })
|
||||
end
|
||||
local dp2 = output.get_by_name("DP-2")
|
||||
local dp3 = output.get_by_name("DP-3")
|
||||
output.set_loc(dp2, { x = 1920, y = 0 })
|
||||
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()
|
||||
-- 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
|
||||
// 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)]
|
||||
pub struct CallbackId(pub u32);
|
||||
|
@ -68,6 +68,13 @@ pub enum Msg {
|
|||
ConnectForAllOutputs {
|
||||
callback_id: CallbackId,
|
||||
},
|
||||
SetOutputLocation {
|
||||
output_name: OutputName,
|
||||
#[serde(default)]
|
||||
x: Option<i32>,
|
||||
#[serde(default)]
|
||||
y: Option<i32>,
|
||||
},
|
||||
|
||||
// Process management
|
||||
/// 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::Keyboard { event } => self.keyboard::<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::PointerButton { event } => self.pointer_button::<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 max_x = self.space.outputs().fold(0, |acc, o| {
|
||||
acc + self
|
||||
|
||||
let nearest_points = self.space.outputs().map(|op| {
|
||||
let size = self
|
||||
.space
|
||||
.output_geometry(o)
|
||||
.expect("Output geometry doesn't exist")
|
||||
.size
|
||||
.w
|
||||
});
|
||||
let clamped_x = pos_x.clamp(0.0, max_x as f64);
|
||||
let max_y = self
|
||||
.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
|
||||
.output_geometry(op)
|
||||
.expect("called output_geometry on unmapped output")
|
||||
.size;
|
||||
let loc = op.current_location();
|
||||
let pos_x = pos_x.clamp(loc.x as f64, (loc.x + size.w) as f64);
|
||||
let pos_y = pos_y.clamp(loc.y as f64, (loc.y + size.h) as f64);
|
||||
(pos_x, pos_y)
|
||||
});
|
||||
|
||||
if let Some(max_y) = max_y {
|
||||
let clamped_y = pos_y.clamp(0.0, max_y as f64);
|
||||
(clamped_x, clamped_y).into()
|
||||
} else {
|
||||
(clamped_x, pos_y).into()
|
||||
}
|
||||
let nearest_point = nearest_points.min_by(|(x1, y1), (x2, y2)| {
|
||||
f64::total_cmp(
|
||||
&((pos_x - x1).powi(2) + (pos_y - y1).powi(2)).sqrt(),
|
||||
&((pos_x - x2).powi(2) + (pos_y - y2).powi(2)).sqrt(),
|
||||
)
|
||||
});
|
||||
|
||||
nearest_point.map(|point| point.into()).unwrap_or(pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,26 @@ use std::cell::RefCell;
|
|||
|
||||
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)]
|
||||
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)]
|
||||
pub struct OutputState {
|
||||
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);
|
||||
}
|
||||
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 => {
|
||||
self.loop_signal.stop();
|
||||
|
|
Loading…
Reference in a new issue