aboutsummaryrefslogblamecommitdiffstats
path: root/lib/ephy-state.c
blob: c59b42d5e374b17ae298fa55e3d65b7b297a4fdc (plain) (tree)
1
2
3
4
5
                                                                           
  


                                                           












                                                                        
                                                                                  
  

   
                   
 
                       
                                   
                              
                         
                             
 
                   
                    
 
                                            

                                                              





                                        

                                            

                                            
                                          
                                        
  
 
                               
                                    

           
                       
 
                       
 
                                                     
                                                          

                                           
                                      

                                           


                                         
                                    
                       
 
                                

 

                               
 


                                
 






                                                      
 






                                                         
 

                      
 



                           
         
                                                                            

                               


                                                                     
                                                             
                                                                  

                                                   
                                                                   
                                                                           




                                                                      
         




                                                              
                                          
                                



                                                                                        
                                                                                
 

                                                                  
         









                                                                          

         
                     
         
                                                          


         
           




                                                                  
                                





                                                                                       
                                                                                        
                                                                                    
 
                                                                     
                                
         

                                                                                       
 



                                                                     

                                                                  


                                                                    


         





















                                                                            

           
                                                               
 


                             







                                                                   
         
                                                                       
         



                                                                      

 



                                                                   

                             
 

                                                                   
 
                                                  

                      
                                                                      
                                                      

















                                                                                       
         

 




                                                    





                                                      
                                                      

         







                                                  

                                                                     
                                                      

         
                     

 



                                       
                                      
                                               
 

                       

                                           
 



                                                                            
 

                                                


                                                                 
         
 






                                                                   







                                          
                                         








                                                  

                                                                               
         
 

                                                      
 
                                                                                      
 



                                                                        

 
               

                                          


                                       

                                                           

                                                                     















                                        
                                                 

                                                   





                                                                         




                                                                              

                                                                     

 
           


                                        
 
                             
 



                                                                    

 




                                        
                           
 



                                                                    


     


                                                








                                   


                                                   





                                                                            




                                                    











                                                                                  

 


                      







                                           
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  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-state.h"
#include "ephy-lib-type-builtins.h"
#include "ephy-file-helpers.h"
#include "ephy-node-db.h"
#include "ephy-node-common.h"

#include <string.h>
#include <gtk/gtk.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_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_save_unmaximized_size (EphyNode *node, int width, int height)
{
    ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_WIDTH,
                    width);
    ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_HEIGHT,
                    height);
    ephy_node_set_property_boolean (node, EPHY_NODE_STATE_PROP_SIZE,
                    TRUE);
}

static void
ephy_state_save_position (EphyNode *node, int x, int y)
{
    ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_POSITION_X,
                    x);
    ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_POSITION_Y,
                    y);
    ephy_node_set_property_boolean (node, EPHY_NODE_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 (window)->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_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 (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);
        ephy_state_save_position (node, x, y);
    }
}

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;

    node = ephy_node_new (states_db);
    ephy_node_add_child (states, node);

    ephy_node_set_property_string (node, EPHY_NODE_STATE_PROP_NAME,
                       name);
    ephy_node_set_property_boolean (node, EPHY_NODE_STATE_PROP_MAXIMIZE,
                    maximize);

    if (flags & EPHY_STATE_WINDOW_SAVE_SIZE)
    {
        ephy_state_save_unmaximized_size (node,
                         default_width,
                         default_height);
    }

        if (flags & EPHY_STATE_WINDOW_SAVE_POSITION)
        {
        /* Constants for now, these should be default_width
           and default_height. */
        ephy_state_save_position (node, 0, 0);
        }

    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;

    width = gtk_paned_get_position (GTK_PANED (paned));
    ephy_node_set_property_int (node, EPHY_NODE_STATE_PROP_WIDTH,
                    width);
    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)
    {
        node = ephy_node_new (states_db);
        ephy_node_add_child (states, node);

        ephy_node_set_property_string (node,
                           EPHY_NODE_STATE_PROP_NAME,
                           name);
        ephy_node_set_property_int (node,
                        EPHY_NODE_STATE_PROP_WIDTH,
                        default_width);
    }

    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)
{
    gboolean is_expanded;

    is_expanded = gtk_expander_get_expanded (expander);
    ephy_node_set_property_boolean (node,
                    EPHY_NODE_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_STATE_PROP_ACTIVE,
                    is_active);
}

void 
ephy_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_STATE_PROP_NAME,
                           name);
        ephy_node_set_property_boolean (node,
                        EPHY_NODE_STATE_PROP_ACTIVE,
                        default_state);
    }

    active = ephy_node_get_property_boolean
        (node, EPHY_NODE_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_state_save (void)
{
    if (states)
    {
        ephy_states_save ();
        ephy_node_unref (states);
        g_object_unref (states_db);
        states = NULL;
        states_db = NULL;
    }
}