-
Notifications
You must be signed in to change notification settings - Fork 569
Make open/save dialogs no longer synchronous (in GTK) #1302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,6 @@ use std::any::Any; | |
| use std::cell::{Cell, RefCell}; | ||
| use std::convert::TryFrom; | ||
| use std::ffi::c_void; | ||
| use std::ffi::OsString; | ||
| use std::os::raw::{c_int, c_uint}; | ||
| use std::panic::Location; | ||
| use std::ptr; | ||
|
|
@@ -45,7 +44,7 @@ use crate::piet::ImageFormat; | |
| use crate::region::Region; | ||
| use crate::scale::{Scalable, Scale, ScaledArea}; | ||
| use crate::window; | ||
| use crate::window::{IdleToken, TimerToken, WinHandler, WindowLevel}; | ||
| use crate::window::{DeferredOp, FileDialogToken, IdleToken, TimerToken, WinHandler, WindowLevel}; | ||
|
|
||
| use super::application::Application; | ||
| use super::dialog; | ||
|
|
@@ -130,6 +129,8 @@ pub(crate) struct WindowState { | |
| /// Used to determine whether to honor close requests from the system: we inhibit them unless | ||
| /// this is true, and this gets set to true when our client requests a close. | ||
| closing: Cell<bool>, | ||
| /// A counter for generating unique tokens. | ||
| next_token: Cell<usize>, | ||
| drawing_area: DrawingArea, | ||
| // A cairo surface for us to render to; we copy this to the drawing_area whenever necessary. | ||
| // This extra buffer is necessitated by DrawingArea's painting model: when our paint callback | ||
|
|
@@ -149,6 +150,7 @@ pub(crate) struct WindowState { | |
| pub(crate) handler: RefCell<Box<dyn WinHandler>>, | ||
| idle_queue: Arc<Mutex<Vec<IdleKind>>>, | ||
| current_keycode: Cell<Option<u16>>, | ||
| deferred_queue: RefCell<Vec<DeferredOp>>, | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
|
|
@@ -243,13 +245,15 @@ impl WindowBuilder { | |
| scale: Cell::new(scale), | ||
| area: Cell::new(area), | ||
| closing: Cell::new(false), | ||
| next_token: Cell::new(0), | ||
| drawing_area, | ||
| surface: RefCell::new(None), | ||
| surface_size: Cell::new((0, 0)), | ||
| invalid: RefCell::new(Region::EMPTY), | ||
| handler: RefCell::new(handler), | ||
| idle_queue: Arc::new(Mutex::new(vec![])), | ||
| current_keycode: Cell::new(None), | ||
| deferred_queue: RefCell::new(Vec::new()), | ||
| }); | ||
|
|
||
| self.app | ||
|
|
@@ -623,7 +627,10 @@ impl WindowState { | |
| return None; | ||
| } | ||
|
|
||
| self.with_handler_and_dont_check_the_other_borrows(f) | ||
| let ret = self.with_handler_and_dont_check_the_other_borrows(f); | ||
|
|
||
| self.run_deferred(); | ||
| ret | ||
| } | ||
|
|
||
| #[track_caller] | ||
|
|
@@ -640,6 +647,12 @@ impl WindowState { | |
| } | ||
| } | ||
|
|
||
| fn next_token(&self) -> usize { | ||
| let next = self.next_token.get(); | ||
| self.next_token.set(next + 1); | ||
| next | ||
| } | ||
|
|
||
| fn resize_surface(&self, width: i32, height: i32) -> Result<(), anyhow::Error> { | ||
| fn next_size(x: i32) -> i32 { | ||
| // We round up to the nearest multiple of `accuracy`, which is between x/2 and x/4. | ||
|
|
@@ -690,6 +703,39 @@ impl WindowState { | |
| log::warn!("Not invalidating rect because region already borrowed"); | ||
| } | ||
| } | ||
|
|
||
| /// Pushes a deferred op onto the queue. | ||
| fn defer(&self, op: DeferredOp) { | ||
| self.deferred_queue.borrow_mut().push(op); | ||
| } | ||
|
|
||
| fn run_deferred(&self) { | ||
| let queue = self.deferred_queue.replace(Vec::new()); | ||
| for op in queue { | ||
| match op { | ||
| DeferredOp::Open(options, token) => { | ||
| let file_info = dialog::get_file_dialog_path( | ||
| self.window.upcast_ref(), | ||
| FileDialogType::Open, | ||
| options, | ||
| ) | ||
| .ok() | ||
| .map(|s| FileInfo { path: s.into() }); | ||
| self.with_handler(|h| h.open_file(token, file_info)); | ||
| } | ||
| DeferredOp::SaveAs(options, token) => { | ||
| let file_info = dialog::get_file_dialog_path( | ||
| self.window.upcast_ref(), | ||
| FileDialogType::Save, | ||
| options, | ||
| ) | ||
| .ok() | ||
| .map(|s| FileInfo { path: s.into() }); | ||
| self.with_handler(|h| h.save_as(token, file_info)); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl WindowHandle { | ||
|
|
@@ -900,16 +946,34 @@ impl WindowHandle { | |
| } | ||
| } | ||
|
|
||
| pub fn open_file_sync(&mut self, options: FileDialogOptions) -> Option<FileInfo> { | ||
| self.file_dialog(FileDialogType::Open, options) | ||
| .ok() | ||
| .map(|s| FileInfo { path: s.into() }) | ||
| pub fn open_file(&mut self, options: FileDialogOptions) -> Option<FileDialogToken> { | ||
| if let Some(state) = self.state.upgrade() { | ||
| let tok = FileDialogToken::new(state.next_token()); | ||
| state.defer(DeferredOp::Open(options, tok)); | ||
| Some(tok) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| pub fn save_as_sync(&mut self, options: FileDialogOptions) -> Option<FileInfo> { | ||
| self.file_dialog(FileDialogType::Save, options) | ||
| .ok() | ||
| .map(|s| FileInfo { path: s.into() }) | ||
| pub fn save_as(&mut self, options: FileDialogOptions) -> Option<FileDialogToken> { | ||
| if let Some(state) = self.state.upgrade() { | ||
| let tok = FileDialogToken::new(state.next_token()); | ||
| state.defer(DeferredOp::SaveAs(options, tok)); | ||
| Some(tok) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| pub fn save_as_sync(&mut self, _options: FileDialogOptions) -> Option<FileInfo> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. am I understanding his correctly that with this patch,
This comment was marked as duplicate.
Sorry, something went wrong.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. The current situation is that druid papers over the druid-shell API nastiness. I did a quick The plan is to implement Any druid users that are using the |
||
| log::error!("save as sync no longer supported on GTK"); | ||
| None | ||
| } | ||
|
|
||
| pub fn open_file_sync(&mut self, _options: FileDialogOptions) -> Option<FileInfo> { | ||
| log::error!("open file sync no longer supported on GTK"); | ||
| None | ||
| } | ||
|
|
||
| /// Get a handle that can be used to schedule an idle task. | ||
|
|
@@ -971,18 +1035,6 @@ impl WindowHandle { | |
| state.window.set_title(&(title.into())); | ||
| } | ||
| } | ||
|
|
||
| fn file_dialog( | ||
| &self, | ||
| ty: FileDialogType, | ||
| options: FileDialogOptions, | ||
| ) -> Result<OsString, ShellError> { | ||
| if let Some(state) = self.state.upgrade() { | ||
| dialog::get_file_dialog_path(state.window.upcast_ref(), ty, options) | ||
| } else { | ||
| Err(anyhow!("Cannot upgrade state from weak pointer to arc").into()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| unsafe impl Send for IdleHandle {} | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.