mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Add output connect signal
untested
This commit is contained in:
parent
1539f73e45
commit
7d94fc4362
11 changed files with 323 additions and 173 deletions
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
4
api/lua/pinnacle/tag/layout.lua
Normal file
4
api/lua/pinnacle/tag/layout.lua
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---@class LayoutModule
|
||||||
|
local layout = {}
|
||||||
|
|
||||||
|
return layout
|
43
src/api.rs
43
src/api.rs
|
@ -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"))?,
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()),
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
101
src/window.rs
101
src/window.rs
|
@ -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!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue