diff --git a/ChangeLog b/ChangeLog index 7cd41d85cb..b99807d26b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +Sat Jan 23 20:36:06 GMT 1999 Austin Donnelly + + * app/color_select.c: don't try and gdk_window_get_size() when we + haven't been realised yet. + + * app/gimpset.[ch]: allow the use of GTK_TYPE_NONE for storing + sets of things that aren't GTK_OBJECTs. Set can also emit new + signal "member_modified" when gimp_set_member_modified (set, + ob) is called. + + * app/layers_dialog.c: show main dialog shell last, to avoid ugly + window manager interaction. + + * app/module_db.c: can now handle not having any modules at all + without segfaulting, plus proper updates on changes. Also now + has refresh button to re-scan the filesystem for modules. + + * modules/colorsel_triangle.c: added module_unload() function. + Still needs someone to spruce up the UI. Volunteers? + + * plug-ins/script-fu/scripts/select_to_image.scm: create display + for newly duplicated image, otherwise you don't see anything. + Sat Jan 23 18:43:23 GMT 1999 Adam D. Moss * plug-ins/gif/gif.c: Multi-line comments, a little more diff --git a/app/color_select.c b/app/color_select.c index ad5f4f51a3..eaee373af3 100644 --- a/app/color_select.c +++ b/app/color_select.c @@ -826,10 +826,14 @@ color_select_update_colors (ColorSelectP csp, blue = csp->values[BLUE]; } - gdk_window_get_size (window, &width, &height); + /* if we haven't yet been realised, there's no need to redraw + * anything. */ + if (!window) return; store_color (&color.pixel, red, green, blue); + gdk_window_get_size (window, &width, &height); + if (csp->gc) { #ifdef OLD_COLOR_AREA diff --git a/app/dialogs/module-dialog.c b/app/dialogs/module-dialog.c index 95f8c49dd8..9e92fea349 100644 --- a/app/dialogs/module-dialog.c +++ b/app/dialogs/module-dialog.c @@ -20,12 +20,15 @@ #include #include +#include +#include #include "appenv.h" #include "module_db.h" #include "gimprc.h" #include "datafiles.h" #include "actionarea.h" +#include "gimpset.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpmodule.h" @@ -52,6 +55,7 @@ static const char * const statename[] = { typedef struct { gchar *fullpath; /* path to the module */ module_state state; /* what's happened to the module */ + gboolean ondisk; /* TRUE if file still exists */ /* stuff from now on may be NULL depending on the state the module is in */ GimpModuleInfo *info; /* returned values from module_init */ GModule *module; /* handle on the module */ @@ -60,7 +64,7 @@ typedef struct { GimpModuleUnloadFunc *unload; } module_info; -#define NUM_INFO_LINES 6 +#define NUM_INFO_LINES 7 typedef struct { GtkWidget *table; @@ -68,10 +72,11 @@ typedef struct { GtkWidget *button_label; module_info *last_update; GtkWidget *button; + GtkWidget *list; } browser_st; -/* global list of module_info */ -static GSList *modules = NULL; +/* global set of module_info pointers */ +static GimpSet *modules; /*#define DUMP_DB*/ @@ -81,15 +86,21 @@ static GSList *modules = NULL; static void module_initialize (char *filename); static void mod_load (module_info *mod, gboolean verbose); static void mod_unload (module_info *mod, gboolean verbose); +static module_info *module_find_by_path (const char *fullpath); #ifdef DUMP_DB static void print_module_info (gpointer data, gpointer user_data); #endif static void browser_popdown_callback (GtkWidget *w, gpointer client_data); -static void browser_info_update (browser_st *st, module_info *mod); -static void browser_info_init (GtkWidget *table); +static void browser_destroy_callback (GtkWidget *w, gpointer client_data); +static void browser_info_update (GimpSet *, module_info *, browser_st *); +static void browser_info_add (GimpSet *, module_info *, browser_st *); +static void browser_info_remove (GimpSet *, module_info *, browser_st *); +static void browser_info_init (browser_st *st, GtkWidget *table); static void browser_select_callback (GtkWidget *widget, GtkWidget *child); static void browser_load_unload_callback (GtkWidget *widget, gpointer data); +static void browser_refresh_callback (GtkWidget *widget, gpointer data); +static void make_list_item (gpointer data, gpointer user_data); /**************************************************************/ @@ -100,16 +111,18 @@ module_db_init (void) { /* Load and initialize gimp modules */ + modules = gimp_set_new (GTK_TYPE_NONE, FALSE); + if (g_module_supported ()) datafiles_read_directories (module_path, module_initialize, 0 /* no flags */); - #ifdef DUMP_DB - g_slist_foreach (modules, print_module_info, NULL); + gimp_set_foreach (modules, print_module_info, NULL); #endif } + GtkWidget * module_db_browser_new (void) { @@ -117,10 +130,7 @@ module_db_browser_new (void) GtkWidget *hbox; GtkWidget *vbox; GtkWidget *listbox; - GtkWidget *list; - GtkWidget *list_item; - GSList *here; - module_info *info; + GtkWidget *button; browser_st *st; ActionAreaItem action_items[] = { @@ -133,7 +143,7 @@ module_db_browser_new (void) gtk_window_set_title (GTK_WINDOW (shell), _("Module DB")); hbox = gtk_hbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 1); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); @@ -145,51 +155,62 @@ module_db_browser_new (void) gtk_widget_set_usize (listbox, 125, 100); gtk_widget_show (listbox); - list = gtk_list_new (); - gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), list); - st = g_new0 (browser_st, 1); - here = modules; - while (here) - { - info = here->data; - here = g_slist_next (here); + st->list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (st->list), GTK_SELECTION_BROWSE); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), + st->list); - if (!st->last_update) - st->last_update = info; + gimp_set_foreach (modules, make_list_item, st); - list_item = gtk_list_item_new_with_label (info->fullpath); - gtk_container_add (GTK_CONTAINER (list), list_item); - gtk_widget_show (list_item); - gtk_object_set_user_data (GTK_OBJECT (list_item), info); - } + gtk_widget_show (st->list); - gtk_widget_show (list); - - vbox = gtk_vbox_new (FALSE, 5); + vbox = gtk_vbox_new (FALSE, 10); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); - st->table = gtk_table_new (2, NUM_INFO_LINES, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), st->table, TRUE, TRUE, 0); + st->table = gtk_table_new (5, NUM_INFO_LINES, FALSE); + gtk_box_pack_start (GTK_BOX (vbox), st->table, FALSE, FALSE, 0); gtk_widget_show (st->table); - st->button = gtk_button_new (); - gtk_box_pack_start (GTK_BOX (vbox), st->button, TRUE, TRUE, 0); + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5); + + button = gtk_button_new_with_label (_("Refresh")); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + browser_refresh_callback, st); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + + st->button = gtk_button_new_with_label (""); + st->button_label = GTK_BIN (st->button)->child; + gtk_box_pack_start (GTK_BOX (hbox), st->button, TRUE, TRUE, 0); gtk_widget_show (st->button); gtk_signal_connect (GTK_OBJECT (st->button), "clicked", browser_load_unload_callback, st); - browser_info_init (st->table); - browser_info_update (st, modules->data); + browser_info_init (st, st->table); + browser_info_update (modules, st->last_update, st); - gtk_object_set_user_data (GTK_OBJECT (list), st); + gtk_object_set_user_data (GTK_OBJECT (st->list), st); - gtk_signal_connect (GTK_OBJECT (list), "select_child", + gtk_signal_connect (GTK_OBJECT (st->list), "select_child", browser_select_callback, NULL); + /* hook the gimpset signals so we can refresh the display + * appropriately. */ + gtk_signal_connect (GTK_OBJECT (modules), "member_modified", + browser_info_update, st); + gtk_signal_connect (GTK_OBJECT (modules), "add", + browser_info_add, st); + gtk_signal_connect (GTK_OBJECT (modules), "remove", + browser_info_remove, st); + + gtk_signal_connect (GTK_OBJECT (shell), "destroy", + browser_destroy_callback, st); + action_items[0].user_data = shell; build_action_area (GTK_DIALOG (shell), action_items, @@ -243,15 +264,21 @@ module_initialize (char *filename) if (!valid_module_name (filename)) return; + /* don't load if we already know about it */ + if (module_find_by_path (filename)) + return; + mod = g_new0 (module_info, 1); - modules = g_slist_append (modules, mod); mod->fullpath = g_strdup (filename); + mod->ondisk = TRUE; if ((be_verbose == TRUE) || (no_splash == TRUE)) g_print (_("load module: \"%s\"\n"), filename); mod_load (mod, TRUE); + + gimp_set_add (modules, mod); } static void @@ -314,6 +341,7 @@ mod_load (module_info *mod, gboolean verbose) mod->unload = symbol; else mod->unload = NULL; + } @@ -329,6 +357,8 @@ mod_unload_completed_callback (void *data) mod->info = NULL; mod->state = ST_UNLOADED_OK; + + gimp_set_member_modified (modules, mod); } static void @@ -385,12 +415,33 @@ browser_popdown_callback (GtkWidget *w, gpointer client_data) gtk_widget_destroy (GTK_WIDGET (client_data)); } +static void +browser_destroy_callback (GtkWidget *w, gpointer client_data) +{ + gtk_signal_disconnect_by_data (GTK_OBJECT (modules), client_data); + g_free (client_data); +} + static void -browser_info_update (browser_st *st, module_info *mod) +browser_info_update (GimpSet *set, module_info *mod, browser_st *st) { int i; - const char *text[NUM_INFO_LINES]; + const char *text[NUM_INFO_LINES - 1]; + char *status; + + /* only update the info if we're actually showing it */ + if (mod != st->last_update) + return; + + if (!mod) + { + for (i=0; i < NUM_INFO_LINES; i++) + gtk_label_set_text (GTK_LABEL (st->label[i]), ""); + gtk_label_set_text (GTK_LABEL(st->button_label), _("")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); + return; + } if (mod->info) { @@ -399,6 +450,7 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = mod->info->version; text[3] = mod->info->copyright; text[4] = mod->info->date; + text[5] = mod->ondisk? _("on disk") : _("only in memory"); } else { @@ -407,43 +459,37 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = "--"; text[3] = "--"; text[4] = "--"; + text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); } + if (mod->state == ST_MODULE_ERROR && mod->last_module_error) { - text[5] = g_malloc (strlen (statename[mod->state]) + 2 + + status = g_malloc (strlen (statename[mod->state]) + 2 + strlen (mod->last_module_error) + 2); - sprintf(text[5], "%s (%s)", statename[mod->state], mod->last_module_error); + sprintf(status, "%s (%s)", statename[mod->state], mod->last_module_error); } else { - text[5] = g_strdup (statename[mod->state]); + status = g_strdup (statename[mod->state]); } - for (i=0; i < NUM_INFO_LINES; i++) + for (i=0; i < NUM_INFO_LINES - 1; i++) { - if (st->label[i]) - gtk_container_remove (GTK_CONTAINER (st->table), st->label[i]); - st->label[i] = gtk_label_new (text[i]); - gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - gtk_widget_show (st->label[i]); + gtk_label_set_text (GTK_LABEL (st->label[i]), text[i]); } - g_free (text[5]); + gtk_label_set_text (GTK_LABEL (st->label[NUM_INFO_LINES-1]), status); + + g_free (status); /* work out what the button should do (if anything) */ switch (mod->state) { case ST_MODULE_ERROR: case ST_LOAD_FAILED: case ST_UNLOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Load")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), TRUE); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); break; case ST_UNLOAD_REQUESTED: @@ -451,11 +497,7 @@ browser_info_update (browser_st *st, module_info *mod) break; case ST_LOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Unload")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->unload? TRUE : FALSE); break; @@ -463,16 +505,17 @@ browser_info_update (browser_st *st, module_info *mod) } static void -browser_info_init (GtkWidget *table) +browser_info_init (browser_st *st, GtkWidget *table) { GtkWidget *label; int i; char *text[] = { N_("Purpose: "), N_("Author: "), - N_("Verson: "), + N_("Version: "), N_("Copyright: "), N_("Date: "), + N_("Location: "), N_("State: ") }; @@ -483,6 +526,12 @@ browser_info_init (GtkWidget *table) gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); gtk_widget_show (label); + + st->label[i] = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, + GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); + gtk_widget_show (st->label[i]); } } @@ -500,7 +549,7 @@ browser_select_callback (GtkWidget *widget, GtkWidget *child) st->last_update = i; - browser_info_update (st, i); + browser_info_update (modules, st->last_update, st); } @@ -514,5 +563,154 @@ browser_load_unload_callback (GtkWidget *widget, gpointer data) else mod_load (st->last_update, FALSE); - browser_info_update (st, st->last_update); + gimp_set_member_modified (modules, st->last_update); +} + + +static void +make_list_item (gpointer data, gpointer user_data) +{ + module_info *info = data; + browser_st *st = user_data; + GtkWidget *list_item; + + if (!st->last_update) + st->last_update = info; + + list_item = gtk_list_item_new_with_label (info->fullpath); + + gtk_widget_show (list_item); + gtk_object_set_user_data (GTK_OBJECT (list_item), info); + + gtk_container_add (GTK_CONTAINER (st->list), list_item); +} + + +static void +browser_info_add (GimpSet *set, module_info *mod, browser_st *st) +{ + make_list_item (mod, st); +} + + +static void +browser_info_remove (GimpSet *set, module_info *mod, browser_st *st) +{ + GList *dlist, *free_list; + GtkWidget *list_item; + module_info *i; + + dlist = gtk_container_children (GTK_CONTAINER (st->list)); + free_list = dlist; + + while (dlist) + { + list_item = dlist->data; + + i = gtk_object_get_user_data (GTK_OBJECT (list_item)); + g_return_if_fail (i != NULL); + + if (i == mod) + { + gtk_container_remove (GTK_CONTAINER (st->list), list_item); + g_list_free(free_list); + return; + } + + dlist = dlist->next; + } + + g_warning ("tried to remove module that wasn't in brower's list"); + g_list_free(free_list); +} + + + +static void +module_db_module_ondisk (gpointer data, gpointer user_data) +{ + module_info *mod = data; + struct stat statbuf; + int ret; + int old_ondisk = mod->ondisk; + GSList **kill_list = user_data; + + ret = stat (mod->fullpath, &statbuf); + if (ret != 0) + mod->ondisk = FALSE; + else + mod->ondisk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. */ + if (!mod->ondisk && !mod->module) + { + *kill_list = g_slist_append (*kill_list, mod); + mod = NULL; + } + + if (mod && mod->ondisk != old_ondisk) + gimp_set_member_modified (modules, mod); +} + + +static void +module_db_module_remove (gpointer data, gpointer user_data) +{ + module_info *mod = data; + + gimp_set_remove (modules, mod); + + if (mod->last_module_error) + g_free (mod->last_module_error); + g_free (mod->fullpath); + g_free (mod); +} + + + +typedef struct { + const char *search_key; + module_info *found; +} find_by_path_closure; + +static void +module_db_path_cmp (gpointer data, gpointer user_data) +{ + module_info *mod = data; + find_by_path_closure *cl = user_data; + + if (!strcmp (mod->fullpath, cl->search_key)) + cl->found = mod; +} + +static module_info * +module_find_by_path (const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_set_foreach (modules, module_db_path_cmp, &cl); + + return cl.found; +} + + + +static void +browser_refresh_callback (GtkWidget *widget, gpointer data) +{ + GSList *kill_list = NULL; + + /* remove modules we don't have on disk anymore */ + gimp_set_foreach (modules, module_db_module_ondisk, &kill_list); + g_slist_foreach (kill_list, module_db_module_remove, NULL); + g_slist_free (kill_list); + kill_list = NULL; + + /* walk filesystem and add new things we find */ + datafiles_read_directories (module_path, + module_initialize, 0 /* no flags */); } diff --git a/app/gimpset.c b/app/gimpset.c index 0310f23b06..8a6012f519 100644 --- a/app/gimpset.c +++ b/app/gimpset.c @@ -11,7 +11,7 @@ typedef struct _GimpSetHandler { } GimpSetHandler; typedef struct { - GimpObject* object; + gpointer object; GArray* handlers; guint destroy_handler; } Node; @@ -20,10 +20,11 @@ enum { ADD, REMOVE, + MEMBER_MODIFIED, LAST_SIGNAL }; -static Node* gimp_set_find_node (GimpSet* set, GimpObject* ob); +static Node* gimp_set_find_node (GimpSet* set, gpointer ob); static Node* gimp_set_node_new (GimpSet* set, gpointer ob); static void gimp_set_node_free (GimpSet* set, Node* n); @@ -69,6 +70,8 @@ gimp_set_class_init (GimpSetClass* klass) gimp_signal_new ("add", 0, type, 0, gimp_sigtype_pointer); gimp_set_signals[REMOVE]= gimp_signal_new ("remove", 0, type, 0, gimp_sigtype_pointer); + gimp_set_signals[MEMBER_MODIFIED]= + gimp_signal_new ("member_modified", 0, type, 0, gimp_sigtype_pointer); gtk_object_class_add_signals (object_class, gimp_set_signals, LAST_SIGNAL); @@ -89,7 +92,13 @@ GtkType gimp_set_get_type (void) GimpSet* gimp_set_new (GtkType type, gboolean weak){ - GimpSet* set=gtk_type_new (gimp_set_get_type ()); + GimpSet* set; + + /* untyped sets must not be weak, since we can't attach a + * destroy handler */ + g_assert(!(type == GTK_TYPE_NONE && weak == TRUE)); + + set=gtk_type_new (gimp_set_get_type ()); set->type=type; set->weak=weak; return set; @@ -102,7 +111,7 @@ gimp_set_destroy_cb (GtkObject* ob, gpointer data){ } static Node* -gimp_set_find_node (GimpSet* set, GimpObject* ob) +gimp_set_find_node (GimpSet* set, gpointer ob) { GSList* l = set->list; for(l = set->list; l; l = l->next){ @@ -166,7 +175,9 @@ gboolean gimp_set_add (GimpSet* set, gpointer val) { g_return_val_if_fail(set, FALSE); - g_return_val_if_fail(GTK_CHECK_TYPE(val, set->type), FALSE); + + if (set->type != GTK_TYPE_NONE) + g_return_val_if_fail(GTK_CHECK_TYPE(val, set->type), FALSE); if(gimp_set_find_node(set, val)) return FALSE; @@ -222,6 +233,10 @@ gimp_set_add_handler(GimpSet* set, const gchar* signame, guint a; g_assert(signame); + + /* you can't set a handler on something that's not a GTK + * object */ + g_assert(set->type != GTK_TYPE_NONE); h.signame = signame; h.func = handler; @@ -258,6 +273,11 @@ void gimp_set_remove_handler(GimpSet* set, GimpSetHandlerId id) { GSList* l; + + /* you can't remove a signal handler on something that's not a + * GTK object */ + g_return_if_fail(set->type != GTK_TYPE_NONE); + for(l=set->list;l;l=l->next){ Node* n = l->data; gtk_signal_disconnect(GTK_OBJECT(n->object), @@ -267,4 +287,10 @@ gimp_set_remove_handler(GimpSet* set, GimpSetHandlerId id) } - +void +gimp_set_member_modified(GimpSet* set, gpointer ob) +{ + g_return_if_fail (gimp_set_find_node (set, ob) != NULL); + + gtk_signal_emit (GTK_OBJECT(set), gimp_set_signals[MEMBER_MODIFIED], ob); +} diff --git a/app/gimpset.h b/app/gimpset.h index 32a3cc0c0a..55fca80695 100644 --- a/app/gimpset.h +++ b/app/gimpset.h @@ -5,10 +5,16 @@ #include "gimpsetF.h" -/* GimpSet - a typed set of objects with signals for adding and - removing of stuff. If it is weak, destroyed objects get removed +/* GimpSet - a (usually) typed set of objects with signals for adding + and removing of stuff. If it is weak, destroyed objects get removed automatically. If it is not, it refs them so they won't be freed - till they are removed. (Though they can be destroyed, of course) */ + till they are removed. (Though they can be destroyed, of course). + + If GTK_TYPE_NONE is specified at gimpset creation time, no type + checking is performed by gimp_set_add() and the + gimp_set_{add,remove}_handler() functions should not be used. It + is also illegal to ask for a weak untyped gimpset. +*/ #define GIMP_TYPE_SET gimp_set_get_type() @@ -21,6 +27,7 @@ /* Signals: add remove + member_modified */ typedef guint GimpSetHandlerId; @@ -43,4 +50,6 @@ GimpSetHandlerId gimp_set_add_handler (GimpSet* set, void gimp_set_remove_handler (GimpSet* set, GimpSetHandlerId id); +void gimp_set_member_modified (GimpSet* set, gpointer ob); + #endif diff --git a/app/gui/color-select.c b/app/gui/color-select.c index ad5f4f51a3..eaee373af3 100644 --- a/app/gui/color-select.c +++ b/app/gui/color-select.c @@ -826,10 +826,14 @@ color_select_update_colors (ColorSelectP csp, blue = csp->values[BLUE]; } - gdk_window_get_size (window, &width, &height); + /* if we haven't yet been realised, there's no need to redraw + * anything. */ + if (!window) return; store_color (&color.pixel, red, green, blue); + gdk_window_get_size (window, &width, &height); + if (csp->gc) { #ifdef OLD_COLOR_AREA diff --git a/app/gui/layers-dialog.c b/app/gui/layers-dialog.c index 1b8d03cc8b..f7d256d3bc 100644 --- a/app/gui/layers-dialog.c +++ b/app/gui/layers-dialog.c @@ -373,9 +373,6 @@ lc_dialog_create (GimpImage* gimage) gtk_widget_show (notebook); - gtk_widget_show (lc_shell); - gtk_widget_show (lc_subshell); - gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(lc_shell)->action_area), 1); /* The close button */ button = gtk_button_new_with_label (_("Close")); @@ -407,6 +404,10 @@ lc_dialog_create (GimpImage* gimage) layers_dialog_update (gimage); channels_dialog_update (gimage); + + gtk_widget_show (lc_subshell); + gtk_widget_show (lc_shell); + gdisplays_flush (); } else @@ -894,7 +895,7 @@ layers_dialog_update (GimpImage* gimage) if (item_list) gtk_list_insert_items (GTK_LIST (layersD->layer_list), item_list, 0); - gtk_signal_connect (GIMP_OBJECT (gimage), + gtk_signal_connect (GTK_OBJECT (gimage), "destroy", GTK_SIGNAL_FUNC (lc_dialog_update_cb), NULL); diff --git a/app/gui/module-browser.c b/app/gui/module-browser.c index 95f8c49dd8..9e92fea349 100644 --- a/app/gui/module-browser.c +++ b/app/gui/module-browser.c @@ -20,12 +20,15 @@ #include #include +#include +#include #include "appenv.h" #include "module_db.h" #include "gimprc.h" #include "datafiles.h" #include "actionarea.h" +#include "gimpset.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpmodule.h" @@ -52,6 +55,7 @@ static const char * const statename[] = { typedef struct { gchar *fullpath; /* path to the module */ module_state state; /* what's happened to the module */ + gboolean ondisk; /* TRUE if file still exists */ /* stuff from now on may be NULL depending on the state the module is in */ GimpModuleInfo *info; /* returned values from module_init */ GModule *module; /* handle on the module */ @@ -60,7 +64,7 @@ typedef struct { GimpModuleUnloadFunc *unload; } module_info; -#define NUM_INFO_LINES 6 +#define NUM_INFO_LINES 7 typedef struct { GtkWidget *table; @@ -68,10 +72,11 @@ typedef struct { GtkWidget *button_label; module_info *last_update; GtkWidget *button; + GtkWidget *list; } browser_st; -/* global list of module_info */ -static GSList *modules = NULL; +/* global set of module_info pointers */ +static GimpSet *modules; /*#define DUMP_DB*/ @@ -81,15 +86,21 @@ static GSList *modules = NULL; static void module_initialize (char *filename); static void mod_load (module_info *mod, gboolean verbose); static void mod_unload (module_info *mod, gboolean verbose); +static module_info *module_find_by_path (const char *fullpath); #ifdef DUMP_DB static void print_module_info (gpointer data, gpointer user_data); #endif static void browser_popdown_callback (GtkWidget *w, gpointer client_data); -static void browser_info_update (browser_st *st, module_info *mod); -static void browser_info_init (GtkWidget *table); +static void browser_destroy_callback (GtkWidget *w, gpointer client_data); +static void browser_info_update (GimpSet *, module_info *, browser_st *); +static void browser_info_add (GimpSet *, module_info *, browser_st *); +static void browser_info_remove (GimpSet *, module_info *, browser_st *); +static void browser_info_init (browser_st *st, GtkWidget *table); static void browser_select_callback (GtkWidget *widget, GtkWidget *child); static void browser_load_unload_callback (GtkWidget *widget, gpointer data); +static void browser_refresh_callback (GtkWidget *widget, gpointer data); +static void make_list_item (gpointer data, gpointer user_data); /**************************************************************/ @@ -100,16 +111,18 @@ module_db_init (void) { /* Load and initialize gimp modules */ + modules = gimp_set_new (GTK_TYPE_NONE, FALSE); + if (g_module_supported ()) datafiles_read_directories (module_path, module_initialize, 0 /* no flags */); - #ifdef DUMP_DB - g_slist_foreach (modules, print_module_info, NULL); + gimp_set_foreach (modules, print_module_info, NULL); #endif } + GtkWidget * module_db_browser_new (void) { @@ -117,10 +130,7 @@ module_db_browser_new (void) GtkWidget *hbox; GtkWidget *vbox; GtkWidget *listbox; - GtkWidget *list; - GtkWidget *list_item; - GSList *here; - module_info *info; + GtkWidget *button; browser_st *st; ActionAreaItem action_items[] = { @@ -133,7 +143,7 @@ module_db_browser_new (void) gtk_window_set_title (GTK_WINDOW (shell), _("Module DB")); hbox = gtk_hbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 1); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); @@ -145,51 +155,62 @@ module_db_browser_new (void) gtk_widget_set_usize (listbox, 125, 100); gtk_widget_show (listbox); - list = gtk_list_new (); - gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), list); - st = g_new0 (browser_st, 1); - here = modules; - while (here) - { - info = here->data; - here = g_slist_next (here); + st->list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (st->list), GTK_SELECTION_BROWSE); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), + st->list); - if (!st->last_update) - st->last_update = info; + gimp_set_foreach (modules, make_list_item, st); - list_item = gtk_list_item_new_with_label (info->fullpath); - gtk_container_add (GTK_CONTAINER (list), list_item); - gtk_widget_show (list_item); - gtk_object_set_user_data (GTK_OBJECT (list_item), info); - } + gtk_widget_show (st->list); - gtk_widget_show (list); - - vbox = gtk_vbox_new (FALSE, 5); + vbox = gtk_vbox_new (FALSE, 10); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); - st->table = gtk_table_new (2, NUM_INFO_LINES, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), st->table, TRUE, TRUE, 0); + st->table = gtk_table_new (5, NUM_INFO_LINES, FALSE); + gtk_box_pack_start (GTK_BOX (vbox), st->table, FALSE, FALSE, 0); gtk_widget_show (st->table); - st->button = gtk_button_new (); - gtk_box_pack_start (GTK_BOX (vbox), st->button, TRUE, TRUE, 0); + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5); + + button = gtk_button_new_with_label (_("Refresh")); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + browser_refresh_callback, st); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + + st->button = gtk_button_new_with_label (""); + st->button_label = GTK_BIN (st->button)->child; + gtk_box_pack_start (GTK_BOX (hbox), st->button, TRUE, TRUE, 0); gtk_widget_show (st->button); gtk_signal_connect (GTK_OBJECT (st->button), "clicked", browser_load_unload_callback, st); - browser_info_init (st->table); - browser_info_update (st, modules->data); + browser_info_init (st, st->table); + browser_info_update (modules, st->last_update, st); - gtk_object_set_user_data (GTK_OBJECT (list), st); + gtk_object_set_user_data (GTK_OBJECT (st->list), st); - gtk_signal_connect (GTK_OBJECT (list), "select_child", + gtk_signal_connect (GTK_OBJECT (st->list), "select_child", browser_select_callback, NULL); + /* hook the gimpset signals so we can refresh the display + * appropriately. */ + gtk_signal_connect (GTK_OBJECT (modules), "member_modified", + browser_info_update, st); + gtk_signal_connect (GTK_OBJECT (modules), "add", + browser_info_add, st); + gtk_signal_connect (GTK_OBJECT (modules), "remove", + browser_info_remove, st); + + gtk_signal_connect (GTK_OBJECT (shell), "destroy", + browser_destroy_callback, st); + action_items[0].user_data = shell; build_action_area (GTK_DIALOG (shell), action_items, @@ -243,15 +264,21 @@ module_initialize (char *filename) if (!valid_module_name (filename)) return; + /* don't load if we already know about it */ + if (module_find_by_path (filename)) + return; + mod = g_new0 (module_info, 1); - modules = g_slist_append (modules, mod); mod->fullpath = g_strdup (filename); + mod->ondisk = TRUE; if ((be_verbose == TRUE) || (no_splash == TRUE)) g_print (_("load module: \"%s\"\n"), filename); mod_load (mod, TRUE); + + gimp_set_add (modules, mod); } static void @@ -314,6 +341,7 @@ mod_load (module_info *mod, gboolean verbose) mod->unload = symbol; else mod->unload = NULL; + } @@ -329,6 +357,8 @@ mod_unload_completed_callback (void *data) mod->info = NULL; mod->state = ST_UNLOADED_OK; + + gimp_set_member_modified (modules, mod); } static void @@ -385,12 +415,33 @@ browser_popdown_callback (GtkWidget *w, gpointer client_data) gtk_widget_destroy (GTK_WIDGET (client_data)); } +static void +browser_destroy_callback (GtkWidget *w, gpointer client_data) +{ + gtk_signal_disconnect_by_data (GTK_OBJECT (modules), client_data); + g_free (client_data); +} + static void -browser_info_update (browser_st *st, module_info *mod) +browser_info_update (GimpSet *set, module_info *mod, browser_st *st) { int i; - const char *text[NUM_INFO_LINES]; + const char *text[NUM_INFO_LINES - 1]; + char *status; + + /* only update the info if we're actually showing it */ + if (mod != st->last_update) + return; + + if (!mod) + { + for (i=0; i < NUM_INFO_LINES; i++) + gtk_label_set_text (GTK_LABEL (st->label[i]), ""); + gtk_label_set_text (GTK_LABEL(st->button_label), _("")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); + return; + } if (mod->info) { @@ -399,6 +450,7 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = mod->info->version; text[3] = mod->info->copyright; text[4] = mod->info->date; + text[5] = mod->ondisk? _("on disk") : _("only in memory"); } else { @@ -407,43 +459,37 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = "--"; text[3] = "--"; text[4] = "--"; + text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); } + if (mod->state == ST_MODULE_ERROR && mod->last_module_error) { - text[5] = g_malloc (strlen (statename[mod->state]) + 2 + + status = g_malloc (strlen (statename[mod->state]) + 2 + strlen (mod->last_module_error) + 2); - sprintf(text[5], "%s (%s)", statename[mod->state], mod->last_module_error); + sprintf(status, "%s (%s)", statename[mod->state], mod->last_module_error); } else { - text[5] = g_strdup (statename[mod->state]); + status = g_strdup (statename[mod->state]); } - for (i=0; i < NUM_INFO_LINES; i++) + for (i=0; i < NUM_INFO_LINES - 1; i++) { - if (st->label[i]) - gtk_container_remove (GTK_CONTAINER (st->table), st->label[i]); - st->label[i] = gtk_label_new (text[i]); - gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - gtk_widget_show (st->label[i]); + gtk_label_set_text (GTK_LABEL (st->label[i]), text[i]); } - g_free (text[5]); + gtk_label_set_text (GTK_LABEL (st->label[NUM_INFO_LINES-1]), status); + + g_free (status); /* work out what the button should do (if anything) */ switch (mod->state) { case ST_MODULE_ERROR: case ST_LOAD_FAILED: case ST_UNLOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Load")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), TRUE); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); break; case ST_UNLOAD_REQUESTED: @@ -451,11 +497,7 @@ browser_info_update (browser_st *st, module_info *mod) break; case ST_LOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Unload")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->unload? TRUE : FALSE); break; @@ -463,16 +505,17 @@ browser_info_update (browser_st *st, module_info *mod) } static void -browser_info_init (GtkWidget *table) +browser_info_init (browser_st *st, GtkWidget *table) { GtkWidget *label; int i; char *text[] = { N_("Purpose: "), N_("Author: "), - N_("Verson: "), + N_("Version: "), N_("Copyright: "), N_("Date: "), + N_("Location: "), N_("State: ") }; @@ -483,6 +526,12 @@ browser_info_init (GtkWidget *table) gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); gtk_widget_show (label); + + st->label[i] = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, + GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); + gtk_widget_show (st->label[i]); } } @@ -500,7 +549,7 @@ browser_select_callback (GtkWidget *widget, GtkWidget *child) st->last_update = i; - browser_info_update (st, i); + browser_info_update (modules, st->last_update, st); } @@ -514,5 +563,154 @@ browser_load_unload_callback (GtkWidget *widget, gpointer data) else mod_load (st->last_update, FALSE); - browser_info_update (st, st->last_update); + gimp_set_member_modified (modules, st->last_update); +} + + +static void +make_list_item (gpointer data, gpointer user_data) +{ + module_info *info = data; + browser_st *st = user_data; + GtkWidget *list_item; + + if (!st->last_update) + st->last_update = info; + + list_item = gtk_list_item_new_with_label (info->fullpath); + + gtk_widget_show (list_item); + gtk_object_set_user_data (GTK_OBJECT (list_item), info); + + gtk_container_add (GTK_CONTAINER (st->list), list_item); +} + + +static void +browser_info_add (GimpSet *set, module_info *mod, browser_st *st) +{ + make_list_item (mod, st); +} + + +static void +browser_info_remove (GimpSet *set, module_info *mod, browser_st *st) +{ + GList *dlist, *free_list; + GtkWidget *list_item; + module_info *i; + + dlist = gtk_container_children (GTK_CONTAINER (st->list)); + free_list = dlist; + + while (dlist) + { + list_item = dlist->data; + + i = gtk_object_get_user_data (GTK_OBJECT (list_item)); + g_return_if_fail (i != NULL); + + if (i == mod) + { + gtk_container_remove (GTK_CONTAINER (st->list), list_item); + g_list_free(free_list); + return; + } + + dlist = dlist->next; + } + + g_warning ("tried to remove module that wasn't in brower's list"); + g_list_free(free_list); +} + + + +static void +module_db_module_ondisk (gpointer data, gpointer user_data) +{ + module_info *mod = data; + struct stat statbuf; + int ret; + int old_ondisk = mod->ondisk; + GSList **kill_list = user_data; + + ret = stat (mod->fullpath, &statbuf); + if (ret != 0) + mod->ondisk = FALSE; + else + mod->ondisk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. */ + if (!mod->ondisk && !mod->module) + { + *kill_list = g_slist_append (*kill_list, mod); + mod = NULL; + } + + if (mod && mod->ondisk != old_ondisk) + gimp_set_member_modified (modules, mod); +} + + +static void +module_db_module_remove (gpointer data, gpointer user_data) +{ + module_info *mod = data; + + gimp_set_remove (modules, mod); + + if (mod->last_module_error) + g_free (mod->last_module_error); + g_free (mod->fullpath); + g_free (mod); +} + + + +typedef struct { + const char *search_key; + module_info *found; +} find_by_path_closure; + +static void +module_db_path_cmp (gpointer data, gpointer user_data) +{ + module_info *mod = data; + find_by_path_closure *cl = user_data; + + if (!strcmp (mod->fullpath, cl->search_key)) + cl->found = mod; +} + +static module_info * +module_find_by_path (const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_set_foreach (modules, module_db_path_cmp, &cl); + + return cl.found; +} + + + +static void +browser_refresh_callback (GtkWidget *widget, gpointer data) +{ + GSList *kill_list = NULL; + + /* remove modules we don't have on disk anymore */ + gimp_set_foreach (modules, module_db_module_ondisk, &kill_list); + g_slist_foreach (kill_list, module_db_module_remove, NULL); + g_slist_free (kill_list); + kill_list = NULL; + + /* walk filesystem and add new things we find */ + datafiles_read_directories (module_path, + module_initialize, 0 /* no flags */); } diff --git a/app/layers_dialog.c b/app/layers_dialog.c index 1b8d03cc8b..f7d256d3bc 100644 --- a/app/layers_dialog.c +++ b/app/layers_dialog.c @@ -373,9 +373,6 @@ lc_dialog_create (GimpImage* gimage) gtk_widget_show (notebook); - gtk_widget_show (lc_shell); - gtk_widget_show (lc_subshell); - gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(lc_shell)->action_area), 1); /* The close button */ button = gtk_button_new_with_label (_("Close")); @@ -407,6 +404,10 @@ lc_dialog_create (GimpImage* gimage) layers_dialog_update (gimage); channels_dialog_update (gimage); + + gtk_widget_show (lc_subshell); + gtk_widget_show (lc_shell); + gdisplays_flush (); } else @@ -894,7 +895,7 @@ layers_dialog_update (GimpImage* gimage) if (item_list) gtk_list_insert_items (GTK_LIST (layersD->layer_list), item_list, 0); - gtk_signal_connect (GIMP_OBJECT (gimage), + gtk_signal_connect (GTK_OBJECT (gimage), "destroy", GTK_SIGNAL_FUNC (lc_dialog_update_cb), NULL); diff --git a/app/module_db.c b/app/module_db.c index 95f8c49dd8..9e92fea349 100644 --- a/app/module_db.c +++ b/app/module_db.c @@ -20,12 +20,15 @@ #include #include +#include +#include #include "appenv.h" #include "module_db.h" #include "gimprc.h" #include "datafiles.h" #include "actionarea.h" +#include "gimpset.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpmodule.h" @@ -52,6 +55,7 @@ static const char * const statename[] = { typedef struct { gchar *fullpath; /* path to the module */ module_state state; /* what's happened to the module */ + gboolean ondisk; /* TRUE if file still exists */ /* stuff from now on may be NULL depending on the state the module is in */ GimpModuleInfo *info; /* returned values from module_init */ GModule *module; /* handle on the module */ @@ -60,7 +64,7 @@ typedef struct { GimpModuleUnloadFunc *unload; } module_info; -#define NUM_INFO_LINES 6 +#define NUM_INFO_LINES 7 typedef struct { GtkWidget *table; @@ -68,10 +72,11 @@ typedef struct { GtkWidget *button_label; module_info *last_update; GtkWidget *button; + GtkWidget *list; } browser_st; -/* global list of module_info */ -static GSList *modules = NULL; +/* global set of module_info pointers */ +static GimpSet *modules; /*#define DUMP_DB*/ @@ -81,15 +86,21 @@ static GSList *modules = NULL; static void module_initialize (char *filename); static void mod_load (module_info *mod, gboolean verbose); static void mod_unload (module_info *mod, gboolean verbose); +static module_info *module_find_by_path (const char *fullpath); #ifdef DUMP_DB static void print_module_info (gpointer data, gpointer user_data); #endif static void browser_popdown_callback (GtkWidget *w, gpointer client_data); -static void browser_info_update (browser_st *st, module_info *mod); -static void browser_info_init (GtkWidget *table); +static void browser_destroy_callback (GtkWidget *w, gpointer client_data); +static void browser_info_update (GimpSet *, module_info *, browser_st *); +static void browser_info_add (GimpSet *, module_info *, browser_st *); +static void browser_info_remove (GimpSet *, module_info *, browser_st *); +static void browser_info_init (browser_st *st, GtkWidget *table); static void browser_select_callback (GtkWidget *widget, GtkWidget *child); static void browser_load_unload_callback (GtkWidget *widget, gpointer data); +static void browser_refresh_callback (GtkWidget *widget, gpointer data); +static void make_list_item (gpointer data, gpointer user_data); /**************************************************************/ @@ -100,16 +111,18 @@ module_db_init (void) { /* Load and initialize gimp modules */ + modules = gimp_set_new (GTK_TYPE_NONE, FALSE); + if (g_module_supported ()) datafiles_read_directories (module_path, module_initialize, 0 /* no flags */); - #ifdef DUMP_DB - g_slist_foreach (modules, print_module_info, NULL); + gimp_set_foreach (modules, print_module_info, NULL); #endif } + GtkWidget * module_db_browser_new (void) { @@ -117,10 +130,7 @@ module_db_browser_new (void) GtkWidget *hbox; GtkWidget *vbox; GtkWidget *listbox; - GtkWidget *list; - GtkWidget *list_item; - GSList *here; - module_info *info; + GtkWidget *button; browser_st *st; ActionAreaItem action_items[] = { @@ -133,7 +143,7 @@ module_db_browser_new (void) gtk_window_set_title (GTK_WINDOW (shell), _("Module DB")); hbox = gtk_hbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 1); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); @@ -145,51 +155,62 @@ module_db_browser_new (void) gtk_widget_set_usize (listbox, 125, 100); gtk_widget_show (listbox); - list = gtk_list_new (); - gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), list); - st = g_new0 (browser_st, 1); - here = modules; - while (here) - { - info = here->data; - here = g_slist_next (here); + st->list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (st->list), GTK_SELECTION_BROWSE); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), + st->list); - if (!st->last_update) - st->last_update = info; + gimp_set_foreach (modules, make_list_item, st); - list_item = gtk_list_item_new_with_label (info->fullpath); - gtk_container_add (GTK_CONTAINER (list), list_item); - gtk_widget_show (list_item); - gtk_object_set_user_data (GTK_OBJECT (list_item), info); - } + gtk_widget_show (st->list); - gtk_widget_show (list); - - vbox = gtk_vbox_new (FALSE, 5); + vbox = gtk_vbox_new (FALSE, 10); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); - st->table = gtk_table_new (2, NUM_INFO_LINES, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), st->table, TRUE, TRUE, 0); + st->table = gtk_table_new (5, NUM_INFO_LINES, FALSE); + gtk_box_pack_start (GTK_BOX (vbox), st->table, FALSE, FALSE, 0); gtk_widget_show (st->table); - st->button = gtk_button_new (); - gtk_box_pack_start (GTK_BOX (vbox), st->button, TRUE, TRUE, 0); + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5); + + button = gtk_button_new_with_label (_("Refresh")); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + browser_refresh_callback, st); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + + st->button = gtk_button_new_with_label (""); + st->button_label = GTK_BIN (st->button)->child; + gtk_box_pack_start (GTK_BOX (hbox), st->button, TRUE, TRUE, 0); gtk_widget_show (st->button); gtk_signal_connect (GTK_OBJECT (st->button), "clicked", browser_load_unload_callback, st); - browser_info_init (st->table); - browser_info_update (st, modules->data); + browser_info_init (st, st->table); + browser_info_update (modules, st->last_update, st); - gtk_object_set_user_data (GTK_OBJECT (list), st); + gtk_object_set_user_data (GTK_OBJECT (st->list), st); - gtk_signal_connect (GTK_OBJECT (list), "select_child", + gtk_signal_connect (GTK_OBJECT (st->list), "select_child", browser_select_callback, NULL); + /* hook the gimpset signals so we can refresh the display + * appropriately. */ + gtk_signal_connect (GTK_OBJECT (modules), "member_modified", + browser_info_update, st); + gtk_signal_connect (GTK_OBJECT (modules), "add", + browser_info_add, st); + gtk_signal_connect (GTK_OBJECT (modules), "remove", + browser_info_remove, st); + + gtk_signal_connect (GTK_OBJECT (shell), "destroy", + browser_destroy_callback, st); + action_items[0].user_data = shell; build_action_area (GTK_DIALOG (shell), action_items, @@ -243,15 +264,21 @@ module_initialize (char *filename) if (!valid_module_name (filename)) return; + /* don't load if we already know about it */ + if (module_find_by_path (filename)) + return; + mod = g_new0 (module_info, 1); - modules = g_slist_append (modules, mod); mod->fullpath = g_strdup (filename); + mod->ondisk = TRUE; if ((be_verbose == TRUE) || (no_splash == TRUE)) g_print (_("load module: \"%s\"\n"), filename); mod_load (mod, TRUE); + + gimp_set_add (modules, mod); } static void @@ -314,6 +341,7 @@ mod_load (module_info *mod, gboolean verbose) mod->unload = symbol; else mod->unload = NULL; + } @@ -329,6 +357,8 @@ mod_unload_completed_callback (void *data) mod->info = NULL; mod->state = ST_UNLOADED_OK; + + gimp_set_member_modified (modules, mod); } static void @@ -385,12 +415,33 @@ browser_popdown_callback (GtkWidget *w, gpointer client_data) gtk_widget_destroy (GTK_WIDGET (client_data)); } +static void +browser_destroy_callback (GtkWidget *w, gpointer client_data) +{ + gtk_signal_disconnect_by_data (GTK_OBJECT (modules), client_data); + g_free (client_data); +} + static void -browser_info_update (browser_st *st, module_info *mod) +browser_info_update (GimpSet *set, module_info *mod, browser_st *st) { int i; - const char *text[NUM_INFO_LINES]; + const char *text[NUM_INFO_LINES - 1]; + char *status; + + /* only update the info if we're actually showing it */ + if (mod != st->last_update) + return; + + if (!mod) + { + for (i=0; i < NUM_INFO_LINES; i++) + gtk_label_set_text (GTK_LABEL (st->label[i]), ""); + gtk_label_set_text (GTK_LABEL(st->button_label), _("")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); + return; + } if (mod->info) { @@ -399,6 +450,7 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = mod->info->version; text[3] = mod->info->copyright; text[4] = mod->info->date; + text[5] = mod->ondisk? _("on disk") : _("only in memory"); } else { @@ -407,43 +459,37 @@ browser_info_update (browser_st *st, module_info *mod) text[2] = "--"; text[3] = "--"; text[4] = "--"; + text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); } + if (mod->state == ST_MODULE_ERROR && mod->last_module_error) { - text[5] = g_malloc (strlen (statename[mod->state]) + 2 + + status = g_malloc (strlen (statename[mod->state]) + 2 + strlen (mod->last_module_error) + 2); - sprintf(text[5], "%s (%s)", statename[mod->state], mod->last_module_error); + sprintf(status, "%s (%s)", statename[mod->state], mod->last_module_error); } else { - text[5] = g_strdup (statename[mod->state]); + status = g_strdup (statename[mod->state]); } - for (i=0; i < NUM_INFO_LINES; i++) + for (i=0; i < NUM_INFO_LINES - 1; i++) { - if (st->label[i]) - gtk_container_remove (GTK_CONTAINER (st->table), st->label[i]); - st->label[i] = gtk_label_new (text[i]); - gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - gtk_widget_show (st->label[i]); + gtk_label_set_text (GTK_LABEL (st->label[i]), text[i]); } - g_free (text[5]); + gtk_label_set_text (GTK_LABEL (st->label[NUM_INFO_LINES-1]), status); + + g_free (status); /* work out what the button should do (if anything) */ switch (mod->state) { case ST_MODULE_ERROR: case ST_LOAD_FAILED: case ST_UNLOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Load")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), TRUE); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); break; case ST_UNLOAD_REQUESTED: @@ -451,11 +497,7 @@ browser_info_update (browser_st *st, module_info *mod) break; case ST_LOADED_OK: - if (st->button_label) - gtk_container_remove (GTK_CONTAINER (st->button), st->button_label); - st->button_label = gtk_label_new (_("Unload")); - gtk_widget_show (st->button_label); - gtk_container_add (GTK_CONTAINER (st->button), st->button_label); + gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->unload? TRUE : FALSE); break; @@ -463,16 +505,17 @@ browser_info_update (browser_st *st, module_info *mod) } static void -browser_info_init (GtkWidget *table) +browser_info_init (browser_st *st, GtkWidget *table) { GtkWidget *label; int i; char *text[] = { N_("Purpose: "), N_("Author: "), - N_("Verson: "), + N_("Version: "), N_("Copyright: "), N_("Date: "), + N_("Location: "), N_("State: ") }; @@ -483,6 +526,12 @@ browser_info_init (GtkWidget *table) gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); gtk_widget_show (label); + + st->label[i] = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, + GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); + gtk_widget_show (st->label[i]); } } @@ -500,7 +549,7 @@ browser_select_callback (GtkWidget *widget, GtkWidget *child) st->last_update = i; - browser_info_update (st, i); + browser_info_update (modules, st->last_update, st); } @@ -514,5 +563,154 @@ browser_load_unload_callback (GtkWidget *widget, gpointer data) else mod_load (st->last_update, FALSE); - browser_info_update (st, st->last_update); + gimp_set_member_modified (modules, st->last_update); +} + + +static void +make_list_item (gpointer data, gpointer user_data) +{ + module_info *info = data; + browser_st *st = user_data; + GtkWidget *list_item; + + if (!st->last_update) + st->last_update = info; + + list_item = gtk_list_item_new_with_label (info->fullpath); + + gtk_widget_show (list_item); + gtk_object_set_user_data (GTK_OBJECT (list_item), info); + + gtk_container_add (GTK_CONTAINER (st->list), list_item); +} + + +static void +browser_info_add (GimpSet *set, module_info *mod, browser_st *st) +{ + make_list_item (mod, st); +} + + +static void +browser_info_remove (GimpSet *set, module_info *mod, browser_st *st) +{ + GList *dlist, *free_list; + GtkWidget *list_item; + module_info *i; + + dlist = gtk_container_children (GTK_CONTAINER (st->list)); + free_list = dlist; + + while (dlist) + { + list_item = dlist->data; + + i = gtk_object_get_user_data (GTK_OBJECT (list_item)); + g_return_if_fail (i != NULL); + + if (i == mod) + { + gtk_container_remove (GTK_CONTAINER (st->list), list_item); + g_list_free(free_list); + return; + } + + dlist = dlist->next; + } + + g_warning ("tried to remove module that wasn't in brower's list"); + g_list_free(free_list); +} + + + +static void +module_db_module_ondisk (gpointer data, gpointer user_data) +{ + module_info *mod = data; + struct stat statbuf; + int ret; + int old_ondisk = mod->ondisk; + GSList **kill_list = user_data; + + ret = stat (mod->fullpath, &statbuf); + if (ret != 0) + mod->ondisk = FALSE; + else + mod->ondisk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. */ + if (!mod->ondisk && !mod->module) + { + *kill_list = g_slist_append (*kill_list, mod); + mod = NULL; + } + + if (mod && mod->ondisk != old_ondisk) + gimp_set_member_modified (modules, mod); +} + + +static void +module_db_module_remove (gpointer data, gpointer user_data) +{ + module_info *mod = data; + + gimp_set_remove (modules, mod); + + if (mod->last_module_error) + g_free (mod->last_module_error); + g_free (mod->fullpath); + g_free (mod); +} + + + +typedef struct { + const char *search_key; + module_info *found; +} find_by_path_closure; + +static void +module_db_path_cmp (gpointer data, gpointer user_data) +{ + module_info *mod = data; + find_by_path_closure *cl = user_data; + + if (!strcmp (mod->fullpath, cl->search_key)) + cl->found = mod; +} + +static module_info * +module_find_by_path (const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_set_foreach (modules, module_db_path_cmp, &cl); + + return cl.found; +} + + + +static void +browser_refresh_callback (GtkWidget *widget, gpointer data) +{ + GSList *kill_list = NULL; + + /* remove modules we don't have on disk anymore */ + gimp_set_foreach (modules, module_db_module_ondisk, &kill_list); + g_slist_foreach (kill_list, module_db_module_remove, NULL); + g_slist_free (kill_list); + kill_list = NULL; + + /* walk filesystem and add new things we find */ + datafiles_read_directories (module_path, + module_initialize, 0 /* no flags */); } diff --git a/libgimpwidgets/gimpcolorselect.c b/libgimpwidgets/gimpcolorselect.c index ad5f4f51a3..eaee373af3 100644 --- a/libgimpwidgets/gimpcolorselect.c +++ b/libgimpwidgets/gimpcolorselect.c @@ -826,10 +826,14 @@ color_select_update_colors (ColorSelectP csp, blue = csp->values[BLUE]; } - gdk_window_get_size (window, &width, &height); + /* if we haven't yet been realised, there's no need to redraw + * anything. */ + if (!window) return; store_color (&color.pixel, red, green, blue); + gdk_window_get_size (window, &width, &height); + if (csp->gc) { #ifdef OLD_COLOR_AREA diff --git a/modules/colorsel_triangle.c b/modules/colorsel_triangle.c index a4d8b72ebc..253c5755e5 100644 --- a/modules/colorsel_triangle.c +++ b/modules/colorsel_triangle.c @@ -49,7 +49,7 @@ static GimpColorSelectorMethods methods = static GimpModuleInfo info = { - NULL /* no shutdown data needed */, + NULL, "Painter-style colour selector as a pluggable colour selector", "Simon Budig ", "v0.01", @@ -111,8 +111,13 @@ static void color_select_update_hsv_values (ColorSelectP); G_MODULE_EXPORT GimpModuleStatus module_init (GimpModuleInfo **inforet) { - if (gimp_color_selector_register ("Triangle", &methods)) + GimpColorSelectorID id; + + id = gimp_color_selector_register ("Triangle", &methods); + + if (id) { + info.shutdown_data = id; *inforet = &info; return GIMP_MODULE_OK; } @@ -123,6 +128,16 @@ module_init (GimpModuleInfo **inforet) } +G_MODULE_EXPORT void +module_unload (void *shutdown_data, + void (*completed_cb)(void *), + void *completed_data) +{ + gimp_color_selector_unregister (shutdown_data, completed_cb, completed_data); +} + + + /*************************************************************/ /* methods */ diff --git a/plug-ins/script-fu/scripts/select-to-image.scm b/plug-ins/script-fu/scripts/select-to-image.scm index b3c4f17a7f..4beae19bc9 100644 --- a/plug-ins/script-fu/scripts/select-to-image.scm +++ b/plug-ins/script-fu/scripts/select-to-image.scm @@ -60,8 +60,8 @@ (gimp-palette-set-background old-bg) (gimp-image-enable-undo image) (gimp-image-set-active-layer image drawable) -; (gimp-display-new brush-image) -; (gimp-displays-flush) + (gimp-display-new brush-image) + (gimp-displays-flush) (script-fu-export-file 1 img drawable RGB 255 FALSE 2 "-export" "png") )) diff --git a/plug-ins/script-fu/scripts/select_to_image.scm b/plug-ins/script-fu/scripts/select_to_image.scm index b3c4f17a7f..4beae19bc9 100644 --- a/plug-ins/script-fu/scripts/select_to_image.scm +++ b/plug-ins/script-fu/scripts/select_to_image.scm @@ -60,8 +60,8 @@ (gimp-palette-set-background old-bg) (gimp-image-enable-undo image) (gimp-image-set-active-layer image drawable) -; (gimp-display-new brush-image) -; (gimp-displays-flush) + (gimp-display-new brush-image) + (gimp-displays-flush) (script-fu-export-file 1 img drawable RGB 255 FALSE 2 "-export" "png") ))