Add output connect signal

untested
This commit is contained in:
Ottatop 2024-02-21 22:48:09 -06:00
parent 1539f73e45
commit 7d94fc4362
11 changed files with 323 additions and 173 deletions

View file

@ -24,6 +24,7 @@ build = {
["pinnacle.output"] = "pinnacle/output.lua", ["pinnacle.output"] = "pinnacle/output.lua",
["pinnacle.process"] = "pinnacle/process.lua", ["pinnacle.process"] = "pinnacle/process.lua",
["pinnacle.tag"] = "pinnacle/tag.lua", ["pinnacle.tag"] = "pinnacle/tag.lua",
["pinnacle.tag.layout"] = "pinnacle/tag/layout.lua",
["pinnacle.window"] = "pinnacle/window.lua", ["pinnacle.window"] = "pinnacle/window.lua",
["pinnacle.util"] = "pinnacle/util.lua", ["pinnacle.util"] = "pinnacle/util.lua",
["pinnacle.signal"] = "pinnacle/signal.lua", ["pinnacle.signal"] = "pinnacle/signal.lua",

View file

@ -42,6 +42,8 @@ end
---@field new_stream function ---@field new_stream function
---@class H2Stream ---@class H2Stream
---@field write_chunk function
---@field shutdown function
---@nodoc ---@nodoc
---@class Client ---@class Client
@ -202,8 +204,6 @@ function client.bidirectional_streaming_request(grpc_request_params, callback)
print(name, value, never_index) print(name, value, never_index)
end end
end end
print("AFTER bidirectional_streaming_request ENDS")
end) end)
return stream return stream

View file

@ -166,6 +166,29 @@ function output.connect_for_all(callback)
end) end)
end end
---@class OutputSignal
---@field connect fun(output: OutputHandle)?
---@param signals OutputSignal
---@return SignalHandles
function output.connect_signal(signals)
---@diagnostic disable-next-line: invisible
local handles = require("pinnacle.signal").handles.new({})
for signal, callback in pairs(signals) do
if signal == "connect" then
require("pinnacle.signal").add_callback("OutputConnect", callback)
---@diagnostic disable-next-line: invisible
local handle = require("pinnacle.signal").handle.new("OutputConnect", callback)
handles[signal] = handle
end
end
return handles
end
---------------------------------------------------------------------
---Set the location of this output in the global space. ---Set the location of this output in the global space.
--- ---
---On startup, Pinnacle will lay out all connected outputs starting at (0, 0) ---On startup, Pinnacle will lay out all connected outputs starting at (0, 0)

View file

@ -49,108 +49,156 @@ local stream_control = {
DISCONNECT = 2, DISCONNECT = 2,
} }
---@type table<SignalServiceMethod, { sender: H2Stream?, callbacks: function[], on_response: fun(response: table) }>
local signals = { local signals = {
output_connect = { OutputConnect = {
---@type H2Stream? ---@type H2Stream?
sender = nil, sender = nil,
---@type (fun(output: OutputHandle))[] ---@type (fun(output: OutputHandle))[]
callbacks = {}, callbacks = {},
---@type fun(response: table)
on_response = nil,
}, },
layout = { Layout = {
---@type H2Stream? ---@type H2Stream?
sender = nil, sender = nil,
---@type (fun(windows: WindowHandle[], tag: TagHandle))[] ---@type (fun(tag: TagHandle, windows: WindowHandle[]))[]
callbacks = {}, callbacks = {},
---@type fun(response: table)
on_response = nil,
}, },
window_pointer_enter = { WindowPointerEnter = {
---@type H2Stream? ---@type H2Stream?
sender = nil, sender = nil,
---@type (fun(output: OutputHandle))[] ---@type (fun(output: OutputHandle))[]
callbacks = {}, callbacks = {},
---@type fun(response: table)
on_response = nil,
}, },
window_pointer_leave = { WindowPointerLeave = {
---@type H2Stream? ---@type H2Stream?
sender = nil, sender = nil,
---@type (fun(output: OutputHandle))[] ---@type (fun(output: OutputHandle))[]
callbacks = {}, callbacks = {},
---@type fun(response: table)
on_response = nil,
}, },
} }
signals.OutputConnect.on_response = function(response)
---@diagnostic disable-next-line: invisible
local handle = require("pinnacle.output").handle.new(response.output_name)
for _, callback in ipairs(signals.OutputConnect.callbacks) do
callback(handle)
end
end
signals.Layout.on_response = function(response)
---@diagnostic disable-next-line: invisible
local window_handles = require("pinnacle.window").handle.new_from_table(response.window_ids or {})
---@diagnostic disable-next-line: invisible
local tag_handle = require("pinnacle.tag").handle.new(response.tag_id)
for _, callback in ipairs(signals.Layout.callbacks) do
callback(tag_handle, window_handles)
end
end
-----------------------------------------------------------------------------
---@class SignalHandleModule
local signal_handle = {}
---@class SignalHandle
---@field signal SignalServiceMethod
---@field callback function The callback you connected
local SignalHandle = {}
---@class SignalHandlesModule
local signal_handles = {}
---@class SignalHandles
local SignalHandles = {}
---@class Signal ---@class Signal
---@field private handle SignalHandleModule
---@field private handles SignalHandlesModule
local signal = {} local signal = {}
signal.handle = signal_handle
signal.handles = signal_handles
---@param fn fun(windows: WindowHandle[], tag: TagHandle) function SignalHandle:disconnect()
function signal.layout_add(fn) local cb_index = nil
if #signals.layout.callbacks == 0 then for i, cb in ipairs(signals[self.signal].callbacks) do
signal.layout_connect() if cb == self.callback then
end cb_index = i
break
table.insert(signals.layout.callbacks, fn)
end
function signal.layout_dc()
signal.layout_disconnect()
end
function signal.output_connect_connect()
local stream = client.bidirectional_streaming_request(
build_grpc_request_params("OutputConnect", {
control = stream_control.READY,
}),
function(response)
---@diagnostic disable-next-line: invisible
local handle = require("pinnacle.output").handle.new(response.output_name)
for _, callback in ipairs(signals.output_connect.callbacks) do
callback(handle)
end
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "OutputConnectRequest", {
control = stream_control.READY,
})
if signals.layout.sender then
signals.layout.sender:write_chunk(chunk)
end
end end
) end
signals.output_connect.sender = stream if cb_index then
end table.remove(signals[self.signal].callbacks, cb_index)
end
function signal.output_connect_disconnect() if #signals[self.signal].callbacks == 0 then
if signals.output_connect.sender then signal.disconnect(self.signal)
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "OutputConnectRequest", {
control = stream_control.DISCONNECT,
})
signals.output_connect.sender:write_chunk(chunk)
signals.output_connect.sender = nil
end end
end end
function signal.layout_connect() ---@return SignalHandle
function signal_handle.new(request, callback)
---@type SignalHandle
local self = {
signal = request,
callback = callback,
}
setmetatable(self, { __index = SignalHandle })
return self
end
---@param self table<string, SignalHandle>
function SignalHandles:disconnect_all()
for _, sig in pairs(self) do
sig:disconnect()
end
end
---@param signal_hdls table<string, SignalHandle>
---@return SignalHandles
function signal_handles.new(signal_hdls)
---@type SignalHandles
local self = signal_hdls
setmetatable(self, { __index = SignalHandles })
return self
end
---@param request SignalServiceMethod
---@param callback function
function signal.add_callback(request, callback)
if #signals[request].callbacks == 0 then
signal.connect(request, signals[request].on_response)
end
table.insert(signals[request].callbacks, callback)
end
---@param request SignalServiceMethod
---@param callback fun(response: table)
function signal.connect(request, callback)
local stream = client.bidirectional_streaming_request( local stream = client.bidirectional_streaming_request(
build_grpc_request_params("Layout", { build_grpc_request_params("Layout", {
control = stream_control.READY, control = stream_control.READY,
}), }),
function(response) function(response)
---@diagnostic disable-next-line: invisible callback(response)
local window_handles = require("pinnacle.window").handle.new_from_table(response.window_ids or {})
---@diagnostic disable-next-line: invisible
local tag_handle = require("pinnacle.tag").handle.new(response.tag_id)
for _, callback in ipairs(signals.layout.callbacks) do if signals[request].sender then
print("calling layout callback") local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. request .. "Request", {
callback(window_handles, tag_handle) control = stream_control.READY,
end })
print("creating control request") local success, err = pcall(signals[request].sender.write_chunk, signals[request].sender, chunk)
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "LayoutRequest", {
control = stream_control.READY,
})
if signals.layout.sender then
local success, err = pcall(signals.layout.sender.write_chunk, signals.layout.sender, chunk)
if not success then if not success then
print("error sending to stream:", err) print("error sending to stream:", err)
os.exit(1) os.exit(1)
@ -159,19 +207,26 @@ function signal.layout_connect()
end end
) )
signals.layout.sender = stream signals[request].sender = stream
end end
function signal.layout_disconnect() ---This should only be called when call callbacks for the signal are removed
if signals.layout.sender then ---@param request SignalServiceMethod
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "LayoutRequest", { function signal.disconnect(request)
if signals[request].sender then
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. request .. "Request", {
control = stream_control.DISCONNECT, control = stream_control.DISCONNECT,
}) })
signals.layout.sender:write_chunk(chunk) local success, err = pcall(signals[request].sender.write_chunk, signals[request].sender, chunk)
signals.layout.sender = nil if not success then
print("error sending to stream:", err)
os.exit(1)
end
signals[request].sender:shutdown()
signals[request].sender = nil
end end
signals.layout.callbacks = {}
end end
return signal return signal

View file

@ -319,9 +319,25 @@ function tag.new_layout_cycler(layouts)
} }
end end
---@param fn fun(windows: WindowHandle[], tag: TagHandle) ---@class TagSignal
function tag.connect_layout(fn) ---@field layout fun(tag: TagHandle, windows: WindowHandle[])?
require("pinnacle.signal").layout_add(fn)
---@param signals TagSignal
---@return SignalHandles
function tag.connect_signal(signals)
---@diagnostic disable-next-line: invisible
local handles = require("pinnacle.signal").handles.new({})
for signal, callback in pairs(signals) do
if signal == "layout" then
require("pinnacle.signal").add_callback("Layout", callback)
---@diagnostic disable-next-line: invisible
local handle = require("pinnacle.signal").handle.new("Layout", callback)
handles[signal] = handle
end
end
return handles
end end
---Remove this tag. ---Remove this tag.

View file

@ -0,0 +1,4 @@
---@class LayoutModule
local layout = {}
return layout

View file

@ -128,7 +128,7 @@ where
fn run_bidirectional_streaming<F1, F2, I, O>( fn run_bidirectional_streaming<F1, F2, I, O>(
fn_sender: StateFnSender, fn_sender: StateFnSender,
mut in_stream: Streaming<I>, mut in_stream: Streaming<I>,
with_client_item: F1, with_client_request: F1,
with_out_stream: F2, with_out_stream: F2,
) -> Result<Response<ResponseStream<O>>, Status> ) -> Result<Response<ResponseStream<O>>, Status>
where where
@ -142,11 +142,11 @@ where
let fn_sender_clone = fn_sender.clone(); let fn_sender_clone = fn_sender.clone();
let with_in_stream = async move { let with_in_stream = async move {
while let Some(t) = in_stream.next().await { while let Some(request) = in_stream.next().await {
let with_client_item = with_client_item.clone(); let with_client_request = with_client_request.clone();
// TODO: handle error // TODO: handle error
let _ = fn_sender_clone.send(Box::new(move |state: &mut State| { let _ = fn_sender_clone.send(Box::new(move |state: &mut State| {
with_client_item(state, t); with_client_request(state, request);
})); }));
} }
}; };
@ -734,11 +734,13 @@ impl tag_service_server::TagService for TagService {
state.update_focus(&output); state.update_focus(&output);
state.schedule_render(&output); state.schedule_render(&output);
state.signal_state.layout.signal(|_| { state.signal_state.layout.signal(|buffer| {
pinnacle_api_defs::pinnacle::signal::v0alpha1::LayoutResponse { buffer.push_back(
window_ids: vec![1, 2, 3], pinnacle_api_defs::pinnacle::signal::v0alpha1::LayoutResponse {
tag_id: Some(1), window_ids: vec![1, 2, 3],
} tag_id: Some(1),
},
);
}); });
}) })
.await .await
@ -1125,7 +1127,7 @@ impl window_service_server::WindowService for WindowService {
async fn close(&self, request: Request<CloseRequest>) -> Result<Response<()>, Status> { async fn close(&self, request: Request<CloseRequest>) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1154,7 +1156,7 @@ impl window_service_server::WindowService for WindowService {
tracing::info!(request = ?request); tracing::info!(request = ?request);
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1205,7 +1207,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> { ) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1248,7 +1250,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> { ) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1291,7 +1293,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> { ) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1334,7 +1336,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> { ) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1362,7 +1364,7 @@ impl window_service_server::WindowService for WindowService {
async fn set_tag(&self, request: Request<SetTagRequest>) -> Result<Response<()>, Status> { async fn set_tag(&self, request: Request<SetTagRequest>) -> Result<Response<()>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1518,12 +1520,7 @@ impl window_service_server::WindowService for WindowService {
let window_ids = state let window_ids = state
.windows .windows
.iter() .iter()
.map(|win| { .map(|win| win.with_state(|state| state.id.0))
win.with_state(|state| match state.id {
WindowId::None => unreachable!(),
WindowId::Some(id) => id,
})
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
window::v0alpha1::GetResponse { window_ids } window::v0alpha1::GetResponse { window_ids }
@ -1537,7 +1534,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<window::v0alpha1::GetPropertiesResponse>, Status> { ) -> Result<Response<window::v0alpha1::GetPropertiesResponse>, Status> {
let request = request.into_inner(); let request = request.into_inner();
let window_id = WindowId::Some( let window_id = WindowId(
request request
.window_id .window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?, .ok_or_else(|| Status::invalid_argument("no window specified"))?,

View file

@ -1,3 +1,5 @@
use std::collections::VecDeque;
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{ use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
signal_service_server, LayoutRequest, LayoutResponse, OutputConnectRequest, signal_service_server, LayoutRequest, LayoutResponse, OutputConnectRequest,
OutputConnectResponse, StreamControl, WindowPointerEnterRequest, WindowPointerEnterResponse, OutputConnectResponse, StreamControl, WindowPointerEnterRequest, WindowPointerEnterResponse,
@ -12,33 +14,61 @@ use super::{run_bidirectional_streaming, ResponseStream, StateFnSender};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SignalState { pub struct SignalState {
pub output_connect: SignalData<OutputConnectResponse>, pub output_connect: SignalData<OutputConnectResponse, VecDeque<OutputConnectResponse>>,
pub layout: SignalData<LayoutResponse>, pub layout: SignalData<LayoutResponse, VecDeque<LayoutResponse>>,
pub window_pointer_enter: SignalData<WindowPointerEnterResponse>, pub window_pointer_enter:
pub window_pointer_leave: SignalData<WindowPointerLeaveResponse>, SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
pub window_pointer_leave:
SignalData<WindowPointerLeaveResponse, VecDeque<WindowPointerLeaveResponse>>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SignalData<T> { #[allow(private_bounds)]
pub struct SignalData<T, B: SignalBuffer<T>> {
sender: Option<UnboundedSender<Result<T, Status>>>, sender: Option<UnboundedSender<Result<T, Status>>>,
join_handle: Option<JoinHandle<()>>, join_handle: Option<JoinHandle<()>>,
ready: bool, ready: bool,
value: Option<T>, buffer: B,
} }
impl<T> SignalData<T> { /// A trait that denotes different types of containers that can be used to buffer signals.
pub fn signal(&mut self, with_data: impl FnOnce(Option<T>) -> T) { trait SignalBuffer<T>: Default {
/// Get the next signal from this buffer.
fn next(&mut self) -> Option<T>;
}
impl<T> SignalBuffer<T> for VecDeque<T> {
fn next(&mut self) -> Option<T> {
self.pop_front()
}
}
impl<T> SignalBuffer<T> for Option<T> {
fn next(&mut self) -> Option<T> {
self.take()
}
}
#[allow(private_bounds)]
impl<T, B: SignalBuffer<T>> SignalData<T, B> {
/// Attempt to send a signal.
///
/// If the client is ready to accept more of this signal, it will be sent immediately.
/// Otherwise, the signal will remain stored in the underlying buffer until the client is ready.
///
/// Use `with_buffer` to populate and manipulate the buffer with the data you want.
pub fn signal(&mut self, with_buffer: impl FnOnce(&mut B)) {
let Some(sender) = self.sender.as_ref() else { let Some(sender) = self.sender.as_ref() else {
return; return;
}; };
with_buffer(&mut self.buffer);
if self.ready { if self.ready {
sender if let Some(data) = self.buffer.next() {
.send(Ok(with_data(self.value.take()))) sender.send(Ok(data)).expect("failed to send signal");
.expect("failed to send signal"); self.ready = false;
self.ready = false; }
} else {
self.value = Some(with_data(self.value.take()));
} }
} }
@ -59,16 +89,19 @@ impl<T> SignalData<T> {
handle.abort(); handle.abort();
} }
self.ready = false; self.ready = false;
self.value.take(); self.buffer = B::default();
} }
/// Mark this signal as ready to send.
///
/// If there are signals already in the buffer, they will be sent.
fn ready(&mut self) { fn ready(&mut self) {
let Some(sender) = self.sender.as_ref() else { let Some(sender) = self.sender.as_ref() else {
return; return;
}; };
if let Some(value) = self.value.take() { if let Some(data) = self.buffer.next() {
sender.send(Ok(value)).expect("failed to send signal"); sender.send(Ok(data)).expect("failed to send signal");
self.ready = false; self.ready = false;
} else { } else {
self.ready = true; self.ready = true;
@ -99,16 +132,18 @@ impl_signal_request!(
WindowPointerLeaveRequest WindowPointerLeaveRequest
); );
fn start_signal_stream<I: SignalRequest + std::fmt::Debug, O>( fn start_signal_stream<I, O, B, F>(
sender: StateFnSender, sender: StateFnSender,
in_stream: Streaming<I>, in_stream: Streaming<I>,
signal: impl Fn(&mut State) -> &mut SignalData<O> + Clone + Send + 'static, with_signal_buffer: F,
) -> Result<Response<ResponseStream<O>>, Status> ) -> Result<Response<ResponseStream<O>>, Status>
where where
I: Send + 'static, I: SignalRequest + std::fmt::Debug + Send + 'static,
O: Send + 'static, O: Send + 'static,
B: SignalBuffer<O>,
F: Fn(&mut State) -> &mut SignalData<O, B> + Clone + Send + 'static,
{ {
let signal_clone = signal.clone(); let with_signal_buffer_clone = with_signal_buffer.clone();
run_bidirectional_streaming( run_bidirectional_streaming(
sender, sender,
@ -122,9 +157,9 @@ where
} }
}; };
tracing::info!("GOT {request:?} FROM CLIENT STREAM"); tracing::debug!("Got {request:?} from client stream");
let signal = signal(state); let signal = with_signal_buffer(state);
match request.control() { match request.control() {
StreamControl::Ready => signal.ready(), StreamControl::Ready => signal.ready(),
StreamControl::Disconnect => signal.disconnect(), StreamControl::Disconnect => signal.disconnect(),
@ -132,7 +167,7 @@ where
} }
}, },
move |state, sender, join_handle| { move |state, sender, join_handle| {
let signal = signal_clone(state); let signal = with_signal_buffer_clone(state);
signal.connect(sender, join_handle); signal.connect(sender, join_handle);
}, },
) )

View file

@ -8,7 +8,9 @@ use std::{
}; };
use anyhow::Context; use anyhow::Context;
use pinnacle_api_defs::pinnacle::output::v0alpha1::ConnectForAllResponse; use pinnacle_api_defs::pinnacle::{
output::v0alpha1::ConnectForAllResponse, signal::v0alpha1::OutputConnectResponse,
};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{ allocator::{
@ -989,6 +991,12 @@ impl State {
output_name: Some(output.name()), output_name: Some(output.name()),
})); }));
} }
self.signal_state.output_connect.signal(|buffer| {
buffer.push_back(OutputConnectResponse {
output_name: Some(output.name()),
})
});
} }
} }

View file

@ -4,6 +4,9 @@ pub mod rules;
use std::{cell::RefCell, time::Duration}; use std::{cell::RefCell, time::Duration};
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
WindowPointerEnterResponse, WindowPointerLeaveResponse,
};
use smithay::{ use smithay::{
backend::input::KeyState, backend::input::KeyState,
desktop::{ desktop::{
@ -330,33 +333,40 @@ impl WindowElement {
} }
impl PointerTarget<State> for WindowElement { impl PointerTarget<State> for WindowElement {
fn frame(&self, seat: &Seat<State>, data: &mut State) { fn frame(&self, seat: &Seat<State>, state: &mut State) {
match self { match self {
WindowElement::Wayland(window) => window.frame(seat, data), WindowElement::Wayland(window) => window.frame(seat, state),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.frame(seat, data) surface.frame(seat, state)
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) { fn enter(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => PointerTarget::enter(window, seat, data, event), WindowElement::Wayland(window) => PointerTarget::enter(window, seat, state, event),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::enter(surface, seat, data, event) PointerTarget::enter(surface, seat, state, event)
} }
_ => unreachable!(), _ => unreachable!(),
} }
let window_id = Some(self.with_state(|state| state.id.0));
state
.signal_state
.window_pointer_enter
.signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id }));
} }
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) { fn motion(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => PointerTarget::motion(window, seat, data, event), WindowElement::Wayland(window) => PointerTarget::motion(window, seat, state, event),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::motion(surface, seat, data, event) PointerTarget::motion(surface, seat, state, event)
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -365,16 +375,16 @@ impl PointerTarget<State> for WindowElement {
fn relative_motion( fn relative_motion(
&self, &self,
seat: &Seat<State>, seat: &Seat<State>,
data: &mut State, state: &mut State,
event: &smithay::input::pointer::RelativeMotionEvent, event: &smithay::input::pointer::RelativeMotionEvent,
) { ) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => { WindowElement::Wayland(window) => {
PointerTarget::relative_motion(window, seat, data, event); PointerTarget::relative_motion(window, seat, state, event);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::relative_motion(surface, seat, data, event); PointerTarget::relative_motion(surface, seat, state, event);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -383,47 +393,54 @@ impl PointerTarget<State> for WindowElement {
fn button( fn button(
&self, &self,
seat: &Seat<State>, seat: &Seat<State>,
data: &mut State, state: &mut State,
event: &smithay::input::pointer::ButtonEvent, event: &smithay::input::pointer::ButtonEvent,
) { ) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => PointerTarget::button(window, seat, data, event), WindowElement::Wayland(window) => PointerTarget::button(window, seat, state, event),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::button(surface, seat, data, event) PointerTarget::button(surface, seat, state, event)
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) { fn axis(&self, seat: &Seat<State>, state: &mut State, frame: AxisFrame) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => PointerTarget::axis(window, seat, data, frame), WindowElement::Wayland(window) => PointerTarget::axis(window, seat, state, frame),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::axis(surface, seat, data, frame) PointerTarget::axis(surface, seat, state, frame)
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) { fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial, time: u32) {
// TODO: ssd // TODO: ssd
match self { match self {
WindowElement::Wayland(window) => { WindowElement::Wayland(window) => {
PointerTarget::leave(window, seat, data, serial, time); PointerTarget::leave(window, seat, state, serial, time);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::leave(surface, seat, data, serial, time) PointerTarget::leave(surface, seat, state, serial, time)
} }
_ => unreachable!(), _ => unreachable!(),
} }
let window_id = Some(self.with_state(|state| state.id.0));
state
.signal_state
.window_pointer_leave
.signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id }));
} }
fn gesture_swipe_begin( fn gesture_swipe_begin(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GestureSwipeBeginEvent, _event: &smithay::input::pointer::GestureSwipeBeginEvent,
) { ) {
todo!() todo!()
@ -432,7 +449,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_swipe_update( fn gesture_swipe_update(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GestureSwipeUpdateEvent, _event: &smithay::input::pointer::GestureSwipeUpdateEvent,
) { ) {
todo!() todo!()
@ -441,7 +458,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_swipe_end( fn gesture_swipe_end(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GestureSwipeEndEvent, _event: &smithay::input::pointer::GestureSwipeEndEvent,
) { ) {
todo!() todo!()
@ -450,7 +467,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_begin( fn gesture_pinch_begin(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GesturePinchBeginEvent, _event: &smithay::input::pointer::GesturePinchBeginEvent,
) { ) {
todo!() todo!()
@ -459,7 +476,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_update( fn gesture_pinch_update(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GesturePinchUpdateEvent, _event: &smithay::input::pointer::GesturePinchUpdateEvent,
) { ) {
todo!() todo!()
@ -468,7 +485,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_end( fn gesture_pinch_end(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GesturePinchEndEvent, _event: &smithay::input::pointer::GesturePinchEndEvent,
) { ) {
todo!() todo!()
@ -477,7 +494,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_hold_begin( fn gesture_hold_begin(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GestureHoldBeginEvent, _event: &smithay::input::pointer::GestureHoldBeginEvent,
) { ) {
todo!() todo!()
@ -486,7 +503,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_hold_end( fn gesture_hold_end(
&self, &self,
_seat: &Seat<State>, _seat: &Seat<State>,
_data: &mut State, _state: &mut State,
_event: &smithay::input::pointer::GestureHoldEndEvent, _event: &smithay::input::pointer::GestureHoldEndEvent,
) { ) {
todo!() todo!()
@ -497,26 +514,26 @@ impl KeyboardTarget<State> for WindowElement {
fn enter( fn enter(
&self, &self,
seat: &Seat<State>, seat: &Seat<State>,
data: &mut State, state: &mut State,
keys: Vec<KeysymHandle<'_>>, keys: Vec<KeysymHandle<'_>>,
serial: Serial, serial: Serial,
) { ) {
match self { match self {
WindowElement::Wayland(window) => { WindowElement::Wayland(window) => {
KeyboardTarget::enter(window, seat, data, keys, serial); KeyboardTarget::enter(window, seat, state, keys, serial);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::enter(surface, seat, data, keys, serial) KeyboardTarget::enter(surface, seat, state, keys, serial)
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) { fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial) {
match self { match self {
WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, data, serial), WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, state, serial),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::leave(surface, seat, data, serial) KeyboardTarget::leave(surface, seat, state, serial)
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -525,18 +542,18 @@ impl KeyboardTarget<State> for WindowElement {
fn key( fn key(
&self, &self,
seat: &Seat<State>, seat: &Seat<State>,
data: &mut State, state: &mut State,
key: KeysymHandle<'_>, key: KeysymHandle<'_>,
state: KeyState, key_state: KeyState,
serial: Serial, serial: Serial,
time: u32, time: u32,
) { ) {
match self { match self {
WindowElement::Wayland(window) => { WindowElement::Wayland(window) => {
KeyboardTarget::key(window, seat, data, key, state, serial, time); KeyboardTarget::key(window, seat, state, key, key_state, serial, time);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::key(surface, seat, data, key, state, serial, time); KeyboardTarget::key(surface, seat, state, key, key_state, serial, time);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -545,16 +562,16 @@ impl KeyboardTarget<State> for WindowElement {
fn modifiers( fn modifiers(
&self, &self,
seat: &Seat<State>, seat: &Seat<State>,
data: &mut State, state: &mut State,
modifiers: ModifiersState, modifiers: ModifiersState,
serial: Serial, serial: Serial,
) { ) {
match self { match self {
WindowElement::Wayland(window) => { WindowElement::Wayland(window) => {
KeyboardTarget::modifiers(window, seat, data, modifiers, serial); KeyboardTarget::modifiers(window, seat, state, modifiers, serial);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::modifiers(surface, seat, data, modifiers, serial); KeyboardTarget::modifiers(surface, seat, state, modifiers, serial);
} }
_ => unreachable!(), _ => unreachable!(),
} }

View file

@ -17,20 +17,14 @@ use super::WindowElement;
/// A unique identifier for each window. /// A unique identifier for each window.
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum WindowId { pub struct WindowId(pub u32);
/// A config API returned an invalid window. It should be using this variant.
None,
/// A valid window id.
#[serde(untagged)]
Some(u32),
}
static WINDOW_ID_COUNTER: AtomicU32 = AtomicU32::new(0); static WINDOW_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
impl WindowId { impl WindowId {
/// Get the next available window id. This always starts at 0. /// Get the next available window id. This always starts at 0.
pub fn next() -> Self { pub fn next() -> Self {
Self::Some(WINDOW_ID_COUNTER.fetch_add(1, Ordering::Relaxed)) Self(WINDOW_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
} }
/// Get the window that has this WindowId. /// Get the window that has this WindowId.