Skip to content

Commit 652fab4

Browse files
committed
live-preview: Update the code handling the menu on apple
Done-with: @tronical
1 parent bf66b86 commit 652fab4

File tree

3 files changed

+83
-81
lines changed

3 files changed

+83
-81
lines changed

tools/lsp/preview/connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod wasm;
77
pub use wasm::*;
88

99
#[cfg(all(not(target_arch = "wasm32"), feature = "preview-builtin"))]
10-
mod native;
10+
pub mod native;
1111
#[cfg(all(not(target_arch = "wasm32"), feature = "preview-builtin"))]
1212
pub use native::*;
1313

tools/lsp/preview/connector/native.rs

Lines changed: 79 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright © SixtyFPS GmbH <[email protected]>
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

4-
// cSpell: ignore condvar
5-
64
use crate::{common, preview};
75

86
use std::cell::RefCell;
@@ -182,10 +180,10 @@ impl Default for RemoteControlledPreviewToLsp {
182180
}
183181

184182
impl RemoteControlledPreviewToLsp {
185-
/// Cretaes a RemoteConfrolledPreviewToLsp connector.
183+
/// Creates a RemoteConfrolledPreviewToLsp connector.
186184
///
187185
/// This means the applications lifetime is bound to the lifetime of the
188-
/// applications's STDIN: We quit as soon as that gets fishy or closed.
186+
/// application's STDIN: We quit as soon as that gets fishy or closed.
189187
///
190188
/// It also means we do not need to join the reader thread: The OS will clean
191189
/// that one up for us anyway.
@@ -223,79 +221,80 @@ impl common::PreviewToLsp for RemoteControlledPreviewToLsp {
223221
}
224222
}
225223

226-
// TODO: Re-enable this
227-
// #[cfg(target_vendor = "apple")]
228-
// fn toggle_always_on_top() {
229-
// use slint::ComponentHandle;
230-
// preview::PREVIEW_STATE.with_borrow_mut(move |preview_state| {
231-
// let Some(ui) = preview_state.ui.as_ref() else { return };
232-
// let api = ui.global::<crate::preview::ui::Api>();
233-
// api.set_always_on_top(!api.get_always_on_top());
234-
// });
235-
// }
236-
237-
// // This function overrides the default app menu and makes the "Quit" item merely hide the UI,
238-
// // as the life-cycle of this process is determined by the editor. The returned menuitem must
239-
// // be kept alive for the duration of the event loop, as otherwise muda crashes.
240-
// #[cfg(target_vendor = "apple")]
241-
// fn init_apple_platform(
242-
// ) -> Result<(muda::MenuItem, muda::CheckMenuItem), i_slint_core::api::PlatformError> {
243-
// use muda::{accelerator, CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu};
244-
245-
// let backend = i_slint_backend_winit::Backend::builder().with_default_menu_bar(false).build()?;
246-
247-
// slint::platform::set_platform(Box::new(backend)).map_err(|set_platform_err| {
248-
// i_slint_core::api::PlatformError::from(set_platform_err.to_string())
249-
// })?;
250-
251-
// let process_name = objc2_foundation::NSProcessInfo::processInfo().processName().to_string();
252-
// let reload_menu_item = MenuItem::new(
253-
// format!("Reload"),
254-
// true,
255-
// Some(accelerator::Accelerator::new(
256-
// Some(accelerator::Modifiers::META),
257-
// accelerator::Code::KeyR,
258-
// )),
259-
// );
260-
// let keep_on_top_menu_item = CheckMenuItem::new(format!("Keep on Top"), true, false, None);
261-
262-
// let menu_bar = Menu::new();
263-
// menu_bar.init_for_nsapp();
264-
// let app_m = Submenu::new("App", true);
265-
// let window_m = Submenu::new("&Window", true);
266-
// menu_bar
267-
// .append(&app_m)
268-
// .and_then(|_| menu_bar.append(&window_m))
269-
// .and_then(|_| {
270-
// app_m.append_items(&[
271-
// &PredefinedMenuItem::services(None),
272-
// &PredefinedMenuItem::separator(),
273-
// &PredefinedMenuItem::hide(None),
274-
// &PredefinedMenuItem::hide_others(None),
275-
// &PredefinedMenuItem::show_all(None),
276-
// &reload_menu_item,
277-
// ])
278-
// })
279-
// .and_then(|_| window_m.append_items(&[&keep_on_top_menu_item]))
280-
// .map_err(|menu_bar_err| {
281-
// i_slint_core::api::PlatformError::Other(menu_bar_err.to_string())
282-
// })?;
283-
284-
// let reload_id = reload_menu_item.id().clone();
285-
// let keep_on_top_id = keep_on_top_menu_item.id().clone();
286-
287-
// muda::MenuEvent::set_event_handler(Some(move |menu_event: muda::MenuEvent| {
288-
// let reload_id = reload_id.clone();
289-
// let keep_on_top_id = keep_on_top_id.clone();
290-
291-
// let _ = slint::invoke_from_event_loop(move || {
292-
// if menu_event.id == reload_id {
293-
// preview::reload_preview();
294-
// } else if menu_event.id == keep_on_top_id {
295-
// toggle_always_on_top();
296-
// }
297-
// });
298-
// }));
299-
300-
// Ok((reload_menu_item, keep_on_top_menu_item))
301-
// }
224+
#[cfg(target_vendor = "apple")]
225+
fn toggle_always_on_top() {
226+
use slint::ComponentHandle;
227+
preview::PREVIEW_STATE.with_borrow_mut(move |preview_state| {
228+
let Some(ui) = preview_state.ui.as_ref() else { return };
229+
let api = ui.global::<crate::preview::ui::Api>();
230+
api.set_always_on_top(!api.get_always_on_top());
231+
});
232+
}
233+
234+
// This function overrides the default app menu and makes the "Quit" item merely hide the UI,
235+
// as the life-cycle of this process is determined by the editor. The returned menuitem must
236+
// be kept alive for the duration of the event loop, as otherwise muda crashes.
237+
#[cfg(target_vendor = "apple")]
238+
pub fn init_apple_platform() -> Result<(), i_slint_core::api::PlatformError> {
239+
use muda::{accelerator, CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu};
240+
241+
let backend = i_slint_backend_winit::Backend::builder().with_default_menu_bar(false).build()?;
242+
243+
slint::platform::set_platform(Box::new(backend)).map_err(|set_platform_err| {
244+
i_slint_core::api::PlatformError::from(set_platform_err.to_string())
245+
})?;
246+
247+
let reload_menu_item = MenuItem::new(
248+
format!("Reload"),
249+
true,
250+
Some(accelerator::Accelerator::new(
251+
Some(accelerator::Modifiers::META),
252+
accelerator::Code::KeyR,
253+
)),
254+
);
255+
let keep_on_top_menu_item = CheckMenuItem::new(format!("Keep on Top"), true, false, None);
256+
257+
let menu_bar = Menu::new();
258+
menu_bar.init_for_nsapp();
259+
let app_m = Submenu::new("App", true);
260+
let window_m = Submenu::new("&Window", true);
261+
menu_bar
262+
.append(&app_m)
263+
.and_then(|_| menu_bar.append(&window_m))
264+
.and_then(|_| {
265+
app_m.append_items(&[
266+
&PredefinedMenuItem::services(None),
267+
&PredefinedMenuItem::separator(),
268+
&PredefinedMenuItem::hide(None),
269+
&PredefinedMenuItem::hide_others(None),
270+
&PredefinedMenuItem::show_all(None),
271+
&reload_menu_item,
272+
&PredefinedMenuItem::quit(Some("Quit Slint Live-Preview")),
273+
])
274+
})
275+
.and_then(|_| window_m.append_items(&[&keep_on_top_menu_item]))
276+
.map_err(|menu_bar_err| {
277+
i_slint_core::api::PlatformError::Other(menu_bar_err.to_string())
278+
})?;
279+
280+
let reload_id = reload_menu_item.id().clone();
281+
let keep_on_top_id = keep_on_top_menu_item.id().clone();
282+
283+
muda::MenuEvent::set_event_handler(Some(move |menu_event: muda::MenuEvent| {
284+
let reload_id = reload_id.clone();
285+
let keep_on_top_id = keep_on_top_id.clone();
286+
287+
let _ = slint::invoke_from_event_loop(move || {
288+
if menu_event.id == reload_id {
289+
preview::reload_preview();
290+
} else if menu_event.id == keep_on_top_id {
291+
toggle_always_on_top();
292+
}
293+
});
294+
}));
295+
296+
// Keep the menu items alive to prevent muda from crashing. The menu bar is a singleton, so this is an acceptable memory leak
297+
let _ = Box::leak(Box::new((reload_menu_item, keep_on_top_menu_item)));
298+
299+
Ok(())
300+
}

tools/lsp/preview/ui.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ pub fn create_ui(
3434
style: &str,
3535
experimental: bool,
3636
) -> Result<PreviewUi, PlatformError> {
37+
#[cfg(all(target_vendor = "apple", not(target_arch = "wasm32")))]
38+
crate::preview::connector::native::init_apple_platform()?;
39+
3740
let ui = PreviewUi::new()?;
3841

3942
// styles:

0 commit comments

Comments
 (0)