1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 2003 Lars Clausen
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* persistence.c -- functions that handle persistent stores, such as
20 * window positions and sizes, font menu, document history etc.
28 #include <sys/types.h>
33 #include "persistence.h"
35 #include "dia_xml_libxml.h"
39 #include <libxml/tree.h>
41 /* Hash table from window role (string) to PersistentWindow structure.
43 static GHashTable
*persistent_windows
, *persistent_entrystrings
, *persistent_lists
;
44 static GHashTable
*persistent_integers
, *persistent_reals
;
45 static GHashTable
*persistent_booleans
, *persistent_strings
;
46 static GHashTable
*persistent_colors
;
48 /* *********************** LOADING FUNCTIONS *********************** */
50 typedef void (*PersistenceLoadFunc
)(gchar
*role
, xmlNodePtr node
);
53 persistence_load_window(gchar
*role
, xmlNodePtr node
)
56 PersistentWindow
*wininfo
= g_new0(PersistentWindow
, 1);
58 attr
= composite_find_attribute(node
, "xpos");
60 wininfo
->x
= data_int(attribute_first_data(attr
));
61 attr
= composite_find_attribute(node
, "ypos");
63 wininfo
->y
= data_int(attribute_first_data(attr
));
64 attr
= composite_find_attribute(node
, "width");
66 wininfo
->width
= data_int(attribute_first_data(attr
));
67 attr
= composite_find_attribute(node
, "height");
69 wininfo
->height
= data_int(attribute_first_data(attr
));
70 attr
= composite_find_attribute(node
, "isopen");
72 wininfo
->isopen
= data_boolean(attribute_first_data(attr
));
74 g_hash_table_insert(persistent_windows
, role
, wininfo
);
77 /** Load a persistent string into the strings hashtable */
79 persistence_load_entrystring(gchar
*role
, xmlNodePtr node
)
84 /* Find the contents? */
85 attr
= composite_find_attribute(node
, "stringvalue");
87 string
= data_string(attribute_first_data(attr
));
92 g_hash_table_insert(persistent_entrystrings
, role
, string
);
96 persistence_load_list(gchar
*role
, xmlNodePtr node
)
101 /* Find the contents? */
102 attr
= composite_find_attribute(node
, "listvalue");
104 string
= data_string(attribute_first_data(attr
));
108 if (string
!= NULL
) {
109 gchar
**strings
= g_strsplit(string
, "\n", -1);
110 PersistentList
*plist
;
113 for (i
= 0; strings
[i
] != NULL
; i
++) {
114 list
= g_list_append(list
, g_strdup(strings
[i
]));
116 /* This frees the strings, too? */
118 /* yes but not the other one --hb */
120 plist
= g_new(PersistentList
, 1);
123 plist
->sorted
= FALSE
;
124 plist
->max_members
= G_MAXINT
;
125 g_hash_table_insert(persistent_lists
, role
, plist
);
130 persistence_load_integer(gchar
*role
, xmlNodePtr node
)
135 /* Find the contents? */
136 attr
= composite_find_attribute(node
, "intvalue");
138 integer
= g_new(gint
, 1);
139 *integer
= data_int(attribute_first_data(attr
));
143 if (g_hash_table_lookup(persistent_integers
, role
) == NULL
)
144 g_hash_table_insert(persistent_integers
, role
, integer
);
146 printf("Int %s registered before loading persistence!\n", role
);
150 persistence_load_real(gchar
*role
, xmlNodePtr node
)
155 /* Find the contents? */
156 attr
= composite_find_attribute(node
, "realvalue");
158 realval
= g_new(real
, 1);
159 *realval
= data_real(attribute_first_data(attr
));
163 if (g_hash_table_lookup(persistent_reals
, role
) == NULL
)
164 g_hash_table_insert(persistent_reals
, role
, realval
);
166 printf("Real %s registered before loading persistence!\n", role
);
170 persistence_load_boolean(gchar
*role
, xmlNodePtr node
)
173 gboolean
*booleanval
;
175 /* Find the contents? */
176 attr
= composite_find_attribute(node
, "booleanvalue");
178 booleanval
= g_new(gboolean
, 1);
179 *booleanval
= data_boolean(attribute_first_data(attr
));
183 if (g_hash_table_lookup(persistent_booleans
, role
) == NULL
)
184 g_hash_table_insert(persistent_booleans
, role
, booleanval
);
186 printf("Boolean %s registered before loading persistence!\n", role
);
190 persistence_load_string(gchar
*role
, xmlNodePtr node
)
195 /* Find the contents? */
196 attr
= composite_find_attribute(node
, "stringvalue");
198 stringval
= data_string(attribute_first_data(attr
));
202 if (g_hash_table_lookup(persistent_strings
, role
) == NULL
)
203 g_hash_table_insert(persistent_strings
, role
, stringval
);
205 printf("String %s registered before loading persistence!\n", role
);
209 persistence_load_color(gchar
*role
, xmlNodePtr node
)
214 /* Find the contents? */
215 attr
= composite_find_attribute(node
, "colorvalue");
217 colorval
= g_new(Color
, 1);
218 data_color(attribute_first_data(attr
), colorval
);
222 if (g_hash_table_lookup(persistent_colors
, role
) == NULL
)
223 g_hash_table_insert(persistent_colors
, role
, colorval
);
225 printf("Color %s registered before loading persistence!\n", role
);
229 find_node_named (xmlNodePtr p
, const char *name
)
231 while (p
&& 0 != strcmp(p
->name
, name
))
236 static GHashTable
*type_handlers
;
238 /** Load the named type of entries using the given function.
239 * func is a void (*func)(gchar *role, xmlNodePtr *node)
242 persistence_load_type(xmlNodePtr node
)
244 const gchar
*typename
= node
->name
;
247 PersistenceLoadFunc func
=
248 (PersistenceLoadFunc
)g_hash_table_lookup(type_handlers
, typename
);
253 name
= xmlGetProp(node
, "role");
263 persistence_set_type_handler(gchar
*name
, PersistenceLoadFunc func
)
265 if (type_handlers
== NULL
)
266 type_handlers
= g_hash_table_new(g_str_hash
, g_str_equal
);
268 g_hash_table_insert(type_handlers
, name
, (gpointer
)func
);
274 persistence_set_type_handler("window", persistence_load_window
);
275 persistence_set_type_handler("entrystring", persistence_load_entrystring
);
276 persistence_set_type_handler("list", persistence_load_list
);
277 persistence_set_type_handler("integer", persistence_load_integer
);
278 persistence_set_type_handler("real", persistence_load_real
);
279 persistence_set_type_handler("boolean", persistence_load_boolean
);
280 persistence_set_type_handler("string", persistence_load_string
);
281 persistence_set_type_handler("color", persistence_load_color
);
283 if (persistent_windows
== NULL
) {
284 persistent_windows
= g_hash_table_new(g_str_hash
, g_str_equal
);
286 if (persistent_entrystrings
== NULL
) {
287 persistent_entrystrings
= g_hash_table_new(g_str_hash
, g_str_equal
);
289 if (persistent_lists
== NULL
) {
290 persistent_lists
= g_hash_table_new(g_str_hash
, g_str_equal
);
292 if (persistent_integers
== NULL
) {
293 persistent_integers
= g_hash_table_new(g_str_hash
, g_str_equal
);
295 if (persistent_reals
== NULL
) {
296 persistent_reals
= g_hash_table_new(g_str_hash
, g_str_equal
);
298 if (persistent_booleans
== NULL
) {
299 persistent_booleans
= g_hash_table_new(g_str_hash
, g_str_equal
);
301 if (persistent_strings
== NULL
) {
302 persistent_strings
= g_hash_table_new(g_str_hash
, g_str_equal
);
304 if (persistent_colors
== NULL
) {
305 persistent_colors
= g_hash_table_new(g_str_hash
, g_str_equal
);
309 /* Load all persistent data. */
314 gchar
*filename
= dia_config_filename("persistence");
318 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
322 doc
= xmlDiaParseFile(filename
);
324 if (doc
->xmlRootNode
!= NULL
) {
325 xmlNsPtr
namespace = xmlSearchNs(doc
, doc
->xmlRootNode
, "dia");
326 if (!strcmp (doc
->xmlRootNode
->name
, "persistence") &&
328 xmlNodePtr child_node
= doc
->xmlRootNode
->children
;
329 for (; child_node
!= NULL
; child_node
= child_node
->next
) {
330 persistence_load_type(child_node
);
339 /* *********************** SAVING FUNCTIONS *********************** */
341 /* Save the position of a window */
343 persistence_save_window(gpointer key
, gpointer value
, gpointer data
)
345 xmlNodePtr tree
= (xmlNodePtr
)data
;
346 PersistentWindow
*window_pos
= (PersistentWindow
*)value
;
349 window
= (ObjectNode
)xmlNewChild(tree
, NULL
, "window", NULL
);
351 xmlSetProp(window
, "role", (char *)key
);
352 data_add_int(new_attribute(window
, "xpos"), window_pos
->x
);
353 data_add_int(new_attribute(window
, "ypos"), window_pos
->y
);
354 data_add_int(new_attribute(window
, "width"), window_pos
->width
);
355 data_add_int(new_attribute(window
, "height"), window_pos
->height
);
356 data_add_boolean(new_attribute(window
, "isopen"), window_pos
->isopen
);
360 /* Save the contents of a string */
362 persistence_save_list(gpointer key
, gpointer value
, gpointer data
)
364 xmlNodePtr tree
= (xmlNodePtr
)data
;
369 listnode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "list", NULL
);
371 xmlSetProp(listnode
, "role", (char *)key
);
372 /* Make a string out of the list */
373 buf
= g_string_new("");
374 for (items
= ((PersistentList
*)value
)->glist
; items
!= NULL
;
375 items
= g_list_next(items
)) {
376 g_string_append(buf
, (gchar
*)items
->data
);
377 if (g_list_next(items
) != NULL
) g_string_append(buf
, "\n");
380 data_add_string(new_attribute(listnode
, "listvalue"), buf
->str
);
381 g_string_free(buf
, TRUE
);
385 persistence_save_entrystring(gpointer key
, gpointer value
, gpointer data
)
387 xmlNodePtr tree
= (xmlNodePtr
)data
;
388 ObjectNode stringnode
;
390 stringnode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "entrystring", NULL
);
392 xmlSetProp(stringnode
, "role", (char *)key
);
393 data_add_string(new_attribute(stringnode
, "stringvalue"), (char *)value
);
397 persistence_save_integer(gpointer key
, gpointer value
, gpointer data
)
399 xmlNodePtr tree
= (xmlNodePtr
)data
;
400 ObjectNode integernode
;
402 integernode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "integer", NULL
);
404 xmlSetProp(integernode
, "role", (char *)key
);
405 data_add_int(new_attribute(integernode
, "intvalue"), *(gint
*)value
);
409 persistence_save_real(gpointer key
, gpointer value
, gpointer data
)
411 xmlNodePtr tree
= (xmlNodePtr
)data
;
414 realnode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "real", NULL
);
416 xmlSetProp(realnode
, "role", (char *)key
);
417 data_add_real(new_attribute(realnode
, "realvalue"), *(real
*)value
);
421 persistence_save_boolean(gpointer key
, gpointer value
, gpointer data
)
423 xmlNodePtr tree
= (xmlNodePtr
)data
;
424 ObjectNode booleannode
;
426 booleannode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "boolean", NULL
);
428 xmlSetProp(booleannode
, "role", (char *)key
);
429 data_add_boolean(new_attribute(booleannode
, "booleanvalue"), *(gboolean
*)value
);
433 persistence_save_string(gpointer key
, gpointer value
, gpointer data
)
435 xmlNodePtr tree
= (xmlNodePtr
)data
;
436 ObjectNode stringnode
;
438 stringnode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "string", NULL
);
440 xmlSetProp(stringnode
, "role", (char *)key
);
441 data_add_string(new_attribute(stringnode
, "stringvalue"), (gchar
*)value
);
445 persistence_save_color(gpointer key
, gpointer value
, gpointer data
)
447 xmlNodePtr tree
= (xmlNodePtr
)data
;
448 ObjectNode colornode
;
450 colornode
= (ObjectNode
)xmlNewChild(tree
, NULL
, "color", NULL
);
452 xmlSetProp(colornode
, "role", (char *)key
);
453 data_add_color(new_attribute(colornode
, "colorvalue"), (Color
*)value
);
458 persistence_save_type(xmlDocPtr doc
, GHashTable
*entries
, GHFunc func
)
460 if (entries
!= NULL
&& g_hash_table_size(entries
) != 0) {
461 g_hash_table_foreach(entries
, func
, doc
->xmlRootNode
);
465 /* Save all persistent data. */
471 gchar
*filename
= dia_config_filename("persistence");
473 doc
= xmlNewDoc("1.0");
474 doc
->encoding
= xmlStrdup("UTF-8");
475 doc
->xmlRootNode
= xmlNewDocNode(doc
, NULL
, "persistence", NULL
);
477 name_space
= xmlNewNs(doc
->xmlRootNode
,
478 DIA_XML_NAME_SPACE_BASE
,
480 xmlSetNs(doc
->xmlRootNode
, name_space
);
482 persistence_save_type(doc
, persistent_windows
, persistence_save_window
);
483 persistence_save_type(doc
, persistent_entrystrings
, persistence_save_string
);
484 persistence_save_type(doc
, persistent_lists
, persistence_save_list
);
485 persistence_save_type(doc
, persistent_integers
, persistence_save_integer
);
486 persistence_save_type(doc
, persistent_reals
, persistence_save_real
);
487 persistence_save_type(doc
, persistent_booleans
, persistence_save_boolean
);
488 persistence_save_type(doc
, persistent_strings
, persistence_save_string
);
489 persistence_save_type(doc
, persistent_colors
, persistence_save_color
);
491 xmlDiaSaveFile(filename
, doc
);
496 /* *********************** USAGE FUNCTIONS *********************** */
498 /* ********* WINDOWS ********* */
500 /* Returns the name used for a window in persistence.
503 persistence_get_window_name(GtkWindow
*window
)
505 const gchar
*name
= gtk_window_get_role(window
);
507 printf("Internal: Window %s has no role.\n", gtk_window_get_title(window
));
514 persistence_store_window_info(GtkWindow
*window
, PersistentWindow
*wininfo
,
517 /* Drawable means visible & mapped, what we usually think of as open. */
519 gtk_window_get_position(window
, &wininfo
->x
, &wininfo
->y
);
520 gtk_window_get_size(window
, &wininfo
->width
, &wininfo
->height
);
521 wininfo
->isopen
= TRUE
;
523 wininfo
->isopen
= FALSE
;
528 persistence_update_window(GtkWindow
*window
, GdkEvent
*event
, gpointer data
)
530 const gchar
*name
= persistence_get_window_name(window
);
531 PersistentWindow
*wininfo
;
534 if (name
== NULL
) return FALSE
;
535 if (persistent_windows
== NULL
) {
536 persistent_windows
= g_hash_table_new(g_str_hash
, g_str_equal
);
538 wininfo
= (PersistentWindow
*)g_hash_table_lookup(persistent_windows
, name
);
540 /* Can't tell the window state from the window itself yet. */
541 isclosed
= (event
->type
== GDK_UNMAP
);
542 if (wininfo
!= NULL
) {
543 persistence_store_window_info(window
, wininfo
, isclosed
);
545 wininfo
= g_new0(PersistentWindow
, 1);
546 persistence_store_window_info(window
, wininfo
, isclosed
);
547 g_hash_table_insert(persistent_windows
, name
, wininfo
);
549 if (wininfo
->window
!= NULL
&& wininfo
->window
!= window
) {
550 g_object_unref(wininfo
->window
);
551 wininfo
->window
= NULL
;
553 if (wininfo
->window
== NULL
) {
554 wininfo
->window
= window
;
555 g_object_ref(window
);
560 /* Call this function after the window has a role assigned to use any
561 * persistence information about the window.
564 persistence_register_window(GtkWindow
*window
)
566 const gchar
*name
= persistence_get_window_name(window
);
567 PersistentWindow
*wininfo
;
569 if (name
== NULL
) return;
570 if (persistent_windows
== NULL
) {
571 persistent_windows
= g_hash_table_new(g_str_hash
, g_str_equal
);
573 wininfo
= (PersistentWindow
*)g_hash_table_lookup(persistent_windows
, name
);
574 if (wininfo
!= NULL
) {
575 gtk_window_move(window
, wininfo
->x
, wininfo
->y
);
576 gtk_window_resize(window
, wininfo
->width
, wininfo
->height
);
577 if (wininfo
->isopen
) gtk_widget_show(GTK_WIDGET(window
));
579 wininfo
= g_new0(PersistentWindow
, 1);
580 gtk_window_get_position(window
, &wininfo
->x
, &wininfo
->y
);
581 gtk_window_get_size(window
, &wininfo
->width
, &wininfo
->height
);
582 /* Drawable means visible & mapped, what we usually think of as open. */
583 wininfo
->isopen
= GTK_WIDGET_DRAWABLE(GTK_WIDGET(window
));
584 g_hash_table_insert(persistent_windows
, name
, wininfo
);
586 if (wininfo
->window
!= NULL
&& wininfo
->window
!= window
) {
587 g_object_unref(wininfo
->window
);
588 wininfo
->window
= NULL
;
590 if (wininfo
->window
== NULL
) {
591 wininfo
->window
= window
;
592 g_object_ref(window
);
595 g_signal_connect(GTK_OBJECT(window
), "configure-event",
596 G_CALLBACK(persistence_update_window
), NULL
);
598 g_signal_connect(GTK_OBJECT(window
), "unmap-event",
599 G_CALLBACK(persistence_update_window
), NULL
);
602 /** Call this function at start-up to have a window creation function
603 * called if the window should be opened at startup.
604 * If no persistence information is available for the given role,
606 * @arg role The role of the window, as will be set by gtk_window_set_role()
607 * @arg createfunc A 0-argument function that creates the window. This
608 * function will be called if the persistence information indicates that the
609 * window should be open. The function should create and show the window.
612 persistence_register_window_create(gchar
*role
, NullaryFunc
*func
)
614 PersistentWindow
*wininfo
;
616 if (role
== NULL
) return;
617 if (persistent_windows
== NULL
) return;
618 wininfo
= (PersistentWindow
*)g_hash_table_lookup(persistent_windows
, role
);
619 if (wininfo
!= NULL
) {
625 /* ********* STRING ENTRIES ********** */
628 persistence_update_string_entry(GtkWidget
*widget
, GdkEvent
*event
,
631 gchar
*role
= (gchar
*)userdata
;
633 if (event
->type
== GDK_FOCUS_CHANGE
) {
634 gchar
*string
= (gchar
*)g_hash_table_lookup(persistent_entrystrings
, role
);
635 const gchar
*entrystring
= gtk_entry_get_text(GTK_ENTRY(widget
));
636 if (string
== NULL
|| strcmp(string
, entrystring
)) {
637 g_hash_table_insert(persistent_entrystrings
, role
, g_strdup(entrystring
));
638 if (string
!= NULL
) g_free(string
);
645 /** Change the contents of the persistently stored string entry.
646 * If widget is non-null, it is updated to reflect the change.
647 * This can be used e.g. for when a dialog is cancelled and the old
648 * contents should be restored.
651 persistence_change_string_entry(gchar
*role
, gchar
*string
,
654 gchar
*old_string
= (gchar
*)g_hash_table_lookup(persistent_entrystrings
, role
);
655 if (old_string
!= NULL
) {
656 if (widget
!= NULL
) {
657 gtk_entry_set_text(GTK_ENTRY(widget
), string
);
659 g_hash_table_insert(persistent_entrystrings
, role
, g_strdup(string
));
666 /** Register a string in a GtkEntry for persistence.
667 * This should include not only a unique name, but some way to update
668 * whereever the string is used.
671 persistence_register_string_entry(gchar
*role
, GtkWidget
*entry
)
674 if (role
== NULL
) return;
675 if (persistent_entrystrings
== NULL
) {
676 persistent_entrystrings
= g_hash_table_new(g_str_hash
, g_str_equal
);
678 string
= (gchar
*)g_hash_table_lookup(persistent_entrystrings
, role
);
679 if (string
!= NULL
) {
680 gtk_entry_set_text(GTK_ENTRY(entry
), string
);
682 string
= g_strdup(gtk_entry_get_text(GTK_ENTRY(entry
)));
683 g_hash_table_insert(persistent_entrystrings
, role
, string
);
685 g_signal_connect(G_OBJECT(entry
), "event",
686 G_CALLBACK(persistence_update_string_entry
), role
);
689 /* ********* LISTS ********** */
691 /* Lists are used for e.g. recent files, selected fonts, etc.
692 * Anywhere where the user occasionally picks from a long list and
693 * is likely to reuse the items.
697 persistence_register_list(const gchar
*role
)
699 PersistentList
*list
;
700 if (role
== NULL
) return NULL
;
701 if (persistent_lists
== NULL
) {
702 persistent_lists
= g_hash_table_new(g_str_hash
, g_str_equal
);
704 list
= (PersistentList
*)g_hash_table_lookup(persistent_lists
, role
);
709 list
= g_new(PersistentList
, 1);
712 list
->sorted
= FALSE
;
713 list
->max_members
= G_MAXINT
;
714 g_hash_table_insert(persistent_lists
, role
, list
);
719 persistent_list_get(const gchar
*role
)
721 PersistentList
*list
;
722 if (role
== NULL
) return NULL
;
723 if (persistent_lists
!= NULL
) {
724 list
= (PersistentList
*)g_hash_table_lookup(persistent_lists
, role
);
729 /* Not registered! */
734 persistent_list_get_glist(const gchar
*role
)
736 PersistentList
*plist
= persistent_list_get(role
);
737 if (plist
== NULL
) return NULL
;
742 persistent_list_cut_length(GList
*list
, gint length
)
744 while (g_list_length(list
) > length
) {
745 GList
*last
= g_list_last(list
);
746 /* Leaking data? See not in persistent_list_add */
747 list
= g_list_remove_link(list
, last
);
753 /** Add a new entry to this persistent list.
754 * @param role The name of a persistent list.
755 * @param item An entry to add.
756 * @returns FALSE if the entry already existed in the list, TRUE otherwise.
759 persistent_list_add(const gchar
*role
, const gchar
*item
)
761 PersistentList
*plist
= persistent_list_get(role
);
763 printf("Can't find list for %s when adding %s\n",
768 /* Sorting not implemented yet. */
771 gboolean existed
= FALSE
;
772 GList
*tmplist
= plist
->glist
;
773 GList
*old_elem
= g_list_find_custom(tmplist
, item
, g_strcasecmp
);
774 while (old_elem
!= NULL
) {
775 tmplist
= g_list_remove_link(tmplist
, old_elem
);
776 /* Don't free this, as it makes recent_files go boom after
777 * selecting a file there several times. Yes, it should be strdup'd,
780 /*g_free(old_elem->data);*/
781 g_list_free_1(old_elem
);
782 old_elem
= g_list_find_custom(tmplist
, item
, g_strcasecmp
);
785 tmplist
= g_list_prepend(tmplist
, g_strdup(item
));
786 tmplist
= persistent_list_cut_length(tmplist
, plist
->max_members
);
787 plist
->glist
= tmplist
;
793 persistent_list_set_max_length(const gchar
*role
, gint max
)
795 PersistentList
*plist
= persistent_list_get(role
);
796 plist
->max_members
= max
;
797 plist
->glist
= persistent_list_cut_length(plist
->glist
, max
);
800 /** Remove an item from the persistent list.
801 * @param role The name of the persistent list.
802 * @param role The entry to remove.
803 * @returns TRUE if the item existed in the list, FALSE otherwise.
806 persistent_list_remove(const gchar
*role
, const gchar
*item
)
808 PersistentList
*plist
= persistent_list_get(role
);
809 /* Leaking data? See not in persistent_list_add */
810 GList
*entry
= g_list_find_custom(plist
->glist
, item
, g_strcasecmp
);
812 plist
->glist
= g_list_remove_link(plist
->glist
, entry
);
819 persistent_list_remove_all(const gchar
*role
)
821 PersistentList
*plist
= persistent_list_get(role
);
822 persistent_list_cut_length(plist
->glist
, 0);
827 PersistenceCallback func
;
832 /** Add a listener to updates on the list, so that if another
833 * instance changes the list, menus and such can be updated.
834 * @param role The name of the persistent list to watch.
835 * @param func A function to call when the list is updated, takes
836 * the given userdata.
837 * @param userdata Data passed back into the callback function.
840 persistent_list_add_listener(const gchar
*role
, PersistenceCallback func
,
841 GObject
*watch
, gpointer userdata
)
843 PersistentList
*plist
= persistent_list_get(role
);
844 ListenerData
*listener
;
847 listener
= g_new(ListenerData
, 1);
848 listener
->func
= func
;
849 listener
->watch
= watch
;
850 g_object_add_weak_pointer(watch
, &listener
->watch
);
851 listener
->userdata
= userdata
;
852 plist
->listeners
= g_list_append(plist
->listeners
, listener
);
856 /** When changing the list, call the listeners.
859 persistent_list_invoke_listeners(gchar
*role
)
862 PersistentList
*plist
= persistent_list_get(role
);
864 for (tmp
= plist
->listeners
; tmp
!= NULL
; tmp
= g_list_next(tmp
)) {
865 ListenerData
*listener
= (ListenerData
*)tmp
->data
;
866 if (listener
->watch
== NULL
) {
868 plist
->listeners
= g_list_remove_link(plist
->listeners
, listener
);
871 /* Still listening */
872 (listener
->func
)(listener
->watch
, listener
->userdata
);
878 /* ********* INTEGERS ********** */
880 persistence_register_integer(gchar
*role
, int defaultvalue
)
883 if (role
== NULL
) return 0;
884 if (persistent_integers
== NULL
) {
885 persistent_integers
= g_hash_table_new(g_str_hash
, g_str_equal
);
887 integer
= (gint
*)g_hash_table_lookup(persistent_integers
, role
);
888 if (integer
== NULL
) {
889 integer
= g_new(gint
, 1);
890 *integer
= defaultvalue
;
891 g_hash_table_insert(persistent_integers
, role
, integer
);
897 persistence_get_integer(gchar
*role
)
900 if (persistent_integers
== NULL
) {
901 printf("No persistent integers to get for %s!\n", role
);
904 integer
= (gint
*)g_hash_table_lookup(persistent_integers
, role
);
905 if (integer
!= NULL
) return *integer
;
906 printf("No integer to get for %s\n", role
);
911 persistence_set_integer(gchar
*role
, gint newvalue
)
914 if (persistent_integers
== NULL
) {
915 printf("No persistent integers yet for %s!\n", role
);
918 integer
= (gint
*)g_hash_table_lookup(persistent_integers
, role
);
919 if (integer
!= NULL
) *integer
= newvalue
;
920 else printf("No integer to set for %s\n", role
);
923 /* ********* REALS ********** */
925 persistence_register_real(gchar
*role
, real defaultvalue
)
928 if (role
== NULL
) return 0;
929 if (persistent_reals
== NULL
) {
930 persistent_reals
= g_hash_table_new(g_str_hash
, g_str_equal
);
932 realval
= (real
*)g_hash_table_lookup(persistent_reals
, role
);
933 if (realval
== NULL
) {
934 realval
= g_new(real
, 1);
935 *realval
= defaultvalue
;
936 g_hash_table_insert(persistent_reals
, role
, realval
);
942 persistence_get_real(gchar
*role
)
945 if (persistent_reals
== NULL
) {
946 printf("No persistent reals to get for %s!\n", role
);
949 realval
= (real
*)g_hash_table_lookup(persistent_reals
, role
);
950 if (realval
!= NULL
) return *realval
;
951 printf("No real to get for %s\n", role
);
956 persistence_set_real(gchar
*role
, real newvalue
)
959 if (persistent_reals
== NULL
) {
960 printf("No persistent reals yet for %s!\n", role
);
963 realval
= (real
*)g_hash_table_lookup(persistent_reals
, role
);
964 if (realval
!= NULL
) *realval
= newvalue
;
965 else printf("No real to set for %s\n", role
);
969 /* ********* BOOLEANS ********** */
971 persistence_register_boolean(gchar
*role
, gboolean defaultvalue
)
973 gboolean
*booleanval
;
974 if (role
== NULL
) return 0;
975 if (persistent_booleans
== NULL
) {
976 persistent_booleans
= g_hash_table_new(g_str_hash
, g_str_equal
);
978 booleanval
= (gboolean
*)g_hash_table_lookup(persistent_booleans
, role
);
979 if (booleanval
== NULL
) {
980 booleanval
= g_new(gboolean
, 1);
981 *booleanval
= defaultvalue
;
982 g_hash_table_insert(persistent_booleans
, role
, booleanval
);
988 persistence_get_boolean(gchar
*role
)
990 gboolean
*booleanval
;
991 if (persistent_booleans
== NULL
) {
992 printf("No persistent booleans to get for %s!\n", role
);
995 booleanval
= (gboolean
*)g_hash_table_lookup(persistent_booleans
, role
);
996 if (booleanval
!= NULL
) return *booleanval
;
997 printf("No boolean to get for %s\n", role
);
1002 persistence_set_boolean(gchar
*role
, gboolean newvalue
)
1004 gboolean
*booleanval
;
1005 if (persistent_booleans
== NULL
) {
1006 printf("No persistent booleans yet for %s!\n", role
);
1009 booleanval
= (gboolean
*)g_hash_table_lookup(persistent_booleans
, role
);
1010 if (booleanval
!= NULL
) *booleanval
= newvalue
;
1011 else printf("No boolean to set for %s\n", role
);
1014 /* ********* STRINGS ********** */
1016 persistence_register_string(gchar
*role
, gchar
*defaultvalue
)
1019 if (role
== NULL
) return 0;
1020 if (persistent_strings
== NULL
) {
1021 persistent_strings
= g_hash_table_new(g_str_hash
, g_str_equal
);
1023 stringval
= (gchar
*)g_hash_table_lookup(persistent_strings
, role
);
1024 if (stringval
== NULL
) {
1025 stringval
= g_strdup(defaultvalue
);
1026 g_hash_table_insert(persistent_strings
, role
, stringval
);
1032 persistence_get_string(gchar
*role
)
1035 if (persistent_strings
== NULL
) {
1036 printf("No persistent strings to get for %s!\n", role
);
1039 stringval
= (gchar
*)g_hash_table_lookup(persistent_strings
, role
);
1040 if (stringval
!= NULL
) return g_strdup(stringval
);
1041 printf("No string to get for %s\n", role
);
1046 persistence_set_string(gchar
*role
, gchar
*newvalue
)
1049 if (persistent_strings
== NULL
) {
1050 printf("No persistent strings yet for %s!\n", role
);
1053 stringval
= (gchar
*)g_hash_table_lookup(persistent_strings
, role
);
1054 if (stringval
!= NULL
) {
1055 g_hash_table_insert(persistent_strings
, role
, g_strdup(newvalue
));
1058 else printf("No string to set for %s\n", role
);
1061 /* ********* COLORS ********** */
1062 /* Remember that colors returned are private, not to be deallocated.
1063 * They will be smashed in some undefined way by persistence_set_color */
1065 persistence_register_color(gchar
*role
, Color
*defaultvalue
)
1068 if (role
== NULL
) return 0;
1069 if (persistent_colors
== NULL
) {
1070 persistent_colors
= g_hash_table_new(g_str_hash
, g_str_equal
);
1072 colorval
= (Color
*)g_hash_table_lookup(persistent_colors
, role
);
1073 if (colorval
== NULL
) {
1074 colorval
= g_new(Color
, 1);
1075 *colorval
= *defaultvalue
;
1076 g_hash_table_insert(persistent_colors
, role
, colorval
);
1082 persistence_get_color(gchar
*role
)
1085 if (persistent_colors
== NULL
) {
1086 printf("No persistent colors to get for %s!\n", role
);
1089 colorval
= (Color
*)g_hash_table_lookup(persistent_colors
, role
);
1090 if (colorval
!= NULL
) return colorval
;
1091 printf("No color to get for %s\n", role
);
1096 persistence_set_color(gchar
*role
, Color
*newvalue
)
1099 if (persistent_colors
== NULL
) {
1100 printf("No persistent colors yet for %s!\n", role
);
1103 colorval
= (Color
*)g_hash_table_lookup(persistent_colors
, role
);
1104 if (colorval
!= NULL
) *colorval
= *newvalue
;
1105 else printf("No color to set for %s\n", role
);