mirror of
https://github.com/tauri-apps/tao.git
synced 2026-01-31 00:35:16 +01:00
refactor(linux): remove zbus and use unity launcher APIs directly (#880)
* refactor(linux): remove zbus and use unity launcher APIs directly * change files * fmt --------- Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
5
.changes/bump-msrv.md
Normal file
5
.changes/bump-msrv.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tao": minor
|
||||
---
|
||||
|
||||
Updated the minimum supported Rust version to 1.70.
|
||||
5
.changes/progress-bar-refactor.md
Normal file
5
.changes/progress-bar-refactor.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tao": minor
|
||||
---
|
||||
|
||||
Progress bar on Linux no longer relies on zbus. Changed `ProgressBarState`'s field `unity_uri` to `desktop_filename`.
|
||||
@@ -7,7 +7,7 @@ authors = [
|
||||
"The winit contributors"
|
||||
]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.70"
|
||||
keywords = [ "windowing" ]
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
@@ -32,9 +32,6 @@ default = [ "rwh_06" ]
|
||||
[workspace]
|
||||
members = [ "tao-macros" ]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1"
|
||||
|
||||
[dependencies]
|
||||
instant = "0.1"
|
||||
lazy_static = "1"
|
||||
@@ -120,6 +117,6 @@ gtk = "0.18"
|
||||
gdkx11-sys = "0.18"
|
||||
gdkwayland-sys = "0.18.0"
|
||||
x11-dl = "2.21"
|
||||
zbus = "4"
|
||||
png = "0.17"
|
||||
parking_lot = "0.12"
|
||||
dlopen2 = "0.7.0"
|
||||
|
||||
@@ -61,7 +61,7 @@ fn main() {
|
||||
window.set_progress_bar(ProgressBarState {
|
||||
progress: Some(progress),
|
||||
state: Some(ProgressState::Normal),
|
||||
unity_uri: None,
|
||||
desktop_filename: None,
|
||||
});
|
||||
} else if modifiers.control_key() {
|
||||
let mut state = ProgressState::None;
|
||||
@@ -77,7 +77,7 @@ fn main() {
|
||||
window.set_progress_bar(ProgressBarState {
|
||||
progress: None,
|
||||
state: Some(state),
|
||||
unity_uri: None,
|
||||
desktop_filename: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,8 +245,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
None
|
||||
};
|
||||
|
||||
let mut taskbar: Option<TaskbarIndicator> = None;
|
||||
let supports_unity = util::is_unity();
|
||||
let mut taskbar = TaskbarIndicator::new();
|
||||
|
||||
// Window Request
|
||||
window_requests_rx.attach(Some(&context), move |(id, request)| {
|
||||
@@ -853,19 +852,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
} else if id == WindowId::dummy() {
|
||||
match request {
|
||||
WindowRequest::ProgressBarState(state) => {
|
||||
if supports_unity {
|
||||
if taskbar.is_none() {
|
||||
if let Ok(indicator) = TaskbarIndicator::new() {
|
||||
taskbar.replace(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(taskbar) = &mut taskbar {
|
||||
if let Err(e) = taskbar.update(state) {
|
||||
log::warn!("Failed to update taskbar progress {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
taskbar.update(state);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
@@ -1,56 +1,138 @@
|
||||
use crate::window::{ProgressBarState, ProgressState};
|
||||
use zbus::{
|
||||
blocking::Connection,
|
||||
fdo::Result,
|
||||
zvariant::{DeserializeDict, SerializeDict, Type},
|
||||
Message,
|
||||
};
|
||||
use std::ffi::CString;
|
||||
|
||||
pub struct TaskbarIndicator {
|
||||
conn: Connection,
|
||||
app_uri: String,
|
||||
use dlopen2::wrapper::{Container, WrapperApi};
|
||||
|
||||
use crate::window::{ProgressBarState, ProgressState};
|
||||
|
||||
#[derive(WrapperApi)]
|
||||
struct UnityLib {
|
||||
unity_launcher_entry_get_for_desktop_id: unsafe extern "C" fn(id: *const i8) -> *const isize,
|
||||
unity_inspector_get_default: unsafe extern "C" fn() -> *const isize,
|
||||
unity_inspector_get_unity_running: unsafe extern "C" fn(inspector: *const isize) -> i32,
|
||||
unity_launcher_entry_set_progress: unsafe extern "C" fn(entry: *const isize, value: f64) -> i32,
|
||||
unity_launcher_entry_set_progress_visible:
|
||||
unsafe extern "C" fn(entry: *const isize, value: i32) -> i32,
|
||||
}
|
||||
|
||||
#[derive(Default, SerializeDict, DeserializeDict, Type, PartialEq, Debug)]
|
||||
#[zvariant(signature = "dict")]
|
||||
struct Progress {
|
||||
progress: Option<f64>,
|
||||
#[zvariant(rename = "progress-visible")]
|
||||
progress_visible: Option<bool>,
|
||||
urgent: Option<bool>,
|
||||
pub struct TaskbarIndicator {
|
||||
desktop_filename: Option<String>,
|
||||
desktop_filename_c_str: Option<CString>,
|
||||
|
||||
is_supported: bool,
|
||||
unity_lib: Option<Container<UnityLib>>,
|
||||
attempted_load: bool,
|
||||
|
||||
unity_inspector: Option<*const isize>,
|
||||
unity_entry: Option<*const isize>,
|
||||
}
|
||||
|
||||
impl TaskbarIndicator {
|
||||
pub fn new() -> Result<Self> {
|
||||
let conn = Connection::session()?;
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
desktop_filename: None,
|
||||
desktop_filename_c_str: None,
|
||||
|
||||
Ok(Self {
|
||||
conn,
|
||||
app_uri: String::new(),
|
||||
})
|
||||
is_supported: is_supported(),
|
||||
unity_lib: None,
|
||||
attempted_load: false,
|
||||
|
||||
unity_inspector: None,
|
||||
unity_entry: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, progress: ProgressBarState) -> Result<()> {
|
||||
let mut properties = Progress::default();
|
||||
|
||||
if let Some(uri) = progress.unity_uri {
|
||||
self.app_uri = uri;
|
||||
fn ensure_lib_load(&mut self) {
|
||||
if self.attempted_load {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(progress) = progress.progress {
|
||||
let progress = if progress > 100 { 100 } else { progress };
|
||||
self.attempted_load = true;
|
||||
|
||||
properties.progress = Some(progress as f64 / 100.0);
|
||||
self.unity_lib = unsafe {
|
||||
Container::load("libunity.so.4")
|
||||
.or_else(|_| Container::load("libunity.so.6"))
|
||||
.or_else(|_| Container::load("libunity.so.9"))
|
||||
.ok()
|
||||
};
|
||||
|
||||
if let Some(unity_lib) = &self.unity_lib {
|
||||
let handle = unsafe { unity_lib.unity_inspector_get_default() };
|
||||
if !handle.is_null() {
|
||||
self.unity_inspector = Some(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_entry_load(&mut self) {
|
||||
if let Some(unity_lib) = &self.unity_lib {
|
||||
if let Some(id) = &self.desktop_filename_c_str {
|
||||
let handle = unsafe { unity_lib.unity_launcher_entry_get_for_desktop_id(id.as_ptr()) };
|
||||
if !handle.is_null() {
|
||||
self.unity_entry = Some(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unity_running(&self) -> bool {
|
||||
if let Some(inspector) = self.unity_inspector {
|
||||
if let Some(unity_lib) = &self.unity_lib {
|
||||
return unsafe { unity_lib.unity_inspector_get_unity_running(inspector) } == 1;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(state) = progress.state {
|
||||
properties.progress_visible = Some(!matches!(state, ProgressState::None));
|
||||
false
|
||||
}
|
||||
|
||||
pub fn update(&mut self, progress: ProgressBarState) {
|
||||
if let Some(uri) = progress.desktop_filename {
|
||||
self.desktop_filename = Some(uri);
|
||||
}
|
||||
|
||||
let signal = Message::signal("/", "com.canonical.Unity.LauncherEntry", "Update")?
|
||||
.build(&(self.app_uri.clone(), properties))?;
|
||||
if !self.is_supported {
|
||||
return;
|
||||
}
|
||||
|
||||
self.conn.send(&signal)?;
|
||||
Ok(())
|
||||
self.ensure_lib_load();
|
||||
|
||||
if !self.is_unity_running() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(uri) = &self.desktop_filename {
|
||||
self.desktop_filename_c_str = Some(CString::new(uri.as_str()).unwrap_or_default());
|
||||
}
|
||||
|
||||
if self.unity_entry.is_none() {
|
||||
self.ensure_entry_load();
|
||||
}
|
||||
if let Some(unity_lib) = &self.unity_lib {
|
||||
if let Some(unity_entry) = &self.unity_entry {
|
||||
if let Some(progress) = progress.progress {
|
||||
let progress = if progress > 100 { 100 } else { progress };
|
||||
let progress = progress as f64 / 100.0;
|
||||
unsafe { (unity_lib.unity_launcher_entry_set_progress)(*unity_entry, progress) };
|
||||
}
|
||||
|
||||
if let Some(state) = progress.state {
|
||||
let is_visible = !matches!(state, ProgressState::None);
|
||||
unsafe {
|
||||
(unity_lib.unity_launcher_entry_set_progress_visible)(
|
||||
*unity_entry,
|
||||
if is_visible { 1 } else { 0 },
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_supported() -> bool {
|
||||
std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.map(|d| {
|
||||
let d = d.to_lowercase();
|
||||
d.contains("unity") || d.contains("gnome")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -70,12 +70,3 @@ pub fn set_size_constraints<W: GtkWindowExt + WidgetExt>(
|
||||
geom_mask,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_unity() -> bool {
|
||||
std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.map(|d| {
|
||||
let d = d.to_lowercase();
|
||||
d.contains("unity") || d.contains("gnome")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ pub struct ProgressBarState {
|
||||
pub state: Option<ProgressState>,
|
||||
/// The progress bar progress. This can be a value ranging from `0` to `100`
|
||||
pub progress: Option<u64>,
|
||||
/// The identifier for your app to communicate with the Unity desktop window manager **Linux Only**
|
||||
pub unity_uri: Option<String>,
|
||||
/// The `.desktop` filename with the Unity desktop window manager, for example `myapp.desktop` **Linux Only**
|
||||
pub desktop_filename: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents a window.
|
||||
|
||||
Reference in New Issue
Block a user