/* * Copyright (C) 2001 Matthew Mueller * Copyright (C) 2002 Jorn Baayen * Copyright (C) 2003 Marco Pesenti Gritti * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ #include "config.h" #include "ephy-state.h" #include "ephy-lib-type-builtins.h" #include "ephy-file-helpers.h" #include "ephy-node-db.h" #include "ephy-node-common.h" #include #include #include #include #include #define EPHY_STATES_XML_FILE "states.xml" #define EPHY_STATES_XML_ROOT (const xmlChar *)"ephy_states" #define EPHY_STATES_XML_VERSION (const xmlChar *)"1.0" enum { EPHY_NODE_STATE_PROP_NAME = 2, EPHY_NODE_STATE_PROP_WIDTH = 3, EPHY_NODE_STATE_PROP_HEIGHT = 4, EPHY_NODE_STATE_PROP_MAXIMIZE = 5, EPHY_NODE_STATE_PROP_POSITION_X = 6, EPHY_NODE_STATE_PROP_POSITION_Y = 7, EPHY_NODE_STATE_PROP_SIZE = 8, EPHY_NODE_STATE_PROP_POSITION = 9, EPHY_NODE_STATE_PROP_ACTIVE = 10 }; static EphyNode *states = NULL; static EphyNodeDb *states_db = NULL; static void ephy_states_save (void) { char *xml_file; xml_file = g_build_filename (ephy_dot_dir (), EPHY_STATES_XML_FILE, NULL); ephy_node_db_write_to_xml_safe (states_db, (const xmlChar *)xml_file, EPHY_STATES_XML_ROOT, EPHY_STATES_XML_VERSION, NULL, /* comment */ states, NULL, NULL, NULL); g_free (xml_file); } static EphyNode * find_by_name (const char *name) { EphyNode *result = NULL; GPtrArray *children; int i; children = ephy_node_get_children (states); for (i = 0; i < children->len; i++) { EphyNode *kid; const char *node_name; kid = g_ptr_array_index (children, i); node_name = ephy_node_get_property_string (kid, EPHY_NODE_STATE_PROP_NAME); if (strcmp (node_name, name) == 0) { result = kid; } } return result; } static void ensure_states (void) { if (states == NULL) { volatile GType flags_type; /* work around gcc's optimiser */ char *xml_file; /* make sure the type is known when we read the db */ flags_type = EPHY_TYPE_STATE_WINDOW_FLAGS; xml_file = g_build_filename (ephy_dot_dir (), EPHY_STATES_XML_FILE, NULL); states_db = ephy_node_db_new (EPHY_NODE_DB_STATES); states = ephy_node_new_with_id (states_db, STATES_NODE_ID); ephy_node_db_load_from_file (states_db, xml_file, EPHY_STATES_XML_ROOT, EPHY_STATES_XML_VERSION); g_free (xml_file); } } static void ephy_state_window_set_size (GtkWidget *window, EphyNode *node) { int width, height, w = -1, h = -1; gboolean maximize, size; width = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_WIDTH); height = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_HEIGHT); maximize = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE); size = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_SIZE); gtk_window_get_default_size (GTK_WINDOW (window), &w, &h); if (size && w == -1 && h == -1) { GdkScreen *screen; int screen_width, screen_height; screen = gdk_screen_get_default (); screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); gtk_window_set_default_size (GTK_WINDOW (window), MIN (width, screen_width), MIN (height, screen_height)); } if (maximize) { gtk_window_maximize (GTK_WINDOW (window)); } } static void ephy_state_window_set_position (GtkWidget *window, EphyNode *node) { GdkScreen *screen; int x, y; int screen_width, screen_height; gboolean maximize, size; g_return_if_fail (GTK_IS_WINDOW (window)); /* Setting the default size doesn't work when the window is already showing. */ g_return_if_fail (!GTK_WIDGET_VISIBLE (window)); maximize = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE); size = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_POSITION); /* Don't set the position of the window if it is maximized */ if ((!maximize) && size) { x = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_POSITION_X); y = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_POSITION_Y); screen = gtk_window_get_screen (GTK_WINDOW (window)); screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); if ((x <= screen_width) && (y <= screen_height) && (x >= 0) && (y >= 0)) { gtk_window_move (GTK_WINDOW (window), x, y); } } } static void ephy_state_window_save_size (GtkWidget *window, EphyNode *node) { int width, height; gboolean maximize; GdkWindowState state; GValue value = { 0, }; state = gdk_window_get_state (GTK_WIDGET (window)->window); maximize = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0); gtk_window_get_size (GTK_WINDOW(window), &width, &height); if (!maximize) { g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, width); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_WIDTH, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, height); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_HEIGHT, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, TRUE); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_SIZE, &value); g_value_unset (&value); } g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, maximize); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_MAXIMIZE, &value); g_value_unset (&value); } static void ephy_state_window_save_position (GtkWidget *window, EphyNode *node) { int x,y; gboolean maximize; GdkWindowState state; GValue value = { 0, }; state = gdk_window_get_state (GTK_WIDGET (window)->window); maximize = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0); /* Don't save the position if maximized */ if (!maximize) { gtk_window_get_position (GTK_WINDOW (window), &x, &y); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, x); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_POSITION_X, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, y); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_POSITION_Y, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, TRUE); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_POSITION, &value); g_value_unset (&value); } } static void ephy_state_window_save (GtkWidget *widget, EphyNode *node) { EphyStateWindowFlags flags; flags = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "state_flags")); if (flags & EPHY_STATE_WINDOW_SAVE_SIZE) { ephy_state_window_save_size (widget, node); } if (flags & EPHY_STATE_WINDOW_SAVE_POSITION) { ephy_state_window_save_position (widget, node); } } static gboolean window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, EphyNode *node) { GdkWindowState state; state = gdk_window_get_state (widget->window); if (!(state & GDK_WINDOW_STATE_FULLSCREEN)) { ephy_state_window_save (widget, node); } return FALSE; } static gboolean window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, EphyNode *node) { if (!(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) { ephy_state_window_save (widget, node); } return FALSE; } static EphyNode * create_window_node (const char *name, int default_width, int default_height, gboolean maximize, EphyStateWindowFlags flags) { EphyNode *node; GValue value = { 0, }; node = ephy_node_new (states_db); ephy_node_add_child (states, node); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, name); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_NAME, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, maximize); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_MAXIMIZE, &value); g_value_unset (&value); if (flags & EPHY_STATE_WINDOW_SAVE_SIZE) { g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, TRUE); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_SIZE, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, default_width); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_WIDTH, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, default_height); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_HEIGHT, &value); g_value_unset (&value); } return node; } void ephy_state_add_window (GtkWidget *window, const char *name, int default_width, int default_height, gboolean maximize, EphyStateWindowFlags flags) { EphyNode *node; ensure_states (); node = find_by_name (name); if (node == NULL) { node = create_window_node (name, default_width, default_height, maximize, flags); } ephy_state_window_set_size (window, node); ephy_state_window_set_position (window, node); g_object_set_data (G_OBJECT (window), "state_flags", GINT_TO_POINTER (flags)); g_signal_connect (window, "configure_event", G_CALLBACK (window_configure_event_cb), node); g_signal_connect (window, "window_state_event", G_CALLBACK (window_state_event_cb), node); } static gboolean paned_sync_position_cb (GtkWidget *paned, GParamSpec *pspec, EphyNode *node) { int width; GValue value = { 0, }; width = gtk_paned_get_position (GTK_PANED (paned)); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, width); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_WIDTH, &value); g_value_unset (&value); return FALSE; } void ephy_state_add_paned (GtkWidget *paned, const char *name, int default_width) { EphyNode *node; int width; ensure_states (); node = find_by_name (name); if (node == NULL) { GValue value = { 0, }; node = ephy_node_new (states_db); ephy_node_add_child (states, node); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, name); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_NAME, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, default_width); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_WIDTH, &value); g_value_unset (&value); } width = ephy_node_get_property_int (node, EPHY_NODE_STATE_PROP_WIDTH); gtk_paned_set_position (GTK_PANED (paned), width); g_signal_connect (paned, "notify::position", G_CALLBACK (paned_sync_position_cb), node); } static void sync_expander_cb (GtkExpander *expander, GParamSpec *pspec, EphyNode *node) { GValue value = { 0, }; g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, gtk_expander_get_expanded (expander)); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_ACTIVE, &value); g_value_unset (&value); } void ephy_state_add_expander (GtkWidget *expander, const char *name, gboolean default_state) { EphyNode *node; gboolean expanded; ensure_states (); node = find_by_name (name); if (node == NULL) { GValue value = { 0, }; node = ephy_node_new (states_db); ephy_node_add_child (states, node); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, name); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_NAME, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, default_state); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_ACTIVE, &value); g_value_unset (&value); } expanded = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_ACTIVE); gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); g_signal_connect (expander, "notify::expanded", G_CALLBACK (sync_expander_cb), node); } static void sync_toggle_cb (GtkToggleButton *toggle, GParamSpec *pspec, EphyNode *node) { GValue value = { 0, }; g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, gtk_toggle_button_get_active (toggle)); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_ACTIVE, &value); g_value_unset (&value); } void ephy_state_add_toggle (GtkWidget *toggle, const char *name, gboolean default_state) { EphyNode *node; gboolean active; ensure_states (); node = find_by_name (name); if (node == NULL) { GValue value = { 0, }; node = ephy_node_new (states_db); ephy_node_add_child (states, node); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, name); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_NAME, &value); g_value_unset (&value); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, default_state); ephy_node_set_property (node, EPHY_NODE_STATE_PROP_ACTIVE, &value); g_value_unset (&value); } active = ephy_node_get_property_boolean (node, EPHY_NODE_STATE_PROP_ACTIVE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), active); g_signal_connect (toggle, "notify::active", G_CALLBACK (sync_toggle_cb), node); } void ephy_state_save (void) { if (states) { ephy_states_save (); ephy_node_unref (states); g_object_unref (states_db); states = NULL; states_db = NULL; } }