mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-06 20:46:37 +01:00
Add output resize and move signals
This commit is contained in:
parent
6d78436d18
commit
023ebe8a2d
11 changed files with 207 additions and 18 deletions
|
@ -166,12 +166,17 @@ function output.connect_for_all(callback)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type table<string, SignalServiceMethod>
|
||||||
local signal_name_to_SignalName = {
|
local signal_name_to_SignalName = {
|
||||||
connect = "OutputConnect",
|
connect = "OutputConnect",
|
||||||
|
resize = "OutputResize",
|
||||||
|
move = "OutputMove",
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class OutputSignal Signals related to output events.
|
---@class OutputSignal Signals related to output events.
|
||||||
---@field connect fun(output: OutputHandle)? An output was connected. FIXME: This currently does not fire for outputs that have been previously connected and disconnected.
|
---@field connect fun(output: OutputHandle)? An output was connected. FIXME: This currently does not fire for outputs that have been previously connected and disconnected.
|
||||||
|
---@field resize fun(output: OutputHandle, logical_width: integer, logical_height: integer)? An output's logical size changed.
|
||||||
|
---@field move fun(output: OutputHandle, x: integer, y: integer)? An output moved.
|
||||||
|
|
||||||
---Connect to an output signal.
|
---Connect to an output signal.
|
||||||
---
|
---
|
||||||
|
|
|
@ -14,6 +14,12 @@ local rpc_types = {
|
||||||
OutputConnect = {
|
OutputConnect = {
|
||||||
response_type = "OutputConnectResponse",
|
response_type = "OutputConnectResponse",
|
||||||
},
|
},
|
||||||
|
OutputResize = {
|
||||||
|
response_type = "OutputResizeResponse",
|
||||||
|
},
|
||||||
|
OutputMove = {
|
||||||
|
response_type = "OutputMoveResponse",
|
||||||
|
},
|
||||||
WindowPointerEnter = {
|
WindowPointerEnter = {
|
||||||
response_type = "WindowPointerEnterResponse",
|
response_type = "WindowPointerEnterResponse",
|
||||||
},
|
},
|
||||||
|
@ -62,6 +68,28 @@ local signals = {
|
||||||
---@type fun(response: table)
|
---@type fun(response: table)
|
||||||
on_response = nil,
|
on_response = nil,
|
||||||
},
|
},
|
||||||
|
OutputResize = {
|
||||||
|
---@nodoc
|
||||||
|
---@type H2Stream?
|
||||||
|
sender = nil,
|
||||||
|
---@nodoc
|
||||||
|
---@type (fun(output: OutputHandle, logical_width: integer, logical_height: integer))[]
|
||||||
|
callbacks = {},
|
||||||
|
---@nodoc
|
||||||
|
---@type fun(response: table)
|
||||||
|
on_response = nil,
|
||||||
|
},
|
||||||
|
OutputMove = {
|
||||||
|
---@nodoc
|
||||||
|
---@type H2Stream?
|
||||||
|
sender = nil,
|
||||||
|
---@nodoc
|
||||||
|
---@type (fun(output: OutputHandle, x: integer, y: integer))[]
|
||||||
|
callbacks = {},
|
||||||
|
---@nodoc
|
||||||
|
---@type fun(response: table)
|
||||||
|
on_response = nil,
|
||||||
|
},
|
||||||
WindowPointerEnter = {
|
WindowPointerEnter = {
|
||||||
---@nodoc
|
---@nodoc
|
||||||
---@type H2Stream?
|
---@type H2Stream?
|
||||||
|
@ -94,6 +122,22 @@ signals.OutputConnect.on_response = function(response)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
signals.OutputResize.on_response = function(response)
|
||||||
|
---@diagnostic disable-next-line: invisible
|
||||||
|
local handle = require("pinnacle.output").handle.new(response.output_name)
|
||||||
|
for _, callback in ipairs(signals.OutputResize.callbacks) do
|
||||||
|
callback(handle, response.logical_width, response.logical_height)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
signals.OutputMove.on_response = function(response)
|
||||||
|
---@diagnostic disable-next-line: invisible
|
||||||
|
local handle = require("pinnacle.output").handle.new(response.output_name)
|
||||||
|
for _, callback in ipairs(signals.OutputMove.callbacks) do
|
||||||
|
callback(handle, response.x, response.y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
signals.WindowPointerEnter.on_response = function(response)
|
signals.WindowPointerEnter.on_response = function(response)
|
||||||
---@diagnostic disable-next-line: invisible
|
---@diagnostic disable-next-line: invisible
|
||||||
local window_handle = require("pinnacle.window").handle.new(response.window_id)
|
local window_handle = require("pinnacle.window").handle.new(response.window_id)
|
||||||
|
|
|
@ -17,6 +17,26 @@ message OutputConnectResponse {
|
||||||
optional string output_name = 1;
|
optional string output_name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message OutputResizeRequest {
|
||||||
|
optional StreamControl control = 1;
|
||||||
|
}
|
||||||
|
// An output's logical size changed
|
||||||
|
message OutputResizeResponse {
|
||||||
|
optional string output_name = 1;
|
||||||
|
optional uint32 logical_width = 2;
|
||||||
|
optional uint32 logical_height = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OutputMoveRequest {
|
||||||
|
optional StreamControl control = 1;
|
||||||
|
}
|
||||||
|
// An output's location in the global space changed
|
||||||
|
message OutputMoveResponse {
|
||||||
|
optional string output_name = 1;
|
||||||
|
optional int32 x = 2;
|
||||||
|
optional int32 y = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message WindowPointerEnterRequest {
|
message WindowPointerEnterRequest {
|
||||||
optional StreamControl control = 1;
|
optional StreamControl control = 1;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +55,8 @@ message WindowPointerLeaveResponse {
|
||||||
|
|
||||||
service SignalService {
|
service SignalService {
|
||||||
rpc OutputConnect(stream OutputConnectRequest) returns (stream OutputConnectResponse);
|
rpc OutputConnect(stream OutputConnectRequest) returns (stream OutputConnectResponse);
|
||||||
|
rpc OutputResize(stream OutputResizeRequest) returns (stream OutputResizeResponse);
|
||||||
|
rpc OutputMove(stream OutputMoveRequest) returns (stream OutputMoveResponse);
|
||||||
rpc WindowPointerEnter(stream WindowPointerEnterRequest) returns (stream WindowPointerEnterResponse);
|
rpc WindowPointerEnter(stream WindowPointerEnterRequest) returns (stream WindowPointerEnterResponse);
|
||||||
rpc WindowPointerLeave(stream WindowPointerLeaveRequest) returns (stream WindowPointerLeaveResponse);
|
rpc WindowPointerLeave(stream WindowPointerLeaveRequest) returns (stream WindowPointerLeaveResponse);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,8 @@ impl Output {
|
||||||
|
|
||||||
match signal {
|
match signal {
|
||||||
OutputSignal::Connect(f) => signal_state.output_connect.add_callback(f),
|
OutputSignal::Connect(f) => signal_state.output_connect.add_callback(f),
|
||||||
|
OutputSignal::Resize(f) => signal_state.output_resize.add_callback(f),
|
||||||
|
OutputSignal::Move(f) => signal_state.output_move.add_callback(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
//! Some of the other modules have a `connect_signal` method that will allow you to pass in
|
//! Some of the other modules have a `connect_signal` method that will allow you to pass in
|
||||||
//! callbacks to run on each signal. Use them to connect to the signals defined here.
|
//! callbacks to run on each signal. Use them to connect to the signals defined here.
|
||||||
|
|
||||||
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{btree_map, BTreeMap},
|
collections::{btree_map, BTreeMap},
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -138,6 +140,42 @@ signals! {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
/// An output's logical size changed.
|
||||||
|
///
|
||||||
|
/// Callbacks receive the output and new width and height.
|
||||||
|
OutputResize = {
|
||||||
|
enum_name = Resize,
|
||||||
|
callback_type = Box<dyn FnMut(&OutputHandle, u32, u32) + Send + 'static>,
|
||||||
|
client_request = output_resize,
|
||||||
|
on_response = |response, callbacks| {
|
||||||
|
if let Some(output_name) = &response.output_name {
|
||||||
|
let output = OUTPUT.get().expect("OUTPUT doesn't exist");
|
||||||
|
let handle = output.new_handle(output_name);
|
||||||
|
|
||||||
|
for callback in callbacks {
|
||||||
|
callback(&handle, response.logical_width(), response.logical_height())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
/// An output's location in the global space changed.
|
||||||
|
///
|
||||||
|
/// Callbacks receive the output and new x and y.
|
||||||
|
OutputMove = {
|
||||||
|
enum_name = Move,
|
||||||
|
callback_type = Box<dyn FnMut(&OutputHandle, i32, i32) + Send + 'static>,
|
||||||
|
client_request = output_move,
|
||||||
|
on_response = |response, callbacks| {
|
||||||
|
if let Some(output_name) = &response.output_name {
|
||||||
|
let output = OUTPUT.get().expect("OUTPUT doesn't exist");
|
||||||
|
let handle = output.new_handle(output_name);
|
||||||
|
|
||||||
|
for callback in callbacks {
|
||||||
|
callback(&handle, response.x(), response.y())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Signals relating to window events.
|
/// Signals relating to window events.
|
||||||
WindowSignal => {
|
WindowSignal => {
|
||||||
|
@ -185,6 +223,8 @@ pub(crate) type SingleWindowFn = Box<dyn FnMut(&WindowHandle) + Send + 'static>;
|
||||||
|
|
||||||
pub(crate) struct SignalState {
|
pub(crate) struct SignalState {
|
||||||
pub(crate) output_connect: SignalData<OutputConnect>,
|
pub(crate) output_connect: SignalData<OutputConnect>,
|
||||||
|
pub(crate) output_resize: SignalData<OutputResize>,
|
||||||
|
pub(crate) output_move: SignalData<OutputMove>,
|
||||||
pub(crate) window_pointer_enter: SignalData<WindowPointerEnter>,
|
pub(crate) window_pointer_enter: SignalData<WindowPointerEnter>,
|
||||||
pub(crate) window_pointer_leave: SignalData<WindowPointerLeave>,
|
pub(crate) window_pointer_leave: SignalData<WindowPointerLeave>,
|
||||||
}
|
}
|
||||||
|
@ -197,6 +237,8 @@ impl SignalState {
|
||||||
let client = SignalServiceClient::new(channel);
|
let client = SignalServiceClient::new(channel);
|
||||||
Self {
|
Self {
|
||||||
output_connect: SignalData::new(client.clone(), fut_sender.clone()),
|
output_connect: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
|
output_resize: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
|
output_move: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
window_pointer_enter: SignalData::new(client.clone(), fut_sender.clone()),
|
window_pointer_enter: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
window_pointer_leave: SignalData::new(client.clone(), fut_sender.clone()),
|
window_pointer_leave: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@ pub mod pinnacle {
|
||||||
|
|
||||||
impl_signal_request!(
|
impl_signal_request!(
|
||||||
OutputConnectRequest,
|
OutputConnectRequest,
|
||||||
|
OutputResizeRequest,
|
||||||
|
OutputMoveRequest,
|
||||||
WindowPointerEnterRequest,
|
WindowPointerEnterRequest,
|
||||||
WindowPointerLeaveRequest
|
WindowPointerLeaveRequest
|
||||||
);
|
);
|
||||||
|
|
11
src/api.rs
11
src/api.rs
|
@ -955,8 +955,7 @@ impl output_service_server::OutputService for OutputService {
|
||||||
if let Some(y) = y {
|
if let Some(y) = y {
|
||||||
loc.y = y;
|
loc.y = y;
|
||||||
}
|
}
|
||||||
output.change_current_state(None, None, None, Some(loc));
|
state.change_output_state(&output, None, None, None, Some(loc));
|
||||||
state.space.map_output(&output, loc);
|
|
||||||
debug!("Mapping output {} to {loc:?}", output.name());
|
debug!("Mapping output {} to {loc:?}", output.name());
|
||||||
state.request_layout(&output);
|
state.request_layout(&output);
|
||||||
})
|
})
|
||||||
|
@ -1016,7 +1015,13 @@ impl output_service_server::OutputService for OutputService {
|
||||||
|
|
||||||
current_scale = f64::max(current_scale, 0.25);
|
current_scale = f64::max(current_scale, 0.25);
|
||||||
|
|
||||||
output.change_current_state(None, None, Some(Scale::Fractional(current_scale)), None);
|
state.change_output_state(
|
||||||
|
&output,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some(Scale::Fractional(current_scale)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
layer_map_for_output(&output).arrange();
|
layer_map_for_output(&output).arrange();
|
||||||
state.request_layout(&output);
|
state.request_layout(&output);
|
||||||
state.schedule_render(&output);
|
state.schedule_render(&output);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
||||||
signal_service_server, OutputConnectRequest, OutputConnectResponse, SignalRequest,
|
signal_service_server, OutputConnectRequest, OutputConnectResponse, OutputMoveRequest,
|
||||||
StreamControl, WindowPointerEnterRequest, WindowPointerEnterResponse,
|
OutputMoveResponse, OutputResizeRequest, OutputResizeResponse, SignalRequest, StreamControl,
|
||||||
WindowPointerLeaveRequest, WindowPointerLeaveResponse,
|
WindowPointerEnterRequest, WindowPointerEnterResponse, WindowPointerLeaveRequest,
|
||||||
|
WindowPointerLeaveResponse,
|
||||||
};
|
};
|
||||||
use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle};
|
use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle};
|
||||||
use tonic::{Request, Response, Status, Streaming};
|
use tonic::{Request, Response, Status, Streaming};
|
||||||
|
@ -15,7 +16,12 @@ use super::{run_bidirectional_streaming, ResponseStream, StateFnSender};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct SignalState {
|
pub struct SignalState {
|
||||||
|
// Output
|
||||||
pub output_connect: SignalData<OutputConnectResponse, VecDeque<OutputConnectResponse>>,
|
pub output_connect: SignalData<OutputConnectResponse, VecDeque<OutputConnectResponse>>,
|
||||||
|
pub output_resize: SignalData<OutputResizeResponse, VecDeque<OutputResizeResponse>>,
|
||||||
|
pub output_move: SignalData<OutputMoveResponse, VecDeque<OutputMoveResponse>>,
|
||||||
|
|
||||||
|
// Window
|
||||||
pub window_pointer_enter:
|
pub window_pointer_enter:
|
||||||
SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
|
SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
|
||||||
pub window_pointer_leave:
|
pub window_pointer_leave:
|
||||||
|
@ -171,6 +177,8 @@ impl SignalService {
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
impl signal_service_server::SignalService for SignalService {
|
impl signal_service_server::SignalService for SignalService {
|
||||||
type OutputConnectStream = ResponseStream<OutputConnectResponse>;
|
type OutputConnectStream = ResponseStream<OutputConnectResponse>;
|
||||||
|
type OutputResizeStream = ResponseStream<OutputResizeResponse>;
|
||||||
|
type OutputMoveStream = ResponseStream<OutputMoveResponse>;
|
||||||
type WindowPointerEnterStream = ResponseStream<WindowPointerEnterResponse>;
|
type WindowPointerEnterStream = ResponseStream<WindowPointerEnterResponse>;
|
||||||
type WindowPointerLeaveStream = ResponseStream<WindowPointerLeaveResponse>;
|
type WindowPointerLeaveStream = ResponseStream<WindowPointerLeaveResponse>;
|
||||||
|
|
||||||
|
@ -185,6 +193,28 @@ impl signal_service_server::SignalService for SignalService {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn output_resize(
|
||||||
|
&self,
|
||||||
|
request: Request<Streaming<OutputResizeRequest>>,
|
||||||
|
) -> Result<Response<Self::OutputResizeStream>, Status> {
|
||||||
|
let in_stream = request.into_inner();
|
||||||
|
|
||||||
|
start_signal_stream(self.sender.clone(), in_stream, |state| {
|
||||||
|
&mut state.signal_state.output_resize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn output_move(
|
||||||
|
&self,
|
||||||
|
request: Request<Streaming<OutputMoveRequest>>,
|
||||||
|
) -> Result<Response<Self::OutputMoveStream>, Status> {
|
||||||
|
let in_stream = request.into_inner();
|
||||||
|
|
||||||
|
start_signal_stream(self.sender.clone(), in_stream, |state| {
|
||||||
|
&mut state.signal_state.output_move
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn window_pointer_enter(
|
async fn window_pointer_enter(
|
||||||
&self,
|
&self,
|
||||||
request: Request<Streaming<WindowPointerEnterRequest>>,
|
request: Request<Streaming<WindowPointerEnterRequest>>,
|
||||||
|
|
|
@ -272,7 +272,7 @@ impl State {
|
||||||
{
|
{
|
||||||
match render_surface.compositor.use_mode(drm_mode) {
|
match render_surface.compositor.use_mode(drm_mode) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
output.change_current_state(Some(mode), None, None, None);
|
self.change_output_state(output, Some(mode), None, None, None);
|
||||||
layer_map_for_output(output).arrange();
|
layer_map_for_output(output).arrange();
|
||||||
}
|
}
|
||||||
Err(err) => error!("Failed to resize output: {err}"),
|
Err(err) => error!("Failed to resize output: {err}"),
|
||||||
|
@ -280,7 +280,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
output.change_current_state(Some(mode), None, None, None);
|
self.change_output_state(output, Some(mode), None, None, None);
|
||||||
layer_map_for_output(output).arrange();
|
layer_map_for_output(output).arrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,6 +1042,8 @@ impl State {
|
||||||
output.add_mode(mode);
|
output.add_mode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output.set_preferred(wl_mode);
|
||||||
|
|
||||||
self.output_focus_stack.set_focus(output.clone());
|
self.output_focus_stack.set_focus(output.clone());
|
||||||
|
|
||||||
let x = self.space.outputs().fold(0, |acc, o| {
|
let x = self.space.outputs().fold(0, |acc, o| {
|
||||||
|
@ -1052,10 +1054,6 @@ impl State {
|
||||||
});
|
});
|
||||||
let position = (x, 0).into();
|
let position = (x, 0).into();
|
||||||
|
|
||||||
output.set_preferred(wl_mode);
|
|
||||||
output.change_current_state(Some(wl_mode), None, None, Some(position));
|
|
||||||
self.space.map_output(&output, position);
|
|
||||||
|
|
||||||
output.user_data().insert_if_missing(|| UdevOutputData {
|
output.user_data().insert_if_missing(|| UdevOutputData {
|
||||||
crtc,
|
crtc,
|
||||||
device_id: node,
|
device_id: node,
|
||||||
|
@ -1122,6 +1120,8 @@ impl State {
|
||||||
|
|
||||||
device.surfaces.insert(crtc, surface);
|
device.surfaces.insert(crtc, surface);
|
||||||
|
|
||||||
|
self.change_output_state(&output, Some(wl_mode), None, None, Some(position));
|
||||||
|
|
||||||
// If there is saved connector state, the connector was previously plugged in.
|
// If there is saved connector state, the connector was previously plugged in.
|
||||||
// In this case, restore its tags and location.
|
// In this case, restore its tags and location.
|
||||||
// TODO: instead of checking the connector, check the monitor's edid info instead
|
// TODO: instead of checking the connector, check the monitor's edid info instead
|
||||||
|
@ -1131,11 +1131,8 @@ impl State {
|
||||||
.get(&OutputName(output.name()))
|
.get(&OutputName(output.name()))
|
||||||
{
|
{
|
||||||
let ConnectorSavedState { loc, tags, scale } = saved_state;
|
let ConnectorSavedState { loc, tags, scale } = saved_state;
|
||||||
|
|
||||||
output.change_current_state(None, None, *scale, Some(*loc));
|
|
||||||
self.space.map_output(&output, *loc);
|
|
||||||
|
|
||||||
output.with_state_mut(|state| state.tags = tags.clone());
|
output.with_state_mut(|state| state.tags = tags.clone());
|
||||||
|
self.change_output_state(&output, None, None, *scale, Some(*loc));
|
||||||
} else {
|
} else {
|
||||||
self.signal_state.output_connect.signal(|buffer| {
|
self.signal_state.output_connect.signal(|buffer| {
|
||||||
buffer.push_back(OutputConnectResponse {
|
buffer.push_back(OutputConnectResponse {
|
||||||
|
|
|
@ -221,7 +221,8 @@ pub fn setup_winit(
|
||||||
size,
|
size,
|
||||||
refresh: 144_000,
|
refresh: 144_000,
|
||||||
};
|
};
|
||||||
output.change_current_state(
|
state.change_output_state(
|
||||||
|
&output,
|
||||||
Some(mode),
|
Some(mode),
|
||||||
None,
|
None,
|
||||||
Some(Scale::Fractional(scale_factor)),
|
Some(Scale::Fractional(scale_factor)),
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use smithay::output::Output;
|
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{OutputMoveResponse, OutputResizeResponse};
|
||||||
|
use smithay::{
|
||||||
|
output::{Mode, Output, Scale},
|
||||||
|
utils::{Logical, Point, Transform},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
focus::WindowKeyboardFocusStack,
|
focus::WindowKeyboardFocusStack,
|
||||||
|
@ -68,3 +72,38 @@ impl OutputState {
|
||||||
self.tags.iter().filter(|tag| tag.active())
|
self.tags.iter().filter(|tag| tag.active())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
/// A wrapper around [`Output::change_current_state`] that additionally sends an output
|
||||||
|
/// geometry signal.
|
||||||
|
pub fn change_output_state(
|
||||||
|
&mut self,
|
||||||
|
output: &Output,
|
||||||
|
mode: Option<Mode>,
|
||||||
|
transform: Option<Transform>,
|
||||||
|
scale: Option<Scale>,
|
||||||
|
location: Option<Point<i32, Logical>>,
|
||||||
|
) {
|
||||||
|
output.change_current_state(mode, transform, scale, location);
|
||||||
|
if let Some(location) = location {
|
||||||
|
self.space.map_output(output, location);
|
||||||
|
self.signal_state.output_move.signal(|buf| {
|
||||||
|
buf.push_back(OutputMoveResponse {
|
||||||
|
output_name: Some(output.name()),
|
||||||
|
x: Some(location.x),
|
||||||
|
y: Some(location.y),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if mode.is_some() || transform.is_some() || scale.is_some() {
|
||||||
|
self.signal_state.output_resize.signal(|buf| {
|
||||||
|
let geo = self.space.output_geometry(output);
|
||||||
|
buf.push_back(OutputResizeResponse {
|
||||||
|
output_name: Some(output.name()),
|
||||||
|
logical_width: geo.map(|geo| geo.size.w as u32),
|
||||||
|
logical_height: geo.map(|geo| geo.size.h as u32),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue