admin管理员组文章数量:1401208
I'm going to wrap a function same as windows api: GetOpenFileName using gtk3. However, at some cases, calling gtk_init results in crash.
#include "gtkdlghelper.h"
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gtk/gtkfilechooser.h>
#include "../log.h"
#define kLogTag "gtk"
namespace Gtk{
class GtkInit{
public:
GtkInit(){
int argc=0;
gtk_init(&argc,nullptr);
SLOG_STMI()<<"init gtk done";
}
};
static GtkInit s_gtkInit;
static char* substr(const char *src, int m, int n)
{
int len = n - m;
char *dest = (char*)malloc(sizeof(char) * (len + 1));
for (int i = m; i < n && (*(src + i) != '\0'); i++) {
*dest = *(src + i);
dest++;
}
*dest = '\0';
return dest - len;
}
static void parseString(GSList** list,
const char* str,
const char* delim)
{
char *_str = strdup(str);
char *token = strtok(_str, delim);
while (token != NULL) {
*list = g_slist_append(*list, (gpointer)strdup(token));
token = strtok(NULL, delim);
}
free(_str);
}
static GtkWindow * native2GtkWindow(HWND winid){
GdkWindow *gdk_wnd = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), winid);
// 创建一个临时的 GTK 窗口
if(!gdk_wnd) return nullptr;
GtkWindow *gtk_wnd = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_widget_realize(GTK_WIDGET(gtk_wnd)); // 确保窗口被实现
gtk_widget_set_window(GTK_WIDGET(gtk_wnd), gdk_wnd); // 设置 GDK 窗口
return gtk_wnd;
}
static bool nativeFileDialog(HWND parent,
Gtk::Mode mode,
char*** filenames,
int* files_count,
const char* title,
const char* file,
const char* path,
const char* flt,
char** sel_filter,
bool sel_multiple)
{
bool ret = false;
GtkFileChooserAction actions[] = {
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
};
GtkWindow *gtk_parent = native2GtkWindow(parent);
GtkWidget *dialog = NULL;
dialog = gtk_file_chooser_dialog_new(title,
gtk_parent,
actions[mode],
g_dgettext("gtk30", "_Cancel"),
GTK_RESPONSE_CANCEL,
mode == Gtk::Mode::OPEN || mode == Gtk::Mode::FOLDER ?
g_dgettext("gtk30", "_Open") : g_dgettext("gtk30", "_Save"),
GTK_RESPONSE_ACCEPT,
NULL);
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE);
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
if (mode == Gtk::Mode::OPEN || mode == Gtk::Mode::FOLDER) {
gtk_file_chooser_set_current_folder(chooser, path);
gtk_file_chooser_set_select_multiple (chooser, sel_multiple ? TRUE : FALSE);
} else {
gtk_file_chooser_set_do_overwrite_confirmation(chooser, FALSE);
gtk_file_chooser_set_current_folder(chooser, path);
gtk_file_chooser_set_current_name(chooser, file);
}
// Filters
GSList *list = NULL;
if (mode != Gtk::Mode::FOLDER) {
parseString(&list, flt, ";;");
for (guint i = 0; i < g_slist_length(list); i++) {
if (char *flt_name = (char*)g_slist_nth(list, i)->data) {
GtkFileFilter *filter = gtk_file_filter_new();
char *start = strchr(flt_name, '(');
char *end = strchr(flt_name, ')');
char *short_flt_name = NULL;
if (mode == Gtk::Mode::OPEN && strlen(flt_name) > 255 && start != NULL) {
int end_index = (int)(start - flt_name - 1);
if (end_index > 0)
short_flt_name = substr(flt_name, 0, end_index);
}
gtk_file_filter_set_name(filter, short_flt_name ? short_flt_name : flt_name);
if (short_flt_name)
free(short_flt_name);
if (start != NULL && end != NULL) {
int start_index = (int)(start - flt_name);
int end_index = (int)(end - flt_name);
if (start_index < end_index) {
char *fltrs = substr(flt_name, start_index + 1, end_index);
//g_print("%s\n", fltrs);
GSList *flt_list = NULL;
parseString(&flt_list, fltrs, " ");
free(fltrs);
for (guint j = 0; j < g_slist_length(flt_list); j++) {
char *nm = (char*)g_slist_nth(flt_list, j)->data;
if (nm != NULL)
gtk_file_filter_add_pattern(filter, nm);
}
if (flt_list)
g_slist_free(flt_list);
}
}
gtk_file_chooser_add_filter(chooser, filter);
if (sel_filter && *sel_filter && strcmp(flt_name, *sel_filter) == 0)
gtk_file_chooser_set_filter(chooser, filter);
}
}
}
gint res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
if (sel_multiple) {
GSList *filenames_list = gtk_file_chooser_get_filenames(chooser);
*files_count = (int)g_slist_length(filenames_list);
*filenames = (char**)calloc((size_t)(*files_count), sizeof(char*));
for (guint i = 0; i < g_slist_length(filenames_list); i++)
(*filenames)[i] = strdup((char*)g_slist_nth(filenames_list, i)->data);
g_slist_free(filenames_list);
} else {
*files_count = 1;
*filenames = (char**)calloc((size_t)(*files_count), sizeof(char*));
**filenames = gtk_file_chooser_get_filename(chooser);
}
ret = true;
}
if (mode != Gtk::Mode::FOLDER) {
GtkFileFilter *s_filter = gtk_file_chooser_get_filter(chooser);
if (sel_filter && *sel_filter)
free(*sel_filter);
if (s_filter && sel_filter)
*sel_filter = strdup(gtk_file_filter_get_name(s_filter));
}
gtk_widget_destroy(dialog);
if (list)
g_slist_free(list);
while (gtk_events_pending())
gtk_main_iteration_do(FALSE);
return ret;
}
bool openGtkFileChooser( std::list<std::string> &files,
HWND parent,
Mode mode,
const std::string &title,
const std::string &file,
const std::string &path,
const std::string &filter,
std::string *sel_filter,
bool sel_multiple)
{
int pos= file.rfind("/");
const std::string _file = (pos != -1) ?
file.substr(pos + 1) : file;
const std::string _path = (path.empty() && pos != -1) ?
file.substr(0, pos) : path;
char **filenames = nullptr;
char *_sel_filter = (sel_filter) ? strdup(sel_filter->c_str()) : nullptr;
int files_count = 0;
bool ret = nativeFileDialog(parent,
mode,
&filenames,
&files_count,
title.c_str(),
_file.c_str(),
_path.c_str(),
filter.c_str(),
&_sel_filter,
sel_multiple);
for (int i = 0; i < files_count; i++) {
if (filenames[i]) {
files.push_back(filenames[i]);
free(filenames[i]);
}
}
if (filenames) {
free(filenames);
}
if (_sel_filter) {
if (sel_filter)
*sel_filter = _sel_filter;
free(_sel_filter);
}
return ret;
}
static inline BYTE tobcolor(double v){
return (BYTE)(v*255);
}
bool gtk_choose_color(HWND parent,COLORREF *out){
bool ret = false;
GtkWindow *gtk_parent = native2GtkWindow(parent);
// 创建颜色选择对话框
GtkWidget * dialog = gtk_color_chooser_dialog_new("Choose Color", gtk_parent);
// 运行对话框并获取用户响应
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
// 获取用户选择的颜色
GdkRGBA color; // 用于存储选择的颜色
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
ret = true;
*out = RGBA(tobcolor(color.red),tobcolor(color.green),tobcolor(color.blue),tobcolor(color.alpha));
}
// 销毁对话框
gtk_widget_destroy(dialog);
while (gtk_events_pending())
gtk_main_iteration_do(FALSE);
return ret;
}
}//end of ns Gtk
using gtk3, for some case, gtk_init causes crash. I don't know why. so I wan't have a try for using gtk4.
I'm not sure why gtk_init crash. If the crash is caused by my fault, fix it and using gtk3 is better than replace it with gtk4.
本文标签: chow to implement choose file dialog like windows api GetOpenFileName using gtk4Stack Overflow
版权声明:本文标题:c++ - how to implement choose file dialog like windows api GetOpenFileName using gtk4? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744221026a2595865.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论