mirror of https://github.com/fltk/fltk
Fix for issue #278: Can we use the qt/kde file picker instead of gtk?
Under the X11 platform, class Fl_Native_File_Chooser will behave as follows : - if the KDE desktop is used and if command "kdialog" is available in the path, the Qt/KDE file chooser is used; - otherwise, if the GTK library is available at run-time, the GTK file chooser is used; - otherwise, the FLTK file chooser is used. In addition, when Fl::OPTION_FNFC_USES_GTK is off, the FLTK file chooser is always used.
This commit is contained in:
parent
939d536b66
commit
663b93a807
|
@ -27,7 +27,9 @@
|
|||
|
||||
class Fl_Native_File_Chooser_FLTK_Driver <== this API implementation is the default FLTK file chooser
|
||||
class Fl_GTK_Native_File_Chooser_Driver <== this API implementation runs a GTK file chooser
|
||||
class Fl_Kdialog_Native_File_Chooser_Driver <== this API implementation runs a KDE file chooser
|
||||
it is determined at run-time if the GTK dynamic libraries are available
|
||||
and the KDE file chooser runs under the KDE desktop
|
||||
|
||||
class Fl_Quartz_Native_File_Chooser_Driver <== this API implementation runs a Mac OS X file chooser
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ if (USE_X11)
|
|||
fl_dnd_x.cxx
|
||||
Fl_Native_File_Chooser_FLTK.cxx
|
||||
Fl_Native_File_Chooser_GTK.cxx
|
||||
Fl_Native_File_Chooser_Kdialog.cxx
|
||||
Fl_get_key.cxx
|
||||
)
|
||||
if (USE_XFT)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
|
||||
//
|
||||
// Copyright 1998-2018 by Bill Spitzak and others.
|
||||
// Copyright 1998-2021 by Bill Spitzak and others.
|
||||
// Copyright 2012 IMM
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include "Fl_Native_File_Chooser_Kdialog.H"
|
||||
|
||||
#if HAVE_DLSYM && HAVE_DLFCN_H
|
||||
#include <FL/platform.H>
|
||||
|
@ -907,17 +908,38 @@ void Fl_GTK_Native_File_Chooser_Driver::probe_for_GTK_libs(void) {
|
|||
#endif // HAVE_DLSYM && HAVE_DLFCN_H
|
||||
|
||||
Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
|
||||
// Use kdialog if available at run-time and if using the KDE desktop,
|
||||
// else, use GTK dialog if available at run-time
|
||||
// otherwise, use FLTK file chooser.
|
||||
platform_fnfc = NULL;
|
||||
if (Fl::option(Fl::OPTION_FNFC_USES_GTK)) {
|
||||
const char *desktop = getenv("XDG_CURRENT_DESKTOP");
|
||||
if (desktop && strcmp(desktop, "KDE") == 0) {
|
||||
if (!Fl_Kdialog_Native_File_Chooser_Driver::have_looked_for_kdialog) {
|
||||
// First Time here, try to find kdialog
|
||||
FILE *pipe = popen("kdialog -v 2> /dev/null", "r");
|
||||
if (pipe) {
|
||||
char line[100] = "";
|
||||
fgets(line, sizeof(line), pipe);
|
||||
if (strlen(line) > 0) Fl_Kdialog_Native_File_Chooser_Driver::did_find_kdialog = true;
|
||||
pclose(pipe);
|
||||
}
|
||||
Fl_Kdialog_Native_File_Chooser_Driver::have_looked_for_kdialog = true;
|
||||
}
|
||||
// if we found kdialog, we will use the Fl_Kdialog_Native_File_Chooser_Driver
|
||||
if (Fl_Kdialog_Native_File_Chooser_Driver::did_find_kdialog) platform_fnfc = new Fl_Kdialog_Native_File_Chooser_Driver(val);
|
||||
}
|
||||
#if HAVE_DLSYM && HAVE_DLFCN_H
|
||||
if (!platform_fnfc) {
|
||||
if ( Fl_GTK_Native_File_Chooser_Driver::have_looked_for_GTK_libs == 0) {
|
||||
// First Time here, try to find the GTK libs if they are installed
|
||||
if (Fl::option(Fl::OPTION_FNFC_USES_GTK)) {
|
||||
Fl_GTK_Native_File_Chooser_Driver::probe_for_GTK_libs();
|
||||
}
|
||||
Fl_GTK_Native_File_Chooser_Driver::have_looked_for_GTK_libs = -1;
|
||||
}
|
||||
// if we found all the GTK functions we need, we will use the GtkFileChooserDialog
|
||||
if (Fl_GTK_Native_File_Chooser_Driver::did_find_GTK_libs) platform_fnfc = new Fl_GTK_Native_File_Chooser_Driver(val);
|
||||
else
|
||||
#endif // HAVE_DLSYM && HAVE_DLFCN_H
|
||||
platform_fnfc = new Fl_Native_File_Chooser_FLTK_Driver(val);
|
||||
}
|
||||
#endif // HAVE_DLSYM && HAVE_DLFCN_H
|
||||
}
|
||||
if (!platform_fnfc) platform_fnfc = new Fl_Native_File_Chooser_FLTK_Driver(val);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// FLTK native file chooser widget : KDE version
|
||||
//
|
||||
// Copyright 2021 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
// file is missing or damaged, see the license at:
|
||||
//
|
||||
// https://www.fltk.org/COPYING.php
|
||||
//
|
||||
// Please see the following page on how to report bugs and issues:
|
||||
//
|
||||
// https://www.fltk.org/bugs.php
|
||||
//
|
||||
|
||||
#ifndef FL_KDIALOG_NATIVE_FILE_CHOOSER_H
|
||||
#define FL_KDIALOG_NATIVE_FILE_CHOOSER_H 1
|
||||
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
|
||||
class FL_EXPORT Fl_Kdialog_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_FLTK_Driver {
|
||||
friend class Fl_Native_File_Chooser;
|
||||
char **_pathnames;
|
||||
int _tpathnames;
|
||||
char *_directory;
|
||||
char *_preset_file;
|
||||
char *_title;
|
||||
static bool did_find_kdialog;
|
||||
static bool have_looked_for_kdialog;
|
||||
Fl_Kdialog_Native_File_Chooser_Driver(int val);
|
||||
~Fl_Kdialog_Native_File_Chooser_Driver();
|
||||
int count() const;
|
||||
const char *filename() const;
|
||||
const char *filename(int i) const;
|
||||
int show();
|
||||
char *parse_filter(const char *f);
|
||||
const char *filter() const;
|
||||
virtual void filter(const char *f);
|
||||
int filters() const;
|
||||
void preset_file(const char *val);
|
||||
const char *preset_file() const;
|
||||
void directory(const char *val);
|
||||
const char *directory() const;
|
||||
void title(const char *val);
|
||||
const char *title() const;
|
||||
};
|
||||
|
||||
#endif // FL_KDIALOG_NATIVE_FILE_CHOOSER_H
|
|
@ -0,0 +1,229 @@
|
|||
//
|
||||
// FLTK native file chooser widget : KDE version
|
||||
//
|
||||
// Copyright 2021 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
// file is missing or damaged, see the license at:
|
||||
//
|
||||
// https://www.fltk.org/COPYING.php
|
||||
//
|
||||
// Please see the following page on how to report bugs and issues:
|
||||
//
|
||||
// https://www.fltk.org/bugs.php
|
||||
//
|
||||
|
||||
#include <config.h>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include "Fl_Native_File_Chooser_Kdialog.H"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* Fl_Kdialog_Native_File_Chooser_Driver : file chooser based on the "kdialog" command */
|
||||
|
||||
bool Fl_Kdialog_Native_File_Chooser_Driver::did_find_kdialog = false;
|
||||
bool Fl_Kdialog_Native_File_Chooser_Driver::have_looked_for_kdialog = false;
|
||||
|
||||
|
||||
Fl_Kdialog_Native_File_Chooser_Driver::Fl_Kdialog_Native_File_Chooser_Driver(int val) : Fl_Native_File_Chooser_FLTK_Driver(val) {
|
||||
_tpathnames = 0;
|
||||
_pathnames = NULL;
|
||||
_directory = NULL;
|
||||
_preset_file = NULL;
|
||||
_title = NULL;
|
||||
}
|
||||
|
||||
|
||||
Fl_Kdialog_Native_File_Chooser_Driver::~Fl_Kdialog_Native_File_Chooser_Driver() {
|
||||
for (int i = 0; i < _tpathnames; i++) delete[] _pathnames[i];
|
||||
delete[] _pathnames;
|
||||
if (_preset_file) free(_preset_file);
|
||||
if (_directory) free(_directory);
|
||||
if (_title) free(_title);
|
||||
}
|
||||
|
||||
|
||||
int Fl_Kdialog_Native_File_Chooser_Driver::show() {
|
||||
Fl::flush(); // to close menus if necessary
|
||||
const char *option;
|
||||
switch (_btype) {
|
||||
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: // not supported
|
||||
option = "--getexistingdirectory";
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
|
||||
option = "--getsavefilename";
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
|
||||
option = "--multiple --getopenfilename";
|
||||
break;
|
||||
|
||||
default:
|
||||
option = "--getopenfilename";
|
||||
}
|
||||
const char *preset = ".";
|
||||
if (_preset_file) preset = _preset_file;
|
||||
else if (_directory) preset = _directory;
|
||||
char *command = new char[strlen(option) + strlen(preset) + (_title?strlen(_title)+11:0) +
|
||||
(_parsedfilt?strlen(_parsedfilt):0) + 50];
|
||||
strcpy(command, "kdialog ");
|
||||
if (_title) {
|
||||
sprintf(command+strlen(command), " --title '%s'", _title);
|
||||
}
|
||||
sprintf(command+strlen(command), " %s %s ", option, preset);
|
||||
if (_parsedfilt) sprintf(command+strlen(command), " \"%s\" ", _parsedfilt);
|
||||
strcat(command, "2> /dev/null"); // get rid of stderr output
|
||||
//puts(command);
|
||||
FILE *pipe = popen(command, "r");
|
||||
char *all_files = NULL;
|
||||
if (pipe) {
|
||||
char *p, tmp[FL_PATH_MAX];
|
||||
do {
|
||||
p = fgets(tmp, sizeof(tmp), pipe);
|
||||
if (p) all_files = strapp(all_files, p);
|
||||
}
|
||||
while (p);
|
||||
pclose(pipe);
|
||||
if (all_files) {
|
||||
if (all_files[strlen(all_files)-1] == '\n') all_files[strlen(all_files)-1] = 0;
|
||||
for (int i = 0; i < _tpathnames; i++) delete[] _pathnames[i];
|
||||
delete[] _pathnames;
|
||||
p = all_files;
|
||||
int count = 1;
|
||||
while ((p = strchr(p+1, ' '))) count++;
|
||||
_pathnames = new char*[count];
|
||||
_tpathnames = 0;
|
||||
char *q = strtok(all_files, " ");
|
||||
while (q) {
|
||||
_pathnames[_tpathnames] = new char[strlen(q)+1];
|
||||
strcpy(_pathnames[_tpathnames], q);
|
||||
_tpathnames++;
|
||||
q = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] command;
|
||||
if (_title) { free(_title); _title = NULL; }
|
||||
if (!pipe) return -1;
|
||||
return (all_files == NULL ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::filename() const {
|
||||
return _tpathnames >= 1 ? _pathnames[0] : NULL;
|
||||
}
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::filename (int i) const {
|
||||
return _tpathnames > i ? _pathnames[i] : NULL;
|
||||
}
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::filter() const {
|
||||
return _filter;
|
||||
}
|
||||
|
||||
int Fl_Kdialog_Native_File_Chooser_Driver::filters() const {
|
||||
return (_nfilters ? _nfilters - 1 : 0);
|
||||
}
|
||||
|
||||
int Fl_Kdialog_Native_File_Chooser_Driver::count() const {
|
||||
return _tpathnames;
|
||||
}
|
||||
|
||||
char *Fl_Kdialog_Native_File_Chooser_Driver::parse_filter(const char *f) {
|
||||
//In: "*.H\n" or "*.H" Out: "(*.H)"
|
||||
//In: "Headers\t*.H\n" Out: "Headers (*.H)"
|
||||
//In: "Headers\t*.{H,h}\n" Out: "Headers (*.H *.h)"
|
||||
const char *p = strchr(f, '\t');
|
||||
if (!p) p = f - 1;
|
||||
const char *q = strchr(f, '\n'); if (!q) q = f + strlen(f);
|
||||
const char *r = strchr(f, '{');
|
||||
char *developed = NULL;
|
||||
if (r) { // with {}
|
||||
char *lead = new char[r-p];
|
||||
memcpy(lead, p+1, (r-p)-1); lead[(r-p)-1] = 0;
|
||||
const char *r2 = strchr(r, '}');
|
||||
char *ends = new char[r2-r];
|
||||
memcpy(ends, r+1, (r2-r)-1); ends[(r2-r)-1] = 0;
|
||||
char *ptr;
|
||||
char *part = strtok_r(ends, ",", &ptr);
|
||||
while (part) {
|
||||
developed = strapp(developed, lead);
|
||||
developed = strapp(developed, part);
|
||||
developed = strapp(developed, " ");
|
||||
part = strtok_r(NULL, ",", &ptr);
|
||||
}
|
||||
if (developed[strlen(developed)-1] == ' ') developed[strlen(developed)-1] = 0;
|
||||
delete[] lead;
|
||||
delete[] ends;
|
||||
}
|
||||
int lout = (p>f?p-f:0) + 2 + (r?strlen(developed):((q-p)-1)) + 2;
|
||||
char *out = new char[lout]; *out = 0;
|
||||
if (p > f) {memcpy(out, f, p-f); out[p-f] = 0; }
|
||||
strcat(out, " (");
|
||||
if (r) {
|
||||
strcpy(out+strlen(out), developed);
|
||||
strfree(developed);
|
||||
}
|
||||
else memcpy(out+strlen(out), p+1, (q-p));
|
||||
strcat(out, ")");
|
||||
//puts(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void Fl_Kdialog_Native_File_Chooser_Driver::filter(const char *f) {
|
||||
_parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any)
|
||||
_nfilters = 0;
|
||||
if (!f) return;
|
||||
_filter = strdup(f);
|
||||
char *f2 = strdup(f);
|
||||
char *ptr;
|
||||
char *part = strtok_r(f2, "\n", &ptr);
|
||||
while (part) {
|
||||
char *p = parse_filter(part);
|
||||
_parsedfilt = strapp(_parsedfilt, p);
|
||||
_parsedfilt = strapp(_parsedfilt, "\\n");
|
||||
delete[] p;
|
||||
_nfilters++;
|
||||
part = strtok_r(NULL, "\n", &ptr);
|
||||
}
|
||||
free(f2);
|
||||
_parsedfilt = strapp(_parsedfilt, "All files (*)");
|
||||
_nfilters++;
|
||||
//puts(_parsedfilt);
|
||||
}
|
||||
|
||||
void Fl_Kdialog_Native_File_Chooser_Driver::preset_file(const char *val) {
|
||||
if (_preset_file) free(_preset_file);
|
||||
_preset_file = strdup(val);
|
||||
}
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::preset_file() const {
|
||||
return _preset_file;
|
||||
}
|
||||
|
||||
void Fl_Kdialog_Native_File_Chooser_Driver::directory(const char *val) {
|
||||
if (_directory) free(_directory);
|
||||
_directory = strdup(val);
|
||||
}
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::directory() const {
|
||||
return _directory;
|
||||
}
|
||||
|
||||
void Fl_Kdialog_Native_File_Chooser_Driver::title(const char *val)
|
||||
{
|
||||
if (_title) free(_title);
|
||||
_title = strdup(val);
|
||||
}
|
||||
|
||||
const char *Fl_Kdialog_Native_File_Chooser_Driver::title() const {
|
||||
return _title;
|
||||
}
|
|
@ -268,6 +268,7 @@ XLIBCPPFILES = \
|
|||
fl_dnd_x.cxx \
|
||||
Fl_Native_File_Chooser_FLTK.cxx \
|
||||
Fl_Native_File_Chooser_GTK.cxx\
|
||||
Fl_Native_File_Chooser_Kdialog.cxx \
|
||||
Fl_get_key.cxx
|
||||
|
||||
# This C file is used under condition: BUILD_X11
|
||||
|
|
Loading…
Reference in New Issue