You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2013 lines
58 KiB
2013 lines
58 KiB
/************************************************************************
|
|
*
|
|
* All dialogs opened are created and used modal.
|
|
*
|
|
************************************************************************
|
|
* (C) Craig Drummond, 2006
|
|
************************************************************************
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
************************************************************************/
|
|
|
|
/*
|
|
NOTES:
|
|
|
|
1. Inkscape does not use the standard Gtk fileters to determine Save type
|
|
...it uses an extra combo, which we try to locate.
|
|
2. Firefox. This has two filters with the same patterns - *.htm and *.html. We
|
|
modify this so that one is *.htm and the other is *.html
|
|
3. Glade-2 I noticed this crash a couple of times on loading - but not always.
|
|
Not sure if this is a Glade problem or not...
|
|
*/
|
|
|
|
/*
|
|
TODO
|
|
abiword: seems to call gtk_widget_show - but just overriding this cuases the dialog to
|
|
appear twice, and then it still donest use result :-(
|
|
Overload font picker!
|
|
Overload normal old file selector? ie. in addtition to file chooser?
|
|
Message boxes: Auto set alternative button order?
|
|
*/
|
|
|
|
/*
|
|
#define KGTK_DEBUG
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <dlfcn.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib.h>
|
|
#include <gdk/gdkx.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <pwd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdarg.h>
|
|
#include "connect.h"
|
|
#include "config.h"
|
|
|
|
#ifndef KGTK_DLSYM_VERSION
|
|
#define KGTK_DLSYM_VERSION "GLIBC_2.0"
|
|
#endif
|
|
|
|
/*
|
|
#define KGTK_DEBUG_DLSYM
|
|
*/
|
|
|
|
/*
|
|
* For SWT apps (e.g. eclipse) we need to override dlsym, but we can only do this if
|
|
* dlvsym is present in libdl. dlvsym is needed so that we can access the real dlsym
|
|
* as well as our fake dlsym
|
|
*/
|
|
#ifdef HAVE_DLVSYM
|
|
static void * real_dlsym (void *handle, const char *name);
|
|
#else
|
|
#define real_dlsym(A, B) dlsym(A, B)
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
APP_ANY,
|
|
APP_GIMP,
|
|
APP_INKSCAPE,
|
|
APP_FIREFOX,
|
|
APP_KINO
|
|
} Application;
|
|
|
|
static const char *kgtkAppName=NULL;
|
|
static gboolean useKde=FALSE;
|
|
static gboolean kdialogdError=FALSE;
|
|
static GMainLoop *kdialogdLoop=NULL;
|
|
static gchar *kgtkFileFilter=NULL;
|
|
static Application kgtkApp=APP_ANY;
|
|
|
|
#define MAX_DATA_LEN 4096
|
|
#define MAX_FILTER_LEN 256
|
|
#define MAX_LINE_LEN 1024
|
|
#define MAX_APP_NAME_LEN 32
|
|
|
|
static char * kgtk_get_app_name(int pid)
|
|
{
|
|
static char app_name[MAX_APP_NAME_LEN+1]="\0";
|
|
|
|
int procFile=-1;
|
|
char cmdline[MAX_LINE_LEN+1];
|
|
|
|
sprintf(cmdline, "/proc/%d/cmdline",pid);
|
|
|
|
if(-1!=(procFile=open(cmdline, O_RDONLY)))
|
|
{
|
|
if(read(procFile, cmdline, MAX_LINE_LEN)>2)
|
|
{
|
|
int len=strlen(cmdline),
|
|
pos=0;
|
|
|
|
for(pos=len-1; pos>0 && cmdline[pos] && cmdline[pos]!='/'; --pos)
|
|
;
|
|
|
|
if(pos>=0 && pos<len)
|
|
{
|
|
strncpy(app_name, &cmdline[pos ? pos+1 : 0], MAX_APP_NAME_LEN);
|
|
app_name[MAX_APP_NAME_LEN]='\0';
|
|
}
|
|
}
|
|
close(procFile);
|
|
}
|
|
|
|
return app_name;
|
|
}
|
|
|
|
/* Try to get name of application executable - either from argv[0], or /proc */
|
|
static const gchar *getAppName(const gchar *app)
|
|
{
|
|
static const char *appName=NULL;
|
|
|
|
if(!appName)
|
|
{
|
|
/* Is there an app name set? - if not read from /proc */
|
|
const gchar *a=app ? app : kgtk_get_app_name(getpid());
|
|
gchar *slash;
|
|
|
|
/* Was the cmdline app java? if so, try to use its parent name - just in case
|
|
its run from a shell script, etc. - e.g. as eclipse does */
|
|
if(a && 0==strcmp(a, "java"))
|
|
a=kgtk_get_app_name(getppid());
|
|
|
|
if(a && a[0]=='\0')
|
|
a=NULL;
|
|
|
|
appName=a && (slash=strrchr(a, '/')) && '\0'!=slash[1]
|
|
? &(slash[1])
|
|
: a ? a : "GtkApp";
|
|
}
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::getAppName: %s\n", appName);
|
|
#endif
|
|
return appName;
|
|
}
|
|
|
|
static gboolean writeString(const char *s)
|
|
{
|
|
unsigned int slen=strlen(s)+1;
|
|
|
|
return writeBlock(kdialogdSocket, (char *)&slen, 4) &&
|
|
writeBlock(kdialogdSocket, s, slen);
|
|
}
|
|
|
|
static gboolean writeBool(gboolean b)
|
|
{
|
|
char bv=b ? 1 : 0;
|
|
|
|
return writeBlock(kdialogdSocket, (char *)&bv, 1);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
GSList *res;
|
|
gchar *selFilter;
|
|
} KGtkData;
|
|
|
|
static gpointer kdialogdMain(gpointer data)
|
|
{
|
|
KGtkData *d=(struct KGtkData *)data;
|
|
char buffer[MAX_DATA_LEN+1]={'\0'};
|
|
int num=0;
|
|
|
|
if(readBlock(kdialogdSocket, (char *)&num, 4))
|
|
{
|
|
int n;
|
|
|
|
for(n=0; n<num && !kdialogdError; ++n)
|
|
{
|
|
int size=0;
|
|
|
|
if(readBlock(kdialogdSocket, (char *)&size, 4))
|
|
{
|
|
if(size>0)
|
|
{
|
|
if(size<=MAX_DATA_LEN && readBlock(kdialogdSocket, buffer, size))
|
|
{
|
|
/*buffer[size-1]='\0'; */
|
|
if('/'==buffer[0])
|
|
d->res=g_slist_prepend(d->res, g_filename_from_utf8(buffer, -1, NULL, NULL, NULL));
|
|
else if(!(d->selFilter))
|
|
d->selFilter=g_strdup(buffer);
|
|
}
|
|
else
|
|
kdialogdError=TRUE;
|
|
}
|
|
}
|
|
else
|
|
kdialogdError=TRUE;
|
|
}
|
|
}
|
|
else
|
|
kdialogdError=TRUE;
|
|
|
|
if(g_main_loop_is_running(kdialogdLoop))
|
|
g_main_loop_quit(kdialogdLoop);
|
|
|
|
return 0L;
|
|
}
|
|
|
|
static gboolean sendMessage(GtkWidget *widget, Operation op, GSList **res, gchar **selFilter,
|
|
const char *title, const char *p1, const char *p2, gboolean overWrite)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::sendMessage\n");
|
|
#endif
|
|
|
|
if(connectToKDialogD(getAppName(kgtkAppName)))
|
|
{
|
|
char o=(char)op;
|
|
int xid=0;
|
|
|
|
if(widget)
|
|
{
|
|
if(widget->parent)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Dialog has a parent!\n");
|
|
#endif
|
|
xid=GDK_WINDOW_XID(gtk_widget_get_toplevel(widget->parent));
|
|
}
|
|
|
|
/*
|
|
Inkscape's 0.44 export bitmap filechooser is set to be transient for the main window, and
|
|
not the export dialog. This makes the KDE dialog appear underneath it! So, for inkscape
|
|
dont try to get the window transient for...
|
|
|
|
...might need to remove this whole section, if it starts to affect too many apps
|
|
*/
|
|
if(!xid && APP_INKSCAPE!=kgtkApp && GTK_IS_WINDOW(widget))
|
|
{
|
|
GtkWindow *win=gtk_window_get_transient_for(GTK_WINDOW(widget));
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Get window transient for...\n");
|
|
#endif
|
|
if(win && win->focus_widget)
|
|
xid=GDK_WINDOW_XID(gtk_widget_get_toplevel(win->focus_widget)->window);
|
|
}
|
|
}
|
|
|
|
if(!xid)
|
|
{
|
|
GList *topWindows,
|
|
*node;
|
|
int prevX=0;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::No xid, need to traverse window list...\n");
|
|
#endif
|
|
for(topWindows=node=gtk_window_list_toplevels(); node; node = node->next)
|
|
{
|
|
GtkWidget *w=node->data;
|
|
|
|
if(w && GTK_IS_WIDGET(w) && w->window)
|
|
if(gtk_window_has_toplevel_focus(GTK_WINDOW(w)) &&
|
|
gtk_window_is_active(GTK_WINDOW(w)))
|
|
{
|
|
/* If the currently active window is a popup - then assume it is a popup-menu,
|
|
* so use the previous window as the one to be transient for...*/
|
|
if(GTK_WINDOW_POPUP==GTK_WINDOW(w)->type && prevX)
|
|
xid=prevX;
|
|
else
|
|
xid=GDK_WINDOW_XID(w->window);
|
|
if(xid)
|
|
break;
|
|
}
|
|
else
|
|
prevX=GDK_WINDOW_XID(w->window);
|
|
}
|
|
g_list_free(topWindows);
|
|
}
|
|
|
|
if(writeBlock(kdialogdSocket, &o, 1) &&
|
|
writeBlock(kdialogdSocket, (char *)&xid, 4) &&
|
|
writeString(title) &&
|
|
(p1 ? writeString(p1) : TRUE) &&
|
|
(p2 ? writeString(p2) : TRUE) &&
|
|
(OP_FILE_SAVE==op ? writeBool(overWrite) : TRUE))
|
|
{
|
|
GtkWidget *dlg=gtk_dialog_new();
|
|
KGtkData d;
|
|
|
|
gtk_widget_set_name(dlg, "--kgtk-modal-dialog-hack--");
|
|
d.res=NULL;
|
|
d.selFilter=NULL;
|
|
|
|
/* Create a tmporary, hidden, dialog so that the kde dialog appears as modal */
|
|
g_object_ref(dlg);
|
|
gtk_window_set_modal(GTK_WINDOW(dlg), TRUE);
|
|
gtk_window_iconify(GTK_WINDOW(dlg));
|
|
gtk_dialog_set_has_separator(GTK_DIALOG(dlg), FALSE);
|
|
gtk_window_set_has_frame(GTK_WINDOW(dlg), FALSE);
|
|
gtk_window_set_decorated(GTK_WINDOW(dlg), FALSE);
|
|
gtk_window_set_keep_below(GTK_WINDOW(dlg), TRUE);
|
|
gtk_window_set_opacity(GTK_WINDOW(dlg), 100);
|
|
gtk_window_set_type_hint(GTK_WINDOW(dlg), GDK_WINDOW_TYPE_HINT_DOCK);
|
|
gtk_widget_show(dlg);
|
|
gtk_window_move(GTK_WINDOW(dlg), 32768, 32768);
|
|
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dlg), TRUE);
|
|
gtk_window_set_skip_pager_hint(GTK_WINDOW(dlg), TRUE);
|
|
kdialogdLoop = g_main_loop_new (NULL, FALSE);
|
|
kdialogdError=FALSE;
|
|
g_thread_create(&kdialogdMain, &d, FALSE, NULL);
|
|
|
|
GDK_THREADS_LEAVE();
|
|
g_main_loop_run(kdialogdLoop);
|
|
GDK_THREADS_ENTER();
|
|
g_main_loop_unref(kdialogdLoop);
|
|
kdialogdLoop = NULL;
|
|
gtk_window_set_modal(GTK_WINDOW(dlg), FALSE);
|
|
g_object_unref(dlg);
|
|
gtk_widget_destroy(dlg);
|
|
if(kdialogdError)
|
|
{
|
|
closeConnection();
|
|
return FALSE;
|
|
}
|
|
if(d.res)
|
|
{
|
|
if(res)
|
|
*res=d.res;
|
|
else
|
|
g_slist_free(d.res);
|
|
}
|
|
if(d.selFilter)
|
|
{
|
|
if(selFilter)
|
|
*selFilter=d.selFilter;
|
|
else
|
|
g_free(d.selFilter);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gchar * firstEntry(GSList *files)
|
|
{
|
|
gchar *file=NULL;
|
|
|
|
if(files)
|
|
{
|
|
file=(gchar *)(files->data);
|
|
files=g_slist_delete_link(files, files);
|
|
if(files)
|
|
{
|
|
g_slist_foreach(files, (GFunc)g_free, NULL);
|
|
g_slist_free(files);
|
|
files=NULL;
|
|
}
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
static const char * getTitle(const char *title, Operation op)
|
|
{
|
|
if(title && strlen(title))
|
|
return title;
|
|
|
|
return ".";
|
|
}
|
|
|
|
static gboolean openKdeDialog(GtkWidget *widget, const char *title, const char *p1, const char *p2,
|
|
Operation op, GSList **res, gchar **selFilter, gboolean overWrite)
|
|
{
|
|
gboolean rv=sendMessage(widget, op, res, selFilter, getTitle(title, op), p1, p2, overWrite);
|
|
|
|
/* If we failed to talk to, or start kdialogd, then dont keep trying - just fall back to Gtk */
|
|
/*
|
|
if(!rv)
|
|
useKde=FALSE;
|
|
*/
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void kgtkExit()
|
|
{
|
|
if(useKde)
|
|
closeConnection();
|
|
}
|
|
|
|
static gboolean isApp(const char *str, const char *app)
|
|
{
|
|
/* Standard case... */
|
|
if(0==strcmp(str, app))
|
|
return TRUE;
|
|
|
|
/* Autopackage'd app */
|
|
#define AUTOPACKAGE_PROXY ".proxy."
|
|
#define AUTOPACKAGE_PROXY_LEN 7
|
|
|
|
if(str==strstr(str, ".proxy.") && strlen(str)>AUTOPACKAGE_PROXY_LEN &&
|
|
0==strcmp(&str[AUTOPACKAGE_PROXY_LEN], app))
|
|
return TRUE;
|
|
|
|
/* gimp and mozilla */
|
|
{
|
|
int app_len=strlen(app);
|
|
|
|
if(strlen(str)>app_len && str==strstr(str, app) &&
|
|
(0==memcmp(&str[app_len], "-2", 2) ||
|
|
0==memcmp(&str[app_len], "-bin", 4)))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean isMozApp(const char *app, const char *check)
|
|
{
|
|
if(0==strcmp(app, check))
|
|
return TRUE;
|
|
else if(app==strstr(app, check))
|
|
{
|
|
int app_len=strlen(app),
|
|
check_len=strlen(check);
|
|
|
|
if(check_len+4 == app_len && 0==strcmp(&app[check_len], "-bin"))
|
|
return TRUE;
|
|
|
|
/* OK check for xulrunner-1.9 */
|
|
{
|
|
double dummy;
|
|
if(app_len>(check_len+1) && 1==sscanf(&app[check_len+1], "%f", &dummy))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean kgtkInit(const char *appName)
|
|
{
|
|
static gboolean initialised=FALSE;
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::kgtkInit %s\n", appName);
|
|
#endif
|
|
if(!initialised)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Running under KDE? %d\n", NULL!=getenv("TDE_FULL_SESSION"));
|
|
#endif
|
|
|
|
initialised=TRUE;
|
|
kgtkAppName=getAppName(appName);
|
|
useKde=NULL!=getenv("TDE_FULL_SESSION") && connectToKDialogD(kgtkAppName);
|
|
if(useKde)
|
|
{
|
|
const gchar *prg=getAppName(NULL);
|
|
|
|
if(prg)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::APP %s\n", prg);
|
|
#endif
|
|
if(isApp(prg, "inkscape"))
|
|
{
|
|
kgtkFileFilter="*.svg|Scalable Vector Graphic";
|
|
kgtkApp=APP_INKSCAPE;
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Inkscape\n");
|
|
#endif
|
|
}
|
|
else if(isApp(prg, "gimp"))
|
|
{
|
|
kgtkApp=APP_GIMP;
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::GIMP\n");
|
|
#endif
|
|
}
|
|
else if(isApp(prg, "kino"))
|
|
{
|
|
kgtkApp=APP_KINO;
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::kino\n");
|
|
#endif
|
|
}
|
|
else if(isMozApp(prg, "firefox") || isMozApp(prg, "swiftfox") || isMozApp(prg, "iceweasel") || isMozApp(prg, "xulrunner"))
|
|
{
|
|
kgtkApp=APP_FIREFOX;
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Firefox\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if(!g_threads_got_initialized)
|
|
g_thread_init(NULL);
|
|
atexit(&kgtkExit);
|
|
}
|
|
}
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::kgtkInit useKde:%d\n", useKde);
|
|
#endif
|
|
|
|
return useKde;
|
|
}
|
|
|
|
/* ......................... */
|
|
|
|
typedef struct _GtkFileSystem GtkFileSystem;
|
|
typedef struct _GtkFilePath GtkFilePath;
|
|
typedef struct _GtkFileSystemModel GtkFileSystemModel;
|
|
struct _GtkFileFilter
|
|
{
|
|
GtkObject parent_instance;
|
|
|
|
gchar *name;
|
|
GSList *rules;
|
|
|
|
GtkFileFilterFlags needed;
|
|
};
|
|
|
|
typedef enum {
|
|
FILTER_RULE_PATTERN,
|
|
FILTER_RULE_MIME_TYPE,
|
|
FILTER_RULE_PIXBUF_FORMATS,
|
|
FILTER_RULE_CUSTOM
|
|
} FilterRuleType;
|
|
|
|
struct _FilterRule
|
|
{
|
|
FilterRuleType type;
|
|
GtkFileFilterFlags needed;
|
|
|
|
union {
|
|
gchar *pattern;
|
|
gchar *mime_type;
|
|
GSList *pixbuf_formats;
|
|
struct {
|
|
GtkFileFilterFunc func;
|
|
gpointer data;
|
|
GDestroyNotify notify;
|
|
} custom;
|
|
} u;
|
|
};
|
|
|
|
#if GTK_CHECK_VERSION(2, 6, 0)
|
|
struct _GtkFileChooserButtonPrivate
|
|
{
|
|
GtkWidget *dialog;
|
|
GtkWidget *button;
|
|
GtkWidget *image;
|
|
GtkWidget *label;
|
|
GtkWidget *combo_box;
|
|
|
|
GtkCellRenderer *icon_cell;
|
|
GtkCellRenderer *name_cell;
|
|
|
|
GtkTreeModel *model;
|
|
GtkTreeModel *filter_model;
|
|
|
|
gchar *backend;
|
|
GtkFileSystem *fs;
|
|
GtkFilePath *old_path;
|
|
|
|
gulong combo_box_changed_id;
|
|
gulong dialog_file_activated_id;
|
|
gulong dialog_folder_changed_id;
|
|
gulong dialog_selection_changed_id;
|
|
gulong fs_volumes_changed_id;
|
|
gulong fs_bookmarks_changed_id;
|
|
};
|
|
#endif
|
|
|
|
/* TreeModel Columns */
|
|
enum
|
|
{
|
|
ICON_COLUMN,
|
|
DISPLAY_NAME_COLUMN,
|
|
TYPE_COLUMN,
|
|
DATA_COLUMN,
|
|
NUM_COLUMNS
|
|
};
|
|
|
|
/* TreeModel Row Types */
|
|
typedef enum
|
|
{
|
|
ROW_TYPE_SPECIAL,
|
|
ROW_TYPE_VOLUME,
|
|
ROW_TYPE_SHORTCUT,
|
|
ROW_TYPE_BOOKMARK_SEPARATOR,
|
|
ROW_TYPE_BOOKMARK,
|
|
ROW_TYPE_CURRENT_FOLDER_SEPARATOR,
|
|
ROW_TYPE_CURRENT_FOLDER,
|
|
ROW_TYPE_OTHER_SEPARATOR,
|
|
ROW_TYPE_OTHER,
|
|
|
|
ROW_TYPE_INVALID = -1
|
|
}
|
|
RowType;
|
|
|
|
static GtkWidget *
|
|
kgtk_file_chooser_dialog_new_valist (const gchar *title,
|
|
GtkWindow *parent,
|
|
GtkFileChooserAction action,
|
|
const gchar *backend,
|
|
const gchar *first_button_text,
|
|
va_list varargs)
|
|
{
|
|
GtkWidget *result;
|
|
const char *button_text = first_button_text;
|
|
gint response_id;
|
|
|
|
result = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
|
|
"title", title,
|
|
"action", action,
|
|
"file-system-backend", backend,
|
|
NULL);
|
|
|
|
if (parent)
|
|
gtk_window_set_transient_for (GTK_WINDOW (result), parent);
|
|
|
|
while (button_text)
|
|
{
|
|
response_id = va_arg (varargs, gint);
|
|
gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
|
|
button_text = va_arg (varargs, const gchar *);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
/* ......................... */
|
|
|
|
gboolean gtk_init_check(int *argc, char ***argv)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
gboolean rv=FALSE;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_init_check");
|
|
|
|
rv=realFunction(argc, argv);
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_init_check\n");
|
|
#endif
|
|
if(rv)
|
|
kgtkInit(argv && argc ? (*argv)[0] : NULL);
|
|
return rv;
|
|
}
|
|
|
|
void gtk_init(int *argc, char ***argv)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_init");
|
|
|
|
realFunction(argc, argv);
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_init\n");
|
|
#endif
|
|
kgtkInit(argv && argc ? (*argv)[0] : NULL);
|
|
}
|
|
|
|
/* Store a hash from widget pointer to folder/file list retried from KDialogD */
|
|
static GHashTable *fileDialogHash=NULL;
|
|
|
|
typedef struct
|
|
{
|
|
gchar *folder;
|
|
gchar *name;
|
|
GSList *files;
|
|
int ok,
|
|
cancel;
|
|
gboolean setOverWrite,
|
|
doOverwrite;
|
|
} KGtkFileData;
|
|
|
|
static KGtkFileData * lookupHash(void *hash, gboolean create)
|
|
{
|
|
KGtkFileData *rv=NULL;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::lookupHash %X\n", (int)hash);
|
|
#endif
|
|
if(!fileDialogHash)
|
|
fileDialogHash=g_hash_table_new(g_int_hash, g_int_equal);
|
|
|
|
rv=(KGtkFileData *)g_hash_table_lookup(fileDialogHash, hash);
|
|
|
|
if(!rv && create)
|
|
{
|
|
rv=(KGtkFileData *)malloc(sizeof(KGtkFileData));
|
|
rv->folder=NULL;
|
|
rv->files=NULL;
|
|
rv->name=NULL;
|
|
rv->ok=GTK_RESPONSE_OK;
|
|
rv->cancel=GTK_RESPONSE_CANCEL;
|
|
rv->setOverWrite=FALSE;
|
|
rv->doOverwrite=FALSE;
|
|
g_hash_table_insert(fileDialogHash, hash, rv);
|
|
rv=g_hash_table_lookup(fileDialogHash, hash);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void freeHash(void *hash)
|
|
{
|
|
KGtkFileData *data=NULL;
|
|
|
|
if(!fileDialogHash)
|
|
fileDialogHash=g_hash_table_new(g_int_hash, g_int_equal);
|
|
|
|
data=(KGtkFileData *)g_hash_table_lookup(fileDialogHash, hash);
|
|
|
|
if(data)
|
|
{
|
|
if(data->folder)
|
|
g_free(data->folder);
|
|
if(data->name)
|
|
g_free(data->name);
|
|
if(data->files)
|
|
{
|
|
g_slist_foreach(data->files, (GFunc)g_free, NULL);
|
|
g_slist_free(data->files);
|
|
}
|
|
data->files=NULL;
|
|
data->folder=NULL;
|
|
data->name=NULL;
|
|
g_hash_table_remove(fileDialogHash, hash);
|
|
}
|
|
}
|
|
|
|
/* Some Gtk apps have filter pattern *.[Pp][Nn][Gg] - wherease TQt/KDE prefer *.png */
|
|
#define MAX_PATTERN_LEN 64
|
|
static gchar *modifyFilter(const char *filter)
|
|
{
|
|
int i=0;
|
|
gboolean brackets=FALSE;
|
|
const char *p;
|
|
static char res[MAX_PATTERN_LEN+1];
|
|
|
|
for(p=filter; p && *p && i<MAX_PATTERN_LEN; ++p)
|
|
switch(*p)
|
|
{
|
|
case '[':
|
|
p++;
|
|
if(p)
|
|
res[i++]=tolower(*p);
|
|
brackets=TRUE;
|
|
break;
|
|
case ']':
|
|
brackets=FALSE;
|
|
break;
|
|
default:
|
|
if(!brackets)
|
|
res[i++]=tolower(*p);
|
|
}
|
|
res[i++]='\0';
|
|
return res;
|
|
}
|
|
|
|
static GtkWidget * getCombo(GtkWidget *widget)
|
|
{
|
|
if(widget && GTK_IS_BOX(widget))
|
|
{
|
|
GList *child=GTK_BOX(widget)->children;
|
|
|
|
for(; child; child=child->next)
|
|
{
|
|
GtkBoxChild *boxChild=(GtkBoxChild *)child->data;
|
|
|
|
if(GTK_IS_COMBO_BOX(boxChild->widget))
|
|
return boxChild->widget;
|
|
else if(GTK_IS_BOX(boxChild->widget))
|
|
{
|
|
GtkWidget *box=getCombo(boxChild->widget);
|
|
|
|
if(box)
|
|
return box;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static GString * getFilters(GtkDialog *dialog, GtkFileChooserAction act)
|
|
{
|
|
GString *filter=NULL;
|
|
GSList *list=gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog));
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Get list of filters...\n");
|
|
#endif
|
|
|
|
if(list)
|
|
{
|
|
GSList *item;
|
|
int filterNum=0;
|
|
|
|
filter=g_string_new("");
|
|
for(item=list; item; item=g_slist_next(item), ++filterNum)
|
|
{
|
|
GtkFileFilter *f=(GtkFileFilter *)(item->data);
|
|
|
|
if(f)
|
|
{
|
|
const gchar *name=gtk_file_filter_get_name(f);
|
|
GSList *rule=((struct _GtkFileFilter *)f)->rules;
|
|
GString *pattern=g_string_new("");
|
|
|
|
for(; rule; rule=g_slist_next(rule))
|
|
switch(((struct _FilterRule *)rule->data)->type)
|
|
{
|
|
case FILTER_RULE_PATTERN:
|
|
{
|
|
const char *modPat=
|
|
modifyFilter(((struct _FilterRule *)rule->data)->u.pattern);
|
|
|
|
/*
|
|
Firefox has:
|
|
*.htm *.html | Web page complete
|
|
*.htm *.html | HTML only
|
|
*.txt *.text | Text
|
|
|
|
We modify this to have:
|
|
*.htm | Web page complete
|
|
*.html | HTML only
|
|
*.txt *.text | Text
|
|
*/
|
|
|
|
if(APP_FIREFOX!=kgtkApp || (strcmp(modPat, "*.html") ? filterNum!=1
|
|
: filterNum))
|
|
{
|
|
if(pattern->len)
|
|
pattern=g_string_append(pattern, " ");
|
|
pattern=g_string_append(pattern, modPat);
|
|
}
|
|
break;
|
|
}
|
|
case FILTER_RULE_MIME_TYPE:
|
|
if(filter->len)
|
|
filter=g_string_append(filter, "\n");
|
|
filter=g_string_append(filter,
|
|
((struct _FilterRule *)rule->data)->u.mime_type);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(name && pattern && pattern->len)
|
|
{
|
|
gchar *n=g_strdup(name),
|
|
*pat=strstr(n, " (*");
|
|
|
|
if(pat)
|
|
*pat='\0';
|
|
|
|
if(filter->len)
|
|
filter=g_string_append(filter, "\n");
|
|
filter=g_string_append(filter, pattern->str);
|
|
filter=g_string_append(filter, "|");
|
|
filter=g_string_append(filter, n);
|
|
g_free(n);
|
|
}
|
|
g_string_free(pattern, TRUE);
|
|
}
|
|
}
|
|
g_slist_free(list);
|
|
}
|
|
|
|
if(!filter)
|
|
{
|
|
/* This is mainly the case for Inkscape save - but try for other apps too... */
|
|
GtkWidget *combo=getCombo(gtk_file_chooser_get_extra_widget(GTK_FILE_CHOOSER(dialog)));
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::No filters found, try to look for an extra combo widget...\n");
|
|
#endif
|
|
|
|
if(combo)
|
|
{
|
|
int i;
|
|
|
|
filter=g_string_new("");
|
|
for(i=0; i<64; ++i)
|
|
{
|
|
gchar *text=NULL;
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
|
|
if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
|
|
break;
|
|
|
|
text=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
|
|
|
|
if(text)
|
|
{
|
|
gchar *pat=strstr(text, " (*");
|
|
|
|
if(pat)
|
|
{
|
|
gchar *close=strstr(pat, ")");
|
|
|
|
*pat='\0';
|
|
|
|
if(close)
|
|
*close='\0';
|
|
|
|
pat+=2; /* Skip past " (" */
|
|
|
|
if(filter->len)
|
|
filter=g_string_append(filter, "\n");
|
|
filter=g_string_append(filter, pat);
|
|
filter=g_string_append(filter, "|");
|
|
filter=g_string_append(filter, text);
|
|
}
|
|
g_free(text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return filter;
|
|
}
|
|
|
|
static void setFilter(const gchar *filter, GtkDialog *dialog, GtkFileChooserAction act)
|
|
{
|
|
gboolean found=FALSE;
|
|
GSList *list=gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog));
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::Need to locate filter:%s\n", filter ? filter : "Null");
|
|
#endif
|
|
|
|
if(list)
|
|
{
|
|
GSList *item;
|
|
unsigned int flen=strlen(filter);
|
|
int filterNum=0;
|
|
|
|
for(item=list; item && !found; item=g_slist_next(item), filterNum++)
|
|
{
|
|
GtkFileFilter *f=(GtkFileFilter *)(item->data);
|
|
|
|
if(f)
|
|
{
|
|
GSList *rule=((struct _GtkFileFilter *)f)->rules;
|
|
char *start=NULL;
|
|
|
|
for(; rule && !found; rule=g_slist_next(rule))
|
|
if(FILTER_RULE_PATTERN==((struct _FilterRule *)rule->data)->type)
|
|
{
|
|
char *filt=modifyFilter(((struct _FilterRule *)rule->data)->u.pattern);
|
|
|
|
/*
|
|
Firefox has:
|
|
*.htm *.html | Web page complete
|
|
*.htm *.html | HTML only
|
|
*.txt *.text | Text
|
|
|
|
We modify this to have:
|
|
*.htm | Web page complete
|
|
*.html | HTML only
|
|
*.txt *.text | Text
|
|
*/
|
|
|
|
if((APP_FIREFOX!=kgtkApp || (strcmp(filt, "*.html") ? filterNum!=1
|
|
: filterNum)) &&
|
|
(start=strstr(filter, filt)))
|
|
{
|
|
unsigned int slen=strlen(filt);
|
|
|
|
if(((start-filter)+slen)<=flen &&
|
|
(' '==start[slen] || '\t'==start[slen] ||
|
|
'\n'==start[slen] || '\0'==start[slen]))
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::FOUND FILTER\n");
|
|
#endif
|
|
found=TRUE;
|
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
g_slist_free(list);
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
/* This is mainly the case for Inkscape save - but try for other apps too... */
|
|
GtkWidget *combo=getCombo(gtk_file_chooser_get_extra_widget(GTK_FILE_CHOOSER(dialog)));
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::No filters found, try to look for an extra combo widget...\n");
|
|
#endif
|
|
if(combo)
|
|
{
|
|
int i,
|
|
flen=strlen(filter);
|
|
|
|
for(i=0; i<64; ++i)
|
|
{
|
|
gchar *text=NULL;
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
|
|
if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
|
|
break;
|
|
|
|
text=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
|
|
|
|
if(text)
|
|
{
|
|
gchar *pat=strstr(text, filter);
|
|
|
|
if(pat)
|
|
{
|
|
if(pat>text && (' '==pat[-1] || '('==pat[-1]) &&
|
|
(' '==pat[flen] || ')'==pat[flen]))
|
|
return; /* found a match, so just return - filter is set */
|
|
}
|
|
g_free(text);
|
|
}
|
|
}
|
|
|
|
/* No match :-( set to last filter... */
|
|
for(i=0; i<64; ++i)
|
|
{
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
|
|
if(i!=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static GSList * addProtocols(GSList *files)
|
|
{
|
|
GSList *item=files;
|
|
|
|
for(; item; item=g_slist_next(item))
|
|
{
|
|
gchar *cur=item->data;
|
|
item->data=g_filename_to_uri(item->data, NULL, NULL);
|
|
g_free(cur);
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
void gtk_window_present(GtkWindow *window)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_window_present");
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_window_present %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(window)),
|
|
GTK_IS_FILE_CHOOSER(window));
|
|
#endif
|
|
if(GTK_IS_FILE_CHOOSER(window)) /* || (APP_GIMP==kgtkApp &&
|
|
0==strcmp(gtk_type_name(GTK_WIDGET_TYPE(window)), "GimpFileDialog")))*/
|
|
gtk_dialog_run(GTK_DIALOG(window));
|
|
else
|
|
realFunction(window);
|
|
}
|
|
|
|
void gtk_widget_show(GtkWidget *widget)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_show");
|
|
|
|
if(widget && !GTK_IS_FILE_CHOOSER_BUTTON(widget) && GTK_IS_FILE_CHOOSER(widget))
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_widget_show %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(widget)),
|
|
GTK_IS_FILE_CHOOSER(widget));
|
|
#endif
|
|
gtk_dialog_run(GTK_DIALOG(widget));
|
|
GTK_OBJECT_FLAGS(widget)|=GTK_REALIZED;
|
|
}
|
|
else
|
|
realFunction(widget);
|
|
}
|
|
|
|
void gtk_widget_hide(GtkWidget *widget)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_hide");
|
|
|
|
if(widget && !GTK_IS_FILE_CHOOSER_BUTTON(widget) && GTK_IS_FILE_CHOOSER(widget))
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_widget_hide %s %d\n", gtk_type_name(GTK_WIDGET_TYPE(widget)),
|
|
GTK_IS_FILE_CHOOSER(widget));
|
|
#endif
|
|
if(GTK_OBJECT_FLAGS(widget)>K_REALIZED)
|
|
GTK_OBJECT_FLAGS(widget)-=GTK_REALIZED;
|
|
}
|
|
else
|
|
realFunction(widget);
|
|
}
|
|
|
|
gboolean gtk_file_chooser_get_do_overwrite_confirmation(GtkFileChooser *widget)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
gboolean rv=FALSE;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_get_do_overwrite_confirmation");
|
|
|
|
if(realFunction)
|
|
{
|
|
KGtkFileData *data=lookupHash(widget, FALSE);
|
|
|
|
if(data)
|
|
{
|
|
if(!data->setOverWrite)
|
|
{
|
|
data->setOverWrite=TRUE;
|
|
data->doOverwrite=(gboolean) realFunction(widget);
|
|
}
|
|
rv=data->doOverwrite;
|
|
}
|
|
else
|
|
rv=(gboolean) realFunction(widget);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* ext => called from app, not kgtk */
|
|
void kgtkFileChooserSetDoOverwriteConfirmation(GtkFileChooser *widget, gboolean v, gboolean ext)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_do_overwrite_confirmation");
|
|
|
|
if(realFunction)
|
|
{
|
|
realFunction(widget, v);
|
|
if(ext)
|
|
{
|
|
KGtkFileData *data=lookupHash(widget, FALSE);
|
|
|
|
if(data)
|
|
{
|
|
data->setOverWrite=TRUE;
|
|
data->doOverwrite=v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gboolean isOnFileChooser(GtkWidget *w)
|
|
{
|
|
return w
|
|
? GTK_IS_FILE_CHOOSER(w)
|
|
? TRUE
|
|
: isOnFileChooser(w->parent)
|
|
: FALSE;
|
|
}
|
|
|
|
int gtk_combo_box_get_active(GtkComboBox *combo)
|
|
{
|
|
int rv=0;
|
|
|
|
if(APP_KINO==kgtkApp && isOnFileChooser(combo))
|
|
return 1;
|
|
else
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_combo_box_get_active");
|
|
|
|
rv=(int)realFunction(combo);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
gint gtk_dialog_run(GtkDialog *dialog)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_dialog_run");
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_dialog_run %s \n", dialog ? gtk_type_name(GTK_WIDGET_TYPE(dialog)) : "<null>");
|
|
#endif
|
|
|
|
if(kgtkInit(NULL) && GTK_IS_FILE_CHOOSER(dialog))
|
|
{
|
|
static gboolean running=FALSE;
|
|
|
|
KGtkFileData *data=lookupHash(dialog, TRUE);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::run file chooser, already running? %d\n", running);
|
|
#endif
|
|
if(!running)
|
|
{
|
|
GtkFileChooserAction act=gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog));
|
|
gchar *current=NULL,
|
|
*selFilter=NULL;
|
|
const gchar *title=gtk_window_get_title(GTK_WINDOW(dialog));
|
|
GString *filter=NULL;
|
|
gint resp=data->cancel;
|
|
gboolean origOverwrite=
|
|
gtk_file_chooser_get_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog));
|
|
|
|
running=TRUE;
|
|
|
|
if(GTK_FILE_CHOOSER_ACTION_OPEN==act || GTK_FILE_CHOOSER_ACTION_SAVE==act)
|
|
filter=getFilters(dialog, act);
|
|
else /* GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER==act ||
|
|
GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER==act */
|
|
if(NULL==(current=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog))))
|
|
current=gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
|
|
|
|
kgtkFileChooserSetDoOverwriteConfirmation(GTK_FILE_CHOOSER(dialog), FALSE, FALSE);
|
|
|
|
switch(act)
|
|
{
|
|
case GTK_FILE_CHOOSER_ACTION_OPEN:
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_OPEN\n");
|
|
#endif
|
|
if(gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog)))
|
|
{
|
|
GSList *files=NULL;
|
|
|
|
openKdeDialog(GTK_WIDGET(dialog), title ? title : "",
|
|
data->folder ? data->folder : "",
|
|
filter && filter->len
|
|
? filter->str
|
|
: kgtkFileFilter
|
|
? kgtkFileFilter
|
|
: "", OP_FILE_OPEN_MULTIPLE, &files,
|
|
&selFilter, FALSE);
|
|
|
|
if(files)
|
|
{
|
|
GSList *c;
|
|
|
|
gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog));
|
|
for(c=files; c; c=g_slist_next(c))
|
|
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog),
|
|
(gchar *)(c->data));
|
|
g_slist_foreach(files, (GFunc)g_free, NULL);
|
|
g_slist_free(files);
|
|
|
|
resp=data->ok;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gchar *file=NULL;
|
|
GSList *res=NULL;
|
|
|
|
openKdeDialog(GTK_WIDGET(dialog), title ? title : "",
|
|
data->folder ? data->folder : "",
|
|
filter && filter->len
|
|
? filter->str
|
|
: kgtkFileFilter
|
|
? kgtkFileFilter
|
|
: "", OP_FILE_OPEN, &res, &selFilter, FALSE);
|
|
file=firstEntry(res);
|
|
|
|
if(file)
|
|
{
|
|
gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog));
|
|
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), file);
|
|
g_free(file);
|
|
resp=data->ok;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case GTK_FILE_CHOOSER_ACTION_SAVE:
|
|
{
|
|
gchar *file=NULL;
|
|
GSList *res=NULL;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_SAVE\n");
|
|
#endif
|
|
if(data->name)
|
|
{
|
|
GString *cur=g_string_new(data->folder ? data->folder
|
|
: get_current_dir_name());
|
|
|
|
cur=g_string_append(cur, "/");
|
|
cur=g_string_append(cur, data->name);
|
|
current=g_string_free(cur, FALSE);
|
|
}
|
|
|
|
openKdeDialog(GTK_WIDGET(dialog), title ? title : "",
|
|
current ? current : (data->folder ? data->folder : ""),
|
|
filter && filter->len
|
|
? filter->str
|
|
: kgtkFileFilter
|
|
? kgtkFileFilter
|
|
: "", OP_FILE_SAVE, &res, &selFilter, origOverwrite);
|
|
file=firstEntry(res);
|
|
|
|
if(file)
|
|
{
|
|
/* Firefox crashes when we save to an existing name -> so just delete it first! */
|
|
if(APP_FIREFOX==kgtkApp && origOverwrite)
|
|
{
|
|
struct stat info;
|
|
|
|
if(0==lstat(file, &info))
|
|
unlink(file);
|
|
}
|
|
gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog));
|
|
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), file);
|
|
g_free(file);
|
|
resp=data->ok;
|
|
}
|
|
break;
|
|
}
|
|
case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
|
|
case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
|
|
{
|
|
GSList *res=NULL;
|
|
gchar *folder=NULL;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
if(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER==act)
|
|
printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER\n");
|
|
else
|
|
printf("KGTK::run file chooser GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER\n");
|
|
#endif
|
|
openKdeDialog(GTK_WIDGET(dialog), title ? title : "",
|
|
data->folder ? data->folder : "", NULL,
|
|
OP_FOLDER, &res, NULL, FALSE);
|
|
folder=firstEntry(res);
|
|
|
|
if(folder)
|
|
{
|
|
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), folder);
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), folder);
|
|
g_free(folder);
|
|
resp=data->ok;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(current)
|
|
g_free(current);
|
|
|
|
if(filter)
|
|
g_string_free(filter, TRUE);
|
|
|
|
if(selFilter)
|
|
{
|
|
setFilter(selFilter, dialog, act);
|
|
g_free(selFilter);
|
|
}
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::RETURN RESP:%d\n", resp);
|
|
#endif
|
|
g_signal_emit_by_name(dialog, "response", resp);
|
|
running=FALSE;
|
|
return resp;
|
|
}
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::ALREADY RUNNING SO RETURN RESP:%d\n", data->cancel);
|
|
#endif
|
|
g_signal_emit_by_name(dialog, "response", data->cancel);
|
|
return data->cancel;
|
|
}
|
|
return realFunction(dialog);
|
|
}
|
|
|
|
void gtk_widget_destroy(GtkWidget *widget)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_widget_destroy");
|
|
|
|
if(fileDialogHash && GTK_IS_FILE_CHOOSER(widget))
|
|
freeHash(widget);
|
|
|
|
realFunction(widget);
|
|
}
|
|
|
|
gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, FALSE);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_filename %d %s\n", data ? g_slist_length(data->files) : 12345,
|
|
data && data->files && data->files->data ? data->files->data : "<>");
|
|
#endif
|
|
return data && data->files && data->files->data ? g_strdup(data->files->data) : NULL;
|
|
}
|
|
|
|
gboolean gtk_file_chooser_select_filename(GtkFileChooser *chooser, const char *filename)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, TRUE);
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_select_filename");
|
|
realFunction(chooser, filename);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_select_filename %s, %d\n", filename,
|
|
data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && filename)
|
|
{
|
|
GSList *c=NULL;
|
|
|
|
for(c=data->files; c; c=g_slist_next(c))
|
|
if(c->data && 0==strcmp((char *)(c->data), filename))
|
|
break;
|
|
|
|
if(!c)
|
|
{
|
|
gchar *folder=g_path_get_dirname(filename);
|
|
|
|
data->files=g_slist_prepend(data->files, g_strdup(filename));
|
|
|
|
if(folder && !data->folder || strcmp(folder, data->folder))
|
|
{
|
|
gtk_file_chooser_set_current_folder(chooser, folder);
|
|
g_free(folder);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void gtk_file_chooser_unselect_all(GtkFileChooser *chooser)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, TRUE);
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_unselect_all");
|
|
realFunction(chooser);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_unselect_all %d\n", data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && data->files)
|
|
{
|
|
g_slist_foreach(data->files, (GFunc)g_free, NULL);
|
|
g_slist_free(data->files);
|
|
data->files=NULL;
|
|
}
|
|
}
|
|
|
|
gboolean gtk_file_chooser_set_filename(GtkFileChooser *chooser, const char *filename)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, TRUE);
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_filename");
|
|
realFunction(chooser, filename);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_set_filename %s %d\n", filename,
|
|
data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && filename)
|
|
{
|
|
gchar *folder=g_path_get_dirname(filename),
|
|
*name=g_path_get_basename(filename);
|
|
|
|
if(data->files)
|
|
{
|
|
g_slist_foreach(data->files, (GFunc)g_free, NULL);
|
|
g_slist_free(data->files);
|
|
data->files=NULL;
|
|
}
|
|
|
|
data->files=g_slist_prepend(data->files, g_strdup(filename));
|
|
|
|
if(name && (!data->name || strcmp(name, data->name)))
|
|
gtk_file_chooser_set_current_name(chooser, name);
|
|
if(name)
|
|
g_free(name);
|
|
if(folder && (!data->folder || strcmp(folder, data->folder)))
|
|
gtk_file_chooser_set_current_folder(chooser, folder);
|
|
if(folder)
|
|
g_free(folder);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void gtk_file_chooser_set_current_name(GtkFileChooser *chooser, const char *filename)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, TRUE);
|
|
GtkFileChooserAction act=gtk_file_chooser_get_action(chooser);
|
|
|
|
if(GTK_FILE_CHOOSER_ACTION_SAVE==act || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER==act)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_current_name");
|
|
realFunction(chooser, filename);
|
|
}
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_set_current_name %s %d\n", filename,
|
|
data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && filename)
|
|
{
|
|
if(data->name)
|
|
g_free(data->name);
|
|
data->name=g_strdup(filename);
|
|
}
|
|
}
|
|
|
|
GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, FALSE);
|
|
GSList *rv=NULL;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_filenames %d\n", data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && data->files)
|
|
{
|
|
GSList *item=data->files;
|
|
|
|
for(; item; item=g_slist_next(item))
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::FILE:%s\n", item->data);
|
|
#endif
|
|
if(item->data)
|
|
rv=g_slist_prepend(rv, g_strdup(item->data));
|
|
}
|
|
}
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_filenames END\n");
|
|
#endif
|
|
return rv;
|
|
}
|
|
|
|
gboolean gtk_file_chooser_set_current_folder(GtkFileChooser *chooser, const gchar *folder)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, TRUE);
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_set_current_folder");
|
|
realFunction(chooser, folder);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_set_current_folder %s %d\n", folder,
|
|
data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(data && folder)
|
|
{
|
|
if(data->folder)
|
|
g_free(data->folder);
|
|
data->folder=g_strdup(folder);
|
|
}
|
|
g_signal_emit_by_name(chooser, "current-folder-changed", 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gchar * gtk_file_chooser_get_current_folder(GtkFileChooser *chooser)
|
|
{
|
|
KGtkFileData *data=lookupHash(chooser, FALSE);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_current_folder %d\n",
|
|
data ? g_slist_length(data->files) : 12345);
|
|
#endif
|
|
if(!data)
|
|
{
|
|
gtk_file_chooser_set_current_folder(chooser, get_current_dir_name());
|
|
data=g_hash_table_lookup(fileDialogHash, chooser);
|
|
}
|
|
|
|
return data && data->folder ? g_strdup(data->folder) : NULL;
|
|
}
|
|
|
|
gchar * gtk_file_chooser_get_uri(GtkFileChooser *chooser)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_uri\n");
|
|
#endif
|
|
gchar *filename=gtk_file_chooser_get_filename(chooser);
|
|
|
|
if(filename)
|
|
{
|
|
gchar *uri=g_filename_to_uri(filename, NULL, NULL);
|
|
|
|
g_free(filename);
|
|
return uri;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
gboolean gtk_file_chooser_set_uri(GtkFileChooser *chooser, const char *uri)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_set_uri\n");
|
|
#endif
|
|
|
|
gchar *file=g_filename_from_uri(uri, NULL, NULL);
|
|
gboolean rv=FALSE;
|
|
|
|
if(file)
|
|
{
|
|
rv=gtk_file_chooser_set_filename(chooser, file);
|
|
|
|
g_free(file);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
GSList * gtk_file_chooser_get_uris(GtkFileChooser *chooser)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_uris\n");
|
|
#endif
|
|
return addProtocols(gtk_file_chooser_get_filenames(chooser));
|
|
}
|
|
|
|
gboolean gtk_file_chooser_set_current_folder_uri(GtkFileChooser *chooser, const gchar *uri)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_set_current_folder_uri\n");
|
|
#endif
|
|
gchar *folder=g_filename_from_uri(uri, NULL, NULL);
|
|
gboolean rv=FALSE;
|
|
|
|
if(folder)
|
|
{
|
|
rv=gtk_file_chooser_set_current_folder(chooser, folder);
|
|
|
|
g_free(folder);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
gchar * gtk_file_chooser_get_current_folder_uri(GtkFileChooser *chooser)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_get_current_folder_uri\n");
|
|
#endif
|
|
|
|
gchar *folder=gtk_file_chooser_get_current_folder(chooser);
|
|
|
|
if(folder)
|
|
{
|
|
gchar *uri=g_filename_to_uri(folder, NULL, NULL);
|
|
|
|
g_free(folder);
|
|
return uri;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void g_signal_stop_emission_by_name(gpointer instance, const gchar *detailed_signal)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "g_signal_stop_emission_by_name");
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::g_signal_stop_emission_by_name %s %s (check)\n", gtk_type_name(GTK_WIDGET_TYPE(instance)), detailed_signal);
|
|
#endif
|
|
|
|
if(kgtkApp!=APP_GIMP || !GTK_IS_FILE_CHOOSER(instance) || strcmp(detailed_signal, "response"))
|
|
realFunction(instance, detailed_signal);
|
|
#ifdef KGTK_DEBUG
|
|
else
|
|
printf("KGTK::g_signal_stop_emission_by_name %s %s\n", gtk_type_name(GTK_WIDGET_TYPE(instance)), detailed_signal);
|
|
#endif
|
|
}
|
|
|
|
GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow *parent,
|
|
GtkFileChooserAction action, const gchar *first_button_text,
|
|
...)
|
|
{
|
|
GtkWidget *dlg=NULL;
|
|
KGtkFileData *data=NULL;
|
|
const char *text=first_button_text;
|
|
gint id;
|
|
va_list varargs;
|
|
|
|
va_start(varargs, first_button_text);
|
|
dlg=kgtk_file_chooser_dialog_new_valist(title, parent, action, NULL, first_button_text, varargs);
|
|
va_end(varargs);
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_dialog_new\n");
|
|
#endif
|
|
data=lookupHash(dlg, TRUE);
|
|
va_start(varargs, first_button_text);
|
|
while(text)
|
|
{
|
|
id = va_arg(varargs, gint);
|
|
|
|
if(text && (0==strcmp(text, GTK_STOCK_CANCEL) || 0==strcmp(text, GTK_STOCK_CLOSE) ||
|
|
0==strcmp(text, GTK_STOCK_QUIT) || 0==strcmp(text, GTK_STOCK_NO)))
|
|
data->cancel=id;
|
|
else if(text && (0==strcmp(text, GTK_STOCK_OK) || 0==strcmp(text, GTK_STOCK_OPEN) ||
|
|
0==strcmp(text, GTK_STOCK_SAVE) || 0==strcmp(text, GTK_STOCK_YES)))
|
|
data->ok=id;
|
|
text=va_arg(varargs, const gchar *);
|
|
}
|
|
va_end(varargs);
|
|
return dlg;
|
|
}
|
|
|
|
#if GTK_CHECK_VERSION(2, 6, 0)
|
|
static void handleGtkFileChooserButtonClicked(GtkButton *button, gpointer user_data)
|
|
{
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::handleGtkFileChooserButtonClicked\n");
|
|
#endif
|
|
gtk_dialog_run(GTK_FILE_CHOOSER_BUTTON(user_data)->priv->dialog);
|
|
}
|
|
|
|
static void handleGtkFileChooserComboChanged(GtkComboBox *combo_box, gpointer user_data)
|
|
{
|
|
static gboolean handle=TRUE;
|
|
GtkTreeIter iter;
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::handleGtkFileChooserComboChanged (handle:%d)\n", handle);
|
|
#endif
|
|
if(!handle)
|
|
return;
|
|
|
|
if(gtk_combo_box_get_active_iter (combo_box, &iter))
|
|
{
|
|
GtkFileChooserButtonPrivate *priv=GTK_FILE_CHOOSER_BUTTON(user_data)->priv;
|
|
gchar type=ROW_TYPE_INVALID;
|
|
|
|
gtk_tree_model_get(priv->filter_model, &iter, TYPE_COLUMN, &type, -1);
|
|
|
|
if(ROW_TYPE_OTHER==type)
|
|
gtk_dialog_run(GTK_FILE_CHOOSER_BUTTON(user_data)->priv->dialog);
|
|
else
|
|
{
|
|
g_signal_handler_unblock(priv->combo_box, priv->combo_box_changed_id);
|
|
handle=FALSE;
|
|
g_signal_emit_by_name(priv->combo_box, "changed");
|
|
handle=TRUE;
|
|
g_signal_handler_block(priv->combo_box, priv->combo_box_changed_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
GtkWidget * gtk_file_chooser_button_new(const gchar *title, GtkFileChooserAction action)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
GtkWidget *button=NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "gtk_file_chooser_button_new");
|
|
|
|
#ifdef KGTK_DEBUG
|
|
printf("KGTK::gtk_file_chooser_button_new\n");
|
|
#endif
|
|
|
|
if(kgtkInit(NULL))
|
|
{
|
|
GtkFileChooserButtonPrivate *priv=NULL;
|
|
|
|
button=realFunction(title, action);
|
|
priv=GTK_FILE_CHOOSER_BUTTON(button)->priv;
|
|
|
|
if(priv->button)
|
|
{
|
|
g_signal_handlers_disconnect_matched(priv->button,
|
|
G_SIGNAL_MATCH_DATA,0, 0, NULL, NULL, button);
|
|
|
|
g_signal_connect(priv->button, "clicked",
|
|
G_CALLBACK(handleGtkFileChooserButtonClicked),
|
|
GTK_FILE_CHOOSER_BUTTON(button));
|
|
}
|
|
if(priv->combo_box)
|
|
{
|
|
g_signal_handler_block(priv->combo_box, priv->combo_box_changed_id);
|
|
|
|
g_signal_connect(priv->combo_box, "changed",
|
|
G_CALLBACK(handleGtkFileChooserComboChanged),
|
|
GTK_FILE_CHOOSER_BUTTON(button));
|
|
}
|
|
}
|
|
return button;
|
|
}
|
|
#endif
|
|
|
|
static gboolean isGtk(const char *str)
|
|
{
|
|
return 'g'==str[0] && 't'==str[1] && 'k'==str[2] && '_'==str[3];
|
|
}
|
|
|
|
static void * kgtk_get_fnptr(const char *raw_name)
|
|
{
|
|
if(raw_name && isGtk(raw_name) && kgtkInit(NULL))
|
|
{
|
|
if(0==strcmp(raw_name, "gtk_file_chooser_get_filename"))
|
|
return >k_file_chooser_get_filename;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_select_filename"))
|
|
return >k_file_chooser_select_filename;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_unselect_all"))
|
|
return >k_file_chooser_unselect_all;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_set_filename"))
|
|
return >k_file_chooser_set_filename;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_name"))
|
|
return >k_file_chooser_set_current_name;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_get_filenames"))
|
|
return >k_file_chooser_get_filenames;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder"))
|
|
return >k_file_chooser_set_current_folder;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder"))
|
|
return >k_file_chooser_get_current_folder;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_get_uri"))
|
|
return >k_file_chooser_get_uri;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_set_uri"))
|
|
return >k_file_chooser_set_uri;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_get_uris"))
|
|
return >k_file_chooser_get_uris;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder_uri"))
|
|
return >k_file_chooser_set_current_folder_uri;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder_uri"))
|
|
return >k_file_chooser_get_current_folder_uri;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_dialog_new"))
|
|
return >k_file_chooser_dialog_new;
|
|
|
|
else if(0==strcmp(raw_name, "gtk_file_chooser_button_new"))
|
|
return >k_file_chooser_button_new;
|
|
|
|
/*
|
|
else if(0==strcmp(raw_name, "gtk_init_check"))
|
|
return >k_init_check;
|
|
*/
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const gchar * kgtk_g_module_check_init(GModule *module)
|
|
{
|
|
return gtk_check_version(GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
|
|
}
|
|
|
|
/* Mozilla specific */
|
|
void * PR_FindFunctionSymbol(struct PR_LoadLibrary *lib, const char *raw_name)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
void *rv=NULL;
|
|
|
|
if(!realFunction)
|
|
realFunction = (void *(*)()) real_dlsym(RTLD_NEXT, "PR_FindFunctionSymbol");
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::PR_FindFunctionSymbol : %s\n", raw_name);
|
|
#endif
|
|
|
|
rv=kgtk_get_fnptr(raw_name);
|
|
|
|
if(!rv)
|
|
{
|
|
if (0==strcmp(raw_name, "g_module_check_init"))
|
|
rv=&kgtk_g_module_check_init;
|
|
else if (isGtk(raw_name))
|
|
rv=real_dlsym(RTLD_NEXT, raw_name);
|
|
}
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::PR_FindFunctionSymbol found? %d\n", (rv || realFunction) ? 1 : 0);
|
|
#endif
|
|
|
|
if ((rv != NULL) || (realFunction != NULL))
|
|
return rv ? rv : realFunction(lib, raw_name);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef HAVE_DLVSYM
|
|
/* Overriding dlsym is required for SWT - which dlsym's the gtk_file_chooser functions! */
|
|
static void * real_dlsym(void *handle, const char *name)
|
|
{
|
|
static void * (*realFunction)() = NULL;
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::real_dlsym : %s\n", name);
|
|
#endif
|
|
|
|
if (!realFunction)
|
|
{
|
|
void *ldHandle=dlopen("libdl.so", RTLD_NOW);
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::real_dlsym : %s\n", name);
|
|
#endif
|
|
|
|
if(ldHandle)
|
|
{
|
|
static const char * versions[]={KGTK_DLSYM_VERSION, "GLIBC_2.3", "GLIBC_2.2.5",
|
|
"GLIBC_2.2", "GLIBC_2.1", "GLIBC_2.0", NULL};
|
|
|
|
int i;
|
|
|
|
for(i=0; versions[i] && !realFunction; ++i)
|
|
realFunction=dlvsym(ldHandle, "dlsym", versions[i]);
|
|
}
|
|
}
|
|
|
|
return realFunction(handle, name);
|
|
}
|
|
|
|
void * dlsym(void *handle, const char *name)
|
|
{
|
|
void *rv=NULL;
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::dlsym : (%04X) %s\n", (int)handle, name);
|
|
#endif
|
|
rv=kgtk_get_fnptr(name);
|
|
|
|
if(!rv)
|
|
rv=real_dlsym(handle, name);
|
|
|
|
if(!rv && 0==strcmp(name, "g_module_check_init"))
|
|
rv=&kgtk_g_module_check_init;
|
|
|
|
#ifdef KGTK_DEBUG_DLSYM
|
|
printf("KGTK::dlsym found? %d\n", rv ? 1 : 0);
|
|
#endif
|
|
return rv;
|
|
}
|
|
#endif
|