Skip to content

Commit

Permalink
Post-merge cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Nov 23, 2024
1 parent c7c9537 commit 0177c1e
Show file tree
Hide file tree
Showing 6 changed files with 409 additions and 70 deletions.
10 changes: 0 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ objc2-app-kit = { version = "0.2.0", features = [
"NSView",
"NSWindow",
] }
deferred-future = "0.1.5"
core-foundation = "0.10.0"
core-foundation-sys = "0.8.7"

Expand Down
25 changes: 15 additions & 10 deletions examples/msg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ::std::io::{ Read, self };
use ::futures::executor::block_on;
use std::io::{self, Read};

fn main() {
#[cfg(not(feature = "gtk3"))]
let res = "";
Expand All @@ -23,16 +23,18 @@ fn main() {
.set_buttons(rfd::MessageButtons::OkCancel)
.set_level(rfd::MessageLevel::Error)
.show();
println!("被点击按钮是 {}。敲击 Ctrl+D 继续。", res);
println!("res: {}, Ctrl+D", res);

let mut stdin = io::stdin();
let mut buffer: Vec<u8> = vec![];
stdin.read_to_end(&mut buffer).unwrap();

#[cfg(any(
target_os = "windows",
target_os = "macos",
all(
any(
target_os = "linux",
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
Expand All @@ -41,17 +43,20 @@ fn main() {
feature = "gtk3"
)
))]
block_on(async move {
futures::executor::block_on(async move {
let res = rfd::AsyncMessageDialog::new()
.set_title("Msg!")
.set_description("Description!")
.set_buttons(rfd::MessageButtons::OkCancel)
.show().await;
println!("被点击按钮是 {}", res);
.show()
.await;
println!("res: {}", res);
});
println!("敲击 Ctrl+D 继续。");

println!("Ctrl+D");
let mut stdin = io::stdin();
let mut buffer: Vec<u8> = vec![];
stdin.read_to_end(&mut buffer).unwrap();
println!("结束");
}
println!();
}

186 changes: 137 additions & 49 deletions src/backend/macos/utils/user_alert.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
use ::objc2_foundation::MainThreadMarker;
use ::deferred_future::ThreadDeferredFuture;
use ::std::{ mem::MaybeUninit, ptr, sync::PoisonError, thread };
use ::core_foundation::{ base::TCFType, string::CFString };
use ::core_foundation_sys::{ base::CFOptionFlags, date::CFTimeInterval, url::CFURLRef, user_notification::{ CFUserNotificationDisplayAlert, kCFUserNotificationStopAlertLevel, kCFUserNotificationCautionAlertLevel, kCFUserNotificationNoteAlertLevel, kCFUserNotificationDefaultResponse, kCFUserNotificationAlternateResponse, kCFUserNotificationOtherResponse, kCFUserNotificationCancelResponse } };
use crate::{
message_dialog::{ MessageButtons, MessageDialog, MessageDialogResult, MessageLevel },
backend::{ DialogFutureType, macos::utils::{ FocusManager, PolicyManager } }
backend::{
macos::utils::{FocusManager, PolicyManager},
DialogFutureType,
},
message_dialog::{MessageButtons, MessageDialog, MessageDialogResult, MessageLevel},
};

use core_foundation::{base::TCFType, string::CFString};
use core_foundation_sys::{
base::CFOptionFlags,
date::CFTimeInterval,
url::CFURLRef,
user_notification::{
kCFUserNotificationAlternateResponse, kCFUserNotificationCancelResponse,
kCFUserNotificationCautionAlertLevel, kCFUserNotificationDefaultResponse,
kCFUserNotificationNoteAlertLevel, kCFUserNotificationOtherResponse,
kCFUserNotificationStopAlertLevel, CFUserNotificationDisplayAlert,
},
};
use objc2_foundation::MainThreadMarker;

use std::{mem::MaybeUninit, ptr, thread};

struct UserAlert {
timeout: CFTimeInterval,
flags: CFOptionFlags,
Expand All @@ -22,16 +37,29 @@ struct UserAlert {
_focus_manager: Option<FocusManager>,
_policy_manager: Option<PolicyManager>,
}

impl UserAlert {
fn new(opt: MessageDialog, mtm: Option<MainThreadMarker>) -> Self {
let mut buttons: [Option<String>; 3] = match &opt.buttons {
MessageButtons::Ok => [None, None, None],
MessageButtons::OkCancel => [None, Some("Cancel".to_string()), None],
MessageButtons::YesNo => [Some("Yes".to_string()), Some("No".to_string()), None],
MessageButtons::YesNoCancel => [Some("Yes".to_string()), Some("No".to_string()), Some("Cancel".to_string())],
MessageButtons::YesNoCancel => [
Some("Yes".to_string()),
Some("No".to_string()),
Some("Cancel".to_string()),
],
MessageButtons::OkCustom(ok_text) => [Some(ok_text.to_string()), None, None],
MessageButtons::OkCancelCustom(ok_text, cancel_text) => [Some(ok_text.to_string()), Some(cancel_text.to_string()), None],
MessageButtons::YesNoCancelCustom(yes_text, no_text, cancel_text) => [Some(yes_text.to_string()), Some(no_text.to_string()), Some(cancel_text.to_string())]
MessageButtons::OkCancelCustom(ok_text, cancel_text) => [
Some(ok_text.to_string()),
Some(cancel_text.to_string()),
None,
],
MessageButtons::YesNoCancelCustom(yes_text, no_text, cancel_text) => [
Some(yes_text.to_string()),
Some(no_text.to_string()),
Some(cancel_text.to_string()),
],
};
UserAlert {
timeout: 0_f64,
Expand All @@ -41,7 +69,7 @@ impl UserAlert {
flags: match opt.level {
MessageLevel::Info => kCFUserNotificationNoteAlertLevel,
MessageLevel::Warning => kCFUserNotificationCautionAlertLevel,
MessageLevel::Error => kCFUserNotificationStopAlertLevel
MessageLevel::Error => kCFUserNotificationStopAlertLevel,
},
alert_header: opt.title,
alert_message: opt.description,
Expand All @@ -50,29 +78,38 @@ impl UserAlert {
other_button_title: buttons[2].take(),
buttons: opt.buttons,
_policy_manager: mtm.map(|mtm| PolicyManager::new(mtm)),
_focus_manager: mtm.map(|mtm| FocusManager::new(mtm))
_focus_manager: mtm.map(|mtm| FocusManager::new(mtm)),
}
}

fn run(self) -> MessageDialogResult {
let alert_header = CFString::new(&self.alert_header[..]);
let alert_header = CFString::new(&self.alert_header[..]);
let alert_message = CFString::new(&self.alert_message[..]);
let default_button_title = self.default_button_title.map(|string| CFString::new(&string[..]));
let alternate_button_title = self.alternate_button_title.map(|value| CFString::new(&value[..]));
let other_button_title = self.other_button_title.map(|value| CFString::new(&value[..]));
let default_button_title = self
.default_button_title
.map(|string| CFString::new(&string[..]));
let alternate_button_title = self
.alternate_button_title
.map(|value| CFString::new(&value[..]));
let other_button_title = self
.other_button_title
.map(|value| CFString::new(&value[..]));
let mut response_flags = MaybeUninit::<CFOptionFlags>::uninit();
let is_cancel = unsafe { CFUserNotificationDisplayAlert(
self.timeout,
self.flags,
self.icon_url,
self.sound_url,
self.localization_url,
alert_header.as_concrete_TypeRef(),
alert_message.as_concrete_TypeRef(),
default_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
alternate_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
other_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
response_flags.as_mut_ptr()
) };
let is_cancel = unsafe {
CFUserNotificationDisplayAlert(
self.timeout,
self.flags,
self.icon_url,
self.sound_url,
self.localization_url,
alert_header.as_concrete_TypeRef(),
alert_message.as_concrete_TypeRef(),
default_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
alternate_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
other_button_title.map_or(ptr::null(), |value| value.as_concrete_TypeRef()),
response_flags.as_mut_ptr(),
)
};
if is_cancel != 0 {
return MessageDialogResult::Cancel;
}
Expand All @@ -81,34 +118,85 @@ impl UserAlert {
return MessageDialogResult::Cancel;
}
match self.buttons {
MessageButtons::Ok if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Ok,
MessageButtons::OkCancel if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Ok,
MessageButtons::OkCancel if response == kCFUserNotificationAlternateResponse => MessageDialogResult::Cancel,
MessageButtons::YesNo if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Yes,
MessageButtons::YesNo if response == kCFUserNotificationAlternateResponse => MessageDialogResult::No,
MessageButtons::YesNoCancel if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Yes,
MessageButtons::YesNoCancel if response == kCFUserNotificationAlternateResponse => MessageDialogResult::No,
MessageButtons::YesNoCancel if response == kCFUserNotificationOtherResponse => MessageDialogResult::Cancel,
MessageButtons::OkCustom(custom) if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::OkCancelCustom(custom, _) if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::OkCancelCustom(_, custom) if response == kCFUserNotificationAlternateResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::YesNoCancelCustom(custom, _, _) if response == kCFUserNotificationDefaultResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::YesNoCancelCustom(_, custom, _) if response == kCFUserNotificationAlternateResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::YesNoCancelCustom(_, _, custom) if response == kCFUserNotificationOtherResponse => MessageDialogResult::Custom(custom.to_owned()),
MessageButtons::Ok if response == kCFUserNotificationDefaultResponse => {
MessageDialogResult::Ok
}
MessageButtons::OkCancel if response == kCFUserNotificationDefaultResponse => {
MessageDialogResult::Ok
}
MessageButtons::OkCancel if response == kCFUserNotificationAlternateResponse => {
MessageDialogResult::Cancel
}
MessageButtons::YesNo if response == kCFUserNotificationDefaultResponse => {
MessageDialogResult::Yes
}
MessageButtons::YesNo if response == kCFUserNotificationAlternateResponse => {
MessageDialogResult::No
}
MessageButtons::YesNoCancel if response == kCFUserNotificationDefaultResponse => {
MessageDialogResult::Yes
}
MessageButtons::YesNoCancel if response == kCFUserNotificationAlternateResponse => {
MessageDialogResult::No
}
MessageButtons::YesNoCancel if response == kCFUserNotificationOtherResponse => {
MessageDialogResult::Cancel
}
MessageButtons::OkCustom(custom) if response == kCFUserNotificationDefaultResponse => {
MessageDialogResult::Custom(custom.to_owned())
}
MessageButtons::OkCancelCustom(custom, _)
if response == kCFUserNotificationDefaultResponse =>
{
MessageDialogResult::Custom(custom.to_owned())
}
MessageButtons::OkCancelCustom(_, custom)
if response == kCFUserNotificationAlternateResponse =>
{
MessageDialogResult::Custom(custom.to_owned())
}
MessageButtons::YesNoCancelCustom(custom, _, _)
if response == kCFUserNotificationDefaultResponse =>
{
MessageDialogResult::Custom(custom.to_owned())
}
MessageButtons::YesNoCancelCustom(_, custom, _)
if response == kCFUserNotificationAlternateResponse =>
{
MessageDialogResult::Custom(custom.to_owned())
}
MessageButtons::YesNoCancelCustom(_, _, custom)
if response == kCFUserNotificationOtherResponse =>
{
MessageDialogResult::Custom(custom.to_owned())
}
_ => MessageDialogResult::Cancel,
}
}
}

pub fn sync_pop_dialog(opt: MessageDialog, mtm: MainThreadMarker) -> MessageDialogResult {
UserAlert::new(opt, Some(mtm)).run()
}

pub fn async_pop_dialog(opt: MessageDialog) -> DialogFutureType<MessageDialogResult> {
let deferred_future = ThreadDeferredFuture::default();
let defer = deferred_future.defer();
let (tx, rx) = crate::oneshot::channel();

thread::spawn(move || {
let mut defer = defer.lock().unwrap_or_else(PoisonError::into_inner);
let message_dialog_result = UserAlert::new(opt.clone(), None).run();
defer.complete(message_dialog_result);
if let Err(err) = tx.send(message_dialog_result) {
log::error!("UserAler result send error: {err}");
}
});
Box::pin(deferred_future)
}

Box::pin(async {
match rx.await {
Ok(res) => res,
Err(err) => {
log::error!("UserAler error: {err}");
MessageDialogResult::Cancel
}
}
})
}

2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ mod file_handle;
pub use file_handle::FileHandle;

mod file_dialog;
#[cfg(target_os = "macos")]
mod oneshot;

#[cfg(not(target_arch = "wasm32"))]
pub use file_dialog::FileDialog;
Expand Down
Loading

0 comments on commit 0177c1e

Please sign in to comment.