Skip to content

Commit e7c56ee

Browse files
authored
Merge pull request #780 from JakeStanger/fix/tray-focus
Fix tray focus issues on Sway
2 parents 3f8afa9 + f161429 commit e7c56ee

File tree

4 files changed

+48
-71
lines changed

4 files changed

+48
-71
lines changed

Diff for: docs/modules/Clock.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ Clicking on the widget opens a popup with the time and a calendar.
88

99
> Type: `clock`
1010
11-
| Name | Type | Default | Description |
12-
|----------------|----------|------------------------------------|-------------------------------------------------------------------------------------|
13-
| `format` | `string` | `%d/%m/%Y %H:%M` | Date/time format string. Pango markup is supported. |
14-
| `format_popup` | `string` | `%H:%M:%S` | Date/time format string to display in the popup header. Pango markup is supported. |
15-
| `locale` | `string` | `$LC_TIME` or `$LANG` or `'POSIX'` | Locale to use (eg `en_GB`). Defaults to the system language (reading from env var). |
16-
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the time on the clock button. |
11+
| Name | Type | Default | Description |
12+
|----------------|------------------------------------------------------------|------------------------------------|-------------------------------------------------------------------------------------|
13+
| `format` | `string` | `%d/%m/%Y %H:%M` | Date/time format string. Pango markup is supported. |
14+
| `format_popup` | `string` | `%H:%M:%S` | Date/time format string to display in the popup header. Pango markup is supported. |
15+
| `locale` | `string` | `$LC_TIME` or `$LANG` or `'POSIX'` | Locale to use (eg `en_GB`). Defaults to the system language (reading from env var). |
16+
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the time on the clock button. |
1717

1818
> Detail on available tokens can be found here: <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>
1919

Diff for: docs/modules/Tray.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ Displays a fully interactive icon tray using the KDE `libappindicator` protocol.
66

77
> Type: `tray`
88
9-
| Name | Type | Default | Description |
10-
|----------------------|-----------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
11-
| `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` |
12-
| `icon_size` | `integer` | `16` | Size in pixels to display tray icons as. |
13-
| `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. |
9+
| Name | Type | Default | Description |
10+
|----------------------|------------------------------------------------------------|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
11+
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | Matches bar orientation | The direction in which to pack tray icons. |
12+
| `icon_size` | `integer` | `16` | Size in pixels to display tray icons as. |
13+
| `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. |
1414

1515
<details>
1616
<summary>JSON</summary>

Diff for: src/modules/tray/interface.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use glib::Propagation;
2+
use gtk::gdk::Gravity;
13
use gtk::prelude::*;
2-
use gtk::{Image, Label, MenuItem};
4+
use gtk::{EventBox, Image, Label, MenuItem};
35
use system_tray::item::{IconPixmap, StatusNotifierItem, Tooltip};
46

57
/// Main tray icon to show on the bar
68
pub(crate) struct TrayMenu {
9+
pub event_box: EventBox,
710
pub widget: MenuItem,
8-
menu_widget: Option<system_tray::gtk_menu::Menu>,
911
image_widget: Option<Image>,
1012
label_widget: Option<Label>,
1113

@@ -17,12 +19,17 @@ pub(crate) struct TrayMenu {
1719

1820
impl TrayMenu {
1921
pub fn new(item: StatusNotifierItem) -> Self {
22+
let event_box = EventBox::new();
23+
2024
let widget = MenuItem::new();
2125
widget.style_context().add_class("item");
26+
event_box.add(&widget);
27+
28+
event_box.show_all();
2229

2330
Self {
31+
event_box,
2432
widget,
25-
menu_widget: None,
2633
image_widget: None,
2734
label_widget: None,
2835
title: item.title,
@@ -99,7 +106,10 @@ impl TrayMenu {
99106
}
100107

101108
pub fn set_menu_widget(&mut self, menu: system_tray::gtk_menu::Menu) {
102-
self.widget.set_submenu(Some(&menu));
103-
self.menu_widget = Some(menu);
109+
self.event_box
110+
.connect_button_press_event(move |event_box, _event| {
111+
menu.popup_at_widget(event_box, Gravity::North, Gravity::South, None);
112+
Propagation::Proceed
113+
});
104114
}
105115
}

Diff for: src/modules/tray/mod.rs

+22-55
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ mod icon;
22
mod interface;
33

44
use crate::clients::tray;
5-
use crate::config::CommonConfig;
5+
use crate::config::{CommonConfig, ModuleOrientation};
66
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
77
use crate::{glib_recv, lock, module_impl, send_async, spawn};
88
use color_eyre::{Report, Result};
9-
use gtk::{prelude::*, PackDirection};
10-
use gtk::{IconTheme, MenuBar};
9+
use gtk::prelude::*;
10+
use gtk::{IconTheme, Orientation};
1111
use interface::TrayMenu;
1212
use serde::Deserialize;
1313
use std::collections::HashMap;
@@ -32,15 +32,13 @@ pub struct TrayModule {
3232
#[serde(default = "default_icon_size")]
3333
icon_size: u32,
3434

35-
/// Direction to display the tray items.
35+
/// The direction in which to pack tray icons.
3636
///
37-
/// **Valid options**: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left`
37+
/// **Valid options**: `horizontal`, `vertical`
3838
/// <br>
39-
/// **Default**: `left_to_right` if bar is horizontal, `top_to_bottom` if bar is vertical
40-
#[serde(default, deserialize_with = "deserialize_pack_direction")]
41-
#[cfg_attr(feature = "schema", schemars(schema_with = "schema_pack_direction"))]
42-
direction: Option<PackDirection>,
43-
39+
/// **Default**: `horizontal` for horizontal bars, `vertical` for vertical bars
40+
#[serde(default)]
41+
direction: Option<ModuleOrientation>,
4442
/// See [common options](module-level-options#common-options).
4543
#[serde(flatten)]
4644
pub common: Option<CommonConfig>,
@@ -50,36 +48,7 @@ const fn default_icon_size() -> u32 {
5048
16
5149
}
5250

53-
fn deserialize_pack_direction<'de, D>(deserializer: D) -> Result<Option<PackDirection>, D::Error>
54-
where
55-
D: serde::Deserializer<'de>,
56-
{
57-
let value = Option::<String>::deserialize(deserializer)?;
58-
value
59-
.map(|v| match v.as_str() {
60-
"left_to_right" => Ok(PackDirection::Ltr),
61-
"right_to_left" => Ok(PackDirection::Rtl),
62-
"top_to_bottom" => Ok(PackDirection::Ttb),
63-
"bottom_to_top" => Ok(PackDirection::Btt),
64-
_ => Err(serde::de::Error::custom("invalid value for direction")),
65-
})
66-
.transpose()
67-
}
68-
69-
#[cfg(feature = "schema")]
70-
fn schema_pack_direction(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
71-
use schemars::JsonSchema;
72-
let mut schema: schemars::schema::SchemaObject = <String>::json_schema(gen).into();
73-
schema.enum_values = Some(vec![
74-
"top_to_bottom".into(),
75-
"bottom_to_top".into(),
76-
"left_to_right".into(),
77-
"right_to_left".into(),
78-
]);
79-
schema.into()
80-
}
81-
82-
impl Module<MenuBar> for TrayModule {
51+
impl Module<gtk::Box> for TrayModule {
8352
type SendMessage = Event;
8453
type ReceiveMessage = ActivateRequest;
8554

@@ -137,19 +106,17 @@ impl Module<MenuBar> for TrayModule {
137106
self,
138107
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
139108
info: &ModuleInfo,
140-
) -> Result<ModuleParts<MenuBar>> {
141-
let container = MenuBar::new();
142-
143-
let direction = self.direction.unwrap_or(
144-
if info.bar_position.orientation() == gtk::Orientation::Vertical {
145-
PackDirection::Ttb
146-
} else {
147-
PackDirection::Ltr
148-
},
149-
);
150-
151-
container.set_pack_direction(direction);
152-
container.set_child_pack_direction(direction);
109+
) -> Result<ModuleParts<gtk::Box>> {
110+
let orientation = self
111+
.direction
112+
.map(Orientation::from)
113+
.unwrap_or(info.bar_position.orientation());
114+
115+
// We use a `Box` here instead of the (supposedly correct) `MenuBar`
116+
// as the latter has issues on Sway with menus focus-stealing from the bar.
117+
//
118+
// Each widget is wrapped in an EventBox, copying what Waybar does here.
119+
let container = gtk::Box::new(orientation, 10);
153120

154121
{
155122
let container = container.clone();
@@ -173,7 +140,7 @@ impl Module<MenuBar> for TrayModule {
173140
/// getting the diff since the previous update and applying it to the menu.
174141
fn on_update(
175142
update: Event,
176-
container: &MenuBar,
143+
container: &gtk::Box,
177144
menus: &mut HashMap<Box<str>, TrayMenu>,
178145
icon_theme: &IconTheme,
179146
icon_size: u32,
@@ -184,7 +151,7 @@ fn on_update(
184151
debug!("Received new tray item at '{address}': {item:?}");
185152

186153
let mut menu_item = TrayMenu::new(*item);
187-
container.add(&menu_item.widget);
154+
container.pack_start(&menu_item.event_box, true, true, 0);
188155

189156
if let Ok(image) = icon::get_image(&menu_item, icon_theme, icon_size, prefer_icons) {
190157
menu_item.set_image(&image);

0 commit comments

Comments
 (0)