Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / lib / ephy-state.c
blob5abac3037f0397cd2ba2926a5e6a24c64c70430e
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright © 2001 Matthew Mueller
4 * Copyright © 2002 Jorn Baayen <jorn@nl.linux.org>
5 * Copyright © 2003 Marco Pesenti Gritti <mpeseng@tin.it>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $Id: ephy-state.c 6952 2007-03-11 19:42:02Z chpe $
24 #include "config.h"
26 #include "ephy-state.h"
27 #include "ephy-lib-type-builtins.h"
28 #include "ephy-file-helpers.h"
29 #include "ephy-node-db.h"
30 #include "ephy-node-common.h"
32 #include <string.h>
33 #include <gtk/gtkwindow.h>
34 #include <gtk/gtkpaned.h>
35 #include <gtk/gtkexpander.h>
36 #include <gtk/gtktogglebutton.h>
38 #define EPHY_STATES_XML_FILE "states.xml"
39 #define EPHY_STATES_XML_ROOT (const xmlChar *)"ephy_states"
40 #define EPHY_STATES_XML_VERSION (const xmlChar *)"1.0"
42 enum
44 EPHY_NODE_STATE_PROP_NAME = 2,
45 EPHY_NODE_STATE_PROP_WIDTH = 3,
46 EPHY_NODE_STATE_PROP_HEIGHT = 4,
47 EPHY_NODE_STATE_PROP_MAXIMIZE = 5,
48 EPHY_NODE_STATE_PROP_POSITION_X = 6,
49 EPHY_NODE_STATE_PROP_POSITION_Y = 7,
50 EPHY_NODE_STATE_PROP_SIZE = 8,
51 EPHY_NODE_STATE_PROP_POSITION = 9,
52 EPHY_NODE_STATE_PROP_ACTIVE = 10
55 static EphyNode *states = NULL;
56 static EphyNodeDb *states_db = NULL;
58 static void
59 ephy_states_save (void)
61 char *xml_file;
63 xml_file = g_build_filename (ephy_dot_dir (),
64 EPHY_STATES_XML_FILE,
65 NULL);
67 ephy_node_db_write_to_xml_safe
68 (states_db,
69 (const xmlChar *)xml_file,
70 EPHY_STATES_XML_ROOT,
71 EPHY_STATES_XML_VERSION,
72 NULL, /* comment */
73 states, NULL, NULL,
74 NULL);
76 g_free (xml_file);
79 static EphyNode *
80 find_by_name (const char *name)
82 EphyNode *result = NULL;
83 GPtrArray *children;
84 int i;
86 children = ephy_node_get_children (states);
87 for (i = 0; i < children->len; i++)
89 EphyNode *kid;
90 const char *node_name;
92 kid = g_ptr_array_index (children, i);
94 node_name = ephy_node_get_property_string
95 (kid, EPHY_NODE_STATE_PROP_NAME);
96 if (strcmp (node_name, name) == 0)
98 result = kid;
102 return result;
105 static void
106 ensure_states (void)
108 if (states == NULL)
110 volatile GType flags_type; /* work around gcc's optimiser */
111 char *xml_file;
113 /* make sure the type is known when we read the db */
114 flags_type = EPHY_TYPE_STATE_WINDOW_FLAGS;
116 xml_file = g_build_filename (ephy_dot_dir (),
117 EPHY_STATES_XML_FILE,
118 NULL);
120 states_db = ephy_node_db_new (EPHY_NODE_DB_STATES);
121 states = ephy_node_new_with_id (states_db, STATES_NODE_ID);
122 ephy_node_db_load_from_file (states_db, xml_file,
123 EPHY_STATES_XML_ROOT,
124 EPHY_STATES_XML_VERSION);
126 g_free (xml_file);
130 static void
131 ephy_state_window_set_size (GtkWidget *window, EphyNode *node)
133 int width, height, w = -1, h = -1;
134 gboolean maximize, size;
136 width = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_WIDTH);
137 height = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_HEIGHT);
138 maximize = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE);
139 size = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_SIZE);
141 gtk_window_get_default_size (GTK_WINDOW (window), &w, &h);
142 if (size && w == -1 && h == -1)
144 GdkScreen *screen;
145 int screen_width, screen_height;
147 screen = gdk_screen_get_default ();
148 screen_width = gdk_screen_get_width (screen);
149 screen_height = gdk_screen_get_height (screen);
151 gtk_window_set_default_size (GTK_WINDOW (window),
152 MIN (width, screen_width),
153 MIN (height, screen_height));
156 if (maximize)
158 gtk_window_maximize (GTK_WINDOW (window));
162 static void
163 ephy_state_window_set_position (GtkWidget *window, EphyNode *node)
165 GdkScreen *screen;
166 int x, y;
167 int screen_width, screen_height;
168 gboolean maximize, size;
170 g_return_if_fail (GTK_IS_WINDOW (window));
172 /* Setting the default size doesn't work when the window is already showing. */
173 g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
175 maximize = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE);
176 size = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_POSITION);
178 /* Don't set the position of the window if it is maximized */
179 if ((!maximize) && size)
181 x = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_POSITION_X);
182 y = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_POSITION_Y);
184 screen = gtk_window_get_screen (GTK_WINDOW (window));
185 screen_width = gdk_screen_get_width (screen);
186 screen_height = gdk_screen_get_height (screen);
188 if ((x <= screen_width) && (y <= screen_height) &&
189 (x >= 0) && (y >= 0))
191 gtk_window_move (GTK_WINDOW (window), x, y);
196 static void
197 ephy_state_save_unmaximized_size (EphyNode *node, int width, int height)
199 ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_WIDTH,
200 width);
201 ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_HEIGHT,
202 height);
203 ephy_node_set_property_boolean (node, EPHY_NODE_STATE_PROP_SIZE,
204 TRUE);
207 static void
208 ephy_state_save_position (EphyNode *node, int x, int y)
210 ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_POSITION_X,
212 ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_POSITION_Y,
214 ephy_node_set_property_boolean (node, EPHY_NODE_STATE_PROP_POSITION,
215 TRUE);
219 static void
220 ephy_state_window_save_size (GtkWidget *window, EphyNode *node)
222 int width, height;
223 gboolean maximize;
224 GdkWindowState state;
226 state = gdk_window_get_state (GTK_WIDGET (window)->window);
227 maximize = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
229 gtk_window_get_size (GTK_WINDOW(window),
230 &width, &height);
232 if (!maximize)
234 ephy_state_save_unmaximized_size (node, width, height);
237 ephy_node_set_property_boolean (node,
238 EPHY_NODE_STATE_PROP_MAXIMIZE,
239 maximize);
242 static void
243 ephy_state_window_save_position (GtkWidget *window, EphyNode *node)
245 int x,y;
246 gboolean maximize;
247 GdkWindowState state;
249 state = gdk_window_get_state (GTK_WIDGET (window)->window);
250 maximize = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
252 /* Don't save the position if maximized */
253 if (!maximize)
255 gtk_window_get_position (GTK_WINDOW (window), &x, &y);
256 ephy_state_save_position (node, x, y);
260 static void
261 ephy_state_window_save (GtkWidget *widget, EphyNode *node)
263 EphyStateWindowFlags flags;
265 flags = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "state_flags"));
267 if (flags & EPHY_STATE_WINDOW_SAVE_SIZE)
269 ephy_state_window_save_size (widget, node);
272 if (flags & EPHY_STATE_WINDOW_SAVE_POSITION)
274 ephy_state_window_save_position (widget, node);
278 static gboolean
279 window_configure_event_cb (GtkWidget *widget,
280 GdkEventConfigure *event,
281 EphyNode *node)
283 GdkWindowState state;
285 state = gdk_window_get_state (widget->window);
287 if (!(state & GDK_WINDOW_STATE_FULLSCREEN))
289 ephy_state_window_save (widget, node);
292 return FALSE;
295 static gboolean
296 window_state_event_cb (GtkWidget *widget,
297 GdkEventWindowState *event,
298 EphyNode *node)
300 if (!(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN))
302 ephy_state_window_save (widget, node);
305 return FALSE;
308 static EphyNode *
309 create_window_node (const char *name,
310 int default_width,
311 int default_height,
312 gboolean maximize,
313 EphyStateWindowFlags flags)
315 EphyNode *node;
317 node = ephy_node_new (states_db);
318 ephy_node_add_child (states, node);
320 ephy_node_set_property_string (node, EPHY_NODE_STATE_PROP_NAME,
321 name);
322 ephy_node_set_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE,
323 maximize);
325 if (flags & EPHY_STATE_WINDOW_SAVE_SIZE)
327 ephy_state_save_unmaximized_size (node,
328 default_width,
329 default_height);
332 if (flags & EPHY_STATE_WINDOW_SAVE_POSITION)
334 /* Constants for now, these should be default_width
335 and default_height. */
336 ephy_state_save_position (node, 0, 0);
339 return node;
342 void
343 ephy_state_add_window (GtkWidget *window,
344 const char *name,
345 int default_width,
346 int default_height,
347 gboolean maximize,
348 EphyStateWindowFlags flags)
350 EphyNode *node;
352 ensure_states ();
354 node = find_by_name (name);
355 if (node == NULL)
357 node = create_window_node (name, default_width, default_height,
358 maximize, flags);
361 ephy_state_window_set_size (window, node);
362 ephy_state_window_set_position (window, node);
364 g_object_set_data (G_OBJECT (window), "state_flags", GINT_TO_POINTER (flags));
366 g_signal_connect (window, "configure_event",
367 G_CALLBACK (window_configure_event_cb), node);
368 g_signal_connect (window, "window_state_event",
369 G_CALLBACK (window_state_event_cb), node);
372 static gboolean
373 paned_sync_position_cb (GtkWidget *paned,
374 GParamSpec *pspec,
375 EphyNode *node)
377 int width;
379 width = gtk_paned_get_position (GTK_PANED (paned));
380 ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_WIDTH,
381 width);
382 return FALSE;
385 void
386 ephy_state_add_paned (GtkWidget *paned,
387 const char *name,
388 int default_width)
390 EphyNode *node;
391 int width;
393 ensure_states ();
395 node = find_by_name (name);
396 if (node == NULL)
398 node = ephy_node_new (states_db);
399 ephy_node_add_child (states, node);
401 ephy_node_set_property_string (node,
402 EPHY_NODE_STATE_PROP_NAME,
403 name);
404 ephy_node_set_property_int (node,
405 EPHY_NODE_STATE_PROP_WIDTH,
406 default_width);
409 width = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_WIDTH);
410 gtk_paned_set_position (GTK_PANED (paned), width);
412 g_signal_connect (paned, "notify::position",
413 G_CALLBACK (paned_sync_position_cb), node);
416 static void
417 sync_expander_cb (GtkExpander *expander,
418 GParamSpec *pspec,
419 EphyNode *node)
421 gboolean is_expanded;
423 is_expanded = gtk_expander_get_expanded (expander);
424 ephy_node_set_property_boolean (node,
425 EPHY_NODE_STATE_PROP_ACTIVE,
426 is_expanded);
429 static void
430 sync_toggle_cb (GtkToggleButton *toggle,
431 GParamSpec *pspec,
432 EphyNode *node)
434 gboolean is_active;
436 is_active = gtk_toggle_button_get_active (toggle);
437 ephy_node_set_property_boolean (node,
438 EPHY_NODE_STATE_PROP_ACTIVE,
439 is_active);
442 void
443 ephy_state_add_expander (GtkWidget *widget,
444 const char *name,
445 gboolean default_state)
447 EphyNode *node;
448 gboolean active;
450 ensure_states ();
452 node = find_by_name (name);
453 if (node == NULL)
455 node = ephy_node_new (states_db);
456 ephy_node_add_child (states, node);
458 ephy_node_set_property_string (node,
459 EPHY_NODE_STATE_PROP_NAME,
460 name);
461 ephy_node_set_property_boolean (node,
462 EPHY_NODE_STATE_PROP_ACTIVE,
463 default_state);
466 active = ephy_node_get_property_boolean
467 (node, EPHY_NODE_STATE_PROP_ACTIVE);
469 if (GTK_IS_TOGGLE_BUTTON (widget))
471 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
472 g_signal_connect (widget, "notify::active",
473 G_CALLBACK (sync_toggle_cb), node);
475 else if (GTK_IS_EXPANDER (widget))
477 gtk_expander_set_expanded (GTK_EXPANDER (widget), active);
478 g_signal_connect (widget, "notify::expanded",
479 G_CALLBACK (sync_expander_cb), node);
483 void
484 ephy_state_save (void)
486 if (states)
488 ephy_states_save ();
489 ephy_node_unref (states);
490 g_object_unref (states_db);
491 states = NULL;
492 states_db = NULL;