Merge pull request #780 from JakeStanger/fix/tray-focus

Fix tray focus issues on Sway
This commit is contained in:
Jake Stanger 2024-11-16 20:39:16 +00:00 committed by GitHub
commit e7c56ee09b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 70 deletions

View File

@ -8,12 +8,12 @@ Clicking on the widget opens a popup with the time and a calendar.
> Type: `clock`
| Name | Type | Default | Description |
|----------------|----------|------------------------------------|-------------------------------------------------------------------------------------|
| `format` | `string` | `%d/%m/%Y %H:%M` | Date/time format string. Pango markup is supported. |
| `format_popup` | `string` | `%H:%M:%S` | Date/time format string to display in the popup header. Pango markup is supported. |
| `locale` | `string` | `$LC_TIME` or `$LANG` or `'POSIX'` | Locale to use (eg `en_GB`). Defaults to the system language (reading from env var). |
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the time on the clock button. |
| Name | Type | Default | Description |
|----------------|------------------------------------------------------------|------------------------------------|-------------------------------------------------------------------------------------|
| `format` | `string` | `%d/%m/%Y %H:%M` | Date/time format string. Pango markup is supported. |
| `format_popup` | `string` | `%H:%M:%S` | Date/time format string to display in the popup header. Pango markup is supported. |
| `locale` | `string` | `$LC_TIME` or `$LANG` or `'POSIX'` | Locale to use (eg `en_GB`). Defaults to the system language (reading from env var). |
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the time on the clock button. |
> Detail on available tokens can be found here: <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>

View File

@ -6,11 +6,11 @@ Displays a fully interactive icon tray using the KDE `libappindicator` protocol.
> Type: `tray`
| Name | Type | Default | Description |
|----------------------|-----------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `direction` | `string` | `left_to_right` if bar is horizontal, `top_to_bottom` otherwise | Direction to display the tray items. Possible values: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left` |
| `icon_size` | `integer` | `16` | Size in pixels to display tray icons as. |
| `prefer_theme_icons` | `bool` | `true` | Requests that icons from the theme be used over the item-provided item. Most items only provide one or the other so this will have no effect in most circumstances. |
| Name | Type | Default | Description |
|----------------------|------------------------------------------------------------|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | Matches bar orientation | The direction in which to pack tray icons. |
| `icon_size` | `integer` | `16` | Size in pixels to display tray icons as. |
| `prefer_theme_icons` | `bool` | `true` | Requests that icons from the theme be used over the item-provided item. Most items only provide one or the other so this will have no effect in most circumstances. |
<details>
<summary>JSON</summary>

View File

@ -1,11 +1,13 @@
use glib::Propagation;
use gtk::gdk::Gravity;
use gtk::prelude::*;
use gtk::{Image, Label, MenuItem};
use gtk::{EventBox, Image, Label, MenuItem};
use system_tray::item::{IconPixmap, StatusNotifierItem, Tooltip};
/// Main tray icon to show on the bar
pub(crate) struct TrayMenu {
pub event_box: EventBox,
pub widget: MenuItem,
menu_widget: Option<system_tray::gtk_menu::Menu>,
image_widget: Option<Image>,
label_widget: Option<Label>,
@ -17,12 +19,17 @@ pub(crate) struct TrayMenu {
impl TrayMenu {
pub fn new(item: StatusNotifierItem) -> Self {
let event_box = EventBox::new();
let widget = MenuItem::new();
widget.style_context().add_class("item");
event_box.add(&widget);
event_box.show_all();
Self {
event_box,
widget,
menu_widget: None,
image_widget: None,
label_widget: None,
title: item.title,
@ -99,7 +106,10 @@ impl TrayMenu {
}
pub fn set_menu_widget(&mut self, menu: system_tray::gtk_menu::Menu) {
self.widget.set_submenu(Some(&menu));
self.menu_widget = Some(menu);
self.event_box
.connect_button_press_event(move |event_box, _event| {
menu.popup_at_widget(event_box, Gravity::North, Gravity::South, None);
Propagation::Proceed
});
}
}

View File

@ -2,12 +2,12 @@ mod icon;
mod interface;
use crate::clients::tray;
use crate::config::CommonConfig;
use crate::config::{CommonConfig, ModuleOrientation};
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
use crate::{glib_recv, lock, module_impl, send_async, spawn};
use color_eyre::{Report, Result};
use gtk::{prelude::*, PackDirection};
use gtk::{IconTheme, MenuBar};
use gtk::prelude::*;
use gtk::{IconTheme, Orientation};
use interface::TrayMenu;
use serde::Deserialize;
use std::collections::HashMap;
@ -32,15 +32,13 @@ pub struct TrayModule {
#[serde(default = "default_icon_size")]
icon_size: u32,
/// Direction to display the tray items.
/// The direction in which to pack tray icons.
///
/// **Valid options**: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left`
/// **Valid options**: `horizontal`, `vertical`
/// <br>
/// **Default**: `left_to_right` if bar is horizontal, `top_to_bottom` if bar is vertical
#[serde(default, deserialize_with = "deserialize_pack_direction")]
#[cfg_attr(feature = "schema", schemars(schema_with = "schema_pack_direction"))]
direction: Option<PackDirection>,
/// **Default**: `horizontal` for horizontal bars, `vertical` for vertical bars
#[serde(default)]
direction: Option<ModuleOrientation>,
/// See [common options](module-level-options#common-options).
#[serde(flatten)]
pub common: Option<CommonConfig>,
@ -50,36 +48,7 @@ const fn default_icon_size() -> u32 {
16
}
fn deserialize_pack_direction<'de, D>(deserializer: D) -> Result<Option<PackDirection>, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = Option::<String>::deserialize(deserializer)?;
value
.map(|v| match v.as_str() {
"left_to_right" => Ok(PackDirection::Ltr),
"right_to_left" => Ok(PackDirection::Rtl),
"top_to_bottom" => Ok(PackDirection::Ttb),
"bottom_to_top" => Ok(PackDirection::Btt),
_ => Err(serde::de::Error::custom("invalid value for direction")),
})
.transpose()
}
#[cfg(feature = "schema")]
fn schema_pack_direction(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
use schemars::JsonSchema;
let mut schema: schemars::schema::SchemaObject = <String>::json_schema(gen).into();
schema.enum_values = Some(vec![
"top_to_bottom".into(),
"bottom_to_top".into(),
"left_to_right".into(),
"right_to_left".into(),
]);
schema.into()
}
impl Module<MenuBar> for TrayModule {
impl Module<gtk::Box> for TrayModule {
type SendMessage = Event;
type ReceiveMessage = ActivateRequest;
@ -137,19 +106,17 @@ impl Module<MenuBar> for TrayModule {
self,
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
info: &ModuleInfo,
) -> Result<ModuleParts<MenuBar>> {
let container = MenuBar::new();
) -> Result<ModuleParts<gtk::Box>> {
let orientation = self
.direction
.map(Orientation::from)
.unwrap_or(info.bar_position.orientation());
let direction = self.direction.unwrap_or(
if info.bar_position.orientation() == gtk::Orientation::Vertical {
PackDirection::Ttb
} else {
PackDirection::Ltr
},
);
container.set_pack_direction(direction);
container.set_child_pack_direction(direction);
// We use a `Box` here instead of the (supposedly correct) `MenuBar`
// as the latter has issues on Sway with menus focus-stealing from the bar.
//
// Each widget is wrapped in an EventBox, copying what Waybar does here.
let container = gtk::Box::new(orientation, 10);
{
let container = container.clone();
@ -173,7 +140,7 @@ impl Module<MenuBar> for TrayModule {
/// getting the diff since the previous update and applying it to the menu.
fn on_update(
update: Event,
container: &MenuBar,
container: &gtk::Box,
menus: &mut HashMap<Box<str>, TrayMenu>,
icon_theme: &IconTheme,
icon_size: u32,
@ -184,7 +151,7 @@ fn on_update(
debug!("Received new tray item at '{address}': {item:?}");
let mut menu_item = TrayMenu::new(*item);
container.add(&menu_item.widget);
container.pack_start(&menu_item.event_box, true, true, 0);
if let Ok(image) = icon::get_image(&menu_item, icon_theme, icon_size, prefer_icons) {
menu_item.set_image(&image);