mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-08-16 22:31:03 +02:00
build: fix compilation for many feature combinations (#932)
* Fix compilation for many feature combinations * fix: keep Mpris as the default music player type * fix: update futures-lite comment * fix: remove redundant "clap" feature dependency from "cli" * fix: don't make IPC a dependency of sysinfo module * refactor: move serde_json feature to "shared" section * refactor: avoid cfgs inside listen_workspace_events by splitting list_keyboards_events out of it, which manages its own connection to the Hyprland IPC socket. * refactor: sort multiline cfg any's * Revert "refactor: avoid cfgs inside listen_workspace_events" This reverts commit 1b4202ed80c9483c609ada8c4436e0fec26a9eef. * refactor: split listen_workspace_events in more functions * style: fix broken identation Not sure why rustfmt didn't catch this.
This commit is contained in:
parent
5744929931
commit
cff6b1fc83
11 changed files with 363 additions and 265 deletions
18
Cargo.toml
18
Cargo.toml
|
@ -30,11 +30,11 @@ default = [
|
||||||
"tray",
|
"tray",
|
||||||
"upower",
|
"upower",
|
||||||
"volume",
|
"volume",
|
||||||
"workspaces+all"
|
"workspaces+all",
|
||||||
]
|
]
|
||||||
|
|
||||||
cli = ["dep:clap", "ipc"]
|
cli = ["ipc"]
|
||||||
ipc = ["dep:serde_json"]
|
ipc = ["dep:serde_json", "dep:clap"]
|
||||||
|
|
||||||
http = ["dep:reqwest"]
|
http = ["dep:reqwest"]
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ custom = []
|
||||||
|
|
||||||
focused = []
|
focused = []
|
||||||
|
|
||||||
keyboard = ["dep:colpetto", "dep:evdev-rs", "dep:rustix"]
|
keyboard = ["dep:colpetto", "dep:evdev-rs", "dep:rustix", "futures-lite"]
|
||||||
"keyboard+all" = ["keyboard", "keyboard+sway", "keyboard+hyprland"]
|
"keyboard+all" = ["keyboard", "keyboard+sway", "keyboard+hyprland"]
|
||||||
"keyboard+sway" = ["keyboard", "sway"]
|
"keyboard+sway" = ["keyboard", "sway"]
|
||||||
"keyboard+hyprland" = ["keyboard", "hyprland"]
|
"keyboard+hyprland" = ["keyboard", "hyprland"]
|
||||||
|
@ -93,10 +93,12 @@ workspaces = ["futures-lite"]
|
||||||
"workspaces+all" = ["workspaces", "workspaces+sway", "workspaces+hyprland", "workspaces+niri"]
|
"workspaces+all" = ["workspaces", "workspaces+sway", "workspaces+hyprland", "workspaces+niri"]
|
||||||
"workspaces+sway" = ["workspaces", "sway"]
|
"workspaces+sway" = ["workspaces", "sway"]
|
||||||
"workspaces+hyprland" = ["workspaces", "hyprland"]
|
"workspaces+hyprland" = ["workspaces", "hyprland"]
|
||||||
"workspaces+niri" = ["workspaces"]
|
"workspaces+niri" = ["workspaces", "niri"]
|
||||||
|
|
||||||
sway = ["swayipc-async", "futures-lite"]
|
sway = ["swayipc-async", "futures-lite"]
|
||||||
|
|
||||||
|
niri = ["dep:serde_json"]
|
||||||
|
|
||||||
schema = ["dep:schemars"]
|
schema = ["dep:schemars"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -136,9 +138,6 @@ cfg-if = "1.0.0"
|
||||||
# cli
|
# cli
|
||||||
clap = { version = "4.5.36", optional = true, features = ["derive"] }
|
clap = { version = "4.5.36", optional = true, features = ["derive"] }
|
||||||
|
|
||||||
# ipc
|
|
||||||
serde_json = { version = "1.0.140", optional = true }
|
|
||||||
|
|
||||||
# http
|
# http
|
||||||
reqwest = { version = "0.12.15", default-features = false, features = ["default-tls", "http2"], optional = true }
|
reqwest = { version = "0.12.15", default-features = false, features = ["default-tls", "http2"], optional = true }
|
||||||
|
|
||||||
|
@ -174,11 +173,12 @@ system-tray = { version = "0.7.0", features = ["dbusmenu-gtk3"], optional = true
|
||||||
libpulse-binding = { version = "2.29.0", optional = true }
|
libpulse-binding = { version = "2.29.0", optional = true }
|
||||||
|
|
||||||
# shared
|
# shared
|
||||||
futures-lite = { version = "2.6.0", optional = true } # network_manager, upower, workspaces
|
futures-lite = { version = "2.6.0", optional = true } # network_manager, upower, workspaces, keyboard
|
||||||
zbus = { version = "5.5.0", default-features = false, features = ["tokio"], optional = true } # network_manager, notifications, upower
|
zbus = { version = "5.5.0", default-features = false, features = ["tokio"], optional = true } # network_manager, notifications, upower
|
||||||
swayipc-async = { version = "2.0.4", optional = true } # workspaces, keyboard
|
swayipc-async = { version = "2.0.4", optional = true } # workspaces, keyboard
|
||||||
hyprland = { version = "0.4.0-alpha.3", features = ["silent"], optional = true } # workspaces, keyboard
|
hyprland = { version = "0.4.0-alpha.3", features = ["silent"], optional = true } # workspaces, keyboard
|
||||||
rustix = { version = "1.0.5", default-features = false, features = ["std", "fs", "pipe", "event"], optional = true } # clipboard, input
|
rustix = { version = "1.0.5", default-features = false, features = ["std", "fs", "pipe", "event"], optional = true } # clipboard, input
|
||||||
|
serde_json = { version = "1.0.140", optional = true } # ipc, niri
|
||||||
|
|
||||||
# schema
|
# schema
|
||||||
schemars = { version = "0.8.22", optional = true }
|
schemars = { version = "0.8.22", optional = true }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{KeyboardLayoutClient, KeyboardLayoutUpdate, Visibility, Workspace, WorkspaceUpdate};
|
use super::{Visibility, Workspace, WorkspaceUpdate};
|
||||||
use crate::{arc_mut, lock, send, spawn_blocking};
|
use crate::{arc_mut, lock, send, spawn_blocking};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use hyprland::ctl::switch_xkb_layout;
|
use hyprland::ctl::switch_xkb_layout;
|
||||||
|
@ -11,35 +11,53 @@ use tokio::sync::broadcast::{Receiver, Sender, channel};
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Client {
|
struct TxRx<T> {
|
||||||
workspace_tx: Sender<WorkspaceUpdate>,
|
tx: Sender<T>,
|
||||||
_workspace_rx: Receiver<WorkspaceUpdate>,
|
_rx: Receiver<T>,
|
||||||
|
}
|
||||||
|
|
||||||
keyboard_layout_tx: Sender<KeyboardLayoutUpdate>,
|
#[derive(Debug)]
|
||||||
_keyboard_layout_rx: Receiver<KeyboardLayoutUpdate>,
|
pub struct Client {
|
||||||
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
|
workspace: TxRx<WorkspaceUpdate>,
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
|
keyboard_layout: TxRx<KeyboardLayoutUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
let (workspace_tx, workspace_rx) = channel(16);
|
let (workspace_tx, workspace_rx) = channel(16);
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
let (keyboard_layout_tx, keyboard_layout_rx) = channel(16);
|
let (keyboard_layout_tx, keyboard_layout_rx) = channel(16);
|
||||||
|
|
||||||
let instance = Self {
|
let instance = Self {
|
||||||
workspace_tx,
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
_workspace_rx: workspace_rx,
|
workspace: TxRx {
|
||||||
keyboard_layout_tx,
|
tx: workspace_tx,
|
||||||
_keyboard_layout_rx: keyboard_layout_rx,
|
_rx: workspace_rx,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
|
keyboard_layout: TxRx {
|
||||||
|
tx: keyboard_layout_tx,
|
||||||
|
_rx: keyboard_layout_rx,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
instance.listen_workspace_events();
|
instance.listen_events();
|
||||||
instance
|
instance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listen_workspace_events(&self) {
|
fn listen_events(&self) {
|
||||||
info!("Starting Hyprland event listener");
|
info!("Starting Hyprland event listener");
|
||||||
|
|
||||||
let tx = self.workspace_tx.clone();
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
let keyboard_layout_tx = self.keyboard_layout_tx.clone();
|
let tx = self.workspace.tx.clone();
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
|
let keyboard_layout_tx = self.keyboard_layout.tx.clone();
|
||||||
|
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let mut event_listener = EventListener::new();
|
let mut event_listener = EventListener::new();
|
||||||
|
@ -48,223 +66,11 @@ impl Client {
|
||||||
let lock = arc_mut!(());
|
let lock = arc_mut!(());
|
||||||
|
|
||||||
// cache the active workspace since Hyprland doesn't give us the prev active
|
// cache the active workspace since Hyprland doesn't give us the prev active
|
||||||
let active = Self::get_active_workspace().expect("Failed to get active workspace");
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
let active = arc_mut!(Some(active));
|
Self::listen_workspace_events(tx, &mut event_listener, &lock);
|
||||||
|
|
||||||
{
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
let tx = tx.clone();
|
Self::listen_keyboard_events(keyboard_layout_tx, &mut event_listener, lock);
|
||||||
let lock = lock.clone();
|
|
||||||
let active = active.clone();
|
|
||||||
|
|
||||||
event_listener.add_workspace_added_handler(move |workspace_type| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
debug!("Added workspace: {workspace_type:?}");
|
|
||||||
|
|
||||||
let workspace_name = get_workspace_name(workspace_type);
|
|
||||||
let prev_workspace = lock!(active);
|
|
||||||
|
|
||||||
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
|
||||||
|
|
||||||
if let Some(workspace) = workspace {
|
|
||||||
send!(tx, WorkspaceUpdate::Add(workspace));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
let active = active.clone();
|
|
||||||
|
|
||||||
event_listener.add_workspace_change_handler(move |workspace_type| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
|
|
||||||
let mut prev_workspace = lock!(active);
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"Received workspace change: {:?} -> {workspace_type:?}",
|
|
||||||
prev_workspace.as_ref().map(|w| &w.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
let workspace_name = get_workspace_name(workspace_type);
|
|
||||||
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
|
||||||
|
|
||||||
workspace.map_or_else(
|
|
||||||
|| {
|
|
||||||
error!("Unable to locate workspace");
|
|
||||||
},
|
|
||||||
|workspace| {
|
|
||||||
// there may be another type of update so dispatch that regardless of focus change
|
|
||||||
if !workspace.visibility.is_focused() {
|
|
||||||
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
let active = active.clone();
|
|
||||||
|
|
||||||
event_listener.add_active_monitor_change_handler(move |event_data| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
let workspace_type = event_data.workspace;
|
|
||||||
|
|
||||||
let mut prev_workspace = lock!(active);
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"Received active monitor change: {:?} -> {workspace_type:?}",
|
|
||||||
prev_workspace.as_ref().map(|w| &w.name)
|
|
||||||
);
|
|
||||||
|
|
||||||
let workspace_name = get_workspace_name(workspace_type);
|
|
||||||
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
|
||||||
|
|
||||||
if let Some((false, workspace)) =
|
|
||||||
workspace.map(|w| (w.visibility.is_focused(), w))
|
|
||||||
{
|
|
||||||
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
|
||||||
} else {
|
|
||||||
error!("unable to locate workspace: {workspace_name}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
|
|
||||||
event_listener.add_workspace_moved_handler(move |event_data| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
let workspace_type = event_data.workspace;
|
|
||||||
debug!("Received workspace move: {workspace_type:?}");
|
|
||||||
|
|
||||||
let mut prev_workspace = lock!(active);
|
|
||||||
|
|
||||||
let workspace_name = get_workspace_name(workspace_type);
|
|
||||||
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
|
||||||
|
|
||||||
if let Some(workspace) = workspace {
|
|
||||||
send!(tx, WorkspaceUpdate::Move(workspace.clone()));
|
|
||||||
|
|
||||||
if !workspace.visibility.is_focused() {
|
|
||||||
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
|
|
||||||
event_listener.add_workspace_rename_handler(move |data| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
debug!("Received workspace rename: {data:?}");
|
|
||||||
|
|
||||||
send!(
|
|
||||||
tx,
|
|
||||||
WorkspaceUpdate::Rename {
|
|
||||||
id: data.workspace_id as i64,
|
|
||||||
name: data.workspace_name
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
|
|
||||||
event_listener.add_workspace_destroy_handler(move |data| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
debug!("Received workspace destroy: {data:?}");
|
|
||||||
send!(tx, WorkspaceUpdate::Remove(data.workspace_id as i64));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
|
|
||||||
event_listener.add_urgent_state_handler(move |address| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
debug!("Received urgent state: {address:?}");
|
|
||||||
|
|
||||||
let clients = match hyprland::data::Clients::get() {
|
|
||||||
Ok(clients) => clients,
|
|
||||||
Err(err) => {
|
|
||||||
error!("Failed to get clients: {err}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
clients.iter().find(|c| c.address == address).map_or_else(
|
|
||||||
|| {
|
|
||||||
error!("Unable to locate client");
|
|
||||||
},
|
|
||||||
|c| {
|
|
||||||
send!(
|
|
||||||
tx,
|
|
||||||
WorkspaceUpdate::Urgent {
|
|
||||||
id: c.workspace.id as i64,
|
|
||||||
urgent: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let tx = keyboard_layout_tx.clone();
|
|
||||||
let lock = lock.clone();
|
|
||||||
|
|
||||||
event_listener.add_keyboard_layout_change_handler(move |layout_event| {
|
|
||||||
let _lock = lock!(lock);
|
|
||||||
|
|
||||||
let layout = if layout_event.layout_name.is_empty() {
|
|
||||||
// FIXME: This field is empty due to bug in `hyprland-rs_0.4.0-alpha.3`. Which is already fixed in last betas
|
|
||||||
|
|
||||||
// The layout may be empty due to a bug in `hyprland-rs`, because of which the `layout_event` is incorrect.
|
|
||||||
//
|
|
||||||
// Instead of:
|
|
||||||
// ```
|
|
||||||
// LayoutEvent {
|
|
||||||
// keyboard_name: "keychron-keychron-c2",
|
|
||||||
// layout_name: "English (US)",
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// We get:
|
|
||||||
// ```
|
|
||||||
// LayoutEvent {
|
|
||||||
// keyboard_name: "keychron-keychron-c2,English (US)",
|
|
||||||
// layout_name: "",
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// Here we are trying to recover `layout_name` from `keyboard_name`
|
|
||||||
|
|
||||||
let layout = layout_event.keyboard_name.as_str().split(',').nth(1);
|
|
||||||
let Some(layout) = layout else {
|
|
||||||
error!(
|
|
||||||
"Failed to get layout from string: {}. The failed logic is a workaround for a bug in `hyprland 0.4.0-alpha.3`", layout_event.keyboard_name);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout.into()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
layout_event.layout_name
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Received layout: {layout:?}");
|
|
||||||
|
|
||||||
send!(tx, KeyboardLayoutUpdate(layout));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
event_listener
|
event_listener
|
||||||
.start_listener()
|
.start_listener()
|
||||||
|
@ -272,8 +78,238 @@ impl Client {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
|
fn listen_workspace_events(
|
||||||
|
tx: Sender<WorkspaceUpdate>,
|
||||||
|
event_listener: &mut EventListener,
|
||||||
|
lock: &std::sync::Arc<std::sync::Mutex<()>>,
|
||||||
|
) {
|
||||||
|
let active = Self::get_active_workspace().expect("Failed to get active workspace");
|
||||||
|
let active = arc_mut!(Some(active));
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
let active = active.clone();
|
||||||
|
|
||||||
|
event_listener.add_workspace_added_handler(move |workspace_type| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
debug!("Added workspace: {workspace_type:?}");
|
||||||
|
|
||||||
|
let workspace_name = get_workspace_name(workspace_type);
|
||||||
|
let prev_workspace = lock!(active);
|
||||||
|
|
||||||
|
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
||||||
|
|
||||||
|
if let Some(workspace) = workspace {
|
||||||
|
send!(tx, WorkspaceUpdate::Add(workspace));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
let active = active.clone();
|
||||||
|
|
||||||
|
event_listener.add_workspace_change_handler(move |workspace_type| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
|
||||||
|
let mut prev_workspace = lock!(active);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Received workspace change: {:?} -> {workspace_type:?}",
|
||||||
|
prev_workspace.as_ref().map(|w| &w.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
let workspace_name = get_workspace_name(workspace_type);
|
||||||
|
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
||||||
|
|
||||||
|
workspace.map_or_else(
|
||||||
|
|| {
|
||||||
|
error!("Unable to locate workspace");
|
||||||
|
},
|
||||||
|
|workspace| {
|
||||||
|
// there may be another type of update so dispatch that regardless of focus change
|
||||||
|
if !workspace.visibility.is_focused() {
|
||||||
|
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
let active = active.clone();
|
||||||
|
|
||||||
|
event_listener.add_active_monitor_change_handler(move |event_data| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
let workspace_type = event_data.workspace;
|
||||||
|
|
||||||
|
let mut prev_workspace = lock!(active);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Received active monitor change: {:?} -> {workspace_type:?}",
|
||||||
|
prev_workspace.as_ref().map(|w| &w.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
let workspace_name = get_workspace_name(workspace_type);
|
||||||
|
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
||||||
|
|
||||||
|
if let Some((false, workspace)) = workspace.map(|w| (w.visibility.is_focused(), w))
|
||||||
|
{
|
||||||
|
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
||||||
|
} else {
|
||||||
|
error!("unable to locate workspace: {workspace_name}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
|
||||||
|
event_listener.add_workspace_moved_handler(move |event_data| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
let workspace_type = event_data.workspace;
|
||||||
|
debug!("Received workspace move: {workspace_type:?}");
|
||||||
|
|
||||||
|
let mut prev_workspace = lock!(active);
|
||||||
|
|
||||||
|
let workspace_name = get_workspace_name(workspace_type);
|
||||||
|
let workspace = Self::get_workspace(&workspace_name, prev_workspace.as_ref());
|
||||||
|
|
||||||
|
if let Some(workspace) = workspace {
|
||||||
|
send!(tx, WorkspaceUpdate::Move(workspace.clone()));
|
||||||
|
|
||||||
|
if !workspace.visibility.is_focused() {
|
||||||
|
Self::send_focus_change(&mut prev_workspace, workspace, &tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
|
||||||
|
event_listener.add_workspace_rename_handler(move |data| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
debug!("Received workspace rename: {data:?}");
|
||||||
|
|
||||||
|
send!(
|
||||||
|
tx,
|
||||||
|
WorkspaceUpdate::Rename {
|
||||||
|
id: data.workspace_id as i64,
|
||||||
|
name: data.workspace_name
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
|
||||||
|
event_listener.add_workspace_destroy_handler(move |data| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
debug!("Received workspace destroy: {data:?}");
|
||||||
|
send!(tx, WorkspaceUpdate::Remove(data.workspace_id as i64));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let tx = tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
|
||||||
|
event_listener.add_urgent_state_handler(move |address| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
debug!("Received urgent state: {address:?}");
|
||||||
|
|
||||||
|
let clients = match hyprland::data::Clients::get() {
|
||||||
|
Ok(clients) => clients,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Failed to get clients: {err}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clients.iter().find(|c| c.address == address).map_or_else(
|
||||||
|
|| {
|
||||||
|
error!("Unable to locate client");
|
||||||
|
},
|
||||||
|
|c| {
|
||||||
|
send!(
|
||||||
|
tx,
|
||||||
|
WorkspaceUpdate::Urgent {
|
||||||
|
id: c.workspace.id as i64,
|
||||||
|
urgent: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
|
fn listen_keyboard_events(
|
||||||
|
keyboard_layout_tx: Sender<KeyboardLayoutUpdate>,
|
||||||
|
event_listener: &mut EventListener,
|
||||||
|
lock: std::sync::Arc<std::sync::Mutex<()>>,
|
||||||
|
) {
|
||||||
|
let tx = keyboard_layout_tx.clone();
|
||||||
|
let lock = lock.clone();
|
||||||
|
|
||||||
|
event_listener.add_keyboard_layout_change_handler(move |layout_event| {
|
||||||
|
let _lock = lock!(lock);
|
||||||
|
|
||||||
|
let layout = if layout_event.layout_name.is_empty() {
|
||||||
|
// FIXME: This field is empty due to bug in `hyprland-rs_0.4.0-alpha.3`. Which is already fixed in last betas
|
||||||
|
|
||||||
|
// The layout may be empty due to a bug in `hyprland-rs`, because of which the `layout_event` is incorrect.
|
||||||
|
//
|
||||||
|
// Instead of:
|
||||||
|
// ```
|
||||||
|
// LayoutEvent {
|
||||||
|
// keyboard_name: "keychron-keychron-c2",
|
||||||
|
// layout_name: "English (US)",
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// We get:
|
||||||
|
// ```
|
||||||
|
// LayoutEvent {
|
||||||
|
// keyboard_name: "keychron-keychron-c2,English (US)",
|
||||||
|
// layout_name: "",
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Here we are trying to recover `layout_name` from `keyboard_name`
|
||||||
|
|
||||||
|
let layout = layout_event.keyboard_name.as_str().split(',').nth(1);
|
||||||
|
let Some(layout) = layout else {
|
||||||
|
error!(
|
||||||
|
"Failed to get layout from string: {}. The failed logic is a workaround for a bug in `hyprland 0.4.0-alpha.3`", layout_event.keyboard_name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.into()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
layout_event.layout_name
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Received layout: {layout:?}");
|
||||||
|
|
||||||
|
send!(tx, KeyboardLayoutUpdate(layout));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends a `WorkspaceUpdate::Focus` event
|
/// Sends a `WorkspaceUpdate::Focus` event
|
||||||
/// and updates the active workspace cache.
|
/// and updates the active workspace cache.
|
||||||
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
fn send_focus_change(
|
fn send_focus_change(
|
||||||
prev_workspace: &mut Option<Workspace>,
|
prev_workspace: &mut Option<Workspace>,
|
||||||
workspace: Workspace,
|
workspace: Workspace,
|
||||||
|
@ -299,6 +335,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a workspace by name from the server, given the active workspace if known.
|
/// Gets a workspace by name from the server, given the active workspace if known.
|
||||||
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
fn get_workspace(name: &str, active: Option<&Workspace>) -> Option<Workspace> {
|
fn get_workspace(name: &str, active: Option<&Workspace>) -> Option<Workspace> {
|
||||||
Workspaces::get()
|
Workspaces::get()
|
||||||
.expect("Failed to get workspaces")
|
.expect("Failed to get workspaces")
|
||||||
|
@ -323,7 +360,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "workspaces")]
|
#[cfg(feature = "workspaces+hyprland")]
|
||||||
impl super::WorkspaceClient for Client {
|
impl super::WorkspaceClient for Client {
|
||||||
fn focus(&self, id: i64) {
|
fn focus(&self, id: i64) {
|
||||||
let identifier = WorkspaceIdentifierWithSpecial::Id(id as i32);
|
let identifier = WorkspaceIdentifierWithSpecial::Id(id as i32);
|
||||||
|
@ -334,7 +371,7 @@ impl super::WorkspaceClient for Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe(&self) -> Receiver<WorkspaceUpdate> {
|
fn subscribe(&self) -> Receiver<WorkspaceUpdate> {
|
||||||
let rx = self.workspace_tx.subscribe();
|
let rx = self.workspace.tx.subscribe();
|
||||||
|
|
||||||
let active_id = HWorkspace::get_active().ok().map(|active| active.name);
|
let active_id = HWorkspace::get_active().ok().map(|active| active.name);
|
||||||
let is_visible = create_is_visible();
|
let is_visible = create_is_visible();
|
||||||
|
@ -349,12 +386,16 @@ impl super::WorkspaceClient for Client {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
send!(self.workspace_tx, WorkspaceUpdate::Init(workspaces));
|
send!(self.workspace.tx, WorkspaceUpdate::Init(workspaces));
|
||||||
|
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
|
use super::{KeyboardLayoutClient, KeyboardLayoutUpdate};
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
impl KeyboardLayoutClient for Client {
|
impl KeyboardLayoutClient for Client {
|
||||||
fn set_next_active(&self) {
|
fn set_next_active(&self) {
|
||||||
let device = Devices::get()
|
let device = Devices::get()
|
||||||
|
@ -376,7 +417,7 @@ impl KeyboardLayoutClient for Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe(&self) -> Receiver<KeyboardLayoutUpdate> {
|
fn subscribe(&self) -> Receiver<KeyboardLayoutUpdate> {
|
||||||
let rx = self.keyboard_layout_tx.subscribe();
|
let rx = self.keyboard_layout.tx.subscribe();
|
||||||
|
|
||||||
let layout = Devices::get()
|
let layout = Devices::get()
|
||||||
.expect("Failed to get devices")
|
.expect("Failed to get devices")
|
||||||
|
@ -386,7 +427,7 @@ impl KeyboardLayoutClient for Client {
|
||||||
.map(|k| k.active_keymap.clone());
|
.map(|k| k.active_keymap.clone());
|
||||||
|
|
||||||
if let Some(layout) = layout {
|
if let Some(layout) = layout {
|
||||||
send!(self.keyboard_layout_tx, KeyboardLayoutUpdate(layout));
|
send!(self.keyboard_layout.tx, KeyboardLayoutUpdate(layout));
|
||||||
} else {
|
} else {
|
||||||
error!("Failed to get current keyboard layout hyprland");
|
error!("Failed to get current keyboard layout hyprland");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,19 @@ use std::sync::Arc;
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
#[cfg(any(feature = "keyboard+hyprland", feature = "workspaces+hyprland"))]
|
#[cfg(feature = "hyprland")]
|
||||||
pub mod hyprland;
|
pub mod hyprland;
|
||||||
#[cfg(feature = "workspaces+niri")]
|
#[cfg(feature = "niri")]
|
||||||
pub mod niri;
|
pub mod niri;
|
||||||
#[cfg(any(feature = "keyboard+sway", feature = "workspaces+sway"))]
|
#[cfg(feature = "sway")]
|
||||||
pub mod sway;
|
pub mod sway;
|
||||||
|
|
||||||
pub enum Compositor {
|
pub enum Compositor {
|
||||||
#[cfg(any(feature = "keyboard+sway", feature = "workspaces+sway"))]
|
#[cfg(feature = "sway")]
|
||||||
Sway,
|
Sway,
|
||||||
#[cfg(any(feature = "keyboard+hyprland", feature = "workspaces+hyprland"))]
|
#[cfg(feature = "hyprland")]
|
||||||
Hyprland,
|
Hyprland,
|
||||||
#[cfg(feature = "workspaces+niri")]
|
#[cfg(feature = "niri")]
|
||||||
Niri,
|
Niri,
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@ impl Display for Compositor {
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "keyboard+sway", feature = "workspaces+sway"))]
|
#[cfg(any(feature = "sway"))]
|
||||||
Self::Sway => "Sway",
|
Self::Sway => "Sway",
|
||||||
#[cfg(any(feature = "keyboard+hyprland", feature = "workspaces+hyprland"))]
|
#[cfg(any(feature = "hyprland"))]
|
||||||
Self::Hyprland => "Hyprland",
|
Self::Hyprland => "Hyprland",
|
||||||
#[cfg(feature = "workspaces+niri")]
|
#[cfg(feature = "workspaces+niri")]
|
||||||
Self::Niri => "Niri",
|
Self::Niri => "Niri",
|
||||||
|
@ -48,17 +48,17 @@ impl Compositor {
|
||||||
fn get_current() -> Self {
|
fn get_current() -> Self {
|
||||||
if std::env::var("SWAYSOCK").is_ok() {
|
if std::env::var("SWAYSOCK").is_ok() {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(feature = "keyboard+sway", feature = "workspaces+sway"))] { Self::Sway }
|
if #[cfg(feature = "sway")] { Self::Sway }
|
||||||
else { tracing::error!("Not compiled with Sway support"); Self::Unsupported }
|
else { tracing::error!("Not compiled with Sway support"); Self::Unsupported }
|
||||||
}
|
}
|
||||||
} else if std::env::var("HYPRLAND_INSTANCE_SIGNATURE").is_ok() {
|
} else if std::env::var("HYPRLAND_INSTANCE_SIGNATURE").is_ok() {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(feature = "keyboard+hyprland", feature = "workspaces+hyprland"))] { Self::Hyprland }
|
if #[cfg(feature = "hyprland")] { Self::Hyprland }
|
||||||
else { tracing::error!("Not compiled with Hyprland support"); Self::Unsupported }
|
else { tracing::error!("Not compiled with Hyprland support"); Self::Unsupported }
|
||||||
}
|
}
|
||||||
} else if std::env::var("NIRI_SOCKET").is_ok() {
|
} else if std::env::var("NIRI_SOCKET").is_ok() {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "workspaces+niri")] { Self::Niri }
|
if #[cfg(feature = "niri")] { Self::Niri }
|
||||||
else {tracing::error!("Not compiled with Niri support"); Self::Unsupported }
|
else {tracing::error!("Not compiled with Niri support"); Self::Unsupported }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,13 +79,16 @@ impl Compositor {
|
||||||
.map(|client| client as Arc<dyn KeyboardLayoutClient + Send + Sync>),
|
.map(|client| client as Arc<dyn KeyboardLayoutClient + Send + Sync>),
|
||||||
#[cfg(feature = "keyboard+hyprland")]
|
#[cfg(feature = "keyboard+hyprland")]
|
||||||
Self::Hyprland => Ok(clients.hyprland()),
|
Self::Hyprland => Ok(clients.hyprland()),
|
||||||
#[cfg(feature = "workspaces")]
|
#[cfg(feature = "niri")]
|
||||||
Self::Niri => Err(Report::msg("Unsupported compositor").note(
|
Self::Niri => Err(Report::msg("Unsupported compositor").note(
|
||||||
"Currently keyboard layout functionality are only supported by Sway and Hyprland",
|
"Currently keyboard layout functionality are only supported by Sway and Hyprland",
|
||||||
)),
|
)),
|
||||||
Self::Unsupported => Err(Report::msg("Unsupported compositor").note(
|
Self::Unsupported => Err(Report::msg("Unsupported compositor").note(
|
||||||
"Currently keyboard layout functionality are only supported by Sway and Hyprland",
|
"Currently keyboard layout functionality are only supported by Sway and Hyprland",
|
||||||
)),
|
)),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(Report::msg("Unsupported compositor")
|
||||||
|
.note("Keyboard layout feature is disabled for this compositor")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +111,9 @@ impl Compositor {
|
||||||
Self::Niri => Ok(Arc::new(niri::Client::new())),
|
Self::Niri => Ok(Arc::new(niri::Client::new())),
|
||||||
Self::Unsupported => Err(Report::msg("Unsupported compositor")
|
Self::Unsupported => Err(Report::msg("Unsupported compositor")
|
||||||
.note("Currently workspaces are only supported by Sway, Niri and Hyprland")),
|
.note("Currently workspaces are only supported by Sway, Niri and Hyprland")),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(Report::msg("Unsupported compositor")
|
||||||
|
.note("Workspaces feature is disabled for this compositor")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use super::{KeyboardLayoutClient, KeyboardLayoutUpdate, Visibility, Workspace, WorkspaceUpdate};
|
use super::{Visibility, Workspace, WorkspaceUpdate};
|
||||||
use crate::clients::sway::Client;
|
use crate::clients::sway::Client;
|
||||||
use crate::{await_sync, error, send, spawn};
|
use crate::{await_sync, error, send, spawn};
|
||||||
use color_eyre::Report;
|
use color_eyre::Report;
|
||||||
use swayipc_async::{InputChange, InputEvent, Node, WorkspaceChange, WorkspaceEvent};
|
use swayipc_async::{InputChange, InputEvent, Node, WorkspaceChange, WorkspaceEvent};
|
||||||
use tokio::sync::broadcast::{Receiver, channel};
|
use tokio::sync::broadcast::{Receiver, channel};
|
||||||
|
|
||||||
#[cfg(feature = "workspaces")]
|
#[cfg(feature = "workspaces+sway")]
|
||||||
impl super::WorkspaceClient for Client {
|
impl super::WorkspaceClient for Client {
|
||||||
fn focus(&self, id: i64) {
|
fn focus(&self, id: i64) {
|
||||||
let client = self.connection().clone();
|
let client = self.connection().clone();
|
||||||
|
@ -153,6 +153,10 @@ impl From<WorkspaceEvent> for WorkspaceUpdate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+sway")]
|
||||||
|
use super::{KeyboardLayoutClient, KeyboardLayoutUpdate};
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+sway")]
|
||||||
impl KeyboardLayoutClient for Client {
|
impl KeyboardLayoutClient for Client {
|
||||||
fn set_next_active(&self) {
|
fn set_next_active(&self) {
|
||||||
let client = self.connection().clone();
|
let client = self.connection().clone();
|
||||||
|
@ -210,6 +214,7 @@ impl KeyboardLayoutClient for Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "keyboard+sway")]
|
||||||
impl TryFrom<InputEvent> for KeyboardLayoutUpdate {
|
impl TryFrom<InputEvent> for KeyboardLayoutUpdate {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(feature = "clipboard")]
|
#[cfg(feature = "clipboard")]
|
||||||
pub mod clipboard;
|
pub mod clipboard;
|
||||||
#[cfg(any(feature = "keyboard", feature = "workspaces"))]
|
#[cfg(any(feature = "keyboard", feature = "workspaces", feature = "hyprland"))]
|
||||||
pub mod compositor;
|
pub mod compositor;
|
||||||
#[cfg(feature = "keyboard")]
|
#[cfg(feature = "keyboard")]
|
||||||
pub mod libinput;
|
pub mod libinput;
|
||||||
|
@ -195,7 +195,10 @@ impl Clients {
|
||||||
self.sys_info
|
self.sys_info
|
||||||
.get_or_insert_with(|| {
|
.get_or_insert_with(|| {
|
||||||
let client = Arc::new(sysinfo::Client::new());
|
let client = Arc::new(sysinfo::Client::new());
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
Ironbar::variable_manager().register_namespace("sysinfo", client.clone());
|
Ironbar::variable_manager().register_namespace("sysinfo", client.clone());
|
||||||
|
|
||||||
client
|
client
|
||||||
})
|
})
|
||||||
.clone()
|
.clone()
|
||||||
|
|
|
@ -70,13 +70,17 @@ pub trait MusicClient: Debug + Send + Sync {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum ClientType {
|
pub enum ClientType {
|
||||||
|
#[cfg(feature = "music+mpd")]
|
||||||
Mpd { host: String, music_dir: PathBuf },
|
Mpd { host: String, music_dir: PathBuf },
|
||||||
|
#[cfg(feature = "music+mpris")]
|
||||||
Mpris,
|
Mpris,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_client(client_type: ClientType) -> Arc<dyn MusicClient> {
|
pub fn create_client(client_type: ClientType) -> Arc<dyn MusicClient> {
|
||||||
match client_type {
|
match client_type {
|
||||||
|
#[cfg(feature = "music+mpd")]
|
||||||
ClientType::Mpd { host, music_dir } => Arc::new(mpd::Client::new(host, music_dir)),
|
ClientType::Mpd { host, music_dir } => Arc::new(mpd::Client::new(host, music_dir)),
|
||||||
|
#[cfg(feature = "music+mpris")]
|
||||||
ClientType::Mpris => Arc::new(mpris::Client::new()),
|
ClientType::Mpris => Arc::new(mpris::Client::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::ironvar::Namespace;
|
|
||||||
use crate::modules::sysinfo::Interval;
|
use crate::modules::sysinfo::Interval;
|
||||||
use crate::{lock, register_client};
|
use crate::{lock, register_client};
|
||||||
use color_eyre::{Report, Result};
|
use color_eyre::{Report, Result};
|
||||||
|
@ -483,6 +482,10 @@ impl FromStr for TokenType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
|
use crate::ironvar::Namespace;
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
impl Namespace for Client {
|
impl Namespace for Client {
|
||||||
fn get(&self, key: &str) -> Option<String> {
|
fn get(&self, key: &str) -> Option<String> {
|
||||||
let get = |value: Value| Some(value.get(Prefix::None).to_string());
|
let get = |value: Value| Some(value.get(Prefix::None).to_string());
|
||||||
|
@ -591,6 +594,7 @@ impl Namespace for Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
impl Namespace for ValueSet {
|
impl Namespace for ValueSet {
|
||||||
fn get(&self, key: &str) -> Option<String> {
|
fn get(&self, key: &str) -> Option<String> {
|
||||||
let function = Function::from_str(key).ok()?;
|
let function = Function::from_str(key).ok()?;
|
||||||
|
|
|
@ -6,10 +6,13 @@ use std::ops::Deref;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
|
feature = "cairo",
|
||||||
|
feature = "clipboard",
|
||||||
feature = "clipboard",
|
feature = "clipboard",
|
||||||
feature = "keyboard",
|
feature = "keyboard",
|
||||||
|
feature = "launcher",
|
||||||
feature = "music",
|
feature = "music",
|
||||||
feature = "workspaces"
|
feature = "workspaces",
|
||||||
))]
|
))]
|
||||||
pub struct IconButton {
|
pub struct IconButton {
|
||||||
button: Button,
|
button: Button,
|
||||||
|
@ -17,10 +20,13 @@ pub struct IconButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
|
feature = "cairo",
|
||||||
|
feature = "clipboard",
|
||||||
feature = "clipboard",
|
feature = "clipboard",
|
||||||
feature = "keyboard",
|
feature = "keyboard",
|
||||||
|
feature = "launcher",
|
||||||
feature = "music",
|
feature = "music",
|
||||||
feature = "workspaces"
|
feature = "workspaces",
|
||||||
))]
|
))]
|
||||||
impl IconButton {
|
impl IconButton {
|
||||||
pub fn new(input: &str, icon_theme: &IconTheme, size: i32) -> Self {
|
pub fn new(input: &str, icon_theme: &IconTheme, size: i32) -> Self {
|
||||||
|
@ -57,6 +63,15 @@ impl IconButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "clipboard",
|
||||||
|
feature = "keyboard",
|
||||||
|
feature = "music",
|
||||||
|
feature = "workspaces",
|
||||||
|
feature = "cairo",
|
||||||
|
feature = "clipboard",
|
||||||
|
feature = "launcher",
|
||||||
|
))]
|
||||||
impl Deref for IconButton {
|
impl Deref for IconButton {
|
||||||
type Target = Button;
|
type Target = Button;
|
||||||
|
|
||||||
|
@ -138,6 +153,7 @@ impl IconLabel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "keyboard", feature = "music", feature = "workspaces"))]
|
||||||
impl Deref for IconLabel {
|
impl Deref for IconLabel {
|
||||||
type Target = gtk::Box;
|
type Target = gtk::Box;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "clipboard",
|
feature = "clipboard",
|
||||||
feature = "keyboard",
|
feature = "keyboard",
|
||||||
|
feature = "launcher",
|
||||||
feature = "music",
|
feature = "music",
|
||||||
feature = "workspaces"
|
feature = "workspaces",
|
||||||
))]
|
))]
|
||||||
mod gtk;
|
mod gtk;
|
||||||
mod provider;
|
mod provider;
|
||||||
|
|
||||||
#[cfg(any(feature = "keyboard", feature = "music", feature = "workspaces"))]
|
#[cfg(any(
|
||||||
|
feature = "clipboard",
|
||||||
|
feature = "keyboard",
|
||||||
|
feature = "launcher",
|
||||||
|
feature = "music",
|
||||||
|
feature = "workspaces",
|
||||||
|
))]
|
||||||
pub use self::gtk::*;
|
pub use self::gtk::*;
|
||||||
pub use provider::ImageProvider;
|
pub use provider::ImageProvider;
|
||||||
|
|
|
@ -74,13 +74,23 @@ impl Default for Icons {
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||||
pub enum PlayerType {
|
pub enum PlayerType {
|
||||||
|
#[cfg(feature = "music+mpd")]
|
||||||
Mpd,
|
Mpd,
|
||||||
|
#[cfg(feature = "music+mpris")]
|
||||||
Mpris,
|
Mpris,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerType {
|
impl Default for PlayerType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Mpris
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "music+mpris")] {
|
||||||
|
Self::Mpris
|
||||||
|
} else if #[cfg(feature = "music+mpd")] {
|
||||||
|
Self::Mpd
|
||||||
|
} else {
|
||||||
|
compile_error!("No player type feature enabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,9 @@ fn get_client(
|
||||||
music_dir: PathBuf,
|
music_dir: PathBuf,
|
||||||
) -> Arc<dyn MusicClient> {
|
) -> Arc<dyn MusicClient> {
|
||||||
let client_type = match player_type {
|
let client_type = match player_type {
|
||||||
|
#[cfg(feature = "music+mpd")]
|
||||||
PlayerType::Mpd => music::ClientType::Mpd { host, music_dir },
|
PlayerType::Mpd => music::ClientType::Mpd { host, music_dir },
|
||||||
|
#[cfg(feature = "music+mpris")]
|
||||||
PlayerType::Mpris => music::ClientType::Mpris,
|
PlayerType::Mpris => music::ClientType::Mpris,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue