From 629fdaeaec9e726d4725d66146d234c93baa354e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ma=C5=A1karinec?= Date: Fri, 19 Apr 2024 11:08:23 +0100 Subject: [PATCH] Add GTK dialog option on linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marek Maškarinec --- README.md | 3 ++- src/sfd.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 72e682e..df2cdd0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ A small C library for opening a file dialog on Windows and Linux. ## Usage **[sfd.c](src/sfd.c?raw=1)** and **[sfd.h](src/sfd.h?raw=1)** should be dropped into an existing project and compiled along with it — on Windows `comdlg32` -should be linked. +should be linked. On Linux, sfd opens a pipe to `zenity` by default. You can +use a GTK dialog instead by defining `SFD_GTK` and linking to gtk3. The library provides a function for *open* dialogs and one for *save* dialogs: diff --git a/src/sfd.c b/src/sfd.c index d84c401..29537b0 100644 --- a/src/sfd.c +++ b/src/sfd.c @@ -162,14 +162,88 @@ const char* sfd_save_dialog(sfd_Options *opt) { #endif +#ifndef _WIN32 +#ifdef SFD_GTK /****************************************************************************** -** Zenity +** GTK *******************************************************************************/ +#include +#include + +static const char* file_dialog(sfd_Options *opt, int save) { + static char result_buf[2048]; + static bool gtk_inited = false; + if (!gtk_inited) { + gtk_init(NULL, NULL); + gtk_inited = true; + } + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + opt->title, NULL, + save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN, + "Cancel", GTK_RESPONSE_CANCEL, + save ? "Save" : "Open", GTK_RESPONSE_ACCEPT, + NULL + ); + + if (opt->path && opt->path[0] != '\0') { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), opt->path); + } + + if (opt->filter) { + GtkFileFilter *filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, opt->filter_name); + + char filter_buf[256]; + strncpy(filter_buf, opt->filter, sizeof(filter_buf) - 1); + filter_buf[sizeof(filter_buf) - 1] = '\0'; + char *s = strtok(filter_buf, "|"); + while (s != NULL) { + gtk_file_filter_add_pattern(filter, s); + s = strtok(NULL, "|"); + } + + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + } + + GtkFileFilter *filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, "All files"); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + gint resp = gtk_dialog_run(GTK_DIALOG(dialog)); + char *out = NULL; + if (resp == GTK_RESPONSE_ACCEPT) { + char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + strncpy(result_buf, filename, sizeof(result_buf) - 1); + result_buf[sizeof(result_buf) - 1] = 0; + g_free(filename); + + if (save && opt->extension && !strstr(result_buf, opt->extension)) { + strncat(result_buf, opt->extension, sizeof(result_buf) - strlen(opt->extension) - 1); + } + } + + gtk_widget_destroy(dialog); + + return result_buf; +} + + +const char* sfd_open_dialog(sfd_Options *opt) { + return file_dialog(opt, 0); +} -#ifndef _WIN32 +const char* sfd_save_dialog(sfd_Options *opt) { + return file_dialog(opt, 1); +} +#else +/****************************************************************************** +** Zenity +*******************************************************************************/ static const char* file_dialog(sfd_Options *opt, int save) { static char result_buf[2048]; char buf[2048]; @@ -257,5 +331,6 @@ const char* sfd_save_dialog(sfd_Options *opt) { return file_dialog(opt, 1); } +#endif #endif