Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Commit

Permalink
Improve file chooser with buttons reliability
Browse files Browse the repository at this point in the history
Following the reviews in #602, this commit:
- uses the `with_buttons` function instead of modifying `new` to keep
  backward compatibility.
- saves the button texts in `Stash` objects to avoid invalid pointers
- panics when the number of buttons is too high (instead of silently
  truncating the number of buttons)
  • Loading branch information
demurgos committed Dec 3, 2017
1 parent 178a7a5 commit 6f5f1dc
Showing 1 changed file with 78 additions and 10 deletions.
88 changes: 78 additions & 10 deletions src/file_chooser_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,91 @@ use Widget;
use Window;

impl FileChooserDialog {
pub fn new<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, action: FileChooserAction, buttons: &[(&str, ResponseType)]) -> FileChooserDialog {
// TODO: Keep the other constructor with buttons support as the only constructor (this one was
// left for compatibility) and rename it to `new` for consistency.
pub fn new<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, action: FileChooserAction) -> FileChooserDialog {
assert_initialized_main_thread!();
unsafe {
Widget::from_glib_none(ffi::gtk_file_chooser_dialog_new(
title.to_glib_none().0,
parent.to_glib_none().0,
action.to_glib(),
ptr::null::<c_char>()
))
.downcast_unchecked()
}
}

/// This function creates a `FileChooserDialog` with buttons:
/// ```
/// let dialog = FileChooserDialog::with_buttons::<ApplicationWindow>(
/// Option::Some("Open File"),
/// Option::None,
/// FileChooserAction::Open,
/// &[("_Cancel", ResponseType::Cancel), ("_Open", ResponseType::Accept)]
/// );
/// ```
pub fn with_buttons<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, action: FileChooserAction, buttons: &[(&str, ResponseType)]) -> FileChooserDialog {
assert_initialized_main_thread!();
unsafe {
Widget::from_glib_none(match buttons.len() {
0 => ffi::gtk_file_chooser_dialog_new(title.to_glib_none().0, parent.to_glib_none().0, action.to_glib(), ptr::null::<c_char>()),
1 => ffi::gtk_file_chooser_dialog_new(title.to_glib_none().0, parent.to_glib_none().0, action.to_glib(), buttons[0].0.to_glib_none().0, buttons[0].1.to_glib(), ptr::null::<c_char>()),
0 => {
ffi::gtk_file_chooser_dialog_new(
title.to_glib_none().0,
parent.to_glib_none().0,
action.to_glib(),
ptr::null::<c_char>()
)
},
1 => {
let first_button_text: Stash<*const c_char, str> = buttons[0].0.to_glib_none();
ffi::gtk_file_chooser_dialog_new(
title.to_glib_none().0,
parent.to_glib_none().0,
action.to_glib(),
first_button_text.0,
buttons[0].1.to_glib(),
ptr::null::<c_char>(),
)
},
2 => {
let second_button_text: *const c_char = buttons[1].0.to_glib_none().0;
ffi::gtk_file_chooser_dialog_new(title.to_glib_none().0, parent.to_glib_none().0, action.to_glib(), buttons[0].0.to_glib_none().0, buttons[0].1.to_glib(), second_button_text, buttons[1].1.to_glib(), ptr::null::<c_char>())
let first_button_text: Stash<*const c_char, str> = buttons[0].0.to_glib_none();
let second_button_text: Stash<*const c_char, str> = buttons[1].0.to_glib_none();
ffi::gtk_file_chooser_dialog_new(
title.to_glib_none().0,
parent.to_glib_none().0,
action.to_glib(),
first_button_text.0,
buttons[0].1.to_glib(),
second_button_text.0,
buttons[1].1.to_glib(),
ptr::null::<c_char>(),
)
},
_ => {
let second_button_text: *const c_char = buttons[1].0.to_glib_none().0;
let third_button_text: *const c_char = buttons[2].0.to_glib_none().0;
ffi::gtk_file_chooser_dialog_new(title.to_glib_none().0, parent.to_glib_none().0, action.to_glib(), buttons[0].0.to_glib_none().0, buttons[0].1.to_glib(), second_button_text, buttons[1].1.to_glib(), third_button_text, buttons[2].1.to_glib(), ptr::null::<c_char>())
3 => {
let first_button_text: Stash<*const c_char, str> = buttons[0].0.to_glib_none();
let second_button_text: Stash<*const c_char, str> = buttons[1].0.to_glib_none();
let third_button_text: Stash<*const c_char, str> = buttons[2].0.to_glib_none();
ffi::gtk_file_chooser_dialog_new(
title.to_glib_none().0,
parent.to_glib_none().0,
action.to_glib(),
first_button_text.0,
buttons[0].1.to_glib(),
second_button_text.0,
buttons[1].1.to_glib(),
third_button_text.0,
buttons[2].1.to_glib(),
ptr::null::<c_char>(),
)
},
_ => {
// TODO: Support arbitrary number of buttons once variadic functions are supported.
// See: https://github.com/rust-lang/rust/issues/44930
panic!(format!("`FileChooserDialog::with_buttons` does not support 4+ buttons, received {}", buttons.len()))
}
})
.downcast_unchecked()
.downcast_unchecked()
}
}
}

0 comments on commit 6f5f1dc

Please sign in to comment.