native-dialog-rs
native-dialog-rs copied to clipboard
Use a native library implementation instead of Zenity or Kdialog
With how often Zenity and Kdialog change their command line tools for creating dialogs, I've been wondering if instead using either Qt or GTK (or both depending on the env, like we're doing now) would be an easier way to implement these dialogs. Qt and GTK change their bindings way less often so despite the higher upfront investment it may be significantly more manageable in terms of maintenance.
+1 for this, I've just faced an issue with this library because GNOME doesn't come with zenity nor Kdialog, and I imagine that there are a plethora of other desktop environments that don't use these like cinnamon or xfce. Choosing QT/GTK would definitely be an excellent move in my opinion. I suggest that we try with a simple QT implementation and see where it goes.
rfd has two backends for dialogs on linux.
GTKwhich adds the gtk dependency. need it in CI pipeline at build time and on end users system (they probably have it though).freedesktopwhich adds the zbus dependency and uses dbus protocol (mostly used by flatpak apps). This will trigger the user's freedesktop-portal handler, which is usually qt/gtk depending your desktop env.
Neither of them are small dependencies :( and do add to compile times. So, keeping kdialog/zenity as alternative backends might be worth considering.
rfdhas two backends for dialogs on linux.1. `GTK` which adds the gtk dependency. need it in CI pipeline at build time and on end users system (they probably have it though). 2. `freedesktop` which adds the zbus dependency and uses dbus protocol (mostly used by flatpak apps). This will trigger the user's freedesktop-portal handler, which is usually qt/gtk depending your desktop env.Neither of them are small dependencies :( and do add to compile times. So, keeping kdialog/zenity as alternative backends might be worth considering.
We could probably allow the user to switch between the two via a feature flag. Something like a use-cli-tools flag. I imagine most don't mind the extra compile time. We could also recommend users use use-cli-tools flag for their debug builds for easier debugging of their apps.
@coderedart correct me if I'm wrong but it seems the freedesktop portal documentation lacks an API for just a dialog box, only having an API for file dialogs https://flatpak.github.io/xdg-desktop-portal/
You are right. Copy pasting from https://docs.rs/rfd/latest/rfd/#xdg-desktop-portal-backend
The XDG Desktop Portal has no API for message dialogs, so the MessageDialog and AsyncMessageDialog structs will not build with this backend.
RFD plans to use zenity as a fallback for xdg portal message dialogs in next release.
I have found a solution! It recently came to me that we could actually just use SDL for the creation of the message dialogue box, there's a catch in that we can't utilize the system theme (least not without extra work), but it makes a universal dialogue box. Here's an example that has some basic formatting, nothing pretty for now but it works
use std::io;
use sdl2::messagebox::{ButtonData, MessageBoxButtonFlag, MessageBoxColorScheme, MessageBoxFlag};
fn main() {
println!("Input any key to pop up dialog box");
let mut input_text = String::new();
io::stdin()
.read_line(&mut input_text)
.expect("failed to read from stdin");
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let mut window = video_subsystem
.window("rust-sdl2 demo", 800, 600)
.position_centered()
.build()
.unwrap();
window.hide();
let flags = MessageBoxFlag::WARNING;
let button1 = ButtonData {
flags: MessageBoxButtonFlag::RETURNKEY_DEFAULT,
button_id: 1,
text: "This is a message",
};
let buttons = vec![button1];
let title = "Title message";
let message = "This is the main message";
let scheme = MessageBoxColorScheme {
background: (255, 255, 255),
text: (0, 0, 0),
button_border: (1, 1, 1),
button_background: (200, 200, 200),
button_selected: (34, 111, 163),
};
let _ =
sdl2::messagebox::show_message_box(flags, &buttons[0..], title, message, &window, scheme)
.unwrap();
test_dual();
println!("Finished!");
}
// If dependents are using SDL will then run into issues if we instantiate SDL internally?
// Turns out no! We can make our own SDL instance and it works just fine, we could also allow users
// pass an SDL instance if we really desire.
fn test_dual() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let mut window = video_subsystem
.window("rust-sdl2 demo", 800, 600)
.position_centered()
.build()
.unwrap();
window.hide();
let flags = MessageBoxFlag::WARNING;
let button1 = ButtonData {
flags: MessageBoxButtonFlag::RETURNKEY_DEFAULT,
button_id: 1,
text: "This is a message",
};
let buttons = vec![button1];
let title = "Title message";
let message = "This is the main message";
let scheme = MessageBoxColorScheme {
background: (255, 255, 255),
text: (0, 0, 0),
button_border: (1, 1, 1),
button_background: (200, 200, 200),
button_selected: (34, 111, 163),
};
let _ =
sdl2::messagebox::show_message_box(flags, &buttons[0..], title, message, &window, scheme)
.unwrap();
println!("Done!");
}