native-dialog-rs icon indicating copy to clipboard operation
native-dialog-rs copied to clipboard

Use a native library implementation instead of Zenity or Kdialog

Open CorneliusCornbread opened this issue 2 years ago • 6 comments
trafficstars

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.

CorneliusCornbread avatar Jul 10 '23 00:07 CorneliusCornbread

+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.

Jm15itch avatar Aug 21 '23 12:08 Jm15itch

rfd has 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.

coderedart avatar Aug 29 '23 09:08 coderedart

rfd has 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.

CorneliusCornbread avatar Aug 29 '23 09:08 CorneliusCornbread

@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/

CorneliusCornbread avatar Sep 02 '23 03:09 CorneliusCornbread

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.

coderedart avatar Sep 02 '23 04:09 coderedart

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 image

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!");
}

CorneliusCornbread avatar Feb 12 '24 18:02 CorneliusCornbread