Skip to content

Commit

Permalink
refactor: fix and enhance the about menu on Linux (rust-windowing#347)
Browse files Browse the repository at this point in the history
* refactor: fix and enhance the about menu on Linux

* simplify

* apply code review suggestions
  • Loading branch information
lucasfernog authored Mar 25, 2022
1 parent 5abdbd1 commit 84c677f
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .changes/enhance-about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tao": minor
---

Enhance the `MenuItem::About` menu on Linux.
**Breaking change:** The About variant now uses an struct instead of a string.
5 changes: 5 additions & 0 deletions .changes/fix-about-menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Fixes the About menu on Linux not being shown.
9 changes: 8 additions & 1 deletion examples/custom_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
keyboard::KeyCode,
menu::{MenuBar as Menu, MenuItem, MenuItemAttributes, MenuType},
menu::{AboutMetadata, MenuBar as Menu, MenuItem, MenuItemAttributes, MenuType},
window::WindowBuilder,
};

Expand Down Expand Up @@ -40,6 +40,13 @@ fn main() {
// in macOS native item are required to get keyboard shortcut
// to works correctly
first_menu.add_native_item(MenuItem::Copy);
first_menu.add_native_item(MenuItem::About(
"tao".into(),
AboutMetadata {
version: Some("1.0.0".into()),
..Default::default()
},
));

// Create custom Copy menu with our clipboard object
let custom_insert_clipboard = first_menu.add_item(MenuItemAttributes::new("Insert clipboard"));
Expand Down
30 changes: 28 additions & 2 deletions src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,29 @@ impl Default for MenuBar {
}
}

/// Application metadata for the [`MenuItem::About`] action.
///
/// ## Platform-specific
///
/// - **Windows / macOS / Android / iOS:** The metadata is ignored on these platforms.
#[derive(Debug, Clone, Default)]
pub struct AboutMetadata {
/// The application name.
pub version: Option<String>,
/// The authors of the application.
pub authors: Option<Vec<String>>,
/// Application comments.
pub comments: Option<String>,
/// The copyright of the application.
pub copyright: Option<String>,
/// The license of the application.
pub license: Option<String>,
/// The application website.
pub website: Option<String>,
/// The website label.
pub website_label: Option<String>,
}

/// A menu item, bound to a pre-defined native action.
///
/// Note some platforms might not support some of the variants.
Expand All @@ -195,13 +218,16 @@ impl Default for MenuBar {
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum MenuItem {
/// Shows a standard "About" item
/// Shows a standard "About" item.
///
/// The first value is the application name, and the second is its metadata.
///
/// ## Platform-specific
///
/// - **Windows / Android / iOS:** Unsupported
/// - **Linux:** The metadata is only applied on Linux
///
About(String),
About(String, AboutMetadata),

/// A standard "hide the app" menu item.
///
Expand Down
37 changes: 32 additions & 5 deletions src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::{
use gdk::{Cursor, CursorType, EventKey, EventMask, WindowEdge, WindowState};
use gio::{prelude::*, Cancellable};
use glib::{source::Priority, Continue, MainContext};
use gtk::{prelude::*, AboutDialog, Inhibit};
use gtk::{builders::AboutDialogBuilder, prelude::*, Inhibit};

use crate::{
accelerator::AcceleratorId,
Expand Down Expand Up @@ -688,10 +688,37 @@ impl<T: 'static> EventLoop<T> {
log::warn!("Failed to send menu event to event channel: {}", e);
}
}
(Some(MenuItem::About(_)), None) => {
let about = AboutDialog::new();
about.show_all();
app_.add_window(&about);
(Some(MenuItem::About(name, app)), None) => {
let mut builder = AboutDialogBuilder::new()
.program_name(&name)
.modal(true)
.resizable(false);
if let Some(version) = &app.version {
builder = builder.version(version);
}
if let Some(authors) = app.authors {
builder = builder.authors(authors);
}
if let Some(comments) = &app.comments {
builder = builder.comments(comments);
}
if let Some(copyright) = &app.copyright {
builder = builder.copyright(copyright);
}
if let Some(license) = &app.license {
builder = builder.license(license);
}
if let Some(website) = &app.website {
builder = builder.website(website);
}
if let Some(website_label) = &app.website_label {
builder = builder.website_label(website_label);
}
let about = builder.build();
about.run();
unsafe {
about.destroy();
}
}
(Some(MenuItem::Hide), None) => window.hide(),
(Some(MenuItem::CloseWindow), None) => window.close(),
Expand Down
20 changes: 16 additions & 4 deletions src/platform_impl/linux/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ use crate::{
macro_rules! menuitem {
( $description:expr, $key:expr, $accel_group:ident, $window_id:expr, $native_menu_item:expr, $tx:ident ) => {{
let item = GtkMenuItem::with_label($description);
let (key, mods) = gtk::accelerator_parse($key);
item.add_accelerator("activate", $accel_group, key, mods, AccelFlags::VISIBLE);
if !$key.is_empty() {
let (key, mods) = gtk::accelerator_parse($key);
item.add_accelerator("activate", $accel_group, key, mods, AccelFlags::VISIBLE);
}
item.connect_activate(move |_| {
if let Err(e) = $tx.send(($window_id, WindowRequest::Menu(($native_menu_item, None)))) {
log::warn!("Fail to send native menu request: {}", e);
Expand Down Expand Up @@ -244,9 +246,19 @@ impl Menu {
}
GtkMenuInfo {
menu_type: GtkMenuType::Native,
menu_item: Some(MenuItem::About(s)),
menu_item: Some(MenuItem::About(name, app)),
..
} => Some(GtkMenuItem::with_label(&format!("About {}", s))),
} => {
let tx_clone = tx.clone();
menuitem!(
&format!("About {}", name),
"",
accel_group,
window_id,
Some(MenuItem::About(name.clone(), app.clone())),
tx_clone
)
}
GtkMenuInfo {
menu_type: GtkMenuType::Native,
menu_item: Some(MenuItem::Hide),
Expand Down
4 changes: 2 additions & 2 deletions src/platform_impl/macos/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ impl Menu {
}
None
}
MenuItem::About(app_name) => {
let title = format!("About {}", app_name);
MenuItem::About(name, _) => {
let title = format!("About {}", name);
Some((
None,
make_menu_item(
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/macos/util/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use objc::{

use crate::{
dpi::LogicalSize,
platform_impl::platform::{ffi, menu, util::IdRef, window::SharedState},
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
};

// Unsafe wrapper type that allows us to dispatch things that aren't Send.
Expand Down

0 comments on commit 84c677f

Please sign in to comment.