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.process"] = "pinnacle/process.lua",
["pinnacle.tag"] = "pinnacle/tag.lua",
["pinnacle.tag.layout"] = "pinnacle/tag/layout.lua",
["pinnacle.window"] = "pinnacle/window.lua",
["pinnacle.util"] = "pinnacle/util.lua",
["pinnacle.signal"] = "pinnacle/signal.lua",

View file

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

View file

@ -166,6 +166,29 @@ function output.connect_for_all(callback)
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.
---
---On startup, Pinnacle will lay out all connected outputs starting at (0, 0)

View file

@ -49,108 +49,156 @@ local stream_control = {
DISCONNECT = 2,
}
---@type table<SignalServiceMethod, { sender: H2Stream?, callbacks: function[], on_response: fun(response: table) }>
local signals = {
output_connect = {
OutputConnect = {
---@type H2Stream?
sender = nil,
---@type (fun(output: OutputHandle))[]
callbacks = {},
---@type fun(response: table)
on_response = nil,
},
layout = {
Layout = {
---@type H2Stream?
sender = nil,
---@type (fun(windows: WindowHandle[], tag: TagHandle))[]
---@type (fun(tag: TagHandle, windows: WindowHandle[]))[]
callbacks = {},
---@type fun(response: table)
on_response = nil,
},
window_pointer_enter = {
WindowPointerEnter = {
---@type H2Stream?
sender = nil,
---@type (fun(output: OutputHandle))[]
callbacks = {},
---@type fun(response: table)
on_response = nil,
},
window_pointer_leave = {
WindowPointerLeave = {
---@type H2Stream?
sender = nil,
---@type (fun(output: OutputHandle))[]
callbacks = {},
---@type fun(response: table)
on_response = nil,
},
}
---@class Signal
local signal = {}
---@param fn fun(windows: WindowHandle[], tag: TagHandle)
function signal.layout_add(fn)
if #signals.layout.callbacks == 0 then
signal.layout_connect()
end
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)
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.output_connect.callbacks) do
for _, callback in ipairs(signals.OutputConnect.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
)
signals.output_connect.sender = stream
end
function signal.output_connect_disconnect()
if signals.output_connect.sender then
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
function signal.layout_connect()
local stream = client.bidirectional_streaming_request(
build_grpc_request_params("Layout", {
control = stream_control.READY,
}),
function(response)
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
print("calling layout callback")
callback(window_handles, tag_handle)
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
---@field private handle SignalHandleModule
---@field private handles SignalHandlesModule
local signal = {}
signal.handle = signal_handle
signal.handles = signal_handles
function SignalHandle:disconnect()
local cb_index = nil
for i, cb in ipairs(signals[self.signal].callbacks) do
if cb == self.callback then
cb_index = i
break
end
end
print("creating control request")
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "LayoutRequest", {
if cb_index then
table.remove(signals[self.signal].callbacks, cb_index)
end
if #signals[self.signal].callbacks == 0 then
signal.disconnect(self.signal)
end
end
---@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(
build_grpc_request_params("Layout", {
control = stream_control.READY,
}),
function(response)
callback(response)
if signals[request].sender then
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. request .. "Request", {
control = stream_control.READY,
})
if signals.layout.sender then
local success, err = pcall(signals.layout.sender.write_chunk, signals.layout.sender, chunk)
local success, err = pcall(signals[request].sender.write_chunk, signals[request].sender, chunk)
if not success then
print("error sending to stream:", err)
os.exit(1)
@ -159,19 +207,26 @@ function signal.layout_connect()
end
)
signals.layout.sender = stream
signals[request].sender = stream
end
function signal.layout_disconnect()
if signals.layout.sender then
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. "LayoutRequest", {
---This should only be called when call callbacks for the signal are removed
---@param request SignalServiceMethod
function signal.disconnect(request)
if signals[request].sender then
local chunk = require("pinnacle.grpc.protobuf").encode(prefix .. request .. "Request", {
control = stream_control.DISCONNECT,
})
signals.layout.sender:write_chunk(chunk)
signals.layout.sender = nil
local success, err = pcall(signals[request].sender.write_chunk, signals[request].sender, chunk)
if not success then
print("error sending to stream:", err)
os.exit(1)
end
signals[request].sender:shutdown()
signals[request].sender = nil
end
signals.layout.callbacks = {}
end
return signal

View file

@ -319,9 +319,25 @@ function tag.new_layout_cycler(layouts)
}
end
---@param fn fun(windows: WindowHandle[], tag: TagHandle)
function tag.connect_layout(fn)
require("pinnacle.signal").layout_add(fn)
---@class TagSignal
---@field layout fun(tag: TagHandle, windows: WindowHandle[])?
---@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
---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_sender: StateFnSender,
mut in_stream: Streaming<I>,
with_client_item: F1,
with_client_request: F1,
with_out_stream: F2,
) -> Result<Response<ResponseStream<O>>, Status>
where
@ -142,11 +142,11 @@ where
let fn_sender_clone = fn_sender.clone();
let with_in_stream = async move {
while let Some(t) = in_stream.next().await {
let with_client_item = with_client_item.clone();
while let Some(request) = in_stream.next().await {
let with_client_request = with_client_request.clone();
// TODO: handle error
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.schedule_render(&output);
state.signal_state.layout.signal(|_| {
state.signal_state.layout.signal(|buffer| {
buffer.push_back(
pinnacle_api_defs::pinnacle::signal::v0alpha1::LayoutResponse {
window_ids: vec![1, 2, 3],
tag_id: Some(1),
}
},
);
});
})
.await
@ -1125,7 +1127,7 @@ impl window_service_server::WindowService for WindowService {
async fn close(&self, request: Request<CloseRequest>) -> Result<Response<()>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1154,7 +1156,7 @@ impl window_service_server::WindowService for WindowService {
tracing::info!(request = ?request);
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1205,7 +1207,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1248,7 +1250,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1291,7 +1293,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1334,7 +1336,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<()>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.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> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.ok_or_else(|| Status::invalid_argument("no window specified"))?,
@ -1518,12 +1520,7 @@ impl window_service_server::WindowService for WindowService {
let window_ids = state
.windows
.iter()
.map(|win| {
win.with_state(|state| match state.id {
WindowId::None => unreachable!(),
WindowId::Some(id) => id,
})
})
.map(|win| win.with_state(|state| state.id.0))
.collect::<Vec<_>>();
window::v0alpha1::GetResponse { window_ids }
@ -1537,7 +1534,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<window::v0alpha1::GetPropertiesResponse>, Status> {
let request = request.into_inner();
let window_id = WindowId::Some(
let window_id = WindowId(
request
.window_id
.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::{
signal_service_server, LayoutRequest, LayoutResponse, OutputConnectRequest,
OutputConnectResponse, StreamControl, WindowPointerEnterRequest, WindowPointerEnterResponse,
@ -12,33 +14,61 @@ use super::{run_bidirectional_streaming, ResponseStream, StateFnSender};
#[derive(Debug, Default)]
pub struct SignalState {
pub output_connect: SignalData<OutputConnectResponse>,
pub layout: SignalData<LayoutResponse>,
pub window_pointer_enter: SignalData<WindowPointerEnterResponse>,
pub window_pointer_leave: SignalData<WindowPointerLeaveResponse>,
pub output_connect: SignalData<OutputConnectResponse, VecDeque<OutputConnectResponse>>,
pub layout: SignalData<LayoutResponse, VecDeque<LayoutResponse>>,
pub window_pointer_enter:
SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
pub window_pointer_leave:
SignalData<WindowPointerLeaveResponse, VecDeque<WindowPointerLeaveResponse>>,
}
#[derive(Debug, Default)]
pub struct SignalData<T> {
#[allow(private_bounds)]
pub struct SignalData<T, B: SignalBuffer<T>> {
sender: Option<UnboundedSender<Result<T, Status>>>,
join_handle: Option<JoinHandle<()>>,
ready: bool,
value: Option<T>,
buffer: B,
}
impl<T> SignalData<T> {
pub fn signal(&mut self, with_data: impl FnOnce(Option<T>) -> T) {
/// A trait that denotes different types of containers that can be used to buffer signals.
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 {
return;
};
with_buffer(&mut self.buffer);
if self.ready {
sender
.send(Ok(with_data(self.value.take())))
.expect("failed to send signal");
if let Some(data) = self.buffer.next() {
sender.send(Ok(data)).expect("failed to send signal");
self.ready = false;
} else {
self.value = Some(with_data(self.value.take()));
}
}
}
@ -59,16 +89,19 @@ impl<T> SignalData<T> {
handle.abort();
}
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) {
let Some(sender) = self.sender.as_ref() else {
return;
};
if let Some(value) = self.value.take() {
sender.send(Ok(value)).expect("failed to send signal");
if let Some(data) = self.buffer.next() {
sender.send(Ok(data)).expect("failed to send signal");
self.ready = false;
} else {
self.ready = true;
@ -99,16 +132,18 @@ impl_signal_request!(
WindowPointerLeaveRequest
);
fn start_signal_stream<I: SignalRequest + std::fmt::Debug, O>(
fn start_signal_stream<I, O, B, F>(
sender: StateFnSender,
in_stream: Streaming<I>,
signal: impl Fn(&mut State) -> &mut SignalData<O> + Clone + Send + 'static,
with_signal_buffer: F,
) -> Result<Response<ResponseStream<O>>, Status>
where
I: Send + 'static,
I: SignalRequest + std::fmt::Debug + 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(
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() {
StreamControl::Ready => signal.ready(),
StreamControl::Disconnect => signal.disconnect(),
@ -132,7 +167,7 @@ where
}
},
move |state, sender, join_handle| {
let signal = signal_clone(state);
let signal = with_signal_buffer_clone(state);
signal.connect(sender, join_handle);
},
)

View file

@ -8,7 +8,9 @@ use std::{
};
use anyhow::Context;
use pinnacle_api_defs::pinnacle::output::v0alpha1::ConnectForAllResponse;
use pinnacle_api_defs::pinnacle::{
output::v0alpha1::ConnectForAllResponse, signal::v0alpha1::OutputConnectResponse,
};
use smithay::{
backend::{
allocator::{
@ -989,6 +991,12 @@ impl State {
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 pinnacle_api_defs::pinnacle::signal::v0alpha1::{
WindowPointerEnterResponse, WindowPointerLeaveResponse,
};
use smithay::{
backend::input::KeyState,
desktop::{
@ -330,33 +333,40 @@ impl 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 {
WindowElement::Wayland(window) => window.frame(seat, data),
WindowElement::Wayland(window) => window.frame(seat, state),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.frame(seat, data)
surface.frame(seat, state)
}
_ => 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
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) => {
PointerTarget::enter(surface, seat, data, event)
PointerTarget::enter(surface, seat, state, event)
}
_ => 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
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) => {
PointerTarget::motion(surface, seat, data, event)
PointerTarget::motion(surface, seat, state, event)
}
_ => unreachable!(),
}
@ -365,16 +375,16 @@ impl PointerTarget<State> for WindowElement {
fn relative_motion(
&self,
seat: &Seat<State>,
data: &mut State,
state: &mut State,
event: &smithay::input::pointer::RelativeMotionEvent,
) {
// TODO: ssd
match self {
WindowElement::Wayland(window) => {
PointerTarget::relative_motion(window, seat, data, event);
PointerTarget::relative_motion(window, seat, state, event);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::relative_motion(surface, seat, data, event);
PointerTarget::relative_motion(surface, seat, state, event);
}
_ => unreachable!(),
}
@ -383,47 +393,54 @@ impl PointerTarget<State> for WindowElement {
fn button(
&self,
seat: &Seat<State>,
data: &mut State,
state: &mut State,
event: &smithay::input::pointer::ButtonEvent,
) {
// TODO: ssd
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) => {
PointerTarget::button(surface, seat, data, event)
PointerTarget::button(surface, seat, state, event)
}
_ => 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
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) => {
PointerTarget::axis(surface, seat, data, frame)
PointerTarget::axis(surface, seat, state, frame)
}
_ => 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
match self {
WindowElement::Wayland(window) => {
PointerTarget::leave(window, seat, data, serial, time);
PointerTarget::leave(window, seat, state, serial, time);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::leave(surface, seat, data, serial, time)
PointerTarget::leave(surface, seat, state, serial, time)
}
_ => 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(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GestureSwipeBeginEvent,
) {
todo!()
@ -432,7 +449,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_swipe_update(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GestureSwipeUpdateEvent,
) {
todo!()
@ -441,7 +458,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_swipe_end(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GestureSwipeEndEvent,
) {
todo!()
@ -450,7 +467,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_begin(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GesturePinchBeginEvent,
) {
todo!()
@ -459,7 +476,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_update(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GesturePinchUpdateEvent,
) {
todo!()
@ -468,7 +485,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_pinch_end(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GesturePinchEndEvent,
) {
todo!()
@ -477,7 +494,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_hold_begin(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GestureHoldBeginEvent,
) {
todo!()
@ -486,7 +503,7 @@ impl PointerTarget<State> for WindowElement {
fn gesture_hold_end(
&self,
_seat: &Seat<State>,
_data: &mut State,
_state: &mut State,
_event: &smithay::input::pointer::GestureHoldEndEvent,
) {
todo!()
@ -497,26 +514,26 @@ impl KeyboardTarget<State> for WindowElement {
fn enter(
&self,
seat: &Seat<State>,
data: &mut State,
state: &mut State,
keys: Vec<KeysymHandle<'_>>,
serial: Serial,
) {
match self {
WindowElement::Wayland(window) => {
KeyboardTarget::enter(window, seat, data, keys, serial);
KeyboardTarget::enter(window, seat, state, keys, serial);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::enter(surface, seat, data, keys, serial)
KeyboardTarget::enter(surface, seat, state, keys, serial)
}
_ => 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 {
WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, data, serial),
WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, state, serial),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::leave(surface, seat, data, serial)
KeyboardTarget::leave(surface, seat, state, serial)
}
_ => unreachable!(),
}
@ -525,18 +542,18 @@ impl KeyboardTarget<State> for WindowElement {
fn key(
&self,
seat: &Seat<State>,
data: &mut State,
state: &mut State,
key: KeysymHandle<'_>,
state: KeyState,
key_state: KeyState,
serial: Serial,
time: u32,
) {
match self {
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) => {
KeyboardTarget::key(surface, seat, data, key, state, serial, time);
KeyboardTarget::key(surface, seat, state, key, key_state, serial, time);
}
_ => unreachable!(),
}
@ -545,16 +562,16 @@ impl KeyboardTarget<State> for WindowElement {
fn modifiers(
&self,
seat: &Seat<State>,
data: &mut State,
state: &mut State,
modifiers: ModifiersState,
serial: Serial,
) {
match self {
WindowElement::Wayland(window) => {
KeyboardTarget::modifiers(window, seat, data, modifiers, serial);
KeyboardTarget::modifiers(window, seat, state, modifiers, serial);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::modifiers(surface, seat, data, modifiers, serial);
KeyboardTarget::modifiers(surface, seat, state, modifiers, serial);
}
_ => unreachable!(),
}

View file

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