Hi, I've been thinking about the following for some time now, but I doubt I'll really ever make any progress on it, so I thought I'd share my plans and ask for feedback from the list.
I was interested in writing a 'reverse libglade', that is, a library which would extract from a traditional GTK program a .glade file. It would be loaded via LD_PRELOAD and have wrappers around all the main GTK procedures. These would then construct in memory a structure representing the UI (perhaps directly using the data structures from the glade code, although I never got as far as looking at it for suitability) before passing over control to the 'proper' GTK procedure in each case. Output and various options would be controlled via environment variables. I'm attaching proxy.c, which is a 10 minute attempt at generalising the wrapper stuff, and the Makefile used to build and apply it, and a small dummy gtk program which can be used in conjunction. This really doesn't amount to much. The point of such a tool would be to aid in refactoring old programs which implemented their UI's directly in GTK. I also intended to use it in order to convert a Java/SWT program to a native/GTK program. Has anyone attempted anything similar, or is anyone interested in persuing this work? Many thanks, -- Jon Dowland http://jon.dowland.name/
#!/usr/bin/make -f CC=gcc FLAGS=`pkg-config --cflags --libs gtk+-2.0` .SUFFIXES: .c .exe steal-gtk.so.1.0.0: steal-gtk.o $(CC) -shared -Wl,-soname,steal-gtk.so.1 -o steal-gtk.so.1.0.0 steal-gtk.o steal-gtk.o: proxy.c $(CC) -o steal-gtk.o -g -c -fPIC -Wall $(FLAGS) proxy.c clean: for i in `ls -1 a.out *.exe core *.o *.so *.so.?.?.?`; do echo $1 && rm $1; done .c.exe: $*.c $(CC) $*.c -o $*.exe $(FLAGS) run: steal-gtk.so.1.0.0 hello2.exe LD_PRELOAD=./steal-gtk.so.1.0.0 ./hello2.exe
#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> #include <gtk/gtk.h> /* * some functions left to wrap * all from libgtk2.0 */ //void gtk_container_set_border_width(GtkContainer *container, guint border_width); //void gtk_widget_show(GtkWidget *widget); //void gtk_main(void); //GtkWidget* gtk_button_new_with_label(const gchar *label); /* * assigns function `name' to the function pointer `real_name' * returns `ret' on error (can be blank) */ #define resolve(name, ret) { \ if(0 == real_##name) real_##name = dlsym(RTLD_NEXT, #name); \ if(NULL != dlerror()) { \ fprintf(stderr, "can't get ahold of real "#name"\n");\ return ret; \ } \ } void gtk_init(int * argc, char ***argv) { static int (*real_gtk_init)(int *, char ***) = 0; resolve(gtk_init, ); printf("this is the fake gtk_init here!\n"); real_gtk_init(argc, argv); } GtkWidget* gtk_window_new(GtkWindowType type) { static GtkWidget* (*real_gtk_window_new)(GtkWindowType) = 0; resolve(gtk_window_new, NULL); printf("this is the fake gtk_window_new!\n"); return real_gtk_window_new(type); } #undef resolve
#include <gtk/gtk.h> static void callback(GtkWidget *widget, gpointer data) { g_print ("%s got pressed\n", (gchar *) data); } static gboolean delete_event(GtkWidget *widget,GdkEvent *event,gpointer data) { gtk_main_quit(); return FALSE; } int main(int argc, char **argv) { GtkWidget *window; GtkWidget *button; GtkWidget *box; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Hello Buttons!"); gtk_container_set_border_width(GTK_CONTAINER(window), 10); /* * X Events */ g_signal_connect(G_OBJECT (window), "delete_event", G_CALLBACK(delete_event), NULL); box = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), box); /* button 1 */ button = gtk_button_new_with_label("button 1"); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), (gpointer) "button 1"); /* expand,fill, padding */ gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); /* button 2 */ button = gtk_button_new_with_label("button 2"); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), (gpointer) "button 2"); gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); gtk_widget_show(box); gtk_widget_show(window); gtk_main(); return 0; }