Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions druid-shell/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ pub use region::Region;
pub use scale::{Scalable, Scale, ScaledArea};
pub use screen::{Monitor, Screen};
pub use window::{
IdleHandle, IdleToken, TimerToken, WinHandler, WindowBuilder, WindowHandle, WindowLevel,
WindowState,
FileDialogToken, IdleHandle, IdleToken, TimerToken, WinHandler, WindowBuilder, WindowHandle,
WindowLevel, WindowState,
};

pub use keyboard_types;
98 changes: 75 additions & 23 deletions druid-shell/src/platform/gtk/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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)]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

am I understanding his correctly that with this patch, save_as_sync won't work on gtk, and save_as won't work elsewhere?

This comment was marked as duplicate.

Copy link
Member Author

Choose a reason for hiding this comment

The 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 rg on runebender and it looks like it should still work, because AFAICT you're using the druid commands instead of manually calling the WIndowHandle methods?

The plan is to implement save_as and open_file for the other backends (just windows and mac, really, because X11 and web don't support file dialogs yet anyway; and I can do windows soon). Then we delete the xxx_sync methods on WindowHandle and remove the fallback hack in druid.

Any druid users that are using the SHOW_OPEN_PANEL, etc, commands shouldn't even notice the change (except that they'll stop getting dropped event warnings).

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.
Expand Down Expand Up @@ -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 {}
Expand Down
12 changes: 11 additions & 1 deletion druid-shell/src/platform/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use crate::keyboard_types::KeyState;
use crate::mouse::{Cursor, CursorDesc, MouseButton, MouseButtons, MouseEvent};
use crate::region::Region;
use crate::scale::Scale;
use crate::window::{IdleToken, TimerToken, WinHandler, WindowLevel, WindowState};
use crate::window::{FileDialogToken, IdleToken, TimerToken, WinHandler, WindowLevel, WindowState};
use crate::Error;

#[allow(non_upper_case_globals)]
Expand Down Expand Up @@ -938,11 +938,21 @@ impl WindowHandle {
.map(|s| FileInfo { path: s.into() })
}

pub fn open_file(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO: implement this and get rid of open_file_sync
None
}

pub fn save_as_sync(&mut self, options: FileDialogOptions) -> Option<FileInfo> {
dialog::get_file_dialog_path(FileDialogType::Save, options)
.map(|s| FileInfo { path: s.into() })
}

pub fn save_as(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO: implement this and get rid of save_as_sync
None
}

/// Set the title for this menu.
pub fn set_title(&self, title: &str) {
unsafe {
Expand Down
10 changes: 9 additions & 1 deletion druid-shell/src/platform/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use crate::keyboard::{KbKey, KeyState, Modifiers};
use crate::mouse::{Cursor, CursorDesc, MouseButton, MouseButtons, MouseEvent};
use crate::region::Region;
use crate::window;
use crate::window::{IdleToken, TimerToken, WinHandler, WindowLevel};
use crate::window::{FileDialogToken, IdleToken, TimerToken, WinHandler, WindowLevel};

// This is a macro instead of a function since KeyboardEvent and MouseEvent has identical functions
// to query modifier key states.
Expand Down Expand Up @@ -571,13 +571,21 @@ impl WindowHandle {
.map(|s| FileInfo { path: s.into() })
}

pub fn open_file(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
None
}

pub fn save_as_sync(&mut self, options: FileDialogOptions) -> Option<FileInfo> {
log::warn!("save_as_sync is currently unimplemented for web.");
self.file_dialog(FileDialogType::Save, options)
.ok()
.map(|s| FileInfo { path: s.into() })
}

pub fn save_as(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
None
}

fn render_soon(&self) {
if let Some(s) = self.0.upgrade() {
let state = s.clone();
Expand Down
12 changes: 11 additions & 1 deletion druid-shell/src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use crate::mouse::{Cursor, CursorDesc, MouseButton, MouseButtons, MouseEvent};
use crate::region::Region;
use crate::scale::{Scalable, Scale, ScaledArea};
use crate::window;
use crate::window::{IdleToken, TimerToken, WinHandler, WindowLevel};
use crate::window::{FileDialogToken, IdleToken, TimerToken, WinHandler, WindowLevel};

/// The platform target DPI.
///
Expand Down Expand Up @@ -1856,6 +1856,11 @@ impl WindowHandle {
}
}

pub fn open_file(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO: implement this and remove open_file_sync
None
}

/// Prompt the user to chose a file to open.
///
/// Blocks while the user picks the file.
Expand All @@ -1870,6 +1875,11 @@ impl WindowHandle {
}
}

pub fn save_as(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO: implement this and remove save_as_sync
None
}

/// Get the raw HWND handle, for uses that are not wrapped in
/// druid_win_shell.
pub fn get_hwnd(&self) -> Option<HWND> {
Expand Down
16 changes: 13 additions & 3 deletions druid-shell/src/platform/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use crate::piet::{Piet, PietText, RenderContext};
use crate::region::Region;
use crate::scale::Scale;
use crate::window;
use crate::window::{IdleToken, TimerToken, WinHandler, WindowLevel};
use crate::window::{FileDialogToken, IdleToken, TimerToken, WinHandler, WindowLevel};

use super::application::Application;
use super::keycodes;
Expand Down Expand Up @@ -1498,17 +1498,27 @@ impl WindowHandle {
}

pub fn open_file_sync(&mut self, _options: FileDialogOptions) -> Option<FileInfo> {
// TODO(x11/file_dialogs): implement WindowHandle::open_file_sync
log::warn!("WindowHandle::open_file_sync is currently unimplemented for X11 platforms.");
None
}

pub fn open_file(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO(x11/file_dialogs): implement WindowHandle::open_file
log::warn!("WindowHandle::open_file is currently unimplemented for X11 platforms.");
None
}

pub fn save_as_sync(&mut self, _options: FileDialogOptions) -> Option<FileInfo> {
// TODO(x11/file_dialogs): implement WindowHandle::save_as_sync
log::warn!("WindowHandle::save_as_sync is currently unimplemented for X11 platforms.");
None
}

pub fn save_as(&mut self, _options: FileDialogOptions) -> Option<FileDialogToken> {
// TODO(x11/file_dialogs): implement WindowHandle::save_as
log::warn!("WindowHandle::save_as is currently unimplemented for X11 platforms.");
None
}

pub fn show_context_menu(&self, _menu: Menu, _pos: Point) {
// TODO(x11/menus): implement WindowHandle::show_context_menu
log::warn!("WindowHandle::show_context_menu is currently unimplemented for X11 platforms.");
Expand Down
Loading