Logo Search packages:      
Sourcecode: sanduhr version File versions  Download package

timer.c

/* timer.c - handle timer objects
 *
 * Copyright (C) 2000  Jochen Voss.  */

static const  char  rcsid[] = "$Id: timer.c 5864 2004-08-09 20:10:50Z voss $";

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <time.h>

#include <gnome.h>

#include "interface.h"
#include "callbacks.h"
#include "support.h"

#include "sandcommon.h"
#include "sand-window.h"


/* interval between display updates in ms */
#define TIMER_STEPSIZE 500

/**********************************************************************
 * Implement the CORBA servant
 */

static SandUhr_Timer_TimerState
impl_SandUhr_Timer__get_State (struct timer *timer,
                         CORBA_Environment *ev)
{
  return  timer->state;
}

static CORBA_char *
impl_SandUhr_Timer__get_TimeSpec (struct timer *timer,
                          CORBA_Environment *ev)
{
  char buffer [64];
  time_t target_time_abs = (int)(timer->target_time_abs + 0.5);

  strftime (buffer, 64, "%Y-%m-%d %H:%M:%S", localtime (&target_time_abs));
  return  CORBA_string_dup (buffer);
}

static void
impl_SandUhr_Timer__set_TimeSpec (struct timer *timer,
                          CORBA_char *value,
                          CORBA_Environment *ev)
{
  begin_arg (value);
  if (yyparse (timer) == 0) {
    timer->time_valid = TRUE;
    initialize_time (timer);
    factory_update_timer (timer->factory, timer);
  } else {
    CORBA_exception_set_system (ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_YES);
  }
}

static CORBA_char *
impl_SandUhr_Timer__get_Message (struct timer *timer,
                         CORBA_Environment *ev)
{
  CORBA_char *retval;

  retval = CORBA_string_dup (timer->message);
  return retval;
}

static void
impl_SandUhr_Timer__set_Message (struct timer *timer,
                         CORBA_char *value, CORBA_Environment *ev)
{
  g_free (timer->message);
  timer->message = g_strdup (value);
  factory_update_timer (timer->factory, timer);
}

static SandUhr_AlarmAction
impl_SandUhr_Timer__get_Alarm (struct timer *timer,
                         CORBA_Environment *ev)
{
  return  CORBA_Object_duplicate (timer->alarm, ev);
}

static void
impl_SandUhr_Timer__set_Alarm (struct timer *timer,
                         SandUhr_AlarmAction value,
                         CORBA_Environment *ev)
{
  SandUhr_Timer timer_ref;

  timer_ref = PortableServer_POA_servant_to_reference (timer->poa, timer, ev);

  SandUhr_AlarmAction_Detach (timer->alarm, timer_ref, ev);
  check_corba_error (ev, GTK_WINDOW (timer->window));
  CORBA_Object_release (timer->alarm, ev);
  
  timer->alarm = CORBA_Object_duplicate (value, ev);
  SandUhr_AlarmAction_Attach (timer->alarm, timer_ref, ev);
  CORBA_Object_release (timer_ref, ev);
}

static SandUhr_Timer_Color
impl_SandUhr_Timer__get_SandColor (struct timer *timer,
                           CORBA_Environment *ev)
{
  SandUhr_Timer_Color retval;
  guint8  r, g, b;

  sand_window_get_color (SAND_WINDOW(timer->window), &r, &g, &b);
  retval.Red = r;
  retval.Green = g;
  retval.Blue = b;
  
  return retval;
}

static void
impl_SandUhr_Timer__set_SandColor (struct timer *timer,
                           SandUhr_Timer_Color *value,
                           CORBA_Environment *ev)
{
  sand_window_set_color (SAND_WINDOW (timer->window),
                   value->Red, value->Green, value->Blue);
}

static CORBA_boolean
impl_SandUhr_Timer__get_WindowDecorations (struct timer *timer,
                                 CORBA_Environment *ev)
{
  return  SAND_WINDOW(timer->window)->decorations ? CORBA_TRUE : CORBA_FALSE;
}

static void
impl_SandUhr_Timer__set_WindowDecorations (struct timer *timer,
                                 CORBA_boolean value,
                                 CORBA_Environment *ev)
{
  g_object_set (GTK_OBJECT (timer->window),
            SAND_WINDOW_PROP_DECORATIONS (value),
            NULL);
}

static SandUhr_Timer_Layer
impl_SandUhr_Timer__get_WindowLayer (struct timer *timer,
                             CORBA_Environment *ev)
{
  return 0;             /* TODO */
}

static void
impl_SandUhr_Timer__set_WindowLayer (struct timer *timer,
                             SandUhr_Timer_Layer value,
                             CORBA_Environment *ev)
{
  return;               /* TODO */
}

static void
impl_SandUhr_Timer_Destroy (struct timer *timer,
                      CORBA_Environment *ev)
{
  delete_timer (timer);
}

static CORBA_unsigned_long
impl_SandUhr_Timer_TimeLeft (struct timer *timer,
                       CORBA_Environment *ev)
{
  if (timer->state != SandUhr_Timer_TSRunning) {
    CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                   ex_SandUhr_Timer_NotRunning,
                   NULL);
    return  0;
  } else {
    double  now = vclock ();
    return  (timer->target_time_abs-now) + 0.5;
  }
}

/**********************************************************************
 * epv structures
 */

static PortableServer_ServantBase__epv impl_SandUhr_Timer_base_epv =
{
  NULL,                       /* _private data */
  NULL,                       /* finalize routine */
  NULL,                       /* default_POA routine */
};

static POA_SandUhr_Timer__epv impl_SandUhr_Timer_epv =
{
  NULL,                       /* _private */

  (gpointer) &impl_SandUhr_Timer__get_State,

  (gpointer) &impl_SandUhr_Timer__get_TimeSpec,
  (gpointer) &impl_SandUhr_Timer__set_TimeSpec,

  (gpointer) &impl_SandUhr_Timer__get_Message,
  (gpointer) &impl_SandUhr_Timer__set_Message,

  (gpointer) &impl_SandUhr_Timer__get_Alarm,
  (gpointer) &impl_SandUhr_Timer__set_Alarm,

  (gpointer) &impl_SandUhr_Timer__get_SandColor,
  (gpointer) &impl_SandUhr_Timer__set_SandColor,

  (gpointer) &impl_SandUhr_Timer__get_WindowDecorations,
  (gpointer) &impl_SandUhr_Timer__set_WindowDecorations,

  (gpointer) &impl_SandUhr_Timer__get_WindowLayer,
  (gpointer) &impl_SandUhr_Timer__set_WindowLayer,

  (gpointer) &impl_SandUhr_Timer_Destroy,

  (gpointer) &impl_SandUhr_Timer_TimeLeft,
};

static POA_SandUhr_Timer__vepv impl_SandUhr_Timer_vepv =
{
  &impl_SandUhr_Timer_base_epv,
  &impl_SandUhr_Timer_epv,
};

/**********************************************************************
 * Menus and callback functions
 */

static void
new_timer_cb (GtkMenuItem *menuitem, gpointer user_data)
{
  struct timer *timer = user_data;
  create_timer (timer->factory, NULL, NULL, NULL);
}

static void
show_control_cb (GtkMenuItem *menuitem, gpointer user_data)
{
  struct timer *timer = user_data;
  gtk_widget_show (timer->factory->window);
}

static void
close_timer_cb (GtkMenuItem *menuitem, gpointer user_data)
{
  struct timer *timer = user_data;
  delete_timer (timer);
}

static void
exit_cb (GtkMenuItem *menuitem, gpointer user_data)
{
  struct timer *timer = user_data;
  int  count;

  count = factory_timer_count (timer->factory);
  if (count > 1) {
    gchar *question;
    int  res;

    if (count == 2) {
      question = g_strdup (_("There is another timer running.  "
                       "Really quit both timers?"));
    } else {
      question = g_strdup_printf (_("There are %d more timers running.  "
                            "Really quit them all?"), count-1);
    }
    res = ask_yes_no_question (question, GTK_WINDOW (timer->window));
    g_free (question);
    if (res != 0)  return;
  }
  gtk_main_quit ();
}


static GnomeUIInfo help1_menu_uiinfo[] =
{
  GNOMEUIINFO_HELP ("sanduhr"),
  GNOMEUIINFO_MENU_ABOUT_ITEM (on_about2_activate, NULL),
  GNOMEUIINFO_END
};

static GnomeUIInfo popup_menu_uiinfo[] =
{
  GNOMEUIINFO_MENU_NEW_ITEM (N_("_New Timer"), N_("Create a new timer"),
                       new_timer_cb, NULL),
  {
    GNOME_APP_UI_ITEM, N_("Show _Control Center"),
    NULL,
    show_control_cb, NULL, NULL,
    GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF,
    0, 0, NULL
  },
  GNOMEUIINFO_SEPARATOR,
  {
    GNOME_APP_UI_ITEM, N_("_Global Preferences ..."),
    N_("Change the default values for new timers"),
    on_preferences1_activate, NULL, NULL,
    GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF,
    0, 0, NULL
  },
  GNOMEUIINFO_MENU_PROPERTIES_ITEM (on_properties1_activate, NULL),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_HELP_TREE (help1_menu_uiinfo),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_CLOSE_ITEM (close_timer_cb, NULL),
  GNOMEUIINFO_MENU_EXIT_ITEM (exit_cb, NULL),
  GNOMEUIINFO_END
};

static void
timer_deliver_alarm (struct timer *timer)
{
  timer->ratio = 1.0;
  sand_window_set_ratio (SAND_WINDOW (timer->window), 1.0);
  sand_window_set_flow (SAND_WINDOW (timer->window), 0);
  deliver_alarm (timer);
}

static gint
timer_tick_cb (gpointer data)
{
  struct timer *timer = data;
  double  now = vclock ();

  timer->ratio = (now-timer->start_time)/timer->target_time_rel;
  sand_window_set_ratio (SAND_WINDOW (timer->window), timer->ratio);
  if (timer->target_time_abs - now < 0.5e-3*TIMER_STEPSIZE) {
    timer_deliver_alarm (timer);
    return  FALSE;
  }
  return  TRUE;
}

static void
timer_start_cb (struct timer *timer)
{
  factory_add_timer (timer->factory, timer);
  gtk_widget_show (timer->window);
  timer->handler_id = g_timeout_add (TIMER_STEPSIZE, timer_tick_cb, timer);
  timer->state = SandUhr_Timer_TSRunning;
}

static void
timer_abort_cb (struct timer *timer)
{
  delete_timer (timer);
}

static gboolean
on_button_press (GtkWidget *win, GdkEvent *event, void *data)
{
  struct timer *timer = data;

  if (event->type == GDK_BUTTON_PRESS) {
    GdkEventButton *ev = (GdkEventButton *)event;
    if (ev->button != 2)  return FALSE;
    gtk_window_begin_move_drag (GTK_WINDOW(timer->window),
                        ev->button,
                        ev->x_root, ev->y_root,
                        ev->time);
    return TRUE;
  }
  return  FALSE;
}

/**********************************************************************
 * external functions for timers
 */

struct timer *
create_timer (struct factory *factory, const char *time_spec, const char *msg,
            CORBA_Environment *parent_ev)
/* Create a new timer servant with alarm time TIME_SPEC and alarm message MSG.
 * If TIME_SPEC is invalid and PARENT_EV is non-null, throw an InvalidTime
 * exception.   If TIME_SPEC is invalid and PARENT_EV is not set, then
 * open a window and ask the user for another time.  */
{
  CORBA_Environment ev;
  struct timer *timer;
  PortableServer_ObjectId *objid;
  GtkWidget *popup_menu;
  SandUhr_Timer timer_ref;

  CORBA_exception_init (&ev);

  timer = g_new (struct timer, 1);
  timer->servant._private = NULL;
  timer->servant.vepv = &impl_SandUhr_Timer_vepv;
  timer->poa = factory->poa;
  POA_SandUhr_Timer__init ((PortableServer_Servant) timer, &ev);
  timer->factory = factory;
  
  timer->state = SandUhr_Timer_TSPrepare;
  main_loop_ref ();
  timer->window = g_object_new (SAND_TYPE_WINDOW,
                        "theme", default_theme,
                        NULL);
  gtk_signal_connect (GTK_OBJECT (timer->window),
                  "destroy",
                  GTK_SIGNAL_FUNC (window_destroy_cb),
                  NULL);
  gtk_window_set_title (GTK_WINDOW (timer->window), "SandUhr");
  popup_menu = gnome_popup_menu_new (popup_menu_uiinfo);
  gnome_popup_menu_attach (popup_menu, timer->window, timer);
#if 0
  /* TODO: for some reason this makes the program crash when I
   *       type C-q before the popup window is popped up for
   *       the first time.  */
  gtk_window_add_accel_group (GTK_WINDOW (timer->window),
                        gtk_menu_get_accel_group(GTK_MENU(popup_menu)));
#endif
  gtk_signal_connect(GTK_OBJECT(timer->window),
                 "event", GTK_SIGNAL_FUNC(on_button_press), timer);
  timer->prop_windows = NULL;
  
  timer->time_valid = FALSE;
  timer->ratio = 0;
  if (msg) {
    timer->message = g_strdup (msg);
  } else {
    timer->message = gnome_config_get_string ("/SandUhr/preferences/message");
  }
  if (timer->message && ! *timer->message) {
    g_free (timer->message);
    timer->message = NULL;
  }

  apply_defaults (timer);
  sand_window_set_ratio (SAND_WINDOW (timer->window), 0);
  
  objid = PortableServer_POA_activate_object (factory->poa, timer, &ev);
  CORBA_free (objid);

  timer_ref = PortableServer_POA_servant_to_reference (timer->poa, timer, &ev);
  SandUhr_AlarmAction_Attach (timer->alarm, timer_ref, &ev);
  CORBA_Object_release (timer_ref, &ev);

  check_corba_error (&ev, GTK_WINDOW (factory->window));
  
  ask_for_time (timer, time_spec, timer_start_cb, timer_abort_cb, parent_ev);
  
  return  timer;
}

void
delete_timer (struct timer *timer)
{
  CORBA_Environment  ev;
  PortableServer_ObjectId *objid;
  SandUhr_Timer timer_ref;
  
  CORBA_exception_init (&ev);

  timer_ref = PortableServer_POA_servant_to_reference (timer->poa, timer, &ev);
  SandUhr_AlarmAction_Detach (timer->alarm, timer_ref, &ev);
  CORBA_Object_release (timer_ref, &ev);
  
  if (timer->prop_windows) {
    GSList *pwlist = timer->prop_windows;
    do {
      gtk_object_destroy (pwlist->data);
      pwlist = pwlist->next;
    } while (pwlist);
    g_slist_free (timer->prop_windows);
    timer->prop_windows = NULL;
  }

  objid = PortableServer_POA_servant_to_id (timer->poa, timer, &ev);
  PortableServer_POA_deactivate_object (timer->poa, objid, &ev);
  CORBA_free (objid);

  factory_remove_timer (timer->factory, timer);

  POA_SandUhr_Timer__fini ((PortableServer_Servant)timer, &ev);

  if (timer->state == SandUhr_Timer_TSRunning)
    g_source_remove (timer->handler_id);
  gtk_object_destroy (GTK_OBJECT (timer->window));
  g_free (timer->message);
  g_free (timer);

  check_corba_error (&ev, NULL);
}

void
initialize_time (struct timer *timer)
/* Fill the absolute time value from the relative one and vice versa.  */
{
  if (timer->is_absolute) {
    timer->target_time_rel = timer->target_time_abs - timer->start_time;
  } else {
    timer->target_time_abs = timer->start_time + timer->target_time_rel;
    timer->is_absolute = TRUE;
  }
}

char *
timer_get_message (const struct timer *timer)
{
  const char *message = timer->message ? timer->message : _("timer elapsed");
  return  g_strdup (message);
}

Generated by  Doxygen 1.6.0   Back to index