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.
kgtk-qt3/gtk2/kgtk2.c

2006 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 tqparent 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 tqparent!\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("KDE_FULL_SESSION"));
#endif
initialised=TRUE;
kgtkAppName=getAppName(appName);
useKde=NULL!=getenv("KDE_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 *tqparent,
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 (tqparent)
gtk_window_set_transient_for (GTK_WINDOW (result), tqparent);
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)&GTK_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 *tqparent,
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, tqparent, 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 &gtk_file_chooser_get_filename;
else if(0==strcmp(raw_name, "gtk_file_chooser_select_filename"))
return &gtk_file_chooser_select_filename;
else if(0==strcmp(raw_name, "gtk_file_chooser_unselect_all"))
return &gtk_file_chooser_unselect_all;
else if(0==strcmp(raw_name, "gtk_file_chooser_set_filename"))
return &gtk_file_chooser_set_filename;
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_name"))
return &gtk_file_chooser_set_current_name;
else if(0==strcmp(raw_name, "gtk_file_chooser_get_filenames"))
return &gtk_file_chooser_get_filenames;
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder"))
return &gtk_file_chooser_set_current_folder;
else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder"))
return &gtk_file_chooser_get_current_folder;
else if(0==strcmp(raw_name, "gtk_file_chooser_get_uri"))
return &gtk_file_chooser_get_uri;
else if(0==strcmp(raw_name, "gtk_file_chooser_set_uri"))
return &gtk_file_chooser_set_uri;
else if(0==strcmp(raw_name, "gtk_file_chooser_get_uris"))
return &gtk_file_chooser_get_uris;
else if(0==strcmp(raw_name, "gtk_file_chooser_set_current_folder_uri"))
return &gtk_file_chooser_set_current_folder_uri;
else if(0==strcmp(raw_name, "gtk_file_chooser_get_current_folder_uri"))
return &gtk_file_chooser_get_current_folder_uri;
else if(0==strcmp(raw_name, "gtk_file_chooser_dialog_new"))
return &gtk_file_chooser_dialog_new;
else if(0==strcmp(raw_name, "gtk_file_chooser_button_new"))
return &gtk_file_chooser_button_new;
/*
else if(0==strcmp(raw_name, "gtk_init_check"))
return &gtk_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);
}
return rv ? rv : realFunction(lib, raw_name);
}
#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