Solved Native file dialog on Linux Ubuntu "swallows" file extensions
-
I think this is a bug. Have a look at this function in the file
qgtk3dialoghelpers.cpp
(beginning at line 473 using Qt 5.11.1 sources):void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters) { GtkDialog *gtkDialog = d->gtkDialog(); foreach (GtkFileFilter *filter, _filters) gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter); _filters.clear(); _filterNames.clear(); foreach (const QString &filter, filters) { GtkFileFilter *gtkFilter = gtk_file_filter_new(); const QString name = filter.left(filter.indexOf(QLatin1Char('('))); const QStringList extensions = cleanFilterList(filter); gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(QLatin1String(", ")) : name)); foreach (const QString &ext, extensions) gtk_file_filter_add_pattern(gtkFilter, qUtf8Printable(ext)); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter); _filters.insert(filter, gtkFilter); _filterNames.insert(gtkFilter, filter); } }
According to the Gtk docs, the function
gtk_file_filter_set_name()
is supposed to set the "human-readable" part of the file filter. But the code immediately above it has stripped the variablename
of the extension, so it seems obvious that it won't be shown.I seem to remember that on Windows, one could add the extension twice in round parentheses; however, it will get cut off at the first round left parenthesis here in this function.
Should I file a bug report? Or has this been fixed in later versions of Qt?
-
@robert-hairgrove said in Native file dialog on Linux Ubuntu "swallows" file extensions:
Or has this been fixed in later versions of Qt?
I don't know, but you can test with the recent Qt version.
-
Test case using the filter string from the Qt docs. Please note that the behavior probably is only shown on Linux with Gtk window manager.
#include <QMainWindow> #include <QApplication> #include <QPushButton> #include <QtCore> #include <QFileDialog> #include <QMessageBox> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow w; QPushButton b; b.setText("Bye!"); w.setCentralWidget(&b); w.connect(&b, &QPushButton::clicked, &w, &QMainWindow::close); QString fn = QFileDialog::getOpenFileName( &w, "Testing the native dialog", QString(), "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"); if (!fn.isEmpty()) { QString msg = "You chose the file:\n"; QMessageBox::information(&w,"File Selected",msg.append(fn)); } fn = QFileDialog::getOpenFileName( &w, "Testing the Qt (non-native) dialog", QString(), "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)", nullptr, QFileDialog::DontUseNativeDialog); if (!fn.isEmpty()) { QString msg = "You chose the file:\n"; QMessageBox::information(&w,"File Selected",msg.append(fn)); } w.show(); return a.exec(); }
-
I just filed a bug report here.
-
I'm trying to create a workaround until this is fixed. Is there any way to determine which platform theme is used at compile time, or lacking that at runtime? I can use
#ifdef __linux__
etc., but there are certainly other window managers which might be used and not just Gtk. And I couldn't find any Gtk-specific macros to use.And since the platform dialog helpers (QPA) are plugins, maybe a runtime decision as to how to format the filter string would be most appropriate. How can I do this?
-
Hi,
You can use QSysInfo for runtime checks.
You have the Q_OS_XXX macros for build time separation.
-
@SGaist Thanks ... these are great suggestions, but I couldn't find any way of querying QSysInfo for the window manager currently being used. I would need something Gnome or Gtk-specific, I suppose.
-
This thread might give you some clues:
-
@SGaist Fantastic ... this will certainly help ... thank you!
-
@Robert-Hairgrove In the meantime, I have resorted to iterating over the environment variables which are available in the
main()
function if you declare it like this:int main(int argc, char*argv[], char*envp[]) { /*...*/ }
If any of the strings contain
"GNOME"
or"GTK_"
, I can set a global flag which allows me to mogrify the filter string so that it isn't swallowed. So if my filter string looks like this:"Text files (*.txt)"
then I insert two Unicode look-alike characters (
u8'FF08'
andu8'FF09'
, full-width parentheses) and duplicate the extension, i.e.:"Text files(*.txt) (*.txt)"
The user will see:
"Text files(*.txt)"
which is good enough for my purposes.