mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-25 09:59:21 +01:00
api/rust: Add error handling
This commit is contained in:
parent
57dab51536
commit
db3bfd9e5f
15 changed files with 339 additions and 198 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -3087,6 +3087,8 @@ dependencies = [
|
|||
"tokio-stream",
|
||||
"tonic",
|
||||
"tower",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"xkbcommon",
|
||||
]
|
||||
|
||||
|
@ -3860,10 +3862,12 @@ dependencies = [
|
|||
"from_variants",
|
||||
"futures",
|
||||
"snowcap-api-defs",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic",
|
||||
"tower",
|
||||
"tracing",
|
||||
"xdg",
|
||||
"xkbcommon",
|
||||
]
|
||||
|
@ -4087,18 +4091,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
version = "1.0.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
version = "1.0.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -55,7 +55,7 @@ In the future, Snowcap will be used for everything Awesome uses its widget syste
|
|||
# Dependencies
|
||||
You will need:
|
||||
|
||||
- [Rust](https://www.rust-lang.org/) 1.75 or newer
|
||||
- [Rust](https://www.rust-lang.org/) 1.76 or newer
|
||||
- The following external dependencies:
|
||||
- `libwayland`
|
||||
- `libxkbcommon`
|
||||
|
|
|
@ -23,6 +23,8 @@ rand = "0.8.5"
|
|||
bitflags = { workspace = true }
|
||||
snowcap-api = { path = "../../snowcap/api/rust", optional = true }
|
||||
indexmap = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["snowcap"]
|
||||
|
|
|
@ -79,8 +79,10 @@ pub fn config(
|
|||
let options = macro_input.options;
|
||||
|
||||
let mut has_internal_tokio = false;
|
||||
let mut has_internal_tracing = false;
|
||||
|
||||
let mut internal_tokio = true;
|
||||
let mut internal_tracing = true;
|
||||
|
||||
for name_value in options.iter() {
|
||||
if name_value.path.get_ident() == Some(&Ident::new("internal_tokio", Span::call_site())) {
|
||||
|
@ -103,9 +105,26 @@ pub fn config(
|
|||
compile_error!("expected `true` or `false`");
|
||||
}
|
||||
.into();
|
||||
} else if name_value.path.get_ident()
|
||||
== Some(&Ident::new("internal_tracing", Span::call_site()))
|
||||
{
|
||||
if has_internal_tracing {
|
||||
return quote_spanned! {name_value.path.span()=>
|
||||
compile_error!("`internal_tracing` defined twice, remove this one");
|
||||
}
|
||||
.into();
|
||||
}
|
||||
|
||||
has_internal_tracing = true;
|
||||
if let Expr::Lit(lit) = &name_value.value {
|
||||
if let Lit::Bool(bool) = &lit.lit {
|
||||
internal_tracing = bool.value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return quote_spanned! {name_value.path.span()=>
|
||||
compile_error!("expected valid option (currently only `internal_tokio`)");
|
||||
compile_error!("expected valid option (`internal_tokio` or `internal_tracing`)");
|
||||
}
|
||||
.into();
|
||||
}
|
||||
|
@ -117,10 +136,18 @@ pub fn config(
|
|||
}
|
||||
});
|
||||
|
||||
let tracing_fn = internal_tracing.then(|| {
|
||||
quote! {
|
||||
::pinnacle_api::set_default_tracing_subscriber();
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#attrs)*
|
||||
#tokio_attr
|
||||
#vis #sig {
|
||||
#tracing_fn
|
||||
|
||||
::pinnacle_api::connect().await.unwrap();
|
||||
|
||||
#(#stmts)*
|
||||
|
|
|
@ -18,6 +18,7 @@ use pinnacle_api_defs::pinnacle::input::{
|
|||
},
|
||||
};
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::error;
|
||||
use xkbcommon::xkb::Keysym;
|
||||
|
||||
use crate::block_on_tokio;
|
||||
|
@ -169,16 +170,20 @@ impl Input {
|
|||
|
||||
let keybind_info: Option<KeybindInfo> = keybind_info.into();
|
||||
|
||||
let mut stream = block_on_tokio(crate::input().set_keybind(SetKeybindRequest {
|
||||
let mut stream = match block_on_tokio(crate::input().set_keybind(SetKeybindRequest {
|
||||
modifiers,
|
||||
key: Some(input::v0alpha1::set_keybind_request::Key::RawCode(
|
||||
key.into_keysym().raw(),
|
||||
)),
|
||||
group: keybind_info.clone().and_then(|info| info.group),
|
||||
description: keybind_info.clone().and_then(|info| info.description),
|
||||
}))
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
})) {
|
||||
Ok(stream) => stream.into_inner(),
|
||||
Err(err) => {
|
||||
error!("Failed to set keybind: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(Ok(_response)) = stream.next().await {
|
||||
|
@ -218,13 +223,17 @@ impl Input {
|
|||
mut action: impl FnMut() + 'static + Send,
|
||||
) {
|
||||
let modifiers = mods.into_iter().map(|modif| modif as i32).collect();
|
||||
let mut stream = block_on_tokio(crate::input().set_mousebind(SetMousebindRequest {
|
||||
let mut stream = match block_on_tokio(crate::input().set_mousebind(SetMousebindRequest {
|
||||
modifiers,
|
||||
button: Some(button as u32),
|
||||
edge: Some(edge as i32),
|
||||
}))
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
})) {
|
||||
Ok(stream) => stream.into_inner(),
|
||||
Err(err) => {
|
||||
error!("Failed to set keybind: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(Ok(_response)) = stream.next().await {
|
||||
|
@ -236,12 +245,17 @@ impl Input {
|
|||
|
||||
/// Get all keybinds and their information.
|
||||
pub fn keybind_descriptions(&self) -> impl Iterator<Item = KeybindDescription> {
|
||||
let descriptions =
|
||||
block_on_tokio(crate::input().keybind_descriptions(KeybindDescriptionsRequest {}))
|
||||
.unwrap();
|
||||
let descriptions = descriptions.into_inner();
|
||||
let descriptions = match block_on_tokio(
|
||||
crate::input().keybind_descriptions(KeybindDescriptionsRequest {}),
|
||||
) {
|
||||
Ok(descs) => descs.into_inner().descriptions,
|
||||
Err(err) => {
|
||||
error!("Failed to get keybind descriptions: {err}");
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
descriptions.descriptions.into_iter().map(|desc| {
|
||||
descriptions.into_iter().map(|desc| {
|
||||
let mods = desc.modifiers().flat_map(|m| match m {
|
||||
input::v0alpha1::Modifier::Unspecified => None,
|
||||
input::v0alpha1::Modifier::Shift => Some(Mod::Shift),
|
||||
|
@ -277,14 +291,15 @@ impl Input {
|
|||
/// });
|
||||
/// ```
|
||||
pub fn set_xkb_config(&self, xkb_config: XkbConfig) {
|
||||
block_on_tokio(crate::input().set_xkb_config(SetXkbConfigRequest {
|
||||
if let Err(err) = block_on_tokio(crate::input().set_xkb_config(SetXkbConfigRequest {
|
||||
rules: xkb_config.rules.map(String::from),
|
||||
variant: xkb_config.variant.map(String::from),
|
||||
layout: xkb_config.layout.map(String::from),
|
||||
model: xkb_config.model.map(String::from),
|
||||
options: xkb_config.options.map(String::from),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set xkb config: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the keyboard's repeat rate.
|
||||
|
@ -302,11 +317,12 @@ impl Input {
|
|||
/// input.set_repeat_rate(25, 500);
|
||||
/// ```
|
||||
pub fn set_repeat_rate(&self, rate: i32, delay: i32) {
|
||||
block_on_tokio(crate::input().set_repeat_rate(SetRepeatRateRequest {
|
||||
if let Err(err) = block_on_tokio(crate::input().set_repeat_rate(SetRepeatRateRequest {
|
||||
rate: Some(rate),
|
||||
delay: Some(delay),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set repeat rate: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a libinput setting.
|
||||
|
@ -357,12 +373,13 @@ impl Input {
|
|||
LibinputSetting::Tap(enable) => Setting::Tap(enable),
|
||||
};
|
||||
|
||||
block_on_tokio(
|
||||
crate::input().set_libinput_setting(SetLibinputSettingRequest {
|
||||
if let Err(err) = block_on_tokio(crate::input().set_libinput_setting(
|
||||
SetLibinputSettingRequest {
|
||||
setting: Some(setting),
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
},
|
||||
)) {
|
||||
error!("Failed to set libinput setting: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the xcursor theme.
|
||||
|
@ -376,11 +393,12 @@ impl Input {
|
|||
/// input.set_xcursor_theme("Adwaita");
|
||||
/// ```
|
||||
pub fn set_xcursor_theme(&self, theme: impl ToString) {
|
||||
block_on_tokio(crate::input().set_xcursor(SetXcursorRequest {
|
||||
if let Err(err) = block_on_tokio(crate::input().set_xcursor(SetXcursorRequest {
|
||||
theme: Some(theme.to_string()),
|
||||
size: None,
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set xcursor theme: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the xcursor size.
|
||||
|
@ -394,11 +412,12 @@ impl Input {
|
|||
/// input.set_xcursor_size(64);
|
||||
/// ```
|
||||
pub fn set_xcursor_size(&self, size: u32) {
|
||||
block_on_tokio(crate::input().set_xcursor(SetXcursorRequest {
|
||||
if let Err(err) = block_on_tokio(crate::input().set_xcursor(SetXcursorRequest {
|
||||
theme: None,
|
||||
size: Some(size),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set xcursor size: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use pinnacle_api_defs::pinnacle::layout::v0alpha1::{
|
|||
};
|
||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{
|
||||
block_on_tokio, layout,
|
||||
|
@ -73,7 +74,7 @@ impl Layout {
|
|||
output_height: response.output_height.unwrap_or_default(),
|
||||
};
|
||||
let geos = manager.lock().unwrap().active_layout(&args).layout(&args);
|
||||
from_client
|
||||
if from_client
|
||||
.send(LayoutRequest {
|
||||
body: Some(Body::Geometries(Geometries {
|
||||
request_id: response.request_id,
|
||||
|
@ -89,7 +90,10 @@ impl Layout {
|
|||
.collect(),
|
||||
})),
|
||||
})
|
||||
.unwrap();
|
||||
.is_err()
|
||||
{
|
||||
debug!("Failed to send layout geometries: channel closed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -235,22 +239,30 @@ impl<T> LayoutRequester<T> {
|
|||
/// If you want to layout a specific output, see [`LayoutRequester::request_layout_on_output`].
|
||||
pub fn request_layout(&self) {
|
||||
let output_name = Output.get_focused().map(|op| op.name);
|
||||
self.sender
|
||||
if self
|
||||
.sender
|
||||
.send(LayoutRequest {
|
||||
body: Some(Body::Layout(ExplicitLayout { output_name })),
|
||||
})
|
||||
.unwrap();
|
||||
.is_err()
|
||||
{
|
||||
debug!("Failed to request layout: channel closed");
|
||||
}
|
||||
}
|
||||
|
||||
/// Request a layout from the compositor for the given output.
|
||||
pub fn request_layout_on_output(&self, output: &OutputHandle) {
|
||||
self.sender
|
||||
if self
|
||||
.sender
|
||||
.send(LayoutRequest {
|
||||
body: Some(Body::Layout(ExplicitLayout {
|
||||
output_name: Some(output.name.clone()),
|
||||
})),
|
||||
})
|
||||
.unwrap();
|
||||
.is_err()
|
||||
{
|
||||
debug!("Failed to request layout on output: channel closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ use tag::Tag;
|
|||
use tokio::sync::{MappedMutexGuard, Mutex, MutexGuard, RwLock};
|
||||
use tonic::transport::{Channel, Endpoint, Uri};
|
||||
use tower::service_fn;
|
||||
use tracing::info;
|
||||
use window::Window;
|
||||
|
||||
pub mod input;
|
||||
|
@ -260,6 +261,9 @@ pub async fn connect() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let socket_path = std::env::var("PINNACLE_GRPC_SOCKET").unwrap();
|
||||
info!("Connected to {socket_path}");
|
||||
|
||||
PINNACLE
|
||||
.write()
|
||||
.await
|
||||
|
@ -321,6 +325,18 @@ pub async fn listen() {
|
|||
signal_module().shutdown();
|
||||
}
|
||||
|
||||
/// Sets the default `tracing_subscriber` to output logs.
|
||||
///
|
||||
/// This subscriber does not include the time or ansi escape codes.
|
||||
/// If you would like to disable this in [`crate::config`], pass in
|
||||
/// `internal_tracing = false`.
|
||||
pub fn set_default_tracing_subscriber() {
|
||||
tracing_subscriber::fmt()
|
||||
.without_time()
|
||||
.with_ansi(false)
|
||||
.init();
|
||||
}
|
||||
|
||||
/// Block on a future using the current Tokio runtime.
|
||||
pub(crate) fn block_on_tokio<F: Future>(future: F) -> F::Output {
|
||||
tokio::task::block_in_place(|| {
|
||||
|
|
|
@ -19,6 +19,7 @@ use pinnacle_api_defs::pinnacle::output::{
|
|||
SetModelineRequest, SetPoweredRequest, SetScaleRequest, SetTransformRequest,
|
||||
},
|
||||
};
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use crate::{
|
||||
block_on_tokio,
|
||||
|
@ -56,9 +57,9 @@ impl Output {
|
|||
crate::output()
|
||||
.get(output::v0alpha1::GetRequest {})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.output_names
|
||||
.map(|resp| resp.into_inner().output_names)
|
||||
.inspect_err(|err| error!("Failed to get outputs: {err}"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|name| self.new_handle(name))
|
||||
.collect()
|
||||
|
@ -151,7 +152,7 @@ impl Output {
|
|||
/// // Add tags 1-3 to all outputs and set tag "1" to active
|
||||
/// output.connect_for_all(|op| {
|
||||
/// let tags = tag.add(&op, ["1", "2", "3"]);
|
||||
/// tags.next().unwrap().set_active(true);
|
||||
/// tags.first()?.set_active(true);
|
||||
/// });
|
||||
/// ```
|
||||
pub fn connect_for_all(&self, mut for_all: impl FnMut(&OutputHandle) + Send + 'static) {
|
||||
|
@ -200,7 +201,7 @@ impl Output {
|
|||
/// // Give all outputs tags 1 through 5
|
||||
/// OutputSetup::new_with_matcher(|_| true).with_tags(["1", "2", "3", "4", "5"]),
|
||||
/// // Give outputs with a preferred mode of 4K a scale of 2.0
|
||||
/// OutputSetup::new_with_matcher(|op| op.preferred_mode().unwrap().pixel_width == 2160)
|
||||
/// OutputSetup::new_with_matcher(|op| op.preferred_mode()?.pixel_width == 2160)
|
||||
/// .with_scale(2.0),
|
||||
/// // Additionally give eDP-1 tags 6 and 7
|
||||
/// OutputSetup::new(OutputId::name("eDP-1")).with_tags(["6", "7"]),
|
||||
|
@ -289,8 +290,11 @@ impl Output {
|
|||
|
||||
placed_outputs.push(output.clone());
|
||||
let props = output.props();
|
||||
let x = props.x.unwrap();
|
||||
let width = props.logical_width.unwrap() as i32;
|
||||
let x = props.x.expect("output should have x-coord");
|
||||
let width = props
|
||||
.logical_width
|
||||
.expect("output should have logical width")
|
||||
as i32;
|
||||
if rightmost_output_and_x.is_none()
|
||||
|| rightmost_output_and_x
|
||||
.as_ref()
|
||||
|
@ -328,8 +332,10 @@ impl Output {
|
|||
|
||||
placed_outputs.push(output.clone());
|
||||
let props = output.props();
|
||||
let x = props.x.unwrap();
|
||||
let width = props.logical_width.unwrap() as i32;
|
||||
let x = props.x.expect("output should have x-coord");
|
||||
let width = props
|
||||
.logical_width
|
||||
.expect("output should have logical width") as i32;
|
||||
if rightmost_output_and_x.is_none()
|
||||
|| rightmost_output_and_x
|
||||
.as_ref()
|
||||
|
@ -353,8 +359,10 @@ impl Output {
|
|||
|
||||
placed_outputs.push(output.clone());
|
||||
let props = output.props();
|
||||
let x = props.x.unwrap();
|
||||
let width = props.logical_width.unwrap() as i32;
|
||||
let x = props.x.expect("output should have x-coord");
|
||||
let width = props
|
||||
.logical_width
|
||||
.expect("output should have logical width") as i32;
|
||||
if rightmost_output_and_x.is_none()
|
||||
|| rightmost_output_and_x
|
||||
.as_ref()
|
||||
|
@ -590,25 +598,11 @@ bitflags::bitflags! {
|
|||
/// A handle to an output.
|
||||
///
|
||||
/// This allows you to manipulate outputs and get their properties.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct OutputHandle {
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
impl PartialEq for OutputHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.name == other.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for OutputHandle {}
|
||||
|
||||
impl std::hash::Hash for OutputHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// The alignment to use for [`OutputHandle::set_loc_adj_to`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Alignment {
|
||||
|
@ -696,13 +690,15 @@ impl OutputHandle {
|
|||
/// // └─────┴───────┘
|
||||
/// // ^x=1920
|
||||
/// ```
|
||||
#[instrument(skip(x, y))]
|
||||
pub fn set_location(&self, x: impl Into<Option<i32>>, y: impl Into<Option<i32>>) {
|
||||
block_on_tokio(crate::output().set_location(SetLocationRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_location(SetLocationRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
x: x.into(),
|
||||
y: y.into(),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this output adjacent to another one.
|
||||
|
@ -822,19 +818,21 @@ impl OutputHandle {
|
|||
/// ```
|
||||
/// output.get_focused()?.set_mode(2560, 1440, 144000);
|
||||
/// ```
|
||||
#[instrument(skip(refresh_rate_millihertz))]
|
||||
pub fn set_mode(
|
||||
&self,
|
||||
pixel_width: u32,
|
||||
pixel_height: u32,
|
||||
refresh_rate_millihertz: impl Into<Option<u32>>,
|
||||
) {
|
||||
block_on_tokio(crate::output().set_mode(SetModeRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_mode(SetModeRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
pixel_width: Some(pixel_width),
|
||||
pixel_height: Some(pixel_height),
|
||||
refresh_rate_millihz: refresh_rate_millihertz.into(),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a custom modeline for this output.
|
||||
|
@ -849,8 +847,9 @@ impl OutputHandle {
|
|||
/// ```
|
||||
/// output.set_modeline("173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync".parse()?);
|
||||
/// ```
|
||||
#[instrument(skip(modeline))]
|
||||
pub fn set_modeline(&self, modeline: Modeline) {
|
||||
block_on_tokio(crate::output().set_modeline(SetModelineRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_modeline(SetModelineRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
clock: Some(modeline.clock),
|
||||
hdisplay: Some(modeline.hdisplay),
|
||||
|
@ -863,8 +862,9 @@ impl OutputHandle {
|
|||
vtotal: Some(modeline.vtotal),
|
||||
hsync_pos: Some(modeline.hsync),
|
||||
vsync_pos: Some(modeline.vsync),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this output's scaling factor.
|
||||
|
@ -874,12 +874,14 @@ impl OutputHandle {
|
|||
/// ```
|
||||
/// output.get_focused()?.set_scale(1.5);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_scale(&self, scale: f32) {
|
||||
block_on_tokio(crate::output().set_scale(SetScaleRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_scale(SetScaleRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
absolute_or_relative: Some(AbsoluteOrRelative::Absolute(scale)),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Increase this output's scaling factor by `increase_by`.
|
||||
|
@ -889,12 +891,14 @@ impl OutputHandle {
|
|||
/// ```
|
||||
/// output.get_focused()?.increase_scale(0.25);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn increase_scale(&self, increase_by: f32) {
|
||||
block_on_tokio(crate::output().set_scale(SetScaleRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_scale(SetScaleRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
absolute_or_relative: Some(AbsoluteOrRelative::Relative(increase_by)),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrease this output's scaling factor by `decrease_by`.
|
||||
|
@ -920,12 +924,14 @@ impl OutputHandle {
|
|||
/// // Rotate 90 degrees counter-clockwise
|
||||
/// output.set_transform(Transform::_90);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_transform(&self, transform: Transform) {
|
||||
block_on_tokio(crate::output().set_transform(SetTransformRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_transform(SetTransformRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
transform: Some(transform as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Power on or off this output.
|
||||
|
@ -939,12 +945,14 @@ impl OutputHandle {
|
|||
/// // Power off `output`
|
||||
/// output.set_powered(false);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_powered(&self, powered: bool) {
|
||||
block_on_tokio(crate::output().set_powered(SetPoweredRequest {
|
||||
if let Err(err) = block_on_tokio(crate::output().set_powered(SetPoweredRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
powered: Some(powered),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all properties of this output.
|
||||
|
@ -963,14 +971,20 @@ impl OutputHandle {
|
|||
}
|
||||
|
||||
/// The async version of [`OutputHandle::props`].
|
||||
#[instrument]
|
||||
pub async fn props_async(&self) -> OutputProperties {
|
||||
let response = crate::output()
|
||||
let response = match crate::output()
|
||||
.get_properties(output::v0alpha1::GetPropertiesRequest {
|
||||
output_name: Some(self.name.clone()),
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
{
|
||||
Ok(resp) => resp.into_inner(),
|
||||
Err(err) => {
|
||||
error!("{err}");
|
||||
return OutputProperties::default();
|
||||
}
|
||||
};
|
||||
|
||||
OutputProperties {
|
||||
make: response.make,
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
|
||||
use std::time::Duration;
|
||||
|
||||
use pinnacle_api_defs::pinnacle::v0alpha1::{
|
||||
use pinnacle_api_defs::pinnacle::{
|
||||
v0alpha1::{
|
||||
PingRequest, QuitRequest, ReloadConfigRequest, ShutdownWatchRequest, ShutdownWatchResponse,
|
||||
},
|
||||
window::v0alpha1::SetFocusedRequest,
|
||||
};
|
||||
use rand::RngCore;
|
||||
use tonic::{Request, Streaming};
|
||||
use tracing::error;
|
||||
|
||||
use crate::{block_on_tokio, pinnacle};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
use pinnacle_api_defs::pinnacle::process::v0alpha1::{SetEnvRequest, SpawnRequest};
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::error;
|
||||
|
||||
use crate::{block_on_tokio, process};
|
||||
|
||||
|
@ -110,9 +111,13 @@ impl Process {
|
|||
has_callback: Some(callbacks.is_some()),
|
||||
};
|
||||
|
||||
let mut stream = block_on_tokio(process().spawn(request))
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let mut stream = match block_on_tokio(process().spawn(request)) {
|
||||
Ok(stream) => stream.into_inner(),
|
||||
Err(err) => {
|
||||
error!("Failed to spawn process: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(mut callbacks) = callbacks else { return };
|
||||
|
@ -149,10 +154,11 @@ impl Process {
|
|||
let key = key.into();
|
||||
let value = value.into();
|
||||
|
||||
block_on_tokio(process().set_env(SetEnvRequest {
|
||||
if let Err(err) = block_on_tokio(process().set_env(SetEnvRequest {
|
||||
key: Some(key),
|
||||
value: Some(value),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set env: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use pinnacle_api_defs::pinnacle::render::v0alpha1::{
|
||||
SetDownscaleFilterRequest, SetUpscaleFilterRequest,
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
use crate::{block_on_tokio, render};
|
||||
|
||||
|
@ -33,10 +34,11 @@ impl Render {
|
|||
/// render.set_upscale_filter(ScalingFilter::NearestNeighbor);
|
||||
/// ```
|
||||
pub fn set_upscale_filter(&self, filter: ScalingFilter) {
|
||||
block_on_tokio(render().set_upscale_filter(SetUpscaleFilterRequest {
|
||||
if let Err(err) = block_on_tokio(render().set_upscale_filter(SetUpscaleFilterRequest {
|
||||
filter: Some(filter as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set upscale filter: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the downscaling filter that will be used for rendering.
|
||||
|
@ -49,9 +51,10 @@ impl Render {
|
|||
/// render.set_downscale_filter(ScalingFilter::NearestNeighbor);
|
||||
/// ```
|
||||
pub fn set_downscale_filter(&self, filter: ScalingFilter) {
|
||||
block_on_tokio(render().set_downscale_filter(SetDownscaleFilterRequest {
|
||||
if let Err(err) = block_on_tokio(render().set_downscale_filter(SetDownscaleFilterRequest {
|
||||
filter: Some(filter as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to set downscale filter: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ impl QuitPrompt {
|
|||
ExclusiveZone::Respect,
|
||||
ZLayer::Overlay,
|
||||
)
|
||||
.unwrap()
|
||||
.on_key_press(|handle, key, _mods| {
|
||||
if key == Keysym::Return {
|
||||
Pinnacle.quit();
|
||||
|
@ -291,6 +292,7 @@ impl KeybindOverlay {
|
|||
ExclusiveZone::Respect,
|
||||
ZLayer::Top,
|
||||
)
|
||||
.unwrap()
|
||||
.on_key_press(|handle, _key, _mods| {
|
||||
handle.close();
|
||||
});
|
||||
|
|
|
@ -37,6 +37,7 @@ use pinnacle_api_defs::pinnacle::{
|
|||
},
|
||||
v0alpha1::SetOrToggle,
|
||||
};
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use crate::{
|
||||
block_on_tokio,
|
||||
|
@ -85,17 +86,17 @@ impl Tag {
|
|||
) -> Vec<TagHandle> {
|
||||
let tag_names = tag_names.into_iter().map(Into::into).collect();
|
||||
|
||||
let response = crate::tag()
|
||||
let tag_ids = crate::tag()
|
||||
.add(AddRequest {
|
||||
output_name: Some(output.name.clone()),
|
||||
tag_names,
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
.map(|resp| resp.into_inner().tag_ids)
|
||||
.inspect_err(|err| error!("Failed to add tags: {err}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
response
|
||||
.tag_ids
|
||||
tag_ids
|
||||
.into_iter()
|
||||
.map(move |id| self.new_handle(id))
|
||||
.collect()
|
||||
|
@ -114,14 +115,14 @@ impl Tag {
|
|||
|
||||
/// The async version of [`Tag::get_all`].
|
||||
pub async fn get_all_async(&self) -> Vec<TagHandle> {
|
||||
let response = crate::tag()
|
||||
let tag_ids = crate::tag()
|
||||
.get(tag::v0alpha1::GetRequest {})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
.map(|resp| resp.into_inner().tag_ids)
|
||||
.inspect_err(|err| error!("Failed to get tags: {err}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
response
|
||||
.tag_ids
|
||||
tag_ids
|
||||
.into_iter()
|
||||
.map(move |id| self.new_handle(id))
|
||||
.collect()
|
||||
|
@ -202,7 +203,9 @@ impl Tag {
|
|||
pub fn remove(&self, tags: impl IntoIterator<Item = TagHandle>) {
|
||||
let tag_ids = tags.into_iter().map(|handle| handle.id).collect::<Vec<_>>();
|
||||
|
||||
block_on_tokio(crate::tag().remove(RemoveRequest { tag_ids })).unwrap();
|
||||
if let Err(err) = block_on_tokio(crate::tag().remove(RemoveRequest { tag_ids })) {
|
||||
error!("Failed to remove tags: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to a tag signal.
|
||||
|
@ -256,11 +259,13 @@ impl TagHandle {
|
|||
/// tag.get("2")?.switch_to(); // Displays Firefox and Discord
|
||||
/// tag.get("3")?.switch_to(); // Displays Steam
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn switch_to(&self) {
|
||||
block_on_tokio(crate::tag().switch_to(SwitchToRequest {
|
||||
if let Err(err) = block_on_tokio(crate::tag().switch_to(SwitchToRequest {
|
||||
tag_id: Some(self.id),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this tag to active or not.
|
||||
|
@ -281,15 +286,17 @@ impl TagHandle {
|
|||
/// tag.get("3")?.set_active(true); // Displays Firefox, Discord, and Steam
|
||||
/// tag.get("2")?.set_active(false); // Displays Steam
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_active(&self, set: bool) {
|
||||
block_on_tokio(crate::tag().set_active(SetActiveRequest {
|
||||
if let Err(err) = block_on_tokio(crate::tag().set_active(SetActiveRequest {
|
||||
tag_id: Some(self.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle this tag between active and inactive.
|
||||
|
@ -311,12 +318,14 @@ impl TagHandle {
|
|||
/// tag.get("3")?.toggle(); // Displays Firefox, Discord
|
||||
/// tag.get("2")?.toggle(); // Displays nothing
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_active(&self) {
|
||||
block_on_tokio(crate::tag().set_active(SetActiveRequest {
|
||||
if let Err(err) = block_on_tokio(crate::tag().set_active(SetActiveRequest {
|
||||
tag_id: Some(self.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove this tag from its output.
|
||||
|
@ -332,11 +341,13 @@ impl TagHandle {
|
|||
/// tags[3].remove();
|
||||
/// // "DP-1" now only has tags "1" and "Buckle"
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn remove(&self) {
|
||||
block_on_tokio(crate::tag().remove(RemoveRequest {
|
||||
if let Err(err) = block_on_tokio(crate::tag().remove(RemoveRequest {
|
||||
tag_ids: vec![self.id],
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all properties of this tag.
|
||||
|
@ -357,14 +368,20 @@ impl TagHandle {
|
|||
}
|
||||
|
||||
/// The async version of [`TagHandle::props`].
|
||||
#[instrument]
|
||||
pub async fn props_async(&self) -> TagProperties {
|
||||
let response = crate::tag()
|
||||
let response = match crate::tag()
|
||||
.get_properties(tag::v0alpha1::GetPropertiesRequest {
|
||||
tag_id: Some(self.id),
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
{
|
||||
Ok(resp) => resp.into_inner(),
|
||||
Err(err) => {
|
||||
error!("{err}");
|
||||
return TagProperties::default();
|
||||
}
|
||||
};
|
||||
|
||||
TagProperties {
|
||||
active: response.active,
|
||||
|
|
|
@ -25,6 +25,7 @@ use pinnacle_api_defs::pinnacle::{
|
|||
},
|
||||
},
|
||||
};
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use crate::{
|
||||
block_on_tokio,
|
||||
|
@ -68,10 +69,10 @@ impl Window {
|
|||
/// });
|
||||
/// ```
|
||||
pub fn begin_move(&self, button: MouseButton) {
|
||||
if let Err(status) = block_on_tokio(crate::window().move_grab(MoveGrabRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().move_grab(MoveGrabRequest {
|
||||
button: Some(button as u32),
|
||||
})) {
|
||||
eprintln!("ERROR: {status}");
|
||||
error!("Failed to begin window move: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,10 +94,11 @@ impl Window {
|
|||
/// });
|
||||
/// ```
|
||||
pub fn begin_resize(&self, button: MouseButton) {
|
||||
block_on_tokio(crate::window().resize_grab(ResizeGrabRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().resize_grab(ResizeGrabRequest {
|
||||
button: Some(button as u32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to begin window resize: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all windows.
|
||||
|
@ -115,9 +117,9 @@ impl Window {
|
|||
crate::window()
|
||||
.get(GetRequest {})
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.window_ids
|
||||
.map(|resp| resp.into_inner().window_ids)
|
||||
.inspect_err(|err| error!("Failed to get windows: {err}"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(move |id| self.new_handle(id))
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -149,11 +151,12 @@ impl Window {
|
|||
///
|
||||
/// See the [`rules`] module for more information.
|
||||
pub fn add_window_rule(&self, cond: WindowRuleCondition, rule: WindowRule) {
|
||||
block_on_tokio(crate::window().add_window_rule(AddWindowRuleRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().add_window_rule(AddWindowRuleRequest {
|
||||
cond: Some(cond.0),
|
||||
rule: Some(rule.0),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("Failed to add window rule: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to a window signal.
|
||||
|
@ -174,25 +177,11 @@ impl Window {
|
|||
/// A handle to a window.
|
||||
///
|
||||
/// This allows you to manipulate the window and get its properties.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct WindowHandle {
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl PartialEq for WindowHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WindowHandle {}
|
||||
|
||||
impl std::hash::Hash for WindowHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a window is fullscreen, maximized, or neither.
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, TryFromPrimitive)]
|
||||
|
@ -256,11 +245,13 @@ impl WindowHandle {
|
|||
/// // Close the focused window
|
||||
/// window.get_focused()?.close()
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn close(&self) {
|
||||
block_on_tokio(crate::window().close(CloseRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().close(CloseRequest {
|
||||
window_id: Some(self.id),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this window to fullscreen or not.
|
||||
|
@ -273,15 +264,17 @@ impl WindowHandle {
|
|||
/// // Set the focused window to fullscreen.
|
||||
/// window.get_focused()?.set_fullscreen(true);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_fullscreen(&self, set: bool) {
|
||||
block_on_tokio(crate::window().set_fullscreen(SetFullscreenRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_fullscreen(SetFullscreenRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle this window between fullscreen and not.
|
||||
|
@ -294,12 +287,14 @@ impl WindowHandle {
|
|||
/// // Toggle the focused window to and from fullscreen.
|
||||
/// window.get_focused()?.toggle_fullscreen();
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_fullscreen(&self) {
|
||||
block_on_tokio(crate::window().set_fullscreen(SetFullscreenRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_fullscreen(SetFullscreenRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this window to maximized or not.
|
||||
|
@ -312,15 +307,17 @@ impl WindowHandle {
|
|||
/// // Set the focused window to maximized.
|
||||
/// window.get_focused()?.set_maximized(true);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_maximized(&self, set: bool) {
|
||||
block_on_tokio(crate::window().set_maximized(SetMaximizedRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_maximized(SetMaximizedRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle this window between maximized and not.
|
||||
|
@ -333,12 +330,14 @@ impl WindowHandle {
|
|||
/// // Toggle the focused window to and from maximized.
|
||||
/// window.get_focused()?.toggle_maximized();
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_maximized(&self) {
|
||||
block_on_tokio(crate::window().set_maximized(SetMaximizedRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_maximized(SetMaximizedRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set this window to floating or not.
|
||||
|
@ -354,15 +353,17 @@ impl WindowHandle {
|
|||
/// // Set the focused window to floating.
|
||||
/// window.get_focused()?.set_floating(true);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_floating(&self, set: bool) {
|
||||
block_on_tokio(crate::window().set_floating(SetFloatingRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_floating(SetFloatingRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle this window to and from floating.
|
||||
|
@ -378,12 +379,14 @@ impl WindowHandle {
|
|||
/// // Toggle the focused window to and from floating.
|
||||
/// window.get_focused()?.toggle_floating();
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_floating(&self) {
|
||||
block_on_tokio(crate::window().set_floating(SetFloatingRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_floating(SetFloatingRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Focus or unfocus this window.
|
||||
|
@ -394,15 +397,17 @@ impl WindowHandle {
|
|||
/// // Unfocus the focused window
|
||||
/// window.get_focused()?.set_focused(false);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_focused(&self, set: bool) {
|
||||
block_on_tokio(crate::window().set_focused(SetFocusedRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_focused(SetFocusedRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle this window to and from focused.
|
||||
|
@ -415,12 +420,14 @@ impl WindowHandle {
|
|||
/// // be a focused window.
|
||||
/// window.get_focused()?.toggle_focused();
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_focused(&self) {
|
||||
block_on_tokio(crate::window().set_focused(SetFocusedRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_focused(SetFocusedRequest {
|
||||
window_id: Some(self.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Move this window to the given `tag`.
|
||||
|
@ -434,12 +441,14 @@ impl WindowHandle {
|
|||
/// // Move the focused window to tag "Code" on the focused output
|
||||
/// window.get_focused()?.move_to_tag(&tag.get("Code", None)?);
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn move_to_tag(&self, tag: &TagHandle) {
|
||||
block_on_tokio(crate::window().move_to_tag(MoveToTagRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().move_to_tag(MoveToTagRequest {
|
||||
window_id: Some(self.id),
|
||||
tag_id: Some(tag.id),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Set or unset a tag on this window.
|
||||
|
@ -453,16 +462,18 @@ impl WindowHandle {
|
|||
/// focused.set_tag(&tg, true); // `focused` now has tag "Potato"
|
||||
/// focused.set_tag(&tg, false); // `focused` no longer has tag "Potato"
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn set_tag(&self, tag: &TagHandle, set: bool) {
|
||||
block_on_tokio(crate::window().set_tag(SetTagRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_tag(SetTagRequest {
|
||||
window_id: Some(self.id),
|
||||
tag_id: Some(tag.id),
|
||||
set_or_toggle: Some(match set {
|
||||
true => SetOrToggle::Set,
|
||||
false => SetOrToggle::Unset,
|
||||
} as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggle a tag on this window.
|
||||
|
@ -478,13 +489,15 @@ impl WindowHandle {
|
|||
/// focused.toggle_tag(&tg); // `focused` now has tag "Potato"
|
||||
/// focused.toggle_tag(&tg); // `focused` no longer has tag "Potato"
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn toggle_tag(&self, tag: &TagHandle) {
|
||||
block_on_tokio(crate::window().set_tag(SetTagRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().set_tag(SetTagRequest {
|
||||
window_id: Some(self.id),
|
||||
tag_id: Some(tag.id),
|
||||
set_or_toggle: Some(SetOrToggle::Toggle as i32),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Raise this window.
|
||||
|
@ -496,11 +509,13 @@ impl WindowHandle {
|
|||
/// ```
|
||||
/// window.get_focused()?.raise();
|
||||
/// ```
|
||||
#[instrument]
|
||||
pub fn raise(&self) {
|
||||
block_on_tokio(crate::window().raise(RaiseRequest {
|
||||
if let Err(err) = block_on_tokio(crate::window().raise(RaiseRequest {
|
||||
window_id: Some(self.id),
|
||||
}))
|
||||
.unwrap();
|
||||
})) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all properties of this window.
|
||||
|
|
2
snowcap
2
snowcap
|
@ -1 +1 @@
|
|||
Subproject commit 35747e3f798c0f604ef401f2b8fdc7e74b1f3d20
|
||||
Subproject commit 7baca8e4299780723f21ea696b19f8998207dc1f
|
Loading…
Reference in a new issue