1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-08-16 22:31:03 +02:00

fix(tray): menu causing bar to lose focus on sway

BREAKING CHANGE: The `direction` option has been changed to only accept `horizontal` or `vertical`
This commit is contained in:
Jake Stanger 2024-11-16 20:35:56 +00:00
parent 3f8afa998d
commit e4e9632caa
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
3 changed files with 41 additions and 64 deletions

View file

@ -6,11 +6,11 @@ Displays a fully interactive icon tray using the KDE `libappindicator` protocol.
> Type: `tray` > Type: `tray`
| Name | Type | Default | Description | | 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` | | `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. | | `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. | | `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> <details>
<summary>JSON</summary> <summary>JSON</summary>

View file

@ -1,11 +1,13 @@
use glib::Propagation;
use gtk::gdk::Gravity;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Image, Label, MenuItem}; use gtk::{EventBox, Image, Label, MenuItem};
use system_tray::item::{IconPixmap, StatusNotifierItem, Tooltip}; use system_tray::item::{IconPixmap, StatusNotifierItem, Tooltip};
/// Main tray icon to show on the bar /// Main tray icon to show on the bar
pub(crate) struct TrayMenu { pub(crate) struct TrayMenu {
pub event_box: EventBox,
pub widget: MenuItem, pub widget: MenuItem,
menu_widget: Option<system_tray::gtk_menu::Menu>,
image_widget: Option<Image>, image_widget: Option<Image>,
label_widget: Option<Label>, label_widget: Option<Label>,
@ -17,12 +19,17 @@ pub(crate) struct TrayMenu {
impl TrayMenu { impl TrayMenu {
pub fn new(item: StatusNotifierItem) -> Self { pub fn new(item: StatusNotifierItem) -> Self {
let event_box = EventBox::new();
let widget = MenuItem::new(); let widget = MenuItem::new();
widget.style_context().add_class("item"); widget.style_context().add_class("item");
event_box.add(&widget);
event_box.show_all();
Self { Self {
event_box,
widget, widget,
menu_widget: None,
image_widget: None, image_widget: None,
label_widget: None, label_widget: None,
title: item.title, title: item.title,
@ -99,7 +106,10 @@ impl TrayMenu {
} }
pub fn set_menu_widget(&mut self, menu: system_tray::gtk_menu::Menu) { pub fn set_menu_widget(&mut self, menu: system_tray::gtk_menu::Menu) {
self.widget.set_submenu(Some(&menu)); self.event_box
self.menu_widget = Some(menu); .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; mod interface;
use crate::clients::tray; use crate::clients::tray;
use crate::config::CommonConfig; use crate::config::{CommonConfig, ModuleOrientation};
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext}; use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
use crate::{glib_recv, lock, module_impl, send_async, spawn}; use crate::{glib_recv, lock, module_impl, send_async, spawn};
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use gtk::{prelude::*, PackDirection}; use gtk::prelude::*;
use gtk::{IconTheme, MenuBar}; use gtk::{IconTheme, Orientation};
use interface::TrayMenu; use interface::TrayMenu;
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
@ -32,15 +32,13 @@ pub struct TrayModule {
#[serde(default = "default_icon_size")] #[serde(default = "default_icon_size")]
icon_size: u32, 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> /// <br>
/// **Default**: `left_to_right` if bar is horizontal, `top_to_bottom` if bar is vertical /// **Default**: `horizontal` for horizontal bars, `vertical` for vertical bars
#[serde(default, deserialize_with = "deserialize_pack_direction")] #[serde(default)]
#[cfg_attr(feature = "schema", schemars(schema_with = "schema_pack_direction"))] direction: Option<ModuleOrientation>,
direction: Option<PackDirection>,
/// See [common options](module-level-options#common-options). /// See [common options](module-level-options#common-options).
#[serde(flatten)] #[serde(flatten)]
pub common: Option<CommonConfig>, pub common: Option<CommonConfig>,
@ -50,36 +48,7 @@ const fn default_icon_size() -> u32 {
16 16
} }
fn deserialize_pack_direction<'de, D>(deserializer: D) -> Result<Option<PackDirection>, D::Error> impl Module<gtk::Box> for TrayModule {
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 {
type SendMessage = Event; type SendMessage = Event;
type ReceiveMessage = ActivateRequest; type ReceiveMessage = ActivateRequest;
@ -137,19 +106,17 @@ impl Module<MenuBar> for TrayModule {
self, self,
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>, context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
info: &ModuleInfo, info: &ModuleInfo,
) -> Result<ModuleParts<MenuBar>> { ) -> Result<ModuleParts<gtk::Box>> {
let container = MenuBar::new(); let orientation = self
.direction
.map(Orientation::from)
.unwrap_or(info.bar_position.orientation());
let direction = self.direction.unwrap_or( // We use a `Box` here instead of the (supposedly correct) `MenuBar`
if info.bar_position.orientation() == gtk::Orientation::Vertical { // as the latter has issues on Sway with menus focus-stealing from the bar.
PackDirection::Ttb //
} else { // Each widget is wrapped in an EventBox, copying what Waybar does here.
PackDirection::Ltr let container = gtk::Box::new(orientation, 10);
},
);
container.set_pack_direction(direction);
container.set_child_pack_direction(direction);
{ {
let container = container.clone(); 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. /// getting the diff since the previous update and applying it to the menu.
fn on_update( fn on_update(
update: Event, update: Event,
container: &MenuBar, container: &gtk::Box,
menus: &mut HashMap<Box<str>, TrayMenu>, menus: &mut HashMap<Box<str>, TrayMenu>,
icon_theme: &IconTheme, icon_theme: &IconTheme,
icon_size: u32, icon_size: u32,
@ -184,7 +151,7 @@ fn on_update(
debug!("Received new tray item at '{address}': {item:?}"); debug!("Received new tray item at '{address}': {item:?}");
let mut menu_item = TrayMenu::new(*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) { if let Ok(image) = icon::get_image(&menu_item, icon_theme, icon_size, prefer_icons) {
menu_item.set_image(&image); menu_item.set_image(&image);