Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Fix some GTK3 memory leaks
- Add GTK4 backend behind the `gtk4` feature
- MSRV is now 1.92
- Fix macOS file dialogs ignoring `set_directory` when `set_file_name` is also used.
Expand Down
66 changes: 24 additions & 42 deletions src/backend/gtk3/file_dialog/dialog_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use crate::FileDialog;
use gtk_sys::GtkFileChooserNative;

use std::{
ffi::{CStr, CString},
ffi::{c_char, CStr, CString, OsStr},
ops::Deref,
os::unix::ffi::OsStrExt,
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -110,62 +111,43 @@ impl GtkFileDialog {
}

pub fn get_result(&self) -> Option<PathBuf> {
let cstr = unsafe {
let chosen_filename = gtk_sys::gtk_file_chooser_get_filename(self.ptr as _);
CStr::from_ptr(chosen_filename).to_str()
};
unsafe {
let filename = gtk_sys::gtk_file_chooser_get_filename(self.ptr as _);
if filename.is_null() {
return None;
}

if let Ok(cstr) = cstr {
Some(PathBuf::from(cstr.to_owned()))
} else {
None
let path = filename_to_path(filename);
glib_sys::g_free(filename as _);
Some(path)
}
}

pub fn get_results(&self) -> Vec<PathBuf> {
#[derive(Debug)]
struct FileList(*mut glib_sys::GSList);

impl Iterator for FileList {
type Item = glib_sys::GSList;
fn next(&mut self) -> Option<Self::Item> {
let curr_ptr = self.0;

if !curr_ptr.is_null() {
let curr = unsafe { *curr_ptr };

self.0 = curr.next;
unsafe {
let filenames = gtk_sys::gtk_file_chooser_get_filenames(self.ptr as _);

Some(curr)
} else {
None
}
let mut paths = Vec::new();
let mut current = filenames;
while !current.is_null() {
paths.push(filename_to_path((*current).data as *const c_char));
current = (*current).next;
}
}

let chosen_filenames =
unsafe { gtk_sys::gtk_file_chooser_get_filenames(self.ptr as *mut _) };

let paths: Vec<PathBuf> = FileList(chosen_filenames)
.filter_map(|item| {
let cstr = unsafe { CStr::from_ptr(item.data as _).to_str() };

if let Ok(cstr) = cstr {
Some(PathBuf::from(cstr.to_owned()))
} else {
None
}
})
.collect();

paths
glib_sys::g_slist_free_full(filenames, Some(glib_sys::g_free));
paths
}
}

pub fn run(&self) -> i32 {
unsafe { gtk_sys::gtk_native_dialog_run(self.ptr as *mut _) }
}
}

unsafe fn filename_to_path(filename: *const c_char) -> PathBuf {
PathBuf::from(OsStr::from_bytes(CStr::from_ptr(filename).to_bytes()))
}

fn parent_gtk_window(opt: &FileDialog) -> *mut gtk_sys::GtkWindow {
if let Some(parent_handle) = &opt.parent {
unsafe { super::super::utils::find_gtk_window(parent_handle) }
Expand Down
10 changes: 6 additions & 4 deletions src/backend/gtk3/message_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,16 @@ unsafe fn is_label(type_instance: *const gobject_sys::GTypeInstance) -> bool {
/// Sets the child labels of a widget selectable
unsafe fn set_child_labels_selectable(dialog: *mut gtk_sys::GtkDialog) {
let area = gtk_sys::gtk_message_dialog_get_message_area(dialog as _);
let mut children = gtk_sys::gtk_container_get_children(area as _);
while !children.is_null() {
let child = (*children).data;
let children = gtk_sys::gtk_container_get_children(area as _);
let mut current = children;
while !current.is_null() {
let child = (*current).data;
if is_label(child as _) {
gtk_sys::gtk_label_set_selectable(child as _, 1);
}
children = (*children).next;
current = (*current).next;
}
glib_sys::g_list_free(children);
}

impl Drop for GtkMessageDialog {
Expand Down
Loading