Logo Search packages:      
Sourcecode: dates version File versions

dates_hildon.c

/* -*- mode:C; tab-width:4; -*- */
/* 
 *  Author: Tomas Frydrych <tf@o-hand.com>
 *
 *  Copyright (c) 2005 - 2006 OpenedHand Ltd - http://o-hand.com
 *
 *  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.
 *
 */

#include <string.h>

#include <libosso.h>
#include <hildon-widgets/hildon-window.h>
#include <hildon-widgets/hildon-program.h>
#include <hildon-widgets/hildon-time-editor.h>
#include <hildon-widgets/hildon-date-editor.h>

#include "dates_types.h"
#include "dates_callbacks.h"

/* functions for hildon hibernation */

/* the osso state data size has to be fixed; this defines the space
 * we need for storing the time stamp (UTC string is at most 20 bytes)
 */
#define ICALTIME_MAX_SIZE 21 

/* Wrapper around the data we save by libosso API
 *
 * For now just a timestamp, but will need to save scroll later
 */
typedef struct 
{
      char t[ICALTIME_MAX_SIZE];
} StateData;

/* saves state data via libosso API
 *
 * The saved data survives application exit until next reboot
 */
gboolean
dates_save_state (DatesData *d)
{
      const icaltimetype * t;
      const char         * t_sz;
      osso_state_t         osd;
      StateData            sd;

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("entered %s", G_STRFUNC);
#endif
      
      g_return_val_if_fail (d && d->view && d->osso_context, FALSE);

      t = dates_view_get_date (d->view);
      g_return_val_if_fail (t, FALSE);
      
      t_sz = icaltime_as_ical_string (*t);
      g_return_val_if_fail (t_sz, FALSE);

      memset (&sd, 0, sizeof (sd));
      strncpy (sd.t, t_sz, sizeof (sd.t));
      
      osd.state_size = sizeof(StateData);
      osd.state_data = (gpointer)&sd;

      if (osso_state_write (d->osso_context, &osd) == OSSO_OK)
      {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("success [%s]", sd.t);
#endif
            return TRUE;
      }

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("saving state failed");
#endif
      return FALSE;
}

/* Load our state data from the libosso storage
 * 
 * We have a problem -- the system uses a dbus message to let us know that we
 * are comming out of hibernation, rather than starting afresh, but
 * unfortunately, it does not work (I think that message is dispatched *before*
 * we had a chance to register our callback, so we never see it. The problem is
 * cause by the fact that the state data is persistent, so we cannot load it
 * on every startup, but only when weaking up from hibernation.
 *
 * We work around this problem by replacing the state data with a single byte
 * placeholder everytime we get topped; we then use the size of the save data to
 * differentiate between real data to use for restore, and phony one to ignore.
 *
 * This hack will not work if the application is closed in some other way than
 * being background killed while in the background, but this should not be
 * happening in Maemo 2, as there is no way to close the up from the TN, but
 * might become issue in the future (hopefully, the will fix the API by then).
 */
gboolean
dates_restore_state (DatesData *d)
{
      icaltimetype t;
      osso_state_t osd;
      StateData    sd;
      char         c = 0;
      
#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("entered %s", G_STRFUNC);
#endif
      
      g_return_val_if_fail (d && d->view && d->osso_context, FALSE);

      osd.state_size = sizeof(c);
      osd.state_data = (gpointer)& c;
      
      if (osso_state_read (d->osso_context, & osd) == OSSO_OK) {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("state date contains place-holder only");
#endif
            d->restored = TRUE;
            return FALSE;
      }
      
      osd.state_size = sizeof(StateData);
      osd.state_data = (gpointer)& sd;
      
      if (osso_state_read (d->osso_context, & osd) != OSSO_OK) {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("Could not read saved state");
#endif
            return FALSE;
      }

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("Retrieved saved date [%s]", sd.t);
#endif
      
      /* I hope this does not leak anything */
      t = icaltime_from_string (sd.t);
      dates_view_set_date (d->view, &t);

      d->restored = TRUE;
      
      return TRUE;
}

/* this is a hack working around the broken hibernation in hildon
 *
 * Basically, this function replaces any previously saved state data with data
 * of size sizeof(char) -- we then use the size of the saved data to
 * differentiate between real saved state and a mere placeholder
 */
gboolean
dates_clear_state (DatesData *d)
{
      osso_state_t         osd;
      char                 t = 0;

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("entered %s", G_STRFUNC);
#endif
      
      g_return_val_if_fail (d && d->view && d->osso_context, FALSE);

      osd.state_size = sizeof(t);
      osd.state_data = (gpointer)&t;

      if (osso_state_write (d->osso_context, &osd) == OSSO_OK)
      {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("success");
#endif
            return TRUE;
      }
      
#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("clearing state failed");
#endif
      return FALSE;
}

static void
dates_is_topmost_notify (GObject *self,
                   GParamSpec *property_param,
                   DatesData * d)
{
      HildonProgram *program = HILDON_PROGRAM (self);
      if (hildon_program_get_is_topmost (program)){
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("dates_is_topmost_notify: TRUE");
#endif

            /* if this is not the initial topping of the application,
             * clear the state data
             */
            if (d->restored) {
                  dates_clear_state(d);
            }
            
            hildon_program_set_can_hibernate (program, FALSE);
      } else {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("dates_is_topmost_notify: FALSE");
#endif
            dates_save_state(d);
            hildon_program_set_can_hibernate (program, TRUE);
      }
}

static gboolean
dates_restore_timeout_cb (gpointer p)
{
      DatesData * d = (DatesData*)p;

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("Entered restore timeout CB");
#endif

      if (d && d->restored) {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("State already restored");
#endif
            return FALSE;
      }
      
      if (!d || !d->init_done) {
#ifdef DEBUG
            if (d->debug & DATES_DEBUG_HIBERNATE)
                  g_debug ("Initialisation not completed, yet ...");
#endif
            return TRUE;
      }

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug ("restoring state");
#endif
      dates_restore_state (d);
      return FALSE;
}


static gint
dates_osso_rpc_event_cb (const gchar     *interface,
                   const gchar     *method,
                   GArray          *arguments,
                   gpointer         p,
                   osso_rpc_t      *retval)
{
      DatesData * d = (DatesData*) d;
      
#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HIBERNATE)
            g_debug("osso_rpc_event_cb() interface [%s], method [%s]",
                  interface, method);
#endif
      
      g_return_val_if_fail (d, OSSO_ERROR);

      
      /* the restored message can arrive *before* the app finished loading --
       * if that happens we cannot retrive the state, so we install a
       * callback to be called in 300ms intervals until the init is finished
       */
         
      if(!strcmp(method, "restored"))
      {
            if(d->init_done)
            {
#ifdef DEBUG
                  if (d->debug & DATES_DEBUG_HIBERNATE)
                        g_debug ("restoring state");
#endif
                  dates_restore_state (d);
            }
            else
                  g_timeout_add (300, dates_restore_timeout_cb, d);
      }

      return OSSO_OK;
}

static GtkWidget *
load_tb_item (GtkWidget * toolbar,
            const char * name, const char * fallback,
            GCallback cb, gpointer data)
{
      GtkToolItem * tb;
      GtkWidget *icon;

      icon = gtk_image_new_from_icon_name (
            name, GTK_ICON_SIZE_SMALL_TOOLBAR);

      if (!icon) {
#ifdef DEBUG
            g_debug ("could not load theme icon [%s] -- using stock [%s]",
                   name, fallback);
#endif
            tb = gtk_tool_button_new_from_stock (fallback);
      } else
            tb = gtk_tool_button_new (icon, NULL);

      gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tb, -1);
      
      g_signal_connect (G_OBJECT (tb), "clicked",
                    cb, data);
      
      return GTK_WIDGET (tb);
}

#define DATES_PLATFORM_create_toolbar
static GtkWidget *
create_toolbar (DatesData * d)
{
      /* Create new GTK toolbar */
      GtkWidget * toolbar = gtk_toolbar_new ();

      /* Set toolbar properties */
      gtk_toolbar_set_orientation( GTK_TOOLBAR(toolbar),
                             GTK_ORIENTATION_HORIZONTAL);
      gtk_toolbar_set_style( GTK_TOOLBAR(toolbar),
                         GTK_TOOLBAR_BOTH_HORIZ);

      /* Create toolitems using defined items from stock */
      d->TBNew = load_tb_item (toolbar,
            "qgn_list_messagin_editor", GTK_STOCK_NEW,
            G_CALLBACK(dates_new_cb), d);
      d->TBEdit = load_tb_item (toolbar, "qgn_list_gene_fldr_opn",
                                            GTK_STOCK_EDIT,
            G_CALLBACK(dates_edit_cb), d);
      d->TBDelete = load_tb_item (toolbar, "qgn_list_gene_invalid",
                                                GTK_STOCK_DELETE,
                                                G_CALLBACK(dates_delete_cb), d);
            
        gtk_toolbar_insert (GTK_TOOLBAR(toolbar),
            GTK_TOOL_ITEM (GTK_SEPARATOR_TOOL_ITEM (
                  gtk_separator_tool_item_new ())), -1);
            
      d->TBBack = load_tb_item (toolbar, "qgn_list_gene_back",
                                            GTK_STOCK_GO_BACK,
                                            G_CALLBACK(dates_back_cb), d);
      d->TBToday = load_tb_item (toolbar, "qgn_toolb_browser_home",
                                             GTK_STOCK_HOME,
                                             G_CALLBACK(dates_today_cb), d);
      d->TBForward = load_tb_item (toolbar, "qgn_list_gene_forward",
                                                 GTK_STOCK_GO_FORWARD,
                                                 G_CALLBACK(dates_forward_cb), d);
            
        gtk_toolbar_insert (GTK_TOOLBAR(toolbar),
            GTK_TOOL_ITEM (GTK_SEPARATOR_TOOL_ITEM (
                  gtk_separator_tool_item_new ())), -1);
                  
      d->TBZoomOut = load_tb_item (toolbar, "qgn_toolb_gene_zoomout",
                                                 GTK_STOCK_ZOOM_OUT,
                                                 G_CALLBACK(dates_zoom_out_cb), d);
      d->TBZoomIn = load_tb_item (toolbar, "qgn_toolb_gene_zoomin",
                                                GTK_STOCK_ZOOM_IN,
                                                G_CALLBACK(dates_zoom_in_cb), d);

      gtk_widget_show_all (GTK_WIDGET (toolbar));
      gtk_widget_hide (d->TBEdit);
      gtk_widget_hide (d->TBDelete);

      return toolbar;
}

#define DATES_PLATFORM_dates_platform_init
void
dates_platform_init (DatesData * d)
{
      d->init_done = FALSE;
      d->restored  = FALSE;

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HILDON)
            g_debug ("Creating HildonProgram");
#endif
      g_set_application_name (_("Dates"));
      d->program = hildon_program_new ();

#ifdef DEBUG
      if (d->debug & DATES_DEBUG_HILDON)
            g_debug ("Initialising HildonProgram");
#endif
      d->osso_context = osso_initialize ("dates", "0.1", TRUE, NULL);

      if (!d->osso_context)
      {
            g_critical("Could not initialize libosso\n");
            exit (-1);
      }

      if (osso_rpc_set_default_cb_f(d->osso_context,
                                                  dates_osso_rpc_event_cb, d) != OSSO_OK)
      {
            g_warning ("Could not register rpc callback");
      }
}

#define DATES_PLATFORM_create_time_dialog
static GtkWidget *
create_time_dialog (DatesData * d)
{
      GtkWidget *dialog_vbox2;
      GtkWidget *vbox1;
      GtkWidget *time_separator_label;
      GtkWidget *hour_button;
      GtkWidget *hour_up_button;
      GtkWidget *hour_up;
      GtkWidget *hour_down_button;
      GtkWidget *hour_down;
      GtkWidget *lminute_up_button;
      GtkWidget *lminute_up;
      GtkWidget *lminute_down_button;
      GtkWidget *lminute_down;
      GtkWidget *rminute_up_button;
      GtkWidget *rminute_up;
      GtkWidget *rminute_down_button;
      GtkWidget *rminute_down;
      GtkWidget *dialog_action_area2;
      GtkWidget *time_closebutton;

      d->time_dialog = gtk_dialog_new ();
      gtk_window_set_title (GTK_WINDOW (d->time_dialog), _("Time"));
      gtk_window_set_modal (GTK_WINDOW (d->time_dialog), TRUE);
      gtk_window_set_resizable (GTK_WINDOW (d->time_dialog), FALSE);
      gtk_window_set_icon_name (GTK_WINDOW (d->time_dialog), "dates");
      gtk_window_set_skip_taskbar_hint (GTK_WINDOW (d->time_dialog), TRUE);
      gtk_window_set_skip_pager_hint (GTK_WINDOW (d->time_dialog), TRUE);
      gtk_window_set_type_hint (GTK_WINDOW (d->time_dialog),
                                            GDK_WINDOW_TYPE_HINT_DIALOG);
      gtk_dialog_set_has_separator (GTK_DIALOG (d->time_dialog), FALSE);

      dialog_vbox2 = GTK_DIALOG (d->time_dialog)->vbox;
      gtk_widget_show (dialog_vbox2);

      vbox1 = gtk_vbox_new (FALSE, 12);
      gtk_widget_show (vbox1);
      gtk_box_pack_start (GTK_BOX (dialog_vbox2), vbox1, TRUE, TRUE, 0);
      gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);

      d->time_date_editor = hildon_date_editor_new ();
      gtk_widget_show (d->time_date_editor);
      gtk_box_pack_start (GTK_BOX (vbox1), d->time_date_editor, TRUE, TRUE, 0);

      d->time_time_editor = hildon_time_editor_new ();
      gtk_widget_show (d->time_time_editor);
      gtk_box_pack_start (GTK_BOX (vbox1), d->time_time_editor, TRUE, TRUE, 0);

      d->time_forever_checkbutton =
            gtk_check_button_new_with_mnemonic (_("Forever"));
      
      gtk_widget_show (d->time_forever_checkbutton);
      gtk_box_pack_start (GTK_BOX (vbox1), d->time_forever_checkbutton,
                                    FALSE, FALSE, 0);

      dialog_action_area2 = GTK_DIALOG (d->time_dialog)->action_area;
      gtk_widget_show (dialog_action_area2);
      gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2),
                                             GTK_BUTTONBOX_END);

      time_closebutton = gtk_button_new_from_stock ("gtk-close");
      gtk_widget_show (time_closebutton);
      gtk_dialog_add_action_widget (GTK_DIALOG (d->time_dialog),
                                                  time_closebutton, GTK_RESPONSE_CLOSE);
      GTK_WIDGET_SET_FLAGS (time_closebutton, GTK_CAN_DEFAULT);


      gtk_widget_grab_focus (time_closebutton);
      gtk_widget_grab_default (time_closebutton);
  
      return d->time_dialog;
}

#define DATES_PLATFORM_create_main_window
static GtkWidget *
create_main_window (DatesData * d, GtkWidget * toolbar,
                              GtkWidget * menu, GtkAccelGroup * accel_group)
{
      GtkWidget *main_vbox;
      GtkWidget *image;
      GtkWidget *scrolled_window;

      gtk_widget_show (menu);
      hildon_program_set_common_menu(d->program, GTK_MENU(menu));
      hildon_program_set_common_toolbar (d->program, GTK_TOOLBAR (toolbar));
      
      d->main_window = hildon_window_new ();
      gtk_window_set_title (GTK_WINDOW (d->main_window), _("Dates"));

      main_vbox = gtk_vbox_new (FALSE, 0);
      gtk_widget_show (main_vbox);
      gtk_container_add (GTK_CONTAINER (d->main_window), main_vbox);

      d->header_eventbox = gtk_event_box_new ();
      gtk_box_pack_start (GTK_BOX (main_vbox), d->header_eventbox,
                                    FALSE, FALSE, 0);

      d->header_label = gtk_label_new (_("<big><b>Dates</b></big>"));
      gtk_widget_show (d->header_label);
      gtk_container_add (GTK_CONTAINER (d->header_eventbox), d->header_label);
      gtk_label_set_use_markup (GTK_LABEL (d->header_label), TRUE);

      gtk_widget_show (GTK_WIDGET (d->view));

      dates_view_set_use_dragbox (d->view, FALSE);

      scrolled_window = gtk_scrolled_window_new (NULL, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                    GTK_POLICY_NEVER,
                                    GTK_POLICY_AUTOMATIC);

      gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (d->view));

      gtk_widget_show (scrolled_window);

      gtk_box_pack_start (GTK_BOX (main_vbox), scrolled_window,
                                    TRUE, TRUE, 0);

      
      GTK_WIDGET_SET_FLAGS (d->view, GTK_CAN_FOCUS);
      GTK_WIDGET_UNSET_FLAGS (d->view, GTK_CAN_DEFAULT);

      gtk_widget_grab_focus (GTK_WIDGET (d->view));
      gtk_window_add_accel_group (GTK_WINDOW (d->main_window), accel_group);

      /* Set nice colours for full-screen date header */
      gtk_widget_set_state (d->header_eventbox, GTK_STATE_SELECTED);
      gtk_widget_set_state (d->header_label, GTK_STATE_SELECTED);
      
      g_signal_connect (G_OBJECT (d->main_window), "window_state_event",
                                G_CALLBACK (dates_window_state_cb), d);
      g_signal_connect (G_OBJECT (d->main_window), "key_press_event",
                                G_CALLBACK (dates_key_press_cb), d);

      return d->main_window;
}

static void
dates_gtk_create_ui (DatesData * d);

void
dates_platform_create_ui (DatesData * d)
{
      dates_gtk_create_ui (d);

      hildon_program_add_window (d->program, HILDON_WINDOW (d->main_window));
      
      g_object_set(G_OBJECT(gtk_widget_get_settings(d->main_window)),
                        "gtk-button-images",
                        FALSE, NULL );
      g_object_set(G_OBJECT(gtk_widget_get_settings(d->main_window)),
                        "gtk-menu-images",
                        FALSE, NULL );

      /* HildonTime/DateEditor are broken, show_all them */
      gtk_widget_show_all (d->time_date_editor);
      gtk_widget_show_all (d->time_time_editor);
}

#define DATES_PLATFORM_dates_platform_pre_show
void dates_platform_pre_show (DatesData *d)
{
      gtk_window_set_default_icon_name ("dates");

      g_signal_connect (G_OBJECT (d->program), "notify::is-topmost",
                                G_CALLBACK (dates_is_topmost_notify), d);

      d->init_done = TRUE;

      if (!d->restored)
            dates_restore_state (d);      
}

#define dates_platform_create_ui dates_gtk_create_ui

#include "dates_gtk.c"

#undef  dates_platform_create_ui


Generated by  Doxygen 1.6.0   Back to index