-
Notifications
You must be signed in to change notification settings - Fork 511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Use FileChooserNative #400
Comments
Thanks, I wasn't aware that FileChooserNative was a thing. |
Well, I've implemented this. Unfortunately I have absolutely no idea how to get it to work, so now you're on your own; I have the patchdiff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 874e88d..91a01c4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -13,6 +13,14 @@ endif()
set(HAVE_SPACEWARE ${SPACEWARE_FOUND})
+if(NOT WIN32 OR APPLE)
+ if(GTKMM_gtkmm-3.0_VERSION VERSION_LESS "3.24.0")
+ set(HAVE_GTK_FILECHOOSERNATIVE 0)
+ else()
+ set(HAVE_GTK_FILECHOOSERNATIVE 1)
+ endif()
+endif()
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/src/config.h.in b/src/config.h.in
index 2f210d7..475b973 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -16,4 +16,7 @@
#cmakedefine HAVE_BACKTRACE
#define BACKTRACE_HEADER @BACKTRACE_HEADER@
+/* If we use GTK, can we use the native file chooser? */
+#cmakedefine HAVE_GTK_FILECHOOSERNATIVE
+
#endif
diff --git a/src/platform/guigtk.cpp b/src/platform/guigtk.cpp
index 8f57afd..d8aeb24 100644
--- a/src/platform/guigtk.cpp
+++ b/src/platform/guigtk.cpp
@@ -15,6 +15,10 @@
#include <gtkmm/cssprovider.h>
#include <gtkmm/entry.h>
#include <gtkmm/filechooserdialog.h>
+#define HAVE_GTK_FILECHOOSERNATIVE
+#if defined(HAVE_GTK_FILECHOOSERNATIVE)
+# include <gtkmm/filechoosernative.h>
+#endif
#include <gtkmm/fixed.h>
#include <gtkmm/glarea.h>
#include <gtkmm/main.h>
@@ -1187,32 +1191,27 @@ MessageDialogRef CreateMessageDialog(WindowRef parentWindow) {
// File dialogs
//-----------------------------------------------------------------------------
-class FileDialogImplGtk final : public FileDialog {
+class FileDialogImplGtk : public FileDialog {
public:
- Gtk::FileChooserDialog gtkDialog;
+ Gtk::FileChooser *gtkChooser;
std::vector<std::string> extensions;
- FileDialogImplGtk(Gtk::FileChooserDialog &&dialog)
- : gtkDialog(std::move(dialog))
- {
- gtkDialog.property_filter().signal_changed().
+ void InitFileChooser(Gtk::FileChooser &chooser) {
+ gtkChooser = &chooser;
+ gtkChooser->property_filter().signal_changed().
connect(sigc::mem_fun(this, &FileDialogImplGtk::FilterChanged));
}
- void SetTitle(std::string title) override {
- gtkDialog.set_title(PrepareTitle(title));
- }
-
void SetCurrentName(std::string name) override {
- gtkDialog.set_current_name(name);
+ gtkChooser->set_current_name(name);
}
Platform::Path GetFilename() override {
- return Path::From(gtkDialog.get_filename());
+ return Path::From(gtkChooser->get_filename());
}
void SetFilename(Platform::Path path) override {
- gtkDialog.set_filename(path.raw);
+ gtkChooser->set_filename(path.raw);
}
void AddFilter(std::string name, std::vector<std::string> extensions) override {
@@ -1233,13 +1232,13 @@ public:
gtkFilter->set_name(name + " (" + desc + ")");
this->extensions.push_back(extensions.front());
- gtkDialog.add_filter(gtkFilter);
+ gtkChooser->add_filter(gtkFilter);
}
std::string GetExtension() {
- auto filters = gtkDialog.list_filters();
+ auto filters = gtkChooser->list_filters();
size_t filterIndex =
- std::find(filters.begin(), filters.end(), gtkDialog.get_filter()) -
+ std::find(filters.begin(), filters.end(), gtkChooser->get_filter()) -
filters.begin();
if(filterIndex < extensions.size()) {
return extensions[filterIndex];
@@ -1249,14 +1248,14 @@ public:
}
void SetExtension(std::string extension) {
- auto filters = gtkDialog.list_filters();
+ auto filters = gtkChooser->list_filters();
size_t extensionIndex =
std::find(extensions.begin(), extensions.end(), extension) -
extensions.begin();
if(extensionIndex < filters.size()) {
- gtkDialog.set_filter(filters[extensionIndex]);
+ gtkChooser->set_filter(filters[extensionIndex]);
} else {
- gtkDialog.set_filter(filters.front());
+ gtkChooser->set_filter(filters.front());
}
}
@@ -1270,21 +1269,46 @@ public:
void FreezeChoices(SettingsRef settings, const std::string &key) override {
settings->FreezeString("Dialog_" + key + "_Folder",
- gtkDialog.get_current_folder());
+ gtkChooser->get_current_folder());
settings->FreezeString("Dialog_" + key + "_Filter", GetExtension());
}
void ThawChoices(SettingsRef settings, const std::string &key) override {
- gtkDialog.set_current_folder(settings->ThawString("Dialog_" + key + "_Folder"));
+ gtkChooser->set_current_folder(settings->ThawString("Dialog_" + key + "_Folder"));
SetExtension(settings->ThawString("Dialog_" + key + "_Filter"));
}
- bool RunModal() override {
- if(gtkDialog.get_action() == Gtk::FILE_CHOOSER_ACTION_SAVE &&
- Path::From(gtkDialog.get_current_name()).FileStem().empty()) {
- gtkDialog.set_current_name(std::string(_("untitled")) + "." + GetExtension());
+ void CheckForUntitledFile() {
+ if(gtkChooser->get_action() == Gtk::FILE_CHOOSER_ACTION_SAVE &&
+ Path::From(gtkChooser->get_current_name()).FileStem().empty()) {
+ gtkChooser->set_current_name(std::string(_("untitled")) + "." + GetExtension());
}
+ }
+};
+class FileDialogGtkImplGtk final : public FileDialogImplGtk {
+public:
+ Gtk::FileChooserDialog gtkDialog;
+
+ FileDialogGtkImplGtk(Gtk::Window >kParent, bool isSave)
+ : gtkDialog(gtkParent,
+ isSave ? C_("title", "Save File")
+ : C_("title", "Open File"),
+ isSave ? Gtk::FILE_CHOOSER_ACTION_SAVE
+ : Gtk::FILE_CHOOSER_ACTION_OPEN) {
+ gtkDialog.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
+ gtkDialog.add_button(isSave ? C_("button", "_Save")
+ : C_("button", "_Open"), Gtk::RESPONSE_OK);
+ gtkDialog.set_default_response(Gtk::RESPONSE_OK);
+ InitFileChooser(gtkDialog);
+ }
+
+ void SetTitle(std::string title) override {
+ gtkDialog.set_title(PrepareTitle(title));
+ }
+
+ bool RunModal() override {
+ CheckForUntitledFile();
if(gtkDialog.run() == Gtk::RESPONSE_OK) {
return true;
} else {
@@ -1293,26 +1317,56 @@ public:
}
};
+#if defined(HAVE_GTK_FILECHOOSERNATIVE)
+
+class FileDialogNativeImplGtk final : public FileDialogImplGtk {
+public:
+ Glib::RefPtr<Gtk::FileChooserNative> gtkNative;
+
+ FileDialogNativeImplGtk(Gtk::Window >kParent, bool isSave) {
+ gtkNative = Gtk::FileChooserNative::create(
+ isSave ? C_("title", "Save File")
+ : C_("title", "Open File"),
+ gtkParent,
+ isSave ? Gtk::FILE_CHOOSER_ACTION_SAVE
+ : Gtk::FILE_CHOOSER_ACTION_OPEN,
+ isSave ? C_("button", "_Save")
+ : C_("button", "_Open"),
+ C_("button", "_Cancel"));
+ // Seriously, GTK?!
+ InitFileChooser(*gtkNative.operator->());
+ }
+
+ void SetTitle(std::string title) override {
+ gtkNative->set_title(PrepareTitle(title));
+ }
+
+ bool RunModal() override {
+ CheckForUntitledFile();
+ if(gtkNative->run() == Gtk::RESPONSE_OK) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+#endif
+
+#if defined(HAVE_GTK_FILECHOOSERNATIVE)
+# define FILE_DIALOG_IMPL FileDialogNativeImplGtk
+#else
+# define FILE_DIALOG_IMPL FileDialogGtkImplGtk
+#endif
+
FileDialogRef CreateOpenFileDialog(WindowRef parentWindow) {
Gtk::Window >kParent = std::static_pointer_cast<WindowImplGtk>(parentWindow)->gtkWindow;
- Gtk::FileChooserDialog gtkDialog(gtkParent, C_("title", "Open File"),
- Gtk::FILE_CHOOSER_ACTION_OPEN);
- gtkDialog.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
- gtkDialog.add_button(C_("button", "_Open"), Gtk::RESPONSE_OK);
- gtkDialog.set_default_response(Gtk::RESPONSE_OK);
- return std::make_shared<FileDialogImplGtk>(std::move(gtkDialog));
-
+ return std::make_shared<FILE_DIALOG_IMPL>(gtkParent, /*isSave=*/false);
}
FileDialogRef CreateSaveFileDialog(WindowRef parentWindow) {
Gtk::Window >kParent = std::static_pointer_cast<WindowImplGtk>(parentWindow)->gtkWindow;
- Gtk::FileChooserDialog gtkDialog(gtkParent, C_("title", "Save File"),
- Gtk::FILE_CHOOSER_ACTION_SAVE);
- gtkDialog.set_do_overwrite_confirmation(true);
- gtkDialog.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
- gtkDialog.add_button(C_("button", "_Save"), Gtk::RESPONSE_OK);
- gtkDialog.set_default_response(Gtk::RESPONSE_OK);
- return std::make_shared<FileDialogImplGtk>(std::move(gtkDialog));
+ return std::make_shared<FILE_DIALOG_IMPL>(gtkParent, /*isSave=*/true);
}
//----------------------------------------------------------------------------- |
Huh, well your patch looks pretty similar to mine. Mine segfaults but it does bring up the native dialog. I think this is going to change at some point, but until then, you need to have the environment variable I'm running it with |
OK, it works with that environment variable set. |
Fixed in bc3e09e. |
I just found out that gtkmm 4 dispenses with that and uses std::shared_ptr. https://www.murrayc.com/permalink/2017/04/20/gtkmm-4-progress/ |
System information
SolveSpace version: 3.0~e7b75f19
Operating system: Arch Linux 5.0.13
Expected behavior
It would be nice if Solvespace used the native file chooser dialog for other desktop environments (such as KDE).
Actual behavior
The default gtk dialog is used. The default gtk dialog leaves much to be desired, and is often painful to use. (i.e. by default, typing doesn't rename the file, but rather opens up a search dialog)
Additional information
There is a fix for this: GTK has introduced
Gtk::FileChooserNative
. Unfortunately, although it is supposed to be nearly a drop-in replacement, in this instance it is not. The Gtk team decided to make the default constructors protected. Already this conflicts with howGtk::FileChooserDialog
is being used. The alternative,Gtk::FileChooserNative::create()
returns the world's worst smart pointerGlib::RefPtr
which cannot be de-referenced.Current state in src/platform/guigtk.cpp:
The text was updated successfully, but these errors were encountered: