mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-25 09:59:21 +01:00
Add tag active signal
This commit is contained in:
parent
c0aa9067f3
commit
1c2f639a56
9 changed files with 171 additions and 13 deletions
|
@ -23,12 +23,17 @@ local rpc_types = {
|
||||||
OutputMove = {
|
OutputMove = {
|
||||||
response_type = "OutputMoveResponse",
|
response_type = "OutputMoveResponse",
|
||||||
},
|
},
|
||||||
|
|
||||||
WindowPointerEnter = {
|
WindowPointerEnter = {
|
||||||
response_type = "WindowPointerEnterResponse",
|
response_type = "WindowPointerEnterResponse",
|
||||||
},
|
},
|
||||||
WindowPointerLeave = {
|
WindowPointerLeave = {
|
||||||
response_type = "WindowPointerLeaveResponse",
|
response_type = "WindowPointerLeaveResponse",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
TagActive = {
|
||||||
|
response_type = "TagActiveResponse",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
---Build GrpcRequestParams
|
---Build GrpcRequestParams
|
||||||
|
@ -126,6 +131,17 @@ local signals = {
|
||||||
---@type fun(response: table)
|
---@type fun(response: table)
|
||||||
on_response = nil,
|
on_response = nil,
|
||||||
},
|
},
|
||||||
|
TagActive = {
|
||||||
|
---@nodoc
|
||||||
|
---@type H2Stream?
|
||||||
|
sender = nil,
|
||||||
|
---@nodoc
|
||||||
|
---@type (fun(tag: TagHandle, active: boolean))[]
|
||||||
|
callbacks = {},
|
||||||
|
---@nodoc
|
||||||
|
---@type fun(response: table)
|
||||||
|
on_response = nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
signals.OutputConnect.on_response = function(response)
|
signals.OutputConnect.on_response = function(response)
|
||||||
|
@ -178,6 +194,15 @@ signals.WindowPointerLeave.on_response = function(response)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
signals.TagActive.on_response = function(response)
|
||||||
|
---@diagnostic disable-next-line: invisible
|
||||||
|
local tag_handle = require("pinnacle.tag").handle.new(response.tag_id)
|
||||||
|
|
||||||
|
for _, callback in ipairs(signals.TagActive.callbacks) do
|
||||||
|
callback(tag_handle, response.active)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
---@nodoc
|
---@nodoc
|
||||||
|
|
|
@ -210,6 +210,52 @@ function tag.remove(tags)
|
||||||
client.unary_request(build_grpc_request_params("Remove", { tag_ids = ids }))
|
client.unary_request(build_grpc_request_params("Remove", { tag_ids = ids }))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type table<string, SignalServiceMethod>
|
||||||
|
local signal_name_to_SignalName = {
|
||||||
|
active = "TagActive",
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class TagSignal Signals related to tag events.
|
||||||
|
---@field active fun(tag: TagHandle, active: boolean)? A tag was set to active or not active.
|
||||||
|
|
||||||
|
---Connect to a tag signal.
|
||||||
|
---
|
||||||
|
---The compositor sends signals about various events. Use this function to run a callback when
|
||||||
|
---some tag signal occurs.
|
||||||
|
---
|
||||||
|
---This function returns a table of signal handles with each handle stored at the same key used
|
||||||
|
---to connect to the signal. See `SignalHandles` for more information.
|
||||||
|
---
|
||||||
|
---# Example
|
||||||
|
---```lua
|
||||||
|
---Tag.connect_signal({
|
||||||
|
--- active = function(tag, active)
|
||||||
|
--- print("Activity for " .. tag:name() .. " was set to", active)
|
||||||
|
--- end
|
||||||
|
---})
|
||||||
|
---```
|
||||||
|
---
|
||||||
|
---@param signals TagSignal The signal you want to connect to
|
||||||
|
---
|
||||||
|
---@return SignalHandles signal_handles Handles to every signal you connected to wrapped in a table, with keys being the same as the connected signal.
|
||||||
|
---
|
||||||
|
---@see SignalHandles.disconnect_all - To disconnect from these signals
|
||||||
|
function tag.connect_signal(signals)
|
||||||
|
---@diagnostic disable-next-line: invisible
|
||||||
|
local handles = require("pinnacle.signal").handles.new({})
|
||||||
|
|
||||||
|
for signal, callback in pairs(signals) do
|
||||||
|
require("pinnacle.signal").add_callback(signal_name_to_SignalName[signal], callback)
|
||||||
|
---@diagnostic disable-next-line: invisible
|
||||||
|
local handle = require("pinnacle.signal").handle.new(signal_name_to_SignalName[signal], callback)
|
||||||
|
handles[signal] = handle
|
||||||
|
end
|
||||||
|
|
||||||
|
return handles
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
---Remove this tag.
|
---Remove this tag.
|
||||||
---
|
---
|
||||||
---### Example
|
---### Example
|
||||||
|
|
|
@ -26,6 +26,7 @@ message OutputDisconnectResponse {
|
||||||
message OutputResizeRequest {
|
message OutputResizeRequest {
|
||||||
optional StreamControl control = 1;
|
optional StreamControl control = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An output's logical size changed
|
// An output's logical size changed
|
||||||
message OutputResizeResponse {
|
message OutputResizeResponse {
|
||||||
optional string output_name = 1;
|
optional string output_name = 1;
|
||||||
|
@ -36,6 +37,7 @@ message OutputResizeResponse {
|
||||||
message OutputMoveRequest {
|
message OutputMoveRequest {
|
||||||
optional StreamControl control = 1;
|
optional StreamControl control = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An output's location in the global space changed
|
// An output's location in the global space changed
|
||||||
message OutputMoveResponse {
|
message OutputMoveResponse {
|
||||||
optional string output_name = 1;
|
optional string output_name = 1;
|
||||||
|
@ -59,11 +61,23 @@ message WindowPointerLeaveResponse {
|
||||||
optional uint32 window_id = 1;
|
optional uint32 window_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TagActiveRequest {
|
||||||
|
optional StreamControl control = 1;
|
||||||
|
}
|
||||||
|
message TagActiveResponse {
|
||||||
|
optional uint32 tag_id = 1;
|
||||||
|
// The tag was set to active or inactive.
|
||||||
|
optional bool active = 2;
|
||||||
|
}
|
||||||
|
|
||||||
service SignalService {
|
service SignalService {
|
||||||
rpc OutputConnect(stream OutputConnectRequest) returns (stream OutputConnectResponse);
|
rpc OutputConnect(stream OutputConnectRequest) returns (stream OutputConnectResponse);
|
||||||
rpc OutputDisconnect(stream OutputDisconnectRequest) returns (stream OutputDisconnectResponse);
|
rpc OutputDisconnect(stream OutputDisconnectRequest) returns (stream OutputDisconnectResponse);
|
||||||
rpc OutputResize(stream OutputResizeRequest) returns (stream OutputResizeResponse);
|
rpc OutputResize(stream OutputResizeRequest) returns (stream OutputResizeResponse);
|
||||||
rpc OutputMove(stream OutputMoveRequest) returns (stream OutputMoveResponse);
|
rpc OutputMove(stream OutputMoveRequest) returns (stream OutputMoveResponse);
|
||||||
|
|
||||||
rpc WindowPointerEnter(stream WindowPointerEnterRequest) returns (stream WindowPointerEnterResponse);
|
rpc WindowPointerEnter(stream WindowPointerEnterRequest) returns (stream WindowPointerEnterResponse);
|
||||||
rpc WindowPointerLeave(stream WindowPointerLeaveRequest) returns (stream WindowPointerLeaveResponse);
|
rpc WindowPointerLeave(stream WindowPointerLeaveRequest) returns (stream WindowPointerLeaveResponse);
|
||||||
|
|
||||||
|
rpc TagActive(stream TagActiveRequest) returns (stream TagActiveResponse);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,9 @@ use tokio::sync::{
|
||||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||||
use tonic::{transport::Channel, Streaming};
|
use tonic::{transport::Channel, Streaming};
|
||||||
|
|
||||||
use crate::{block_on_tokio, output::OutputHandle, window::WindowHandle, ApiModules};
|
use crate::{
|
||||||
|
block_on_tokio, output::OutputHandle, tag::TagHandle, window::WindowHandle, ApiModules,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) trait Signal {
|
pub(crate) trait Signal {
|
||||||
type Callback;
|
type Callback;
|
||||||
|
@ -229,6 +231,24 @@ signals! {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Signals relating to tag events.
|
||||||
|
TagSignal => {
|
||||||
|
/// A tag was set to active or not active.
|
||||||
|
TagActive = {
|
||||||
|
enum_name = Active,
|
||||||
|
callback_type = Box<dyn FnMut(&TagHandle, bool) + Send + 'static>,
|
||||||
|
client_request = tag_active,
|
||||||
|
on_response = |response, callbacks, api| {
|
||||||
|
if let Some(tag_id) = response.tag_id {
|
||||||
|
let handle = api.tag.new_handle(tag_id);
|
||||||
|
|
||||||
|
for callback in callbacks {
|
||||||
|
callback(&handle, response.active.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type SingleOutputFn = Box<dyn FnMut(&OutputHandle) + Send + 'static>;
|
pub(crate) type SingleOutputFn = Box<dyn FnMut(&OutputHandle) + Send + 'static>;
|
||||||
|
@ -239,8 +259,11 @@ pub(crate) struct SignalState {
|
||||||
pub(crate) output_disconnect: SignalData<OutputDisconnect>,
|
pub(crate) output_disconnect: SignalData<OutputDisconnect>,
|
||||||
pub(crate) output_resize: SignalData<OutputResize>,
|
pub(crate) output_resize: SignalData<OutputResize>,
|
||||||
pub(crate) output_move: SignalData<OutputMove>,
|
pub(crate) output_move: SignalData<OutputMove>,
|
||||||
|
|
||||||
pub(crate) window_pointer_enter: SignalData<WindowPointerEnter>,
|
pub(crate) window_pointer_enter: SignalData<WindowPointerEnter>,
|
||||||
pub(crate) window_pointer_leave: SignalData<WindowPointerLeave>,
|
pub(crate) window_pointer_leave: SignalData<WindowPointerLeave>,
|
||||||
|
|
||||||
|
pub(crate) tag_active: SignalData<TagActive>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for SignalState {
|
impl std::fmt::Debug for SignalState {
|
||||||
|
@ -262,6 +285,7 @@ impl SignalState {
|
||||||
output_move: SignalData::new(client.clone(), fut_sender.clone()),
|
output_move: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
window_pointer_enter: SignalData::new(client.clone(), fut_sender.clone()),
|
window_pointer_enter: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
window_pointer_leave: SignalData::new(client.clone(), fut_sender.clone()),
|
window_pointer_leave: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
|
tag_active: SignalData::new(client.clone(), fut_sender.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +296,7 @@ impl SignalState {
|
||||||
self.output_move.api.set(api.clone()).unwrap();
|
self.output_move.api.set(api.clone()).unwrap();
|
||||||
self.window_pointer_enter.api.set(api.clone()).unwrap();
|
self.window_pointer_enter.api.set(api.clone()).unwrap();
|
||||||
self.window_pointer_leave.api.set(api.clone()).unwrap();
|
self.window_pointer_leave.api.set(api.clone()).unwrap();
|
||||||
|
self.tag_active.api.set(api.clone()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,14 @@ use pinnacle_api_defs::pinnacle::{
|
||||||
};
|
};
|
||||||
use tonic::transport::Channel;
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
use crate::{block_on_tokio, output::OutputHandle, util::Batch, window::WindowHandle, ApiModules};
|
use crate::{
|
||||||
|
block_on_tokio,
|
||||||
|
output::OutputHandle,
|
||||||
|
signal::{SignalHandle, TagSignal},
|
||||||
|
util::Batch,
|
||||||
|
window::WindowHandle,
|
||||||
|
ApiModules,
|
||||||
|
};
|
||||||
|
|
||||||
/// A struct that allows you to add and remove tags and get [`TagHandle`]s.
|
/// A struct that allows you to add and remove tags and get [`TagHandle`]s.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -227,6 +234,19 @@ impl Tag {
|
||||||
|
|
||||||
block_on_tokio(client.remove(RemoveRequest { tag_ids })).unwrap();
|
block_on_tokio(client.remove(RemoveRequest { tag_ids })).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connect to a tag signal.
|
||||||
|
///
|
||||||
|
/// The compositor will fire off signals that your config can listen for and act upon.
|
||||||
|
/// You can pass in a [`TagSignal`] along with a callback and it will get run
|
||||||
|
/// with the necessary arguments every time a signal of that type is received.
|
||||||
|
pub fn connect_signal(&self, signal: TagSignal) -> SignalHandle {
|
||||||
|
let mut signal_state = block_on_tokio(self.api.get().unwrap().signal.write());
|
||||||
|
|
||||||
|
match signal {
|
||||||
|
TagSignal::Active(f) => signal_state.tag_active.add_callback(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle to a tag.
|
/// A handle to a tag.
|
||||||
|
|
|
@ -67,7 +67,8 @@ pub mod pinnacle {
|
||||||
OutputResizeRequest,
|
OutputResizeRequest,
|
||||||
OutputMoveRequest,
|
OutputMoveRequest,
|
||||||
WindowPointerEnterRequest,
|
WindowPointerEnterRequest,
|
||||||
WindowPointerLeaveRequest
|
WindowPointerLeaveRequest,
|
||||||
|
TagActiveRequest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/api.rs
14
src/api.rs
|
@ -706,9 +706,9 @@ impl tag_service_server::TagService for TagService {
|
||||||
};
|
};
|
||||||
|
|
||||||
match set_or_toggle {
|
match set_or_toggle {
|
||||||
SetOrToggle::Set => tag.set_active(true),
|
SetOrToggle::Set => tag.set_active(true, state),
|
||||||
SetOrToggle::Unset => tag.set_active(false),
|
SetOrToggle::Unset => tag.set_active(false, state),
|
||||||
SetOrToggle::Toggle => tag.set_active(!tag.active()),
|
SetOrToggle::Toggle => tag.set_active(!tag.active(), state),
|
||||||
SetOrToggle::Unspecified => unreachable!(),
|
SetOrToggle::Unspecified => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,11 +736,11 @@ impl tag_service_server::TagService for TagService {
|
||||||
let Some(tag) = tag_id.tag(state) else { return };
|
let Some(tag) = tag_id.tag(state) else { return };
|
||||||
let Some(output) = tag.output(state) else { return };
|
let Some(output) = tag.output(state) else { return };
|
||||||
|
|
||||||
output.with_state_mut(|state| {
|
output.with_state_mut(|op_state| {
|
||||||
for op_tag in state.tags.iter_mut() {
|
for op_tag in op_state.tags.iter_mut() {
|
||||||
op_tag.set_active(false);
|
op_tag.set_active(false, state);
|
||||||
}
|
}
|
||||||
tag.set_active(true);
|
tag.set_active(true, state);
|
||||||
});
|
});
|
||||||
|
|
||||||
state.request_layout(&output);
|
state.request_layout(&output);
|
||||||
|
|
|
@ -3,8 +3,9 @@ use std::collections::VecDeque;
|
||||||
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
||||||
signal_service_server, OutputConnectRequest, OutputConnectResponse, OutputDisconnectRequest,
|
signal_service_server, OutputConnectRequest, OutputConnectResponse, OutputDisconnectRequest,
|
||||||
OutputDisconnectResponse, OutputMoveRequest, OutputMoveResponse, OutputResizeRequest,
|
OutputDisconnectResponse, OutputMoveRequest, OutputMoveResponse, OutputResizeRequest,
|
||||||
OutputResizeResponse, SignalRequest, StreamControl, WindowPointerEnterRequest,
|
OutputResizeResponse, SignalRequest, StreamControl, TagActiveRequest, TagActiveResponse,
|
||||||
WindowPointerEnterResponse, WindowPointerLeaveRequest, WindowPointerLeaveResponse,
|
WindowPointerEnterRequest, WindowPointerEnterResponse, WindowPointerLeaveRequest,
|
||||||
|
WindowPointerLeaveResponse,
|
||||||
};
|
};
|
||||||
use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle};
|
use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle};
|
||||||
use tonic::{Request, Response, Status, Streaming};
|
use tonic::{Request, Response, Status, Streaming};
|
||||||
|
@ -27,6 +28,9 @@ pub struct SignalState {
|
||||||
SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
|
SignalData<WindowPointerEnterResponse, VecDeque<WindowPointerEnterResponse>>,
|
||||||
pub window_pointer_leave:
|
pub window_pointer_leave:
|
||||||
SignalData<WindowPointerLeaveResponse, VecDeque<WindowPointerLeaveResponse>>,
|
SignalData<WindowPointerLeaveResponse, VecDeque<WindowPointerLeaveResponse>>,
|
||||||
|
|
||||||
|
// Tag
|
||||||
|
pub tag_active: SignalData<TagActiveResponse, VecDeque<TagActiveResponse>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignalState {
|
impl SignalState {
|
||||||
|
@ -184,9 +188,12 @@ impl signal_service_server::SignalService for SignalService {
|
||||||
type OutputDisconnectStream = ResponseStream<OutputDisconnectResponse>;
|
type OutputDisconnectStream = ResponseStream<OutputDisconnectResponse>;
|
||||||
type OutputResizeStream = ResponseStream<OutputResizeResponse>;
|
type OutputResizeStream = ResponseStream<OutputResizeResponse>;
|
||||||
type OutputMoveStream = ResponseStream<OutputMoveResponse>;
|
type OutputMoveStream = ResponseStream<OutputMoveResponse>;
|
||||||
|
|
||||||
type WindowPointerEnterStream = ResponseStream<WindowPointerEnterResponse>;
|
type WindowPointerEnterStream = ResponseStream<WindowPointerEnterResponse>;
|
||||||
type WindowPointerLeaveStream = ResponseStream<WindowPointerLeaveResponse>;
|
type WindowPointerLeaveStream = ResponseStream<WindowPointerLeaveResponse>;
|
||||||
|
|
||||||
|
type TagActiveStream = ResponseStream<TagActiveResponse>;
|
||||||
|
|
||||||
async fn output_connect(
|
async fn output_connect(
|
||||||
&self,
|
&self,
|
||||||
request: Request<Streaming<OutputConnectRequest>>,
|
request: Request<Streaming<OutputConnectRequest>>,
|
||||||
|
@ -252,4 +259,15 @@ impl signal_service_server::SignalService for SignalService {
|
||||||
&mut state.signal_state.window_pointer_leave
|
&mut state.signal_state.window_pointer_leave
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn tag_active(
|
||||||
|
&self,
|
||||||
|
request: Request<Streaming<TagActiveRequest>>,
|
||||||
|
) -> Result<Response<Self::TagActiveStream>, Status> {
|
||||||
|
let in_stream = request.into_inner();
|
||||||
|
|
||||||
|
start_signal_stream(self.sender.clone(), in_stream, |state| {
|
||||||
|
&mut state.signal_state.tag_active
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/tag.rs
11
src/tag.rs
|
@ -87,8 +87,17 @@ impl Tag {
|
||||||
self.0.lock().expect("tag already locked").active
|
self.0.lock().expect("tag already locked").active
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active(&self, active: bool) {
|
pub fn set_active(&self, active: bool, state: &mut State) {
|
||||||
self.0.lock().expect("tag already locked").active = active;
|
self.0.lock().expect("tag already locked").active = active;
|
||||||
|
|
||||||
|
state.signal_state.tag_active.signal(|buf| {
|
||||||
|
buf.push_back(
|
||||||
|
pinnacle_api_defs::pinnacle::signal::v0alpha1::TagActiveResponse {
|
||||||
|
tag_id: Some(self.id().0),
|
||||||
|
active: Some(self.active()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue