more leaks plugged and more *_OPTIONAL
[dia.git] / app / persistence.c
blob94a8398bcce2a3c7ee53f58f135a0b7af6e04271
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.
23 #include "config.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 #include "persistence.h"
34 #include "dia_dirs.h"
35 #include "dia_xml_libxml.h"
36 #include "dia_xml.h"
38 #include <gtk/gtk.h>
39 #include <libxml/tree.h>
41 /* Hash table from window role (string) to PersistentWindow structure.
43 static GHashTable *persistent_windows;
45 /* Returns the name used for a window in persistence.
47 static gchar *
48 persistence_get_window_name(GtkWindow *window)
50 gchar *name = gtk_window_get_role(window);
51 if (name == NULL) {
52 printf("Internal: Window %s has no role.\n", gtk_window_get_title(window));
53 return NULL;
55 return name;
58 static xmlNodePtr
59 find_node_named (xmlNodePtr p, const char *name)
61 while (p && 0 != strcmp(p->name, name))
62 p = p->next;
63 return p;
66 static void
67 persistence_load_window(xmlNodePtr node)
69 AttributeNode attr;
70 PersistentWindow *wininfo = g_new0(PersistentWindow, 1);
71 gchar *name;
73 attr = composite_find_attribute(node, "role");
74 if (attr != NULL) {
75 name = data_string(attribute_first_data(attr));
76 } else {
77 g_free(wininfo);
78 return;
81 attr = composite_find_attribute(node, "xpos");
82 if (attr != NULL)
83 wininfo->x = data_int(attribute_first_data(attr));
84 attr = composite_find_attribute(node, "ypos");
85 if (attr != NULL)
86 wininfo->y = data_int(attribute_first_data(attr));
87 attr = composite_find_attribute(node, "width");
88 if (attr != NULL)
89 wininfo->width = data_int(attribute_first_data(attr));
90 attr = composite_find_attribute(node, "height");
91 if (attr != NULL)
92 wininfo->height = data_int(attribute_first_data(attr));
93 attr = composite_find_attribute(node, "isopen");
94 if (attr != NULL)
95 wininfo->isopen = data_boolean(attribute_first_data(attr));
97 if (persistent_windows == NULL) {
98 persistent_windows = g_hash_table_new(g_str_hash, g_str_equal);
99 } else {
100 /* Do anything to avoid dups? */
102 g_hash_table_insert(persistent_windows, name, wininfo);
105 /* Load all persistent data. */
106 void
107 persistence_load()
109 xmlDocPtr doc;
110 gchar *filename = dia_config_filename("persistence");
111 struct stat statbuf;
113 if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) return;
115 doc = xmlDiaParseFile(filename);
116 if (doc != NULL) {
117 if (doc->xmlRootNode != NULL) {
118 xmlNsPtr namespace = xmlSearchNs(doc, doc->xmlRootNode, "dia");
119 if (!strcmp (doc->xmlRootNode->name, "persistence") &&
120 namespace != NULL) {
121 xmlNodePtr window_node;
122 window_node = find_node_named(doc->xmlRootNode->xmlChildrenNode,
123 "window");
124 while (window_node != NULL) {
125 persistence_load_window(window_node);
126 window_node = window_node->next;
130 xmlFreeDoc(doc);
132 g_free(filename);
135 static void
136 persistence_store_window_info(GtkWindow *window, PersistentWindow *wininfo,
137 gboolean isclosed)
139 /* Drawable means visible & mapped, what we usually think of as open. */
140 if (!isclosed) {
141 gtk_window_get_position(window, &wininfo->x, &wininfo->y);
142 gtk_window_get_size(window, &wininfo->width, &wininfo->height);
143 wininfo->isopen = TRUE;
144 } else {
145 wininfo->isopen = FALSE;
149 gboolean
150 persistence_update_window(GtkWindow *window, GdkEvent *event, gpointer data)
152 gchar *name = persistence_get_window_name(window);
153 PersistentWindow *wininfo;
154 gboolean isclosed;
156 if (name == NULL) return FALSE;
157 if (persistent_windows == NULL) {
158 persistent_windows = g_hash_table_new(g_str_hash, g_str_equal);
160 wininfo = (PersistentWindow *)g_hash_table_lookup(persistent_windows, name);
162 /* Can't tell the window state from the window itself yet. */
163 isclosed = (event->type == GDK_UNMAP);
164 if (wininfo != NULL) {
165 persistence_store_window_info(window, wininfo, isclosed);
166 } else {
167 wininfo = g_new0(PersistentWindow, 1);
168 persistence_store_window_info(window, wininfo, isclosed);
169 g_hash_table_insert(persistent_windows, name, wininfo);
171 if (wininfo->window != NULL && wininfo->window != window) {
172 g_object_unref(wininfo->window);
173 wininfo->window = NULL;
175 if (wininfo->window == NULL) {
176 wininfo->window = window;
177 g_object_ref(window);
179 return FALSE;
182 /* Call this function after the window has a role assigned to use any
183 * persistence information about the window.
185 void
186 persistence_register_window(GtkWindow *window)
188 gchar *name = persistence_get_window_name(window);
189 PersistentWindow *wininfo;
191 if (name == NULL) return;
192 if (persistent_windows == NULL) {
193 persistent_windows = g_hash_table_new(g_str_hash, g_str_equal);
195 wininfo = (PersistentWindow *)g_hash_table_lookup(persistent_windows, name);
196 if (wininfo != NULL) {
197 gtk_window_move(window, wininfo->x, wininfo->y);
198 gtk_window_resize(window, wininfo->width, wininfo->height);
199 if (wininfo->isopen) gtk_widget_show(window);
200 } else {
201 wininfo = g_new0(PersistentWindow, 1);
202 gtk_window_get_position(window, &wininfo->x, &wininfo->y);
203 gtk_window_get_size(window, &wininfo->width, &wininfo->height);
204 /* Drawable means visible & mapped, what we usually think of as open. */
205 wininfo->isopen = GTK_WIDGET_DRAWABLE(GTK_WIDGET(window));
206 g_hash_table_insert(persistent_windows, name, wininfo);
208 if (wininfo->window != NULL && wininfo->window != window) {
209 g_object_unref(wininfo->window);
210 wininfo->window = NULL;
212 if (wininfo->window == NULL) {
213 wininfo->window = window;
214 g_object_ref(window);
217 g_signal_connect(GTK_OBJECT(window), "configure-event",
218 G_CALLBACK(persistence_update_window), NULL);
220 g_signal_connect(GTK_OBJECT(window), "unmap-event",
221 G_CALLBACK(persistence_update_window), NULL);
224 /** Call this function at start-up to have a window creation function
225 * called if the window should be opened at startup.
226 * If no persistence information is available for the given role,
227 * nothing happens.
228 * @arg role The role of the window, as will be set by gtk_window_set_role()
229 * @arg createfunc A 0-argument function that creates the window. This
230 * function will be called if the persistence information indicates that the
231 * window should be open. The function should create and show the window.
233 void
234 persistence_register_window_create(gchar *role, NullaryFunc *func)
236 PersistentWindow *wininfo;
238 if (role == NULL) return;
239 if (persistent_windows == NULL) return;
240 wininfo = (PersistentWindow *)g_hash_table_lookup(persistent_windows, role);
241 if (wininfo != NULL) {
242 (*func)();
246 /* Save the position of a window */
247 static void
248 persistence_save_window(gpointer key, gpointer value, gpointer data)
250 xmlNodePtr tree = (xmlNodePtr)data;
251 PersistentWindow *window_pos = (PersistentWindow *)value;
252 ObjectNode window;
253 AttributeNode attr;
255 window = (ObjectNode)xmlNewChild(tree, NULL, "window", NULL);
257 data_add_string(new_attribute(window, "role"), key);
258 data_add_int(new_attribute(window, "xpos"), window_pos->x);
259 data_add_int(new_attribute(window, "ypos"), window_pos->y);
260 data_add_int(new_attribute(window, "width"), window_pos->width);
261 data_add_int(new_attribute(window, "height"), window_pos->height);
262 data_add_boolean(new_attribute(window, "isopen"), window_pos->isopen);
266 /* Save all persistent data. */
267 void
268 persistence_save()
270 xmlDocPtr doc;
271 xmlNs *name_space;
272 gchar *filename = dia_config_filename("persistence");
274 doc = xmlNewDoc("1.0");
275 doc->encoding = xmlStrdup("UTF-8");
276 doc->xmlRootNode = xmlNewDocNode(doc, NULL, "persistence", NULL);
278 name_space = xmlNewNs(doc->xmlRootNode,
279 "http://www.lysator.liu.se/~alla/dia/",
280 "dia");
281 xmlSetNs(doc->xmlRootNode, name_space);
283 /* Save any persistent window positions */
284 if (persistent_windows != NULL &&
285 g_hash_table_size(persistent_windows) != 0) {
286 g_hash_table_foreach(persistent_windows, persistence_save_window,
287 doc->xmlRootNode);
290 xmlDiaSaveFile(filename, doc);
291 g_free(filename);
292 xmlFreeDoc(doc);