eww icon indicating copy to clipboard operation
eww copied to clipboard

WIP: feat: naive system tray widget

Open oknozor opened this issue 2 years ago β€’ 39 comments

This is still a work in progress, properties needs to be added at least to configure the icon size, gtk menu and menuitem scss classes for the system tray.

While this is functional this needs to be tested against various applications.

Description

Add a system tray widget

Usage

For now there is just a (system-tray) widget with no prop binding.

Showcase

see #111

Checklist

Please make sure you can check all the boxes that apply to this PR.

  • [ ] All widgets I've added are correctly documented.
  • [ ] I added my changes to CHANGELOG.md, if appropriate.
  • [ ] The documentation in the docs/content/main directory has been adjusted to reflect my changes.
  • [x] I used cargo fmt to automatically format all code before committing

oknozor avatar Apr 30 '22 09:04 oknozor

I've had a first look through the code right now, and this looks very promising! Not a fan of the amount of .unwrap / .expect calls currently, but I assume that's gonna be relatively easy to sort out and do cleanly. Having global state for this is generally fine - as i'm assuming that's pretty much unavoidable. I think the functions etc in system_tray could definitely use some more comments and a bit more structure -- currently, spawn_local_handler does a lot more than just spawn some handler ^^

I haven't looked into the all the exact details yet, but the approach taken here definitely looks good! Good job already!

elkowar avatar May 10 '22 08:05 elkowar

Actually there is one big problem here. Every time a menu gets updated it closes and reopen.

For instance when using nm-applet --indicator if an update occurs (a new wifi network is seen on the interface) while I open the applet, the menu closes and I need to reopen it to see the update.

I have talked with the gtk-rs folks and it seems the solution is to implement a custom MenuModel. This seems doable but it involves a lot more boiler plate, and unsafe ffi function usage(an example for gio::ListModel https://github.com/gtk-rs/gtk-rs-core/blob/master/gio/src/subclass/list_model.rs.

So I will probably break everything again soon.

Now I am wondering if it would be better to expose the custom MenuModel from my crate or keep the gtk stuff in eww.

I'll keep you updated :)

oknozor avatar May 10 '22 11:05 oknozor

I'd think if you wanted to put some GTK stuff into your crate, it might be worth it to actually make a second crate (gtk-stray or sth), to keep the core system tray handling separate from specific frontend stuff -- that'd allow other projects to also make use of your stray implementation without necessarily needing to use the gtk frontend. Generally tho, if this does become complex enough, I could see putting the gtk-stuff into a separate crate rather than into eww be worthwhile πŸ‘πŸ»

elkowar avatar May 10 '22 13:05 elkowar

Hey @elkowar I've tried to implement a custom MenuModel without success. I don't think I will be able to do it without help. That said the current, naive implementation work as is : screenshot-2022-06-15T11:16:51

Let me know what you want to do.

oknozor avatar Jun 15 '22 09:06 oknozor

Awesome work! I'm looking forward for this to be merged to master. I think I might be able to help. Is there any place to converse about this? any EWW room or such?

ribosomerocker avatar Jun 25 '22 03:06 ribosomerocker

May I ask what the current state is of this PR?

TornaxO7 avatar Jul 13 '22 20:07 TornaxO7

For what it's worth, I'm trying this out on NixOS on River (Wayland) and I get the following error about icon info lookup:

thread 'main' panicked at 'Failed to lookup icon info', crates/eww/src/widgets/system_tray.rs:76:88
stack backtrace:
   0:     0x5580aa0ff2dc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h90d86d5e49dcdb23
   1:     0x5580aa138c8e - core::fmt::write::hf402a79d5884ad76
   2:     0x5580aa104fd1 - std::io::Write::write_fmt::h1839547170afd413
   3:     0x5580aa1120a5 - std::panicking::default_hook::{{closure}}::h1d6d5b9a19e531e9
   4:     0x5580aa111d2a - std::panicking::default_hook::h78a6ac0c850df841
   5:     0x5580aa11258c - std::panicking::rust_panic_with_hook::ha3460b9892f156c0
   6:     0x5580aa100007 - std::panicking::begin_panic_handler::{{closure}}::h89605b23b2447736
   7:     0x5580aa0ff6b4 - std::sys_common::backtrace::__rust_end_short_backtrace::h20c2a9b05a320fe6
   8:     0x5580aa112252 - rust_begin_unwind
   9:     0x5580a98dd4b3 - core::panicking::panic_fmt::hab911959b97bc6d9
  10:     0x5580aa13ed81 - core::panicking::panic_display::he8b09729440fceed
  11:     0x5580aa13ed2b - core::panicking::panic_str::h4e2544976daaf571
  12:     0x5580a98dd676 - core::option::expect_failed::h7c61aacccb08ad84
  13:     0x5580a9a37f85 - eww::widgets::system_tray::NotifierItem::get_icon::h44c3fc2ad0506b71
  14:     0x5580a99b1190 - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h4f6e11f34a6f16ef
  15:     0x5580aa0e328c - glib::main_context::<impl glib::auto::main_context::MainContext>::with_thread_default::hccad9d8f02533033
  16:     0x5580aa0decaa - glib::main_context_futures::TaskSource::dispatch::h575e8baf5d618d63
  17:     0x7f5001e8ddfb - g_main_context_dispatch
  18:     0x7f5001e8e0a8 - g_main_context_iterate.constprop.0
  19:     0x7f5001e8e393 - g_main_loop_run
  20:     0x7f50025fa375 - gtk_main
  21:     0x5580a9aba579 - eww::server::initialize_server::h172ed4c880e186da
  22:     0x5580a9a39302 - eww::main::h4d89aa5698bad2de
  23:     0x5580a99fa923 - std::sys_common::backtrace::__rust_begin_short_backtrace::hfcca3777e9002403
  24:     0x5580a99ce469 - std::rt::lang_start::{{closure}}::hb1e9e012b522d946
  25:     0x5580aa104951 - std::rt::lang_start_internal::he9577dbc8903283e
  26:     0x5580a9a3c512 - main
  27:     0x7f5001b89237 - __libc_start_call_main
  28:     0x7f5001b892f5 - __libc_start_main_impl
  29:     0x5580a98dd6a1 - _start
  30:                0x0 - <unknown>

dnordstrom avatar Aug 02 '22 04:08 dnordstrom

Some more info:

Doesn't matter which icon theme I use. I've tried setting a few different ones with dconf Editor (there are no schemas installed in "gsettings", but dconf Editor does the trick) as well as by editing the settings.ini for GTK 3 and 4, including setting it back to the default.

I suppose it shouldn't panic if it can't find an icon anyway, but the tray works fine in Sway with Waybar so that's a bit strange. Waybar ~~causes River to panic and exit for me though, even if I just have a clock enabled~~ never mind, finally found the culprit: a negative bottom margin. Waybar shows the tray just fine in River now. But Eww is so much more fun... :stuck_out_tongue:

dnordstrom avatar Aug 02 '22 04:08 dnordstrom

Some more info:

Doesn't matter which icon theme I use. I've tried setting a few different ones with dconf Editor (there are no schemas installed in "gsettings", but dconf Editor does the trick) as well as by editing the settings.ini for GTK 3 and 4, including setting it back to the default.

I suppose it shouldn't panic if it can't find an icon anyway, but the tray works fine in Sway with Waybar so that's a bit strange. Waybar ~causes River to panic and exit for me though, even if I just have a clock enabled~ never mind, finally found the culprit: a negative bottom margin. Waybar shows the tray just fine in River now. But Eww is so much more fun... stuck_out_tongue

Well looking at that line, it would seem to be a gtk issue

yavko avatar Aug 08 '22 03:08 yavko

Yeah, indeed. Maybe I'm missing some dependency, I don't know. I'm still running this branch, can try it in Sway when I get a chance and see if it works there. Wish I knew more Rust and could be more helpful.

EWW is awesome either way though, crazy addictive. For now, I'm just changing the settings so that apps don't close to tray. :slightly_smiling_face:

dnordstrom avatar Aug 09 '22 16:08 dnordstrom

Exactly the same stack trace in Sway as well.

dnordstrom avatar Aug 09 '22 16:08 dnordstrom

What's needed for this to be merged? No system tray is the only thing keeping me from using eww as my main bar.

tralph3 avatar Aug 24 '22 05:08 tralph3

What's needed for this to be merged? No system tray is the only thing keeping me from using eww as my main bar.

This NEEDS to be merged, I know eww has slowed down in development, but for those of us who want the power of eww, this is kind of a deal breaker, what is a bar without a system tray. (a GNOME panel)

yavko avatar Aug 24 '22 05:08 yavko

I tried this PR and it seems to be a prototype with lots of problems. Currently, I am trying hard to implement a system tray based on the same idea. However, Linux's system tray specifications are really complicated.

sunziping2016 avatar Aug 24 '22 05:08 sunziping2016

Hey @sunziping2016 I am currently working on something else but maybe we can join our effort ?

This is indeed a prototype but it's not far form being usable. Actually I am using it as a daily driver. If you want to help improving the current behavior maybe we can work together on https://github.com/oknozor/stray/ ?

The main issue, imo is not the dbus system tray implementation, but the gtk integration, which require building a custom MenuModel and involve messing with some ffi bindings with the C api.

If anyone has experience with gtk-rs help would be more than welcome.

oknozor avatar Aug 24 '22 09:08 oknozor

@oknozor I did some investigation, and found some systray implementations leverage libdbusmenu. It seems there is no existing Rust binding for libdbusmenu.

For those why are trying libdbusmenu, see gtk-rs/gir for instruction to generate bindings. I am currently working on it, and nearly finish it. xembed-sni-proxy can be used to bridge between XEmbed apps and StatusNotifierItem apps.

I believe I can implement a native systray soon.

sunziping2016 avatar Aug 31 '22 12:08 sunziping2016

Awesome. I have been waiting for this feature for forever. If there's anything I can do (I do have Rust experience, just not gtk-rs) -- then let me know.

ribosomerocker avatar Sep 05 '22 23:09 ribosomerocker

Any updates on this?

kapilpokhrel avatar Oct 30 '22 15:10 kapilpokhrel

Any updates on this?

Bit inappropriate in open-source, especially when people are devoting their free time to unpaid work. Also irrelevant to the technical discussion of the PR itself. https://teejeetech.medium.com/etiquette-in-open-source-projects-f302b6e19c38

Asking for ETAsβ€Šβ€”β€ŠAvoid asking for ETAs for issues and feature requests. It’s more rude than you may realize. People working on open-source projects are not your employees. They have no obligation to implement every feature you request, to fix every issue you report, or to provide technical support that you are not even paying for. I do not enjoy spending my time working on features that are of no interest to me, or investigating issues that I never face. If I fix such an issue, it’s usually because I’m curious as to what’s causing it, or because that issue is affecting a lot of people and can be fixed quickly. The same goes for feature requests. I may add a feature for the sake of completeness, because it’s interesting, or maybe because it’s easy to implement. If it’s time consuming then it will remain undone till I find the time, or till someone else comes along, implements the feature, and submits a pull request.

If you want to contribute, I imagine submitting your own PR would be far more welcome.

eclairevoyant avatar Oct 31 '22 02:10 eclairevoyant

Any updates on this?

Bit inappropriate in open-source, especially when people are devoting their free time to unpaid work. Also irrelevant to the technical discussion of the PR itself. https://teejeetech.medium.com/etiquette-in-open-source-projects-f302b6e19c38

Asking for ETAsβ€Šβ€”β€ŠAvoid asking for ETAs for issues and feature requests. It’s more rude than you may realize. People working on open-source projects are not your employees. They have no obligation to implement every feature you request, to fix every issue you report, or to provide technical support that you are not even paying for. I do not enjoy spending my time working on features that are of no interest to me, or investigating issues that I never face. If I fix such an issue, it’s usually because I’m curious as to what’s causing it, or because that issue is affecting a lot of people and can be fixed quickly. The same goes for feature requests. I may add a feature for the sake of completeness, because it’s interesting, or maybe because it’s easy to implement. If it’s time consuming then it will remain undone till I find the time, or till someone else comes along, implements the feature, and submits a pull request.

If you want to contribute, I imagine submitting your own PR would be far more welcome.

I am very sorry, I didn't realize that. I was just very excited to see this PR. Again, sorry, I didn't want to be rude.

kapilpokhrel avatar Oct 31 '22 02:10 kapilpokhrel

Also the pr author has started his own bar project, so i doubt he will complete this pr soon

yavko avatar Oct 31 '22 07:10 yavko

@oknozor I used your fork to try the systray integration, then added this on my yuck file:

(defwidget systray []
	(system-tray))

But the window is empty, and it prints in the log thread 'tokio-runtime-worker' panicked at 'Error occurred in notifier watcher task: name already taken on the bus', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stray-0.1.1/src/lib.rs:38:18. I'm using Awesome WM so I tried to remove its systray management but the problem is still there.

I also tried to rebase this PR, but when I try to compile with stray v0.1.0 or v0.1.2 the compilation raises those errors:

error[E0432]: unresolved imports `stray::tokio_stream`, `stray::SystemTray`
  --> crates/eww/src/widgets/system_tray.rs:14:5
   |
14 |     tokio_stream::StreamExt,
   |     ^^^^^^^^^^^^ could not find `tokio_stream` in `stray`
15 |     SystemTray,
   |     ^^^^^^^^^^ no `SystemTray` in the root

warning: unused import: `glib::signal::SignalHandlerId`
  --> crates/eww/src/widgets/widget_definitions.rs:14:5
   |
14 | use glib::signal::SignalHandlerId;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

error[E0308]: mismatched types
   --> crates/eww/src/widgets/system_tray.rs:109:53
    |
109 |                     state.insert(id, NotifierItem { item, menu });
    |                                                     ^^^^ expected struct `StatusNotifierItem`, found struct `Box`
    |
    = note: expected struct `StatusNotifierItem`
               found struct `std::boxed::Box<StatusNotifierItem>`
help: consider unboxing the value
    |
109 |                     state.insert(id, NotifierItem { item: *item, menu });
    |                                                     +++++++

warning: unused import: `std::hash::Hasher`
  --> crates/eww/src/widgets/widget_definitions.rs:18:5
   |
18 | use std::hash::Hasher;
   |     ^^^^^^^^

Anarky avatar Dec 13 '22 17:12 Anarky

I don't have time to update this PR know but it should work using my eww fork if yo carefully killing other apps using the dbus system stray.

I don't know about awesome specifics but it works on i3 and sway.

Maybe you want to use dfleet to find the app using the system tray.

oknozor avatar Dec 13 '22 17:12 oknozor

Thanks for suggesting d-feet. When I start eww, org.freedesktop.StatusNotifierHost-[eww PID]-MyNotifierHost and org.kde.StatusNotifierWatch appear in the session bus tab, with "activatable: no, cmd: eww daemon".

It disappears when I kill eww so it should be the only one to use org.freedesktop.StatusNotifierHost, even when Awesome has its systray activated it's not listed.

Anarky avatar Dec 13 '22 18:12 Anarky

@Anarky this snippet – taken from the gtk-tray example on the stray repo (except the unbox in line 111) – works for me:

diff --git a/crates/eww/src/widgets/system_tray.rs b/crates/eww/src/widgets/system_tray.rs
index bc2e088..c297e58 100644
--- a/crates/eww/src/widgets/system_tray.rs
+++ b/crates/eww/src/widgets/system_tray.rs
@@ -11,8 +11,7 @@ use stray::{
         tray::StatusNotifierItem,
         NotifierItemCommand, NotifierItemMessage,
     },
-    tokio_stream::StreamExt,
-    SystemTray,
+    StatusNotifierWatcher,
 };
 use tokio::{runtime::Runtime, sync::mpsc};

@@ -85,11 +84,14 @@ pub fn start_communication_thread(sender: mpsc::Sender<NotifierItemMessage>, cmd
         let runtime = Runtime::new().expect("Failed to create tokio RT");

         runtime.block_on(async {
-            let mut tray = SystemTray::new(cmd_rx).await;
+            let tray = StatusNotifierWatcher::new(cmd_rx).await.unwrap();
+            let mut host = tray.create_notifier_host("MyHost").await.unwrap();

-            while let Some(message) = tray.next().await {
+            while let Ok(message) = host.recv().await {
                 sender.send(message).await.expect("failed to send message to UI");
             }
+
+            host.destroy().await.unwrap();
         })
     });
 }
@@ -106,7 +108,7 @@ pub fn spawn_local_handler(

             match item {
                 NotifierItemMessage::Update { address: id, item, menu } => {
-                    state.insert(id, NotifierItem { item, menu });
+                    state.insert(id, NotifierItem { item: *item, menu });
                 }
                 NotifierItemMessage::Remove { address } => {
                     state.remove(&address);
diff --git a/crates/eww/src/widgets/widget_definitions.rs b/crates/eww/src/widgets/widget_definitions.rs
index 02f142d..26cca19 100644
--- a/crates/eww/src/widgets/widget_definitions.rs
+++ b/crates/eww/src/widgets/widget_definitions.rs
@@ -11,11 +11,9 @@ use eww_shared_util::Spanned;
 use gdk::{ModifierType, NotifyType};

 use glib::translate::FromGlib;
-use glib::signal::SignalHandlerId;
 use gtk::{self, glib, prelude::*, DestDefaults, TargetEntry, TargetList};
 use itertools::Itertools;
 use once_cell::sync::Lazy;
-use std::hash::Hasher;

 use crate::widgets::system_tray::{spawn_local_handler, start_communication_thread};
 use std::{

Edit: now without the two unused import warnings

VuiMuich avatar Dec 16 '22 19:12 VuiMuich

@VuiMuich thanks for your help! I attached a zip containing a patch that applies for the current revision (678e4db) with stray 0.1.2, and a PKGBUILD for arch. Unfortunately it still doesn't work for me, even when using startx I have this error:

thread 'tokio-runtime-worker' panicked at 'Unexpected StatusNotifierError : DbusError(NameTaken)', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stray-0.1.2/src/notifier_watcher/mod.rs:37:22
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: DbusError(NameTaken)', crates/eww/src/widgets/system_tray.rs:88:70

stray.zip

Anarky avatar Dec 21 '22 17:12 Anarky

It does not run very stable for me neither. I tried to put stray in a window to toggle it on and off, but that causes some panics as well. Had no time yet, to debug that.i

But I basically get the same error:

~ >>> eww open-many tags left right --debug
 2022-12-22T09:01:53.115Z WARN  eww > Failed to connect to daemon: Failed to connect to daemon
 2022-12-22T09:01:53.115Z INFO  eww > Initializing eww server. (/run/user/1000/eww-server_9df4f14eefddaddf)
Run `eww logs` to see any errors while editing your configuration.
 2022-12-22T09:01:53.115Z INFO  eww::server > Loading paths: config-dir: /home/vuimuich/.config/leftwm/themes/serika/eww, ipc-socket: /run/user/1000/eww-server_9df4f14eefddaddf, log-file: /home/vuimuich/.cache/eww_9df4f14eefddaddf.log

~ >>> eww logs

┏━━━━━━━━━━━━━━━━━━━━━━━┓
┃Initializing eww daemon┃
┗━━━━━━━━━━━━━━━━━━━━━━━┛

 2022-12-22T09:01:53.192Z INFO  eww::app    > Opening window tags
 2022-12-22T09:01:53.193Z INFO  eww::ipc_server > IPC server initialized
 2022-12-22T09:01:53.214Z INFO  eww::app        > Opening window left
 2022-12-22T09:01:53.227Z INFO  eww::app        > Opening window right
 2022-12-22T09:02:05.211Z INFO  eww::app        > Opening window tray
 2022-12-22T09:02:07.480Z INFO  eww::app        > Closing gtk window tray
 2022-12-22T09:02:09.898Z INFO  eww::app        > Opening window tray
thread 'thread 'tokio-runtime-worker<unnamed>' panicked at '' panicked at 'Unexpected StatusNotifierError : DbusError(NameTaken)called `Result::unwrap()` on an `Err` value: DbusError(NameTaken)', ', /home/vuimuich/.cargo/registry/src/github.com-1ecc6299db9ec823/stray-0.1.2/src/notifier_watcher/mod.rscrates/eww/src/widgets/system_tray.rs::3788::2270

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 2022-12-22T09:02:12.213Z INFO  eww::app        > Closing gtk window tray
 2022-12-22T09:02:14.447Z INFO  eww::app        > Opening window tray
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: DbusError(NameTaken)', crates/eww/src/widgets/system_tray.rs:88:70
 2022-12-22T09:02:17.884Z INFO  eww::app        > Closing gtk window tray
^C⏎  

VuiMuich avatar Dec 22 '22 08:12 VuiMuich

For what it's worth, I'm trying this out on NixOS on River (Wayland) and I get the following error about icon info lookup:

thread 'main' panicked at 'Failed to lookup icon info', crates/eww/src/widgets/system_tray.rs

@dnordstrom I had the same issue and did a bit of digging and I don't think it's an issue with this project. It seems to be https://github.com/NixOS/nixpkgs/issues/163107/. The fix at the bottom of this comment -- https://github.com/NixOS/nixpkgs/issues/163107#issuecomment-1100569484 -- worked for me.

ralismark avatar Jan 08 '23 12:01 ralismark

This is a feature I want, but the PR has kinda stalled, so I've been fixing some things over at https://github.com/ralismark/eww. I'm happy to try and get this into a mergeable state, but I haven't properly looked at all of the current changes, plus I'll be a bit busy for the next few weeks, so it might take some time.

@elkowar @oknozor what are your thoughts? Should I e.g. create a new pr?

ralismark avatar Jan 10 '23 11:01 ralismark

@ralismark besides the fix for nixos, does your fork's systray work properly? I would be very interested in testing it

PhilTaken avatar Jan 10 '23 14:01 PhilTaken

I tried to use @ralismark's fork but after some groking only 1 of 6 icons appeared.

I hope that this features will get more attention, in the meantime I use Stalonetray with a eww button widget to toggle it.

tkapias avatar Jan 19 '23 15:01 tkapias