Re: Xfce timer plugin

Kemal Eroglu <[email protected]>
Newsgroups gmane.comp.desktop.xfce.goodies.devel
Message-ID <[email protected]>

   Hi again,

   Here's the second version with slight modifications. I'm just sending 
the two modified files. I added the option for choosing progress bar 
orientation. I'm still desperately looking for a way to shrink the size of 
the main container widget. I also added two separators on each side to 
fill the unused space.

   Ilgar


On Wed, 7 Sep 2005, Kemal Eroglu wrote:

>
>  Hi all,
>
>  Here's my version 0.1 of a timer plugin for XFCE4. It's similar to KTeaTime 
> for those of you who are faimilar with KDE. You can define a number of 
> alarms. You can either specify a countdown period or a time of the day for 
> the alarm. You select the one you want from a popup menu and start the 
> coundown. When the countdown ends, a Gtk warning window is displayed, or, a 
> command specified by the user is run.
>
>  Clearly, this first version is waiting for testers and suggestions. Some of 
> the ideas in my mind are in the TODO file. The only serious issue right now 
> is the progressbar: This is the main widget in the plugin display; it "fills" 
> as the countdown approaches to its end. I'm trying to get a thin progressbar 
> but the panel insists on producing a big, fat one. One other issue is that 
> you get some warnings when you remove the plugin right after you add it to 
> the panel. It doesn't crash though. It appears to be related to the freeing 
> of a gtk_list_store object (pd->list in the code).
>
>  Finally: I'm supposing that this is a plugin which would be added to the 
> panel only when needed; but one also would like to keep the settings. The XML 
> system provided in the plugin read/write_config functions loses the settings 
> when the plugin is removed from the panel. For this reason I'm currently 
> writing the settings to the file
>
> ~/.config/xfce4/panel/timer_settings
>
>  It's a file with the format of a GKeyFile. This may not be a very good 
> solution; and I'm waiting for hints on how to properly achieve the purpose.
>
>  Test and enjoy!
>
>  Ilgar
xfcetimer.h (text/plain, 2.3 KB)
/*  
 *
 *  Copyright (C) 2005 Kemal Ilgar Eroglu <[email protected]>
 *
 *  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 of the License, 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 Library 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.
 */


#define 	TIMEOUT_TIME 2000 			/* Countdown update period in 
							   milliseconds */

typedef struct {
  GtkWidget 	*eventbox,				/* Main container widget
		 					   in ctrl->base */
		*box,					/* v/hbox that holds pbar */  
		*pbar, 					/* Progress bar */
		*tree, 					/* Treeview */
		*buttonadd,*buttonedit,*buttonremove,	/* options window buttons */
		*menu,
		*base;					/* ctrl->base */
  GtkListStore *list;					/* The alarms list */
  gint 		count,					/* Nubmer of alarms */
		selected,timeout_period_in_sec;		/* Active countdown period */
  guint 	timeout;				/* The timeout ID */
  gboolean 	timer_on;				/* TRUE if countdown 
							   is in progress */
  GtkTooltips 	*tip;					/* Tooltip for panel */
  gboolean 	is_horizontal;				/* Progressbar alignment */
  GArray 	*menuarray;				/* Array of popup 
							   menuitems (alarms). These 
							   are used to find the index
							   of the selected menuitem. */
  gchar 	*timeout_command;			/* Command when countdown ends */
  GTimer 	*timer;					/* Keeps time elapsed */
} plugin_data;

typedef struct {
  GtkSpinButton	*timeh,*times,*timem,			/* Spinbuttons for h-m-s 
							   format */
		*time_h,*time_m;			/* Spinbuttons for 24h format */
  GtkEntry 	*name,*command;				/* Name, and command entries */
  GtkRadioButton *rb1;					/* Radio button for the
							   h-m-s format */
  GtkWindow 	*window;				/* Add/Edit window */
  plugin_data 	*pd;					/* Plugin data */
} alarm_data;
xfcetimer.c (text/plain, 37.6 KB)
/*  
 *
 *  Copyright (C) 2005 Kemal Ilgar Eroglu <[email protected]>
 *
 *  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 of the License, 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 Library 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.
 */



#define TIMEOUT_TIME 	2000 /* Countdown update period in milliseconds */
#define PBAR_THICKNESS 	16

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

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

#include <gtk/gtk.h>

#include <libxfce4util/libxfce4util.h>
#include <libxfcegui4/xfce_iconbutton.h>

#include <panel/xfce.h>
#include <panel/plugins.h>

#include "xfcetimer.h"

void make_menu(plugin_data *pd);


/**
 * This is the timeout function that updates the 
 * tooltip, pbar and keeps track of elapsed time
**/
static gboolean timeout_function (gpointer data){

  plugin_data *pd=(plugin_data *)data;
  gint elapsed_sec,remaining;
  gchar tiptext[32];
  GtkWidget *dialog;
  gulong zip;

  elapsed_sec=(gint)g_timer_elapsed(pd->timer,&zip);

  /*g_fprintf(stderr,"\nElapsed %d seconds of %d",elapsed_sec,pd-
					>timeout_period_in_sec);*/

  /* If countdown is not over, update tooltip */
  if(elapsed_sec < pd->timeout_period_in_sec){

     remaining=pd->timeout_period_in_sec-elapsed_sec;

     if(remaining>=3600)
       g_snprintf(tiptext,31,"%dh %dm %ds left",remaining/3600, (remaining%3600)/60, 
			remaining%60);
     else if (remaining>=60)
       g_snprintf(tiptext,31,"%dm %ds left",remaining/60, remaining%60);
     else
       g_snprintf(tiptext,31,"%ds left",remaining);

     gtk_progress_bar_set_fraction	(GTK_PROGRESS_BAR(pd->pbar),
					((gdouble)elapsed_sec)/pd->  						timeout_period_in_sec);  

     gtk_tooltips_set_tip(pd->tip,pd->base,tiptext,NULL);

     return TRUE;
     
  }

  /* Countdown is over, stop timer and free resources */

  /*g_fprintf(stderr,"\nTimer command is ==> %s...",pd->timeout_command);*/
    
  if(strlen(pd->timeout_command)>0)
     g_spawn_command_line_async (pd->timeout_command,NULL);
  else{
      gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->pbar),1);  
      dialog = gtk_message_dialog_new 	(NULL,
                                  	GTK_DIALOG_MODAL,
                                  	GTK_MESSAGE_WARNING,
                                  	GTK_BUTTONS_CLOSE,
                                  	"Beeep! :) \nTime is up!");
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
  }

  if(pd->timer)
     g_timer_destroy(pd->timer);
  pd->timer=NULL;
  gtk_tooltips_disable(pd->tip);
  if(pd->timeout_command)
     g_free(pd->timeout_command);

  pd->timeout_command=NULL;
  pd->timeout=0;

  pd->timer_on=FALSE;

  /* reset pbar */
  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->pbar),0);  

  make_menu(pd);

  /* This function won't be called again */
  return FALSE;

}

/**
 * This is the callback function called when a timer
 * is selected in the popup menu
**/

static void timer_selected (GtkWidget* menuitem, GdkEventButton* event, gpointer data){

  plugin_data *pd=(plugin_data *)data;
  gint row_count;

  row_count=0;

  /* Find the index of the menuitem selected, save it in pd->selected. Not very 
     elegant, though */
  while (GTK_MENU_ITEM(menuitem)!=g_array_index(pd->menuarray,GtkMenuItem*,row_count) )
     row_count++;
   
  pd->selected=row_count;

  /*g_fprintf(stderr,"\n Selecten menuitem is %d",row_count);*/
  
}

/**
 * This is the callback function called when the
 * start/stop item is selected in the popup menu
**/

static void start_stop_selected (GtkWidget* menuitem, GdkEventButton* event, gpointer 
										data){

  plugin_data *pd=(plugin_data *)data;
  GtkTreeIter iter;
  gboolean valid;
  GSList *group=NULL;
  gchar *timerinfo,*tout_command;
  gchar temp[8];
  gint row_count,cur_h,cur_m,cur_s,time;
  gint timeout_period;
  gboolean is_cd;
  GTimeVal timeval;
  struct tm *current;

  /* If counting down, we stop the timer and free the resources */
  if(pd->timer_on){
      
    /*g_fprintf(stderr,"\nTimer is running, shutting down...");*/
    if(pd->timer)
       g_timer_destroy(pd->timer);
    if(pd->timeout)
       g_source_remove(pd->timeout);
    if(pd->timeout_command)
       g_free(pd->timeout_command);

    pd->timer=NULL;
    pd->timeout_command=NULL;
    pd->timeout=0;
    pd->timer_on=FALSE;

    /* Disable tooltips, reset pbar */
    gtk_tooltips_disable(pd->tip);
    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->pbar),0);  

    /* update menu*/
    make_menu(pd);

    return;

  }

  /* If we're here then the timer is off, so we start it */

  /*g_fprintf(stderr,"\nStarting timer...");*/

  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(pd->list), &iter);
  row_count=0;
  
  /* Empty timer list-> Nothing to do. pd->selected=0, though. */
  if(!valid)
    return;

  /* Search the list item with the  right index */
  while (valid && row_count!=pd->selected){
      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(pd->list), &iter);
      row_count++;
  }

  gtk_tree_model_get 	(GTK_TREE_MODEL(pd->list), &iter, 2, &timerinfo, 3, 
			&tout_command, 4, &is_cd ,5, &time, -1);

  /* This will not be freed until the timeout is destroyed */
  pd->timeout_command=tout_command;

  /* If it's a 24h type alarm, we find the difference with current time
     Here 'time' is in minutes */
  if(!is_cd) {

     g_get_current_time(&timeval);
     current = localtime((time_t *)&timeval.tv_sec);
     strftime(temp,7,"%H",current);
     cur_h=atoi(temp);
     /*g_fprintf(stderr,"\n Current time: %d : ",cur_h);*/
     strftime(temp,7,"%M",current);
     cur_m=atoi(temp);
     /*g_fprintf(stderr,"%d : ",cur_m);*/
     strftime(temp,7,"%S",current);
     cur_s=atoi(temp);
     /*g_fprintf(stderr,"%d \n",cur_s);*/

     timeout_period=time*60 - ((60*cur_h + cur_m)*60 + cur_s);
 
     if(timeout_period <0)
        timeout_period+= 24*60*60;
 
  }
  /* Else 'time' already gives the countdown period in seconds */ 
  else
      timeout_period=time;

  pd->timeout_period_in_sec=timeout_period;

  /* start the timer */
  pd->timer=g_timer_new();
  pd->timer_on=TRUE;
  
  /* update stuff */
  make_menu(pd);

  gtk_tooltips_set_tip(pd->tip, GTK_WIDGET(pd->base), timerinfo, NULL);
  gtk_tooltips_enable(pd->tip);
  g_free(timerinfo);

  g_timer_start(pd->timer);
  pd->timeout = g_timeout_add(TIMEOUT_TIME, timeout_function,pd);


}

/**
 * Callback when clicking on pbar. Pops the menu up/down
**/
static void pbar_clicked (GtkWidget *pbar, GdkEventButton *event, gpointer data){

    plugin_data *pd=(plugin_data *)data;

    /*g_fprintf(stderr,"\nReceived click on button %d",event->button);*/
 

    if(!pd->menu){
      g_fprintf(stderr,"\nNo menu\n");
      return;
    }

    if(event->button==1)
      gtk_menu_popup (GTK_MENU(pd->menu),NULL,NULL,NULL,NULL,event->button,event->time);
    else
      gtk_menu_popdown(GTK_MENU(pd->menu));

}

/**
 * This function generates the popup menu
**/
void make_menu(plugin_data *pd){

  GtkTreeIter iter;
  gboolean valid;
  GSList *group=NULL;
  GtkWidget *menuitem;
  gchar *timername,*timerinfo;
  gchar itemtext[256];
  gint row_count;


  /* Destroy the existing one */
  if(pd->menu)
    gtk_widget_destroy(pd->menu);

  if(pd->menuarray)
    g_array_free(pd->menuarray,TRUE);

  pd->menu=gtk_menu_new();
  pd->menuarray=g_array_new(FALSE,TRUE,sizeof(menuitem));


  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(pd->list), &iter);
  row_count=0;

  while (valid){
    
      /* Run through the list, read name and timer period info */

      /*g_fprintf(stderr,"\nMaking menuitem %d while selected is %d",row_count,pd-> 
								selected);*/
      gtk_tree_model_get(GTK_TREE_MODEL(pd->list),&iter,1,&timername,2,&timerinfo,-1);
      g_snprintf(itemtext,255,"%s (%s)",timername,timerinfo);
      menuitem=gtk_radio_menu_item_new_with_label(group,itemtext);
      gtk_widget_show(menuitem);
      g_free(timername);
      g_free(timerinfo);
      group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
      g_signal_connect	(G_OBJECT(menuitem),"button_press_event", 
			G_CALLBACK(timer_selected),pd);
      /* The selected timer is always active */
      if(row_count==pd->selected)
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),TRUE);
      else if(pd->timer_on) /* others are disabled when timer is already running */
        gtk_widget_set_sensitive(GTK_WIDGET(menuitem),FALSE);

      gtk_menu_shell_append(GTK_MENU_SHELL(pd->menu),menuitem);

      /*g_fprintf(stderr,"\nAdding menuitem with label : %s",itemtext);*/

      /* We add the address of menuitem to the array */
      g_array_append_val(pd->menuarray,menuitem);
      
      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(pd->list), &iter);
      row_count++;
  }

  /* Horizontal line (empty item) */
  menuitem=gtk_menu_item_new();
  gtk_menu_shell_append(GTK_MENU_SHELL(pd->menu),menuitem);
  gtk_widget_show(menuitem);

  /* Start/stop menu item */
  if(pd->timer_on)
    menuitem=gtk_menu_item_new_with_label("Stop timer");
  else
    menuitem=gtk_menu_item_new_with_label("Start timer");

  gtk_menu_shell_append	(GTK_MENU_SHELL(pd->menu),menuitem);
  g_signal_connect	(G_OBJECT(menuitem),"button_press_event",
			G_CALLBACK(start_stop_selected),pd);
  gtk_widget_show(menuitem);

  gtk_widget_show(pd->menu);
    
}


/**
 * Callback to the OK button in the Add window
**/
static void ok_add(GtkButton *button, gpointer data){

  alarm_data *adata = (alarm_data *)data;
  GtkTreeIter iter;
  gint t1,t2,t3,t;
  gchar timeinfo[16];

  /* Add item to the list */
  gtk_list_store_append(adata->pd->list,&iter);
    
  gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,
			0,adata->pd->count,
			1,gtk_entry_get_text(GTK_ENTRY(adata->name)),
			3,gtk_entry_get_text(GTK_ENTRY(adata->command)), 
			4,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(adata-> 
									rb1)),-1);
  /* Item count goes up by one */
  adata->pd->count=adata->pd->count+1;

  /* If the h-m-s format was chosen, convert time to seconds,
     save the choice into the list */
  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(adata->rb1))){

    t1=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->timeh));
    t2=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->timem));
    t3=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->times));
    t=t1*3600+t2*60+t3;

    gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,5,t,-1);
    if(t1>0)
       g_snprintf(timeinfo,15,"%dh %dm %ds",t1,t2,t3);
    else if(t2>0)
       g_snprintf(timeinfo,15,"%dm %ds",t2,t3);
    else
       g_snprintf(timeinfo,15,"%ds",t3);

    gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,2,timeinfo,-1);
  }
  else{ /* The 24h format. Save time in minutes */

    t1=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->time_h));
    t2=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->time_m));
    t=t1*60+t2;
    gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,5,t,-1);
    g_snprintf(timeinfo,9,"At %02d:%02d",t1,t2);
    gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,2,timeinfo,-1);

  }

  /* Update menu */  
  make_menu(adata->pd);

  /* Free resources */
  gtk_widget_destroy(GTK_WIDGET(adata->window));

  g_free(adata);
}



/**
 * Callback for cancelling Add and Edit. Just closes the window :).
**/
static void cancel_add_edit(GtkButton *button, gpointer data){

  alarm_data *adata=(alarm_data *)data;
 
  gtk_widget_destroy(GTK_WIDGET(adata->window));

  g_free(adata);

}


/**
 * Callback for OK button on Edit window. See ok_add for comments.
**/
static void ok_edit(GtkButton *button, gpointer data){

  alarm_data *adata = (alarm_data *)data;
  GtkTreeIter iter;
  gint t1,t2,t3,t;
  gchar timeinfo[10];

  GtkTreeSelection *select;
  GtkTreeModel *model;

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (adata->pd->tree));

  if (gtk_tree_selection_get_selected (select, &model, &iter))
  {    
     gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,
			1,gtk_entry_get_text(GTK_ENTRY(adata->name)),
			3,gtk_entry_get_text(GTK_ENTRY(adata->command)), 
			4,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(adata-> 
									rb1)),-1);
     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(adata->rb1))){

        t1=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->timeh));
        t2=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->timem));
        t3=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->times));
        t=t1*3600+t2*60+t3;
        gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,5,t,-1);
       if(t1>0)
          g_snprintf(timeinfo,15,"%dh %dm %ds",t1,t2,t3);
       else if(t2>0)
          g_snprintf(timeinfo,15,"%dm %ds",t2,t3);
       else
          g_snprintf(timeinfo,15,"%ds",t3);

        gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,2,timeinfo,-1);
      }
      else{

        t1=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->time_h));
        t2=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adata->time_m));
        t=t1*60+t2;
        gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,5,t,-1);
        g_snprintf(timeinfo,9,"At %02d:%02d",t1,t2);
        gtk_list_store_set(GTK_LIST_STORE(adata->pd->list),&iter,2,timeinfo,-1);

      }
  
  }

  make_menu(adata->pd);

  gtk_widget_destroy(GTK_WIDGET(adata->window));

  g_free(adata);
}


/**
 * Callback to the Add button in options window.
 * Creates the Add window.
**/
static void add_edit_clicked (GtkButton *buttonn, gpointer data){

  plugin_data *pd = (plugin_data *)data;

  GtkWindow *window;
  GtkLabel *label;
  GtkEntry *name,*command;
  GtkSpinButton *timeh,*timem,*times,*time_h,*time_m;
  GtkRadioButton *rb1,*rb2;
  GtkWidget *hbox,*vbox,*button;
  alarm_data *adata=g_new(alarm_data,1);
  gchar *nc; gboolean is_cd; gint time;
  GtkTreeIter iter;
  GtkTreeSelection *select;
  GtkTreeModel *model;

  window = (GtkWindow *)gtk_window_new(GTK_WINDOW_TOPLEVEL);

  adata->window=window;
  adata->pd=pd;
  
  gtk_window_set_modal(GTK_WINDOW(window),TRUE);

  vbox=gtk_vbox_new(FALSE,0);
  gtk_container_add(GTK_CONTAINER(window),vbox);

  /***********/
  hbox=gtk_hbox_new(TRUE,0);
  gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);  

  label = (GtkLabel *)gtk_label_new ("Name");
  name = (GtkEntry *) gtk_entry_new_with_max_length(1023);
  adata->name=name;

  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(label),TRUE,TRUE,0);  
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(name),TRUE,TRUE,0);  

  /**********/
  rb1=(GtkRadioButton *)gtk_radio_button_new_with_label(NULL,"Enter the countdown time");
  rb2=(GtkRadioButton *)gtk_radio_button_new_with_label(gtk_radio_button_get_group
					(rb1),"Enter the time of alarm (24h format)");
  adata->rb1=rb1;

  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(rb1),TRUE,TRUE,0);

  hbox=gtk_hbox_new(FALSE,0);
  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(hbox),TRUE,TRUE,0);  

  timeh = (GtkSpinButton *)gtk_spin_button_new_with_range(0,23,1);
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(timeh),FALSE,FALSE,0);  
  adata->timeh=timeh;
  label = (GtkLabel *)gtk_label_new ("h");
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(label),FALSE,FALSE,2);
  timem = (GtkSpinButton *)gtk_spin_button_new_with_range(0,59,1);
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(timem),FALSE,FALSE,5);  
  adata->timem=timem;
  label = (GtkLabel *)gtk_label_new ("m");
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(label),FALSE,FALSE,2);
  times = (GtkSpinButton *)gtk_spin_button_new_with_range(0,59,1);
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(times),FALSE,FALSE,5);  
  adata->times=times;
  label = (GtkLabel *)gtk_label_new ("s");
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(label),FALSE,FALSE,2);

  label = (GtkLabel *)gtk_label_new ("\nor\n");
  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(label),TRUE,TRUE,0);


  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(rb2),TRUE,TRUE,0);

  hbox=gtk_hbox_new(FALSE,0);
  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(hbox),TRUE,TRUE,0);  

  time_h = (GtkSpinButton *)gtk_spin_button_new_with_range(0,23,1);
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(time_h),FALSE,FALSE,0);  
  adata->time_h=time_h;
  label = (GtkLabel *)gtk_label_new (":");
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(label),FALSE,FALSE,5);
  time_m = (GtkSpinButton *)gtk_spin_button_new_with_range(0,59,1);
  gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(time_m),FALSE,FALSE,5);  
  adata->time_m=time_m;

  /****************/

  label = (GtkLabel *)gtk_label_new ("\nThe command to run");
  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(label),TRUE,TRUE,0);
  command = (GtkEntry *)gtk_entry_new_with_max_length(1023);
  adata->command=command;
  gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(command),TRUE,TRUE,0);

  /****************/

  hbox=gtk_hbox_new(TRUE,0);
  gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,0);  

  button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
  gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE,0);
  g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(cancel_add_edit),adata);

  button=gtk_button_new_from_stock(GTK_STOCK_OK);
  gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE,0);  
  if(GTK_WIDGET(buttonn)==pd->buttonadd)
     g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(ok_add),adata);
  else
     g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(ok_edit),adata);

  

  /* If this is the add window, we're done */
  if(GTK_WIDGET(buttonn)==pd->buttonadd) {
    gtk_window_set_title(window,"Add new alarm");
    gtk_widget_show_all(GTK_WIDGET(window));
    return;
  }

  /* Else fill the values in the boxes with the current choices */
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (pd->tree));
  /*gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);*/

  if (gtk_tree_selection_get_selected (select, &model, &iter)){
      gtk_tree_model_get(model,&iter,1,&nc,-1);
      gtk_entry_set_text(GTK_ENTRY(name),nc);
      g_free(nc);

      gtk_tree_model_get(model,&iter,3,&nc,-1);
      gtk_entry_set_text(GTK_ENTRY(command),nc);
      g_free(nc);

      gtk_tree_model_get(model,&iter,4,&is_cd,-1);
      gtk_tree_model_get(model,&iter,5,&time,-1);

      if(is_cd){
         
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(timeh),time/3600);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(timem),(time%3600)/60);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(times),time%60);
         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb1),TRUE);
      }
      else{

         gtk_spin_button_set_value(GTK_SPIN_BUTTON(time_h),time/60);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(time_m),time%60);
         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb2),TRUE);
         
      }
     
  }

  gtk_window_set_title(window,"Edit alarm");
  gtk_widget_show_all(GTK_WIDGET(window));

}


/**
 * Calllback for the remove button in the options
**/
static void remove_clicked(GtkButton *button, gpointer data){

  plugin_data *pd = (plugin_data *)data;

  GtkTreeIter iter,iter_remove;
  GtkTreeSelection *select;
  GtkTreePath *path;
  GtkTreeModel *model;
  gboolean valid;
  gint row_count;

  /* Get the selected row */
  select=gtk_tree_view_get_selection(GTK_TREE_VIEW(pd->tree));

  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(pd->list), &iter);

  row_count=0;

  while (valid){

     /* Re-index the other rows */

     /* The selected one is removed, the corresponding menuitem array is also 
        updated */
     if(gtk_tree_selection_iter_is_selected(select,&iter)){
       /*g_fprintf(stderr,"\n Removing node %d ...\n", row_count);*/
       iter_remove=iter; /* Mark to be deleted */
       g_array_remove_index(pd->menuarray,row_count);
       if(pd->selected==row_count) /* Update the index of the selected item */
          pd->selected=0; /* If the selected is deleted, new selected one is the first 
				one. The first radiomenuitem gets activated anyway */
       else if(pd->selected > row_count)
          pd->selected=pd->selected-1;  /* Those coming after are shifted one behind */
     }
     else{  
       /* Save new index on the remaning ones */
       gtk_list_store_set (pd->list, &iter, 0,row_count, -1);
       row_count++;
    }

    valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(pd->list), &iter);

  }

  /* Remove the marked one */
  gtk_list_store_remove (pd->list, &iter_remove);

  /* Update item count and menu */
  pd->count=row_count;

  make_menu(pd);
  
}

/**
 * Adds the progressbar, taking into account the orientation.
 * pd->pbar is not destroyed, just reparented (saves fraction setting code etc.).
**/
static void add_pbar(plugin_data *pd){

  gtk_widget_hide(pd->eventbox);


  /* Always true except at initialization */
  if(pd->box){
    g_object_ref(G_OBJECT(pd->pbar));
    gtk_container_remove(GTK_CONTAINER(pd->box),pd->pbar);
    gtk_widget_destroy(pd->box);
  }

  /* vertical bar -- the default */
  if(!pd->is_horizontal){
    pd->box=gtk_hbox_new(TRUE,0);
    gtk_container_add(GTK_CONTAINER(pd->eventbox),pd->box);
    gtk_progress_bar_set_orientation	(GTK_PROGRESS_BAR(pd-> 
					pbar),GTK_PROGRESS_BOTTOM_TO_TOP);
    gtk_widget_set_size_request(GTK_WIDGET(pd->pbar),PBAR_THICKNESS,0);
    gtk_box_pack_start(GTK_BOX(pd->box),gtk_vseparator_new(),FALSE,FALSE,0);
    gtk_box_pack_start(GTK_BOX(pd->box),pd->pbar,FALSE,FALSE,0);
    gtk_box_pack_start(GTK_BOX(pd->box),gtk_vseparator_new(),FALSE,FALSE,0);
    
  }
  else{ /* horizontal bar */
    pd->box=gtk_vbox_new(TRUE,0);
    gtk_container_add(GTK_CONTAINER(pd->eventbox),pd->box);
    gtk_progress_bar_set_orientation	(GTK_PROGRESS_BAR(pd-> 
	  				pbar),GTK_PROGRESS_LEFT_TO_RIGHT);
    gtk_widget_set_size_request(GTK_WIDGET(pd->pbar),0,PBAR_THICKNESS);
    gtk_box_pack_start(GTK_BOX(pd->box),gtk_hseparator_new(),FALSE,FALSE,0);
    gtk_box_pack_start(GTK_BOX(pd->box),pd->pbar,FALSE,FALSE,0);
    gtk_box_pack_start(GTK_BOX(pd->box),gtk_hseparator_new(),FALSE,FALSE,0);

  }

  gtk_widget_show_all(pd->eventbox);
}

/**
 * Loads the list from a keyfile, then saves them in a list_store
**/ 
static void load_settings(plugin_data *pd)
{

  gchar groupname[8];
  gchar *timerstring;
  gint groupnum,time;
  gboolean is_cd;
  GtkTreeIter iter;
  GError *error=NULL;
  gchar settings[1024];
  
  GKeyFile *keyfile=g_key_file_new();

  /*g_fprintf(stderr,"\n Running read\n");*/

  g_snprintf(settings,1023,"%s/.config/xfce4/panel/timer_settings",g_get_home_dir());

  /*g_fprintf(stderr,"\n ** %s \n",settings);*/

  /*if(g_file_test(settings,G_FILE_TEST_EXISTS))*/ /* somehow this returns false */
    if(!g_key_file_load_from_file(keyfile,settings,G_KEY_FILE_NONE,&error))
       g_fprintf(stderr,"\n ==> %s\n",error->message);
  /*else{
    g_fprintf(stderr,"\nNokeyfile\n");
    return;
  }*/

  groupnum=0;
  g_sprintf(groupname,"G0");

  /*if(!g_key_file_has_group(keyfile,groupname))
    g_fprintf(stderr,"\nNo zero group");*/


  while(g_key_file_has_group(keyfile,groupname)){

     /*g_fprintf(stderr,"\nLoading item %d\n",groupnum);*/
     gtk_list_store_append(pd->list,&iter);

     timerstring=g_key_file_get_value(keyfile,groupname,"timername",NULL);
     gtk_list_store_set(pd->list,&iter,0,groupnum,1,timerstring,-1);
     g_free(timerstring);

     timerstring=g_key_file_get_value(keyfile,groupname,"timercommand",NULL);
     gtk_list_store_set(pd->list,&iter,3,timerstring,-1);
     /*g_fprintf(stderr,"\nLoaded timer command ==> %s... with length %d", 
						timerstring,strlen(timerstring));*/
     g_free(timerstring);

     timerstring=g_key_file_get_value(keyfile,groupname,"timerinfo",NULL);
     gtk_list_store_set(pd->list,&iter,2,timerstring,-1);

     g_free(timerstring);

     is_cd=g_key_file_get_boolean(keyfile,groupname,"is_countdown",NULL);
     time=g_key_file_get_integer(keyfile,groupname,"time",NULL);

     /* No longer needed, time info is also saved and read now
     if(is_cd){
        if(time<60)
          g_snprintf(timeinfo,15,"%02ds",time);
        else if (time < 3600)
          g_snprintf(timeinfo,15,"%02dm %02ds",time/60,time%60);
        else
          g_snprintf(timeinfo,15,"%02dh %d02m %02ds",time/3660,(time%3600)/60,time%60);
      }
     else 
          g_snprintf(timeinfo,15,"At %02d:%02d",time/60,time%60);
     */

     gtk_list_store_set(pd->list,&iter,4,is_cd,5,time,-1);

     groupnum++;
     g_snprintf(groupname,5,"G%d",groupnum);
   
  }

  pd->count=groupnum;
  

  /* Read other options */
  if(g_key_file_has_group(keyfile,"others"))
    pd->is_horizontal= g_key_file_get_boolean(keyfile,"others","is_horizontal",NULL);

  add_pbar(pd);  

  g_free(keyfile);

}


/**
 * Saves the list to a keyfile
**/ 
static void save_settings(plugin_data *pd){

  gchar *timername,*timercommand,*timerinfo;
  gint time;
  gboolean is_cd;
  gchar settings[1024];
  gchar settingsbak[1024];
  gchar line[1024];
  GtkTreeIter iter;
  gboolean valid;
  gint row_count;
  gsize size;

  GIOChannel *io;

  /*g_fprintf(stderr,"\n Running write\n");*/

  g_snprintf(settings,1023,"%s/.config/xfce4/panel/timer_settings",g_get_home_dir());

  io = g_io_channel_new_file(settings,"w",NULL);


  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(pd->list), &iter);

  row_count=0;

  while (valid){

      gtk_tree_model_get (GTK_TREE_MODEL(pd->list), &iter,
			1, &timername, 
			2, &timerinfo, 
			3, &timercommand, 
			4, &is_cd,
			5, &time, -1);

      g_snprintf(line,1023,"[G%d]\n",row_count);
      g_io_channel_write_chars(io,line,-1,&size,NULL);

      g_snprintf(line,1023,"timername=%s\n",timername);
      g_io_channel_write_chars(io,line,-1,&size,NULL);

      g_snprintf(line,1023,"time=%d\n",time);
      g_io_channel_write_chars(io,line,-1,&size,NULL);

      g_snprintf(line,1023,"timercommand=%s\n",timercommand);
      g_io_channel_write_chars(io,line,-1,&size,NULL);

      g_snprintf(line,1023,"timerinfo=%s\n",timerinfo);
      g_io_channel_write_chars(io,line,-1,&size,NULL);

      if(is_cd)
        g_io_channel_write_chars(io,"is_countdown=true\n",-1,&size,NULL);
      else
        g_io_channel_write_chars(io,"is_countdown=false\n",-1,&size,NULL);

      g_free(timername);
      g_free(timercommand);
      g_free(timerinfo);

      row_count ++;
      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(pd->list), &iter);
  }


  /* save the other options */  
  g_io_channel_write_chars(io,"\n[others]\n",-1,&size,NULL);

  if(pd->is_horizontal)
    g_io_channel_write_chars(io,"is_horizontal=true\n",-1,&size,NULL);
  else
    g_io_channel_write_chars(io,"is_horizontal=false\n",-1,&size,NULL);



  g_io_channel_flush(io,NULL);
  g_io_channel_close(io);

  g_free(io);



}


/**
 * Activates the Edit and Remove buttons when an item in the list is selected
**/

static void tree_selected (GtkTreeSelection *select, gpointer data){

  plugin_data *pd=(plugin_data *)data;

  gtk_widget_set_sensitive(pd->buttonedit,TRUE);
  gtk_widget_set_sensitive(pd->buttonremove,TRUE);

}

/**
 * Callback for the horizontal progressbar checkbox
**/

static void toggle_horiz (GtkToggleButton *button, gpointer data){

  plugin_data *pd=(plugin_data *)data;

  pd->is_horizontal = gtk_toggle_button_get_active(button);
 
  add_pbar(pd);

}

/**
 * create_sample_control
 *
 * Create a new instance of the plugin.
 * 
 * @control : #Control parent container
 *
 * Returns %TRUE on success, %FALSE on failure.
 **/
static gboolean
create_plugin_control (Control * ctrl)
{

  GtkWidget *base,*menu,*socket,*menuitem,*box,*pbar2;
  GtkTooltips *tooltip;
  xmlNodePtr write=NULL,read=NULL;
  char command[1024]; 


  plugin_data *pd=g_new(plugin_data,1);

  pd->base=GTK_WIDGET(ctrl->base);
  pd->count=0;
  pd->pbar=gtk_progress_bar_new();
  pd->list=gtk_list_store_new(6, 
		 G_TYPE_INT,     /* Column 0: Index */
		 G_TYPE_STRING,  /* Column 1: Name */
		 G_TYPE_STRING,  /* Column 2: Timer period/alarm time */
		 G_TYPE_STRING,  /* Command to run */
		 G_TYPE_BOOLEAN, /* TRUE= Is countdown, i.e. h-m-s format. 
				    FALSE= 24h format */
		 G_TYPE_INT);    /* Timer period in seconds if countdown.
				    Alarm time in minutes if 24h format is used,
				    (i.e. 60 x Hr + Min) */

  pd->eventbox=gtk_event_box_new();			 
  pd->box=NULL;
  pd->timer_on=FALSE;
  pd->is_horizontal=FALSE;
  pd->timeout=0;
  pd->buttonadd=NULL;
  pd->buttonedit=NULL;
  pd->buttonremove=NULL;
  pd->menu=NULL;
  pd->menuarray=NULL;
  pd->selected=0;
  pd->tip=gtk_tooltips_new();
  pd->timeout_command=NULL;
  pd->timer=NULL;

 
  /*gtk_box_set_child_packing(GTK_BOX(pd->base->parent),pd-> 
				base,FALSE,FALSE,0,GTK_PACK_START);*/

  gtk_tooltips_set_tip(pd->tip, GTK_WIDGET(ctrl->base), "", NULL);
  gtk_tooltips_disable(pd->tip);
  
  g_object_ref(pd->list);

  load_settings(pd);

  make_menu(pd);

  g_signal_connect	(G_OBJECT(pd->eventbox), "button_press_event",
 			G_CALLBACK(pbar_clicked), pd);

  gtk_progress_bar_set_bar_style	(GTK_PROGRESS_BAR(pd->pbar), 
					GTK_PROGRESS_CONTINUOUS);
  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->pbar),0);

  add_pbar(pd);

  /* Trying to get a thin box, but no way */
  gtk_widget_set_size_request(pd->eventbox,0,0);
  gtk_widget_set_size_request(GTK_WIDGET(ctrl->base),-1,-1);
  gtk_container_add(GTK_CONTAINER(ctrl->base),pd->eventbox);

  gtk_widget_show_all(GTK_WIDGET(ctrl->base));

  ctrl->data = (gpointer) pd;

  ctrl->with_popup = FALSE;

  return(TRUE);
}


/**
 * sample_read_config
 *
 * @control : the #Control to read configuration for
 * @node    : an #xmlNodePtr (part of the panel config file) containing the
 *            configuration.
 **/
static void
plugin_read_config (Control * control, xmlNodePtr node)
{

}

/**
 * sample_write_config
 *
 * @control : the #Control to write configuration for
 * @node    : an #xmlNodePtr (part of the panel config file) containing the
 *            configuration.
 **/
static void
plugin_write_config (Control * control, xmlNodePtr parent)
{


}


/**
 * sample_attach_callback
 *
 * @control  : the #Control to attach callbacks to
 * @signal   : the signal name
 * @callback : callback function
 * @data     : user data
 *
 * The plugin is expected to run g_signal_connect() on all widgets that
 * receive events, at least one. This is used, for example to connect the
 * right-click menu.
 **/
static void
sample_attach_callback (Control * control, const char *signal,
			GCallback callback, gpointer data)
{

}


/**
 * sample_free
 *
 * free the memory allocated for a sample #Control
 *
 * @control : the #Control to free memory for.
 **/
static void
plugin_free (Control * ctrl)
{
  plugin_data *pd;



  g_return_if_fail(ctrl != NULL);

  g_return_if_fail(ctrl-> data != NULL);



  pd = (plugin_data*) ctrl->data;



  /* remove timeout */

  if (pd->timeout!=0) g_source_remove(pd->timeout);


  save_settings(pd);

  if(pd->timer)
    g_timer_destroy(pd->timer);

  if(pd->timeout_command)
    g_free(pd->timeout_command);

  gtk_object_destroy(GTK_OBJECT(pd->tip));

  if(pd->timeout)
    g_source_remove(pd->timeout);

  if(pd->menuarray)
    g_array_free(pd->menuarray,TRUE);


  /* destroy all widgets */

  gtk_widget_destroy(GTK_WIDGET(pd->eventbox));


  /* destroy the tooltips */
  /*gtk_object_destroy(GTK_OBJECT(pd->tip));*/

  if(G_IS_OBJECT(pd->list))
    g_free(pd->list);
  else
    g_fprintf(stderr,"\npd->list is non-object");


  /* free the plugin data structure */

  g_free(pd);
}



/* options dialog */
static void plugin_create_options (Control *ctrl, GtkContainer *con, GtkWidget *done) {

  plugin_data *pd=(plugin_data *)ctrl->data;

  GtkWidget *vbox=gtk_vbox_new(FALSE,0); /*outermost box */
  GtkWidget *hbox=gtk_hbox_new(FALSE,0); /* holds the treeview and buttons */
  GtkWidget *buttonbox,*button,*sw,*tree;
  GtkTreeSelection *select;
  GtkCellRenderer *renderer;
  GtkTreeViewColumn *column;
  GtkTreeIter iter;

  gtk_container_add(GTK_CONTAINER(con),vbox);
  gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,0);
  
  sw = gtk_scrolled_window_new (NULL, NULL);

  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
                                           GTK_SHADOW_ETCHED_IN);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
				 GTK_POLICY_AUTOMATIC,
				 GTK_POLICY_AUTOMATIC);
  
  gtk_box_pack_start(GTK_BOX(hbox),sw,TRUE,TRUE,0);  

  tree=gtk_tree_view_new_with_model(GTK_TREE_MODEL(pd->list));
  pd->tree=tree;
  gtk_tree_view_set_rules_hint 	(GTK_TREE_VIEW (tree), TRUE);
  gtk_tree_selection_set_mode 	(gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)),
				 GTK_SELECTION_SINGLE);
  
  renderer = gtk_cell_renderer_text_new ();

  column = gtk_tree_view_column_new_with_attributes ("Timer\nname", renderer,
							"text", 1, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);


  column = gtk_tree_view_column_new_with_attributes ("Countdown period /\nAlarm time", 
							renderer, "text", 2, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);

  column = gtk_tree_view_column_new_with_attributes ("Alarm command", renderer, 
							"text", 3, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);


  if(tree)
     gtk_container_add(GTK_CONTAINER(sw),tree);
  else
     g_fprintf(stderr,"\n pd->tree is NULL\n");

  gtk_widget_set_size_request(GTK_WIDGET(sw),350,250);

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (pd->tree));
  gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
  g_signal_connect 	(G_OBJECT (select), "changed", 
			G_CALLBACK(tree_selected), pd);


  buttonbox=gtk_vbutton_box_new();
  gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonbox),GTK_BUTTONBOX_START);
  gtk_box_pack_start(GTK_BOX(hbox),buttonbox,FALSE,FALSE,0);

  button = gtk_button_new_from_stock (GTK_STOCK_ADD);
  pd->buttonadd=button;
  gtk_box_pack_start(GTK_BOX (buttonbox), button, FALSE, FALSE,0);
  gtk_widget_set_sensitive(button,TRUE);
  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(add_edit_clicked), 									pd);


  button = gtk_button_new_from_stock (GTK_STOCK_EDIT);
  pd->buttonedit=button;
  gtk_box_pack_start(GTK_BOX (buttonbox), button, FALSE, FALSE,0);
  gtk_widget_set_sensitive(button,FALSE);
  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(add_edit_clicked), 									pd);

  button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
  pd->buttonremove=button;
  gtk_box_pack_start(GTK_BOX (buttonbox), button, FALSE, FALSE,0);
  gtk_widget_set_sensitive(button,FALSE);
  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(remove_clicked), 										pd);

  gtk_box_pack_start(GTK_BOX(vbox),gtk_hseparator_new(),TRUE,TRUE,20);

  button=gtk_check_button_new_with_label("Horizontal progressbar");
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),pd->is_horizontal);
  g_signal_connect(G_OBJECT(button),"toggled",G_CALLBACK(toggle_horiz),pd);
  gtk_box_pack_start(GTK_BOX(vbox),button,TRUE,TRUE,0);

  gtk_widget_show_all(GTK_WIDGET(con));

}


/**
 * xfce_control_class_init
 *
 * Ideally, this should be the only exported symbol in the plugin, since this
 * is the only function that is directly accessed from the panel.
 *
 * Here you set up the virtual function table for the plugin and specify its
 * behaviour (e.g. uniqueness).
 * 
 * @cc : #ControlClass to initialize
 **/
G_MODULE_EXPORT void
xfce_control_class_init (ControlClass * cc)
{
    /*xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");*/

    /* Must be present: 
       - name            : unique id 
       - caption         : display name 
       - create_control  : create a new instance
       - attach_callback : connect a signal (e.g. right-click menu)
       - free            : free allocated resources of Control instance
     */
    cc->name = "xfce4_timerr";
    cc->caption = _("XFCE4 Timer");

    cc->create_control = (CreateControlFunc) create_plugin_control;

    cc->attach_callback = sample_attach_callback;
    cc->free = plugin_free;
    cc->create_options    = plugin_create_options;
    /* Optional, leave as NULL to get default behaviour
       - read_config     : read configuration from xml
       - write_config    : write configuration to xml
       - create_options  : create widgets for the options dialog
       - set_size        : set size (SMALL, NORMAL, LARGE or HUGE)
       - set_orientation : set orientation (HORIZONTAL or VERTICAL)
       - set_theme       : set icon theme
       - about           : show an about dialog
     */
    cc->read_config = plugin_read_config;
    cc->write_config = plugin_write_config;


}

/* Macro that checks panel API version */
XFCE_PLUGIN_CHECK_INIT
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.