aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ephy-initial-state.c
diff options
context:
space:
mode:
authorXan Lopez <xan@igalia.com>2012-12-16 17:31:16 +0800
committerXan Lopez <xan@igalia.com>2012-12-16 17:31:16 +0800
commit3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48 (patch)
tree217babbda3a8e3427c09b8600e12c0b82e12059c /lib/ephy-initial-state.c
parent13dd37b49c84e15470a8cba37f08f34a2d9c87d3 (diff)
downloadgsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar.gz
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar.bz2
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar.lz
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar.xz
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.tar.zst
gsoc2013-epiphany-3b0dc557ca0fe21d59fba8bf7cd653c63b32ea48.zip
ephy-state: rename to 'ephy-initial-state'
The purpose of EphyState is to track the sizes and positions of windows, paned or expanders in order to remember what is the preferred *initial* and *default* state of those UI elements. So for example we merge the tracking of the size/positions of all main windows in one record, because we only need an initial value which we'll use as default for newly created EphyWindows. Since this is a very specific task, different to the actual tracking of all sizes and positions in EphySession in order to restore them at startup, rename the class to EphyInitialState to avoid confusions.
Diffstat (limited to 'lib/ephy-initial-state.c')
-rw-r--r--lib/ephy-initial-state.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/lib/ephy-initial-state.c b/lib/ephy-initial-state.c
new file mode 100644
index 000000000..fb625ac45
--- /dev/null
+++ b/lib/ephy-initial-state.c
@@ -0,0 +1,462 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright © 2001 Matthew Mueller
+ * Copyright © 2002 Jorn Baayen <jorn@nl.linux.org>
+ * Copyright © 2003 Marco Pesenti Gritti <mpeseng@tin.it>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ephy-initial-state.h"
+
+#include "ephy-file-helpers.h"
+#include "ephy-lib-type-builtins.h"
+#include "ephy-node-common.h"
+#include "ephy-node-db.h"
+
+#include <gtk/gtk.h>
+#include <string.h>
+
+#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_INITIAL_STATE_PROP_NAME = 2,
+ EPHY_NODE_INITIAL_STATE_PROP_WIDTH = 3,
+ EPHY_NODE_INITIAL_STATE_PROP_HEIGHT = 4,
+ EPHY_NODE_INITIAL_STATE_PROP_MAXIMIZE = 5,
+ EPHY_NODE_INITIAL_STATE_PROP_POSITION_X = 6,
+ EPHY_NODE_INITIAL_STATE_PROP_POSITION_Y = 7,
+ EPHY_NODE_INITIAL_STATE_PROP_SIZE = 8,
+ EPHY_NODE_INITIAL_STATE_PROP_POSITION = 9,
+ EPHY_NODE_INITIAL_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_INITIAL_STATE_PROP_NAME);
+
+ if (strcmp (node_name, name) == 0)
+ result = kid;
+ }
+
+ return result;
+}
+
+static void
+ensure_states (void)
+{
+ if (states == NULL) {
+ char *xml_file;
+
+ 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_INITIAL_STATE_PROP_WIDTH);
+ height = ephy_node_get_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_HEIGHT);
+ maximize = ephy_node_get_property_boolean (node, EPHY_NODE_INITIAL_STATE_PROP_MAXIMIZE);
+ size = ephy_node_get_property_boolean (node, EPHY_NODE_INITIAL_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_get_visible (window));
+
+ maximize = ephy_node_get_property_boolean (node, EPHY_NODE_INITIAL_STATE_PROP_MAXIMIZE);
+ size = ephy_node_get_property_boolean (node, EPHY_NODE_INITIAL_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_INITIAL_STATE_PROP_POSITION_X);
+ y = ephy_node_get_property_int (node, EPHY_NODE_INITIAL_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_save_unmaximized_size (EphyNode *node, int width, int height)
+{
+ ephy_node_set_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_WIDTH,
+ width);
+ ephy_node_set_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_HEIGHT,
+ height);
+ ephy_node_set_property_boolean (node, EPHY_NODE_INITIAL_STATE_PROP_SIZE,
+ TRUE);
+}
+
+static void
+ephy_state_save_position (EphyNode *node, int x, int y)
+{
+ ephy_node_set_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_POSITION_X,
+ x);
+ ephy_node_set_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_POSITION_Y,
+ y);
+ ephy_node_set_property_boolean (node, EPHY_NODE_INITIAL_STATE_PROP_POSITION,
+ TRUE);
+}
+
+
+static void
+ephy_state_window_save_size (GtkWidget *window, EphyNode *node)
+{
+ int width, height;
+ gboolean maximize;
+ GdkWindowState state;
+
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+ maximize = ((state & GDK_WINDOW_STATE_MAXIMIZED) > 0);
+
+ gtk_window_get_size (GTK_WINDOW(window),
+ &width, &height);
+
+ if (!maximize)
+ ephy_state_save_unmaximized_size (node, width, height);
+
+ ephy_node_set_property_boolean (node,
+ EPHY_NODE_INITIAL_STATE_PROP_MAXIMIZE,
+ maximize);
+}
+
+static void
+ephy_state_window_save_position (GtkWidget *window, EphyNode *node)
+{
+ int x,y;
+ gboolean maximize;
+ GdkWindowState state;
+
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (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);
+ ephy_state_save_position (node, x, y);
+ }
+}
+
+static void
+ephy_state_window_save (GtkWidget *widget, EphyNode *node)
+{
+ EphyInitialStateWindowFlags flags;
+
+ flags = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "state_flags"));
+
+ if (flags & EPHY_INITIAL_STATE_WINDOW_SAVE_SIZE)
+ ephy_state_window_save_size (widget, node);
+
+ if (flags & EPHY_INITIAL_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 (gtk_widget_get_window (widget));
+
+ 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,
+ EphyInitialStateWindowFlags flags)
+{
+ EphyNode *node;
+
+ node = ephy_node_new (states_db);
+ ephy_node_add_child (states, node);
+
+ ephy_node_set_property_string (node, EPHY_NODE_INITIAL_STATE_PROP_NAME,
+ name);
+ ephy_node_set_property_boolean (node, EPHY_NODE_INITIAL_STATE_PROP_MAXIMIZE,
+ maximize);
+
+ if (flags & EPHY_INITIAL_STATE_WINDOW_SAVE_SIZE) {
+ ephy_state_save_unmaximized_size (node,
+ default_width,
+ default_height);
+ }
+
+ if (flags & EPHY_INITIAL_STATE_WINDOW_SAVE_POSITION) {
+ /* Constants for now, these should be default_wi dth
+ and default_height. */
+ ephy_state_save_position (node, 0, 0);
+ }
+
+ return node;
+}
+
+void
+ephy_initial_state_add_window (GtkWidget *window,
+ const char *name,
+ int default_width,
+ int default_height,
+ gboolean maximize,
+ EphyInitialStateWindowFlags flags)
+{
+ EphyNode *node;
+
+ g_return_if_fail (GTK_IS_WIDGET (window));
+ g_return_if_fail (name != NULL);
+
+ 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;
+
+ width = gtk_paned_get_position (GTK_PANED (paned));
+ ephy_node_set_property_int (node, EPHY_NODE_INITIAL_STATE_PROP_WIDTH,
+ width);
+ return FALSE;
+}
+
+void
+ephy_initial_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) {
+ node = ephy_node_new (states_db);
+ ephy_node_add_child (states, node);
+
+ ephy_node_set_property_string (node,
+ EPHY_NODE_INITIAL_STATE_PROP_NAME,
+ name);
+ ephy_node_set_property_int (node,
+ EPHY_NODE_INITIAL_STATE_PROP_WIDTH,
+ default_width);
+ }
+
+ width = ephy_node_get_property_int (node, EPHY_NODE_INITIAL_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)
+{
+ gboolean is_expanded;
+
+ is_expanded = gtk_expander_get_expanded (expander);
+ ephy_node_set_property_boolean (node,
+ EPHY_NODE_INITIAL_STATE_PROP_ACTIVE,
+ is_expanded);
+}
+
+static void
+sync_toggle_cb (GtkToggleButton *toggle,
+ GParamSpec *pspec,
+ EphyNode *node)
+{
+ gboolean is_active;
+
+ is_active = gtk_toggle_button_get_active (toggle);
+ ephy_node_set_property_boolean (node,
+ EPHY_NODE_INITIAL_STATE_PROP_ACTIVE,
+ is_active);
+}
+
+void
+ephy_initial_state_add_expander (GtkWidget *widget,
+ const char *name,
+ gboolean default_state)
+{
+ EphyNode *node;
+ gboolean active;
+
+ ensure_states ();
+
+ node = find_by_name (name);
+
+ if (node == NULL) {
+ node = ephy_node_new (states_db);
+ ephy_node_add_child (states, node);
+
+ ephy_node_set_property_string (node,
+ EPHY_NODE_INITIAL_STATE_PROP_NAME,
+ name);
+ ephy_node_set_property_boolean (node,
+ EPHY_NODE_INITIAL_STATE_PROP_ACTIVE,
+ default_state);
+ }
+
+ active = ephy_node_get_property_boolean
+ (node, EPHY_NODE_INITIAL_STATE_PROP_ACTIVE);
+
+ if (GTK_IS_TOGGLE_BUTTON (widget)) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+ g_signal_connect (widget, "notify::active",
+ G_CALLBACK (sync_toggle_cb), node);
+ } else if (GTK_IS_EXPANDER (widget)) {
+ gtk_expander_set_expanded (GTK_EXPANDER (widget), active);
+ g_signal_connect (widget, "notify::expanded",
+ G_CALLBACK (sync_expander_cb), node);
+ }
+}
+
+void
+ephy_initial_state_save (void)
+{
+ if (states) {
+ ephy_states_save ();
+ ephy_node_unref (states);
+ g_object_unref (states_db);
+ states = NULL;
+ states_db = NULL;
+ }
+}