/* gtkcombocal - combocal widget for gtk+
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * gtkcombo modified
 */

#undef GTK_DISABLE_DEPRECATED



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

#include "gtkarrow.h"
#include "gtklabel.h"
#include "gtkentry.h"
#include "gtkcalendar.h"
#include "gtkeventbox.h"
#include "gtkbutton.h"
#include "gtkscrolledwindow.h"
#include "gtkmain.h"
#include "gtkwindow.h"
#include "gdk/gdkkeysyms.h"
#include "gtkcombocal.h"
#include "gtkframe.h"
#include "gtkintl.h"

#define DEFAULT_DATE_FORMAT 1
#define DEFAULT_DATE_SEPARATOR '/'

const gchar *gtk_combocal_string_key = "gtk-combocal-string-value";

enum {
  PROP_0,
  PROP_ENABLE_ARROW_KEYS,
  PROP_ENABLE_ARROWS_ALWAYS,
  PROP_ALLOW_EMPTY,
  PROP_DATE_FORMAT,
  PROP_DATE_SEPARATOR
};

enum {
  DDMMYY,
  DDMMCCYY,
  MMDDYY,
  MMDDCCYY,
  YYDDMM,
  CCYYDDMM
};

static void	gtk_combocal_class_init         (GtkCombocalClass    *klass);
static void	gtk_combocal_init               (GtkCombocal	*combocal);
static void	gtk_combocal_destroy            (GtkObject	*combocal);
static void	gtk_combocal_destroy 		(GtkObject 	*object);
//static gint	gtk_combocal_focus_idle		(GtkCombocal	*combocal);
static void	gtk_combocal_get_pos		(GtkCombocal	*combocal,
						 		gint * x,
								gint * y,
								gint * height,
								gint * width);
static void	gtk_combocal_popup_calendar	(GtkCombocal	*combocal);
static void	gtk_combocal_popdown_calendar	(GtkCombocal	*combocal);
/*
static void	popup_grab_on_window		(GdkWindow	*window,
						 guint32	activate_time);
*/
static void	gtk_combocal_activate		(GtkWidget	*widget,
						 GtkCombocal	*combocal);
static gboolean	gtk_combocal_popup_button_press (GtkWidget	*button,
						 GdkEventButton	*event,
						 GtkCombocal	*combocal);
static gboolean	gtk_combocal_popup_button_leave	(GtkWidget	*button,
						 GdkEventCrossing	*event,
						 GtkCombocal	*combocal);
static void	gtk_combocal_update_entry	(GtkCombocal	*combocal);
static void	gtk_combocal_date_changed	(GtkCalendar	*calendar,
						 GtkCombocal	*combocal);
static gint	gtk_combocal_button_press	(GtkWidget	*widget,
						 GdkEvent	*event,
						 GtkCombocal	*combocal);
static gboolean	is_within			(GtkWidget	*widget,
						 GtkWidget	*ancestor);
static void	gtk_combocal_update_calendar	(GtkEntry	*entry,
						 GtkCombocal	*combocal);
/*
static void	gtk_combocal_realize		(GtkWidget	*widget);
static void	gtk_combocal_unrealize		(GtkWidget	*widget);
*/
static void	gtk_combocal_size_allocate	(GtkWidget	*widget,
						 GtkAllocation	*allocation);
static void	gtk_combocal_set_property       (GObject         *object,
						 guint            prop_id,
						 const GValue    *value,
						 GParamSpec      *pspec);
static void	gtk_combocal_get_property       (GObject         *object,
						 guint            prop_id,
						 GValue          *value,
						 GParamSpec      *pspec);

static gint	gtk_combocal_entry_key_press	(GtkEntry * entry,
						 GdkEventKey * event,
						 GtkCombocal * combocal);

static gint	gtk_combocal_calendar_key_press	(GtkCalendar *calendar,
						 GdkEventKey * event,
						 GtkCombocal * combocal);

static gboolean	gtk_combocal_calendar_day_selected_double_click	(GtkCalendar * calendar,
						 GtkCombocal * combocal);
/* à définir gtk_combocal_entry_focus_out */
static gint	gtk_combocal_entry_focus_out	(GtkEntry * entry,
						 GdkEventFocus *event,
						 GtkCombocal *combocal);

static void	gtk_combocal_button_event_after (GtkWidget *widget,
			         		 GdkEvent  *event,
			         		 GtkCombocal  *combocal);
static gint	gtk_combocal_window_key_press 	(GtkWidget   *window,
			    			 GdkEventKey *event,
			    			 GtkCombocal    *combocal);

static void		gtk_combocal_format_text( GtkCombocal	*combocal, 
		  				  guint		year,
						  guint		month,
						  guint		day,
						  gchar		**str);

static gboolean		gtk_combocal_check_date	( GtkEntry	*entry,
						  GtkCombocal	*combocal);

static void		gtk_combocal_get_last_month_day ( guint month,
							  guint year,
							  guint **day);

static GtkHBoxClass *parent_class = NULL;

static void
gtk_combocal_class_init (GtkCombocalClass * klass)
{
  GObjectClass *gobject_class;
  GtkObjectClass *oclass;
  GtkWidgetClass *widget_class;

  gobject_class = (GObjectClass *) klass;
  oclass = (GtkObjectClass *) klass;
  widget_class = (GtkWidgetClass *) klass;

  parent_class = g_type_class_peek_parent (klass);

  gobject_class->set_property = gtk_combocal_set_property; 
  gobject_class->get_property = gtk_combocal_get_property; 

  g_object_class_install_property (gobject_class,
                                   PROP_ENABLE_ARROW_KEYS,
                                   g_param_spec_boolean ("enable_arrow_keys",
                                                         _("Enable arrow keys"),
                                                         _("Whether the arrow keys move through the calendar date"),
                                                         TRUE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  
  g_object_class_install_property (gobject_class,
                                   PROP_ENABLE_ARROWS_ALWAYS,
                                   g_param_spec_boolean ("enable_arrow_always",
                                                         _("Always enable arrows"),
                                                         _("Whether the arrow keys work"),
                                                         TRUE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  
  g_object_class_install_property (gobject_class,
                                   PROP_ALLOW_EMPTY,
                                   g_param_spec_boolean ("allow_empty",
                                                         _("Allow empty"),
							 _("Whether an empty value may be entered in this field"),
                                                         TRUE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (gobject_class,
                                   PROP_DATE_FORMAT,
                                   g_param_spec_int ("date format",
                                                         _("Date format"),
							 _("Specify the date format to display"),
                                                         0, DEFAULT_DATE_FORMAT, 0,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  g_object_class_install_property (gobject_class,
                                   PROP_DATE_SEPARATOR,
                                   g_param_spec_unichar ("date separator",
                                                         _("Date separator"),
							 _("The character to use when displaying the date"),
                                                         DEFAULT_DATE_SEPARATOR,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));

  oclass->destroy = gtk_combocal_destroy;
  
  widget_class->size_allocate = gtk_combocal_size_allocate;
/*
  widget_class->realize = gtk_combocal_realize;
  widget_class->unrealize = gtk_combocal_unrealize;
*/
}

static void
gtk_combocal_set_property (GObject         *object,
			guint            prop_id,
			const GValue    *value,
			GParamSpec      *pspec)
{
  GtkCombocal *combocal = GTK_COMBOCAL (object);
  
  switch (prop_id)
    {
    case PROP_ENABLE_ARROW_KEYS:
      gtk_combocal_set_use_arrows (combocal, g_value_get_boolean (value));
      break;
    case PROP_ENABLE_ARROWS_ALWAYS:
      gtk_combocal_set_use_arrows_always (combocal, g_value_get_boolean (value));
      break;
    case PROP_ALLOW_EMPTY:
      combocal->ok_if_empty = g_value_get_boolean (value);
      break;
    case PROP_DATE_FORMAT:
      gtk_combocal_set_date_format (combocal, g_value_get_int (value));
      break;
    case PROP_DATE_SEPARATOR:
      gtk_combocal_set_date_separator (combocal, g_value_get_uint (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
  
}

static void
gtk_combocal_get_property (GObject         *object,
			guint            prop_id,
			GValue          *value,
			GParamSpec      *pspec)
{
  GtkCombocal *combocal = GTK_COMBOCAL (object);
  
  switch (prop_id)
    {
    case PROP_ENABLE_ARROW_KEYS:
      g_value_set_boolean (value, combocal->use_arrows);
      break;
    case PROP_ENABLE_ARROWS_ALWAYS:
      g_value_set_boolean (value, combocal->use_arrows_always);
      break;
    case PROP_ALLOW_EMPTY:
      g_value_set_boolean (value, combocal->ok_if_empty);
      break;
    case PROP_DATE_FORMAT:
      g_value_set_uint (value, combocal->date_format);
      break;
    case PROP_DATE_SEPARATOR:
      g_value_set_uint (value, combocal->date_separator);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

void
gtk_combocal_set_use_arrows (GtkCombocal * combocal, gboolean val)
{
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));
  val = val != FALSE;

  if (combocal->use_arrows != val) 
    {
  combocal->use_arrows = val;
  g_object_notify (G_OBJECT (combocal), "enable_arrow_keys");
    }
}

void
gtk_combocal_set_use_arrows_always (GtkCombocal * combocal, gboolean val)
{
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));
  val = val != FALSE;

  if (combocal->use_arrows_always != val) 
    {
       g_object_freeze_notify (G_OBJECT (combocal));
  combocal->use_arrows_always = val;
       g_object_notify (G_OBJECT (combocal), "enable_arrows_always");

       if (combocal->use_arrows != TRUE) 
         {
  combocal->use_arrows = TRUE;
  g_object_notify (G_OBJECT (combocal), "enable_arrow_keys");
         }
  g_object_thaw_notify (G_OBJECT (combocal));
    }
}

void
gtk_combocal_set_date_format ( GtkCombocal *combocal,
			       guint date_format)
{
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));
 
  combocal->date_format = date_format; 
  switch (combocal->date_format)
    {
    case 0: case 2: case 4:
      gtk_entry_set_max_length (GTK_ENTRY(combocal->entry), 8);
      break;
    default:
      gtk_entry_set_max_length (GTK_ENTRY(combocal->entry), 10);
      break;
    }
  g_object_notify (G_OBJECT (combocal), "date_format");
}  

void
gtk_combocal_set_date_separator ( GtkCombocal *combocal,
				  gunichar date_separator)
{
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));
 
  if ( !date_separator ) 
     return;
  else
    {
    combocal->date_separator = date_separator;
    }
}
  

static void
gtk_combocal_init (GtkCombocal * combocal)
{
  GtkWidget *arrow;
  GtkWidget *frame;
  GtkWidget *event_box;

  combocal->ok_if_empty = TRUE;
  combocal->use_arrows = TRUE;
  combocal->use_arrows_always = TRUE;
  combocal->date_format = DDMMCCYY;
  combocal->date_separator = DEFAULT_DATE_SEPARATOR;
  combocal->entry = gtk_entry_new_with_max_length (10);
  combocal->button = gtk_button_new ();
  combocal->current_button = 0;
  arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
  gtk_widget_show (arrow);
  gtk_container_add (GTK_CONTAINER (combocal->button), arrow);
  gtk_box_pack_start (GTK_BOX(combocal), combocal->entry, TRUE, TRUE, 0);
  gtk_box_pack_end (GTK_BOX(combocal), combocal->button, FALSE, FALSE, 0);
  GTK_WIDGET_UNSET_FLAGS(combocal->button, GTK_CAN_FOCUS);
  gtk_widget_show(combocal->entry);
  gtk_widget_show(combocal->button);
  combocal->entry_change_id = g_signal_connect (combocal->entry, "changed",
						G_CALLBACK (gtk_combocal_update_calendar),
						combocal);
  g_signal_connect (combocal->entry, "key_press_event",
		    G_CALLBACK (gtk_combocal_entry_key_press), combocal);
  g_signal_connect_after (combocal->entry, "focus_out_event",
			  G_CALLBACK (gtk_combocal_entry_focus_out), combocal);
  combocal->activate_id = g_signal_connect (combocal->entry, "activate",
					    G_CALLBACK (gtk_combocal_activate), combocal);
  g_signal_connect (combocal->button, "button_press_event",
		    G_CALLBACK (gtk_combocal_popup_button_press), combocal);
  g_signal_connect (combocal->button, "leave_notify_event",
		    G_CALLBACK (gtk_combocal_popup_button_leave), combocal);

  combocal->popwin = gtk_window_new (GTK_WINDOW_POPUP);
  g_object_ref (combocal->popwin);
  gtk_window_set_resizable (GTK_WINDOW (combocal->popwin), FALSE);

  g_signal_connect (combocal->popwin, "key_press_event",
		    G_CALLBACK (gtk_combocal_window_key_press), combocal);
  
  gtk_widget_set_events (combocal->popwin, GDK_KEY_PRESS_MASK);

  event_box = gtk_event_box_new();
  gtk_container_add (GTK_CONTAINER (combocal->popwin), event_box);
  //g_signal_connect (event_box, "realize",
//		    G_CALLBACK (combocal_event_box_realize), NULL);
  gtk_widget_show (event_box);

  frame = gtk_frame_new(NULL);
  gtk_container_add (GTK_CONTAINER(event_box), frame);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  gtk_widget_show (frame);

  combocal->popup = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (combocal->popup),
				  GTK_POLICY_NEVER, GTK_POLICY_NEVER);
  GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (combocal->popup)->hscrollbar, GTK_CAN_FOCUS);
  GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (combocal->popup)->vscrollbar, GTK_CAN_FOCUS);
  gtk_container_add (GTK_CONTAINER (frame), combocal->popup);
  gtk_widget_show (combocal->popup);
  
  combocal->calendar = gtk_calendar_new();
  /* We'll use enter notify events to figure out when to transfer
   * the grab to the calendar
   */
  gtk_widget_set_events (combocal->calendar, GDK_ENTER_NOTIFY_MASK);

  gtk_scrolled_window_add_with_viewport ( GTK_SCROLLED_WINDOW (combocal->popup), combocal->calendar);

  gtk_widget_show(combocal->calendar);

  combocal->calendar_month_change_id = g_signal_connect (combocal->calendar, "month_changed",
						   G_CALLBACK (gtk_combocal_date_changed), combocal);
  combocal->calendar_day_change_id = g_signal_connect (combocal->calendar, "day_selected",
						   G_CALLBACK (gtk_combocal_date_changed), combocal);
  combocal->calendar_change_id = g_signal_connect (combocal->calendar, "day_selected_double_click",
						   G_CALLBACK (gtk_combocal_calendar_day_selected_double_click), combocal);
  g_signal_connect (combocal->calendar, "key_press_event",
  		    G_CALLBACK (gtk_combocal_calendar_key_press), combocal);
  //dini
  g_signal_connect (combocal->popwin, "button_press_event",
		    G_CALLBACK (gtk_combocal_button_press), combocal);
  g_signal_connect (combocal->popwin, "event_after",
		    G_CALLBACK (gtk_combocal_button_event_after), combocal);

  //g_signal_connect (combocal->calendar, "enter_notify_event",
  //		    G_CALLBACK (gtk_combocal_calendar_enter), combocal);
}

GType
gtk_combocal_get_type (void)
{
  static GType combocal_type = 0;
  if (!combocal_type)
    {
      static const GTypeInfo combocal_info =
      {
	sizeof 		(GtkCombocalClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
	(GClassInitFunc) gtk_combocal_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof 		(GtkCombocal),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gtk_combocal_init,
      };
      combocal_type = g_type_register_static (GTK_TYPE_HBOX, "GtkCombocal",
					   &combocal_info, 0);
    }
  return combocal_type;
}

GtkWidget*
gtk_combocal_new (void)
{
  return g_object_new(GTK_TYPE_COMBOCAL, NULL);
}

static void
gtk_combocal_destroy (GtkObject *object)
{
  GtkCombocal *combocal = GTK_COMBOCAL (object);
  
  if (combocal->popwin)
    {
      gtk_widget_destroy (combocal->popwin);
      g_object_unref (combocal->popwin);
      combocal->popwin = NULL;
    }
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
}


static void
gtk_combocal_get_pos (GtkCombocal * combocal, gint * x, gint * y, gint * height, gint * width)
{
  GtkBin *popwin;
  GtkWidget *widget;
  GtkScrolledWindow *popup;
  
  gint real_height;
  GtkRequisition  calendar_requisition;
  gint avail_height;
  gint min_height;
  gint alloc_width;
  gint avail_width;
  gint work_height;
  gint entry_width = 0, entry_height = 0;
  gint scrollbar_spacing;
  
  widget = GTK_WIDGET(combocal);
  popup  = GTK_SCROLLED_WINDOW (combocal->popup);
  popwin = GTK_BIN (combocal->popwin);
  
  scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (popup);
  
  gdk_window_get_origin (combocal->entry->window, x, y);
  real_height = MIN( combocal->entry->requisition.height,
		     combocal->entry->allocation.height);
  *y +=real_height;
  avail_height = gdk_screen_height () - *y;
  avail_width = gdk_screen_width () - *x;

  gtk_widget_size_request (combocal->calendar, &calendar_requisition);
  min_height = MIN (calendar_requisition.height,
		    popup->vscrollbar->requisition.height);

  alloc_width = ( calendar_requisition.width +10-
		 2 * popwin->child->style->xthickness -
		 2 * GTK_CONTAINER (popwin->child)->border_width -
		 2 * GTK_CONTAINER (combocal->popup)->border_width -
		 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width - 
		 2 * GTK_BIN (popup)->child->style->xthickness);
  
  work_height = (2 * popwin->child->style->ythickness +
		 2 * GTK_CONTAINER (popwin->child)->border_width +
		 2 * GTK_CONTAINER (combocal->popup)->border_width +
		 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width +
		 2 * GTK_BIN (popup)->child->style->ythickness);
  
  if (avail_width < calendar_requisition.width + 10)
	{
	gdk_drawable_get_size (combocal->entry->window, &entry_width, &entry_height);
	*x = *x + entry_width - calendar_requisition.width;
	}
  if (avail_height < calendar_requisition.height + 10)
	{
	gdk_drawable_get_size (combocal->entry->window, &entry_width, &entry_height);
	*y = *y - entry_height - calendar_requisition.height - work_height;
	}
  
    *width = alloc_width; 
    *height = work_height + calendar_requisition.height;
  
  if (*x < 0)
    *x = 0;
}

static void
gtk_combocal_popup_calendar (GtkCombocal * combocal)
{
  gint height, width, x, y;
  gint old_width, old_height;

  old_width = combocal->popwin->allocation.width;
  old_height = combocal->popwin->allocation.height;

  gtk_combocal_get_pos (combocal, &x, &y, &height, &width);

  /* workaround for gtk_scrolled_window_size_allocate bug */
  if (old_width != width || old_height != height)
    {
      gtk_widget_hide (GTK_SCROLLED_WINDOW (combocal->popup)->hscrollbar);
      gtk_widget_hide (GTK_SCROLLED_WINDOW (combocal->popup)->vscrollbar);
    }
  
  /* gtk_combocal_select_date (GTK_ENTRY(combocal->entry), combocal); */

  gtk_window_move (GTK_WINDOW (combocal->popwin), x, y);
  gtk_widget_set_size_request (combocal->popwin, GTK_WIDGET(combocal->calendar)->allocation.width, height);
  gtk_widget_set_size_request (combocal->popwin, width, height);
  gtk_widget_show (combocal->popwin);
  
  gtk_widget_grab_focus (combocal->popwin);
}

static void
gtk_combocal_popdown_calendar (GtkCombocal *combocal)
{
  combocal->current_button = 0;
      
  if (GTK_BUTTON (combocal->button)->in_button)
    {
      GTK_BUTTON (combocal->button)->in_button = FALSE;
      gtk_button_released (GTK_BUTTON (combocal->button));
    }

  if (GTK_WIDGET_HAS_GRAB (combocal->popwin))
    {
      gtk_grab_remove (combocal->popwin);
      gdk_pointer_ungrab (GDK_CURRENT_TIME);
    }
  
  gtk_widget_hide (combocal->popwin);
}

static void
gtk_combocal_update_calendar (GtkEntry * entry, GtkCombocal * combocal)
{
  GtkCalendar *calendar = GTK_CALENDAR (combocal->calendar);

  gtk_grab_remove (GTK_WIDGET (combocal));

  g_signal_handler_block (entry, combocal->entry_change_id);
  gtk_calendar_clear_marks(calendar);
  /* select date here */
  //gtk_calendar_select_month(calendar, 2003, 1);
  //gtk_calendar_select_day(calendar, 15);
  g_signal_handler_unblock (entry, combocal->entry_change_id);
}


/*
static gboolean
popup_grab_on_window (GdkWindow *window,
		      guint32    activate_time)
{
  if ((gdk_pointer_grab (window, TRUE,
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
			 GDK_POINTER_MOTION_MASK,
			 NULL, NULL, activate_time) == 0))
    {
      if (gdk_keyboard_grab (window, TRUE,
			     activate_time) == 0)
	return TRUE;
      else
	{
	  gdk_display_pointer_ungrab (gdk_drawable_get_display (window),
				      activate_time);
	  return FALSE;
	}
    }

  return FALSE;
}
*/

static void        
gtk_combocal_activate (GtkWidget        *widget,
		       GtkCombocal         *combocal)
{
/*
  if (!combocal->button->window ||
      !popup_grab_on_window (combocal->button->window,
			     gtk_get_current_event_time ()))
    return;
*/
  gtk_combocal_popup_calendar (combocal);
  
  /* This must succeed since we already have the grab */
/*
  popup_grab_on_window (combocal->popwin->window,
			gtk_get_current_event_time ());
*/

  if (!GTK_WIDGET_HAS_FOCUS (combocal->entry))
    gtk_widget_grab_focus (combocal->entry);

  gtk_grab_add (combocal->popwin);
}

static gboolean
gtk_combocal_popup_button_press (GtkWidget        *button,
			         GdkEventButton   *event,
			         GtkCombocal         *combocal)
{
  if (!GTK_WIDGET_HAS_FOCUS (combocal->entry))
    gtk_widget_grab_focus (combocal->entry);

  if (event->button != 1)
    return FALSE;

/*
  if (!popup_grab_on_window (combocal->button->window,
			     gtk_get_current_event_time ()))
    return FALSE;
*/
  combocal->current_button = event->button;

  gtk_combocal_popup_calendar (combocal);

  /* This must succeed since we already have the grab */
/*
  popup_grab_on_window (combocal->popwin->window,
			gtk_get_current_event_time ());
*/
  gtk_button_pressed (GTK_BUTTON (button));

  gtk_grab_add (combocal->popwin);

  return TRUE;
}

static gboolean
gtk_combocal_popup_button_leave (GtkWidget        *button,
			         GdkEventCrossing *event,
			         GtkCombocal         *combocal)
{
  /* The idea here is that we want to keep the button down if the
   * popup is popped up.
   */
  return combocal->current_button != 0;
}

static void
gtk_combocal_update_entry (GtkCombocal * combocal)
{
  GtkCalendar *calendar = GTK_CALENDAR (combocal->calendar);
  gint year, month, day;
  char *text = NULL;

  g_signal_handler_block (GTK_ENTRY(combocal->entry), combocal->entry_change_id);
  gtk_calendar_get_date ( calendar, &year, &month, &day);
  
  if (year && day)
    gtk_combocal_format_text( combocal, year, month, day, &text);
  else
    text = "";

  gtk_entry_set_text (GTK_ENTRY (combocal->entry), text);
  if (text) g_free(text);
  g_signal_handler_unblock (GTK_ENTRY(combocal->entry), combocal->entry_change_id);
}


static void
gtk_combocal_date_changed (GtkCalendar  *calendar,
			        GtkCombocal *combocal)
{
  gtk_combocal_update_entry (combocal);
}

static gint
gtk_combocal_button_press (GtkWidget * widget, GdkEvent * event, GtkCombocal * combocal)
{
  GtkWidget *child;

  child = gtk_get_event_widget (event);

  /* We don't ask for button press events on the grab widget, so
   *  if an event is reported directly to the grab widget, it must
   *  be on a window outside the application (and thus we remove
   *  the popup window). Otherwise, we check if the widget is a child
   *  of the grab widget, and only remove the popup window if it
   *  is not.
   */
  if (child != widget)
    {
      while (child)
	{
	  if (child == widget)
	    return FALSE;
	  child = child->parent;
	}
    }

  gtk_combocal_popdown_calendar (combocal);

  return TRUE;
}

static gboolean
is_within (GtkWidget *widget,
	   GtkWidget *ancestor)
{
  return widget == ancestor || gtk_widget_is_ancestor (widget, ancestor);
}


static void
gtk_combocal_button_event_after (GtkWidget *widget,
			         GdkEvent  *event,
			         GtkCombocal  *combocal)
{
  GtkWidget *child;

  if (event->type != GDK_BUTTON_RELEASE)
    return;
  
  child = gtk_get_event_widget ((GdkEvent*) event);

  if ((combocal->current_button != 0) && (event->button.button == 1))
    {
      /* This was the initial button press */

      combocal->current_button = 0;

      /* Check to see if we released inside the button */
      if (child && is_within (child, combocal->button))
	{
	  gtk_grab_add (combocal->popwin);
	  gdk_pointer_grab (combocal->popwin->window, TRUE,
			    GDK_BUTTON_PRESS_MASK | 
			    GDK_BUTTON_RELEASE_MASK |
			    GDK_POINTER_MOTION_MASK, 
			    NULL, NULL, GDK_CURRENT_TIME);
	  return;
	}
    }

}


/*
static void
gtk_combocal_realize (GtkWidget *widget)
{
  GtkCombocal *combocal = GTK_COMBOCAL (widget);

  gtk_window_set_screen (GTK_WINDOW (combocal->popwin), 
			 gtk_widget_get_screen (widget));
  
  GTK_WIDGET_CLASS( parent_class )->realize (widget);  
}

static void        
gtk_combocal_unrealize (GtkWidget *widget)
{
  GtkCombocal *combocal = GTK_COMBOCAL (widget);

  gtk_combo_popdown_calendar (combocal);
  gtk_widget_unrealize (combocal->popwin);
  
  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
}
*/

static void
gtk_combocal_size_allocate (GtkWidget     *widget,
			    GtkAllocation *allocation)
{
  GtkCombocal *combocal;

  g_return_if_fail (IS_GTK_COMBOCAL (widget));
  g_return_if_fail (allocation != NULL);

  GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
  
  combocal = GTK_COMBOCAL (widget);

  if (combocal->entry->allocation.height > combocal->entry->requisition.height)
    {
      GtkAllocation button_allocation;

      button_allocation = combocal->button->allocation;
      button_allocation.height = combocal->entry->requisition.height;
      button_allocation.y = combocal->entry->allocation.y + 
	(combocal->entry->allocation.height - combocal->entry->requisition.height) 
	/ 2;
      gtk_widget_size_allocate (combocal->button, &button_allocation);
    }
}


void
gtk_combocal_disable_activate (GtkCombocal* combocal)
{
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));

  if ( combocal->activate_id ) {
    g_signal_handler_disconnect (combocal->entry, combocal->activate_id);
    combocal->activate_id = 0;
  }
}

static gint
gtk_combocal_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombocal * combocal)
{

  gchar *text = NULL;

  // completion 

  if ((event->keyval == GDK_Tab ||
     event->keyval == GDK_KP_Tab))
	{
        if (GTK_WIDGET_HAS_FOCUS (entry))
	  {
          GTK_WIDGET_UNSET_FLAGS(entry, GTK_HAS_FOCUS);
          return FALSE;
          }
        }
  if ((event->keyval == GDK_Tab ||
       event->keyval == GDK_KP_Tab) &&
      (event->state & GDK_MOD1_MASK)) 
    {
      GtkEditable *editable = GTK_EDITABLE (entry);
    gchar* prefix;
    gchar* nprefix = NULL;
    gint pos;

    gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");

    pos = gtk_editable_get_position (editable);
    prefix = gtk_editable_get_chars (editable, 0, pos);

    if (nprefix && strlen (nprefix) > strlen (prefix)) 
      {
    	gtk_editable_insert_text (editable, nprefix + pos, 
				  strlen (nprefix) - strlen (prefix), &pos);
	gtk_editable_set_position (editable, pos);
    }
    if (nprefix)
      g_free (nprefix);
    g_free (prefix);
    if (GTK_WIDGET_HAS_FOCUS (entry))
       GTK_WIDGET_UNSET_FLAGS(entry, GTK_HAS_FOCUS);
    return TRUE;
  } 



  if (!combocal->use_arrows)
    return FALSE;
    
  if ((event->keyval == GDK_Up)
      || (event->keyval == GDK_KP_Up)
      || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'p') || (event->keyval == 'P'))))
    {
      if (combocal->use_arrows_always)
	{ 
	// set next day here
	  guint day, month, year, *last_day;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( entry, combocal->entry_change_id);
	  gtk_calendar_get_date ( GTK_CALENDAR (combocal->calendar ), &year, &month, &day);
	  gtk_combocal_get_last_month_day ( month, year, &last_day );
	  if ( day + 1  > (gint) last_day )
	    {
	    day = 1;
	    if ( month + 1 > 11 )
		{
		month = 0;
		year++;
		}
	    else
		{
		month++;
		}
	    }
	  else
	    day++;
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month , year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  if (year && day)
	    gtk_combocal_format_text( combocal, year, month, day , &text);
	  else
	    text = "";

	  gtk_entry_set_text ( entry, text);
          g_signal_handler_unblock ( entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Down)
	   || (event->keyval == GDK_KP_Down)
	   || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'n') || (event->keyval == 'N'))))
    {
      if (combocal->use_arrows_always)
	{
	// set previous day here
	  guint day = 0, month = 0, year = 0, *last_day  = NULL;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( entry, combocal->entry_change_id);
	  gtk_calendar_get_date ( GTK_CALENDAR (combocal->calendar ), &year, &month, &day);
	  day--;
	  if (day == 0)
	    {
	    month--;
	    if (month == -1)
		{
		month=11;
		year--;
		}
	    gtk_combocal_get_last_month_day ( month, year, &last_day );
	    day = *last_day;
	    gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month, year);
	    }
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  if (year && day)
	    gtk_combocal_format_text( combocal, year, month, day , &text);
	  else
	    text = "";

	  gtk_entry_set_text ( entry, text);
          g_signal_handler_unblock ( entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);

	  gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Page_Up)
      || (event->keyval == GDK_KP_Page_Up))
    {
      if (combocal->use_arrows_always)
	{
    // set next month 
	  guint *last_day = 0;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( entry, combocal->entry_change_id);
	  if (GTK_CALENDAR (combocal->calendar )->month == 11)
	    {
	    GTK_CALENDAR (combocal->calendar )->month  = 0;
	    GTK_CALENDAR (combocal->calendar )->year++;
	    }
	  else
	    GTK_CALENDAR (combocal->calendar )->month++;
	  gtk_combocal_get_last_month_day(GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year, &last_day);
	  if ((GTK_CALENDAR (combocal->calendar )->selected_day) > (gint) last_day)
	     GTK_CALENDAR (combocal->calendar )->selected_day = (gint) last_day;
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( entry, text);

          g_signal_handler_unblock ( entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Page_Down)
      || (event->keyval == GDK_KP_Page_Down))
    {
      if (combocal->use_arrows_always)
	{
    // set previous month 
	  guint *last_day = 0;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( entry, combocal->entry_change_id);
	  if (GTK_CALENDAR (combocal->calendar )->month == 0)
	    {
	    (GTK_CALENDAR (combocal->calendar ))->month  = 11;
	    (GTK_CALENDAR (combocal->calendar ))->year--;
	    }
	  else
	    GTK_CALENDAR (combocal->calendar )->month--;
	  gtk_combocal_get_last_month_day(GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year, &last_day);
	  if ((GTK_CALENDAR (combocal->calendar )->selected_day) > (gint) last_day)
	     GTK_CALENDAR (combocal->calendar )->selected_day = (gint) last_day;
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( entry, text);

          g_signal_handler_unblock ( entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Home)
      || (event->keyval == GDK_KP_Home))
    {
      if (combocal->use_arrows_always)
	{
  	  time_t secs;
  	  struct tm *tm;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( entry, combocal->entry_change_id);
  	  secs = time (NULL);
  	  tm = localtime (&secs);
  	  GTK_CALENDAR (combocal->calendar )->month = tm->tm_mon;
  	  GTK_CALENDAR (combocal->calendar )->year  = 1900 + tm->tm_year;
          GTK_CALENDAR (combocal->calendar )->selected_day = tm->tm_mday;
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( entry, text);

          g_signal_handler_unblock ( entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  // And now, let 's filter a little bit 
  else if (event->keyval == GDK_KP_Divide ||
	   event->keyval == GDK_KP_Subtract)
	event->keyval = event->keyval - 65408;
  else if (event->keyval != GDK_0 && event->keyval != GDK_1 &&
	   event->keyval != GDK_KP_0 && event->keyval != GDK_KP_1 &&
	   event->keyval != GDK_2 && event->keyval != GDK_3 &&
	   event->keyval != GDK_KP_2 && event->keyval != GDK_KP_3 &&
	   event->keyval != GDK_4 && event->keyval != GDK_5 &&
	   event->keyval != GDK_KP_4 && event->keyval != GDK_KP_5 &&
	   event->keyval != GDK_6 && event->keyval != GDK_7 &&
	   event->keyval != GDK_KP_6 && event->keyval != GDK_KP_7 &&
	   event->keyval != GDK_8 && event->keyval != GDK_9 &&
	   event->keyval != GDK_KP_8 && event->keyval != GDK_KP_9 &&
	   event->keyval != GDK_Left && event->keyval != GDK_Right &&
	   event->keyval != GDK_KP_Left && event->keyval != GDK_KP_Right &&
	   event->keyval != GDK_Delete && event->keyval != GDK_KP_Delete &&
	   event->keyval != GDK_BackSpace && event->keyval != combocal->date_separator)
	{
		event->keyval = (gint)NULL;
	    	return TRUE;
	}
  return FALSE;
}

static gint
gtk_combocal_calendar_key_press	(GtkCalendar *calendar,
				 GdkEventKey * event,
				 GtkCombocal * combocal)
{
  gchar *text = NULL;
  if (!combocal->use_arrows)
    return FALSE;
    


  gtk_signal_emit_stop_by_name (GTK_OBJECT (calendar), "key_press_event");
  if ((event->keyval == GDK_Up)
      || (event->keyval == GDK_KP_Up)
      || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'p') || (event->keyval == 'P'))))
    {
      if (combocal->use_arrows_always)
	{ 
	// set next day here
	  guint day, month, year, *last_day;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
	  gtk_calendar_get_date ( GTK_CALENDAR (combocal->calendar ), &year, &month, &day);
	  gtk_combocal_get_last_month_day ( month, year, &last_day );
	  if ( day + 1  > (gint) last_day )
	    {
	    day = 1;
	    if ( month + 1 > 11 )
		{
		month = 0;
		year++;
		}
	    else
		{
		month++;
		}
	    }
	  else
	    day++;
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month , year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  if (year && day)
	    gtk_combocal_format_text( combocal, year, month, day , &text);
	  else
	    text = "";

	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
          g_signal_handler_unblock ( combocal->entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Down)
	   || (event->keyval == GDK_KP_Down)
	   || ((event->state & GDK_MOD1_MASK) && ((event->keyval == 'n') || (event->keyval == 'N'))))
    {
      if (combocal->use_arrows_always)
	{
	// set previous day here
	  guint day = 0, month = 0, year = 0, *last_day = NULL;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
	  gtk_calendar_get_date ( GTK_CALENDAR (combocal->calendar ), &year, &month, &day);
	  day--;
	  if (day == 0)
	    {
	    month--;
	    if (month == -1)
		{
		month=11;
		year--;
		}
	    gtk_combocal_get_last_month_day ( month, year, &last_day );
	    day = *last_day;
	    gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month, year);
	    }
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  if (year && day)
	    gtk_combocal_format_text( combocal, year, month, day , &text);
	  else
	    text = "";

	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
          g_signal_handler_unblock ( combocal->entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Page_Up)
      || (event->keyval == GDK_KP_Page_Up))
    {
      if (combocal->use_arrows_always)
	{
    // set next month 
	  guint *last_day = 0;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
	  if (GTK_CALENDAR (combocal->calendar )->month == 11)
	    {
	    GTK_CALENDAR (combocal->calendar )->month  = 0;
	    GTK_CALENDAR (combocal->calendar )->year++;
	    }
	  else
	    GTK_CALENDAR (combocal->calendar )->month++;
	  gtk_combocal_get_last_month_day(GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year, &last_day);
	  if ((GTK_CALENDAR (combocal->calendar )->selected_day) > (gint) last_day)
	     GTK_CALENDAR (combocal->calendar )->selected_day = (gint) last_day;
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year);
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);

          g_signal_handler_unblock ( combocal->entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Page_Down)
      || (event->keyval == GDK_KP_Page_Down))
    {
      if (combocal->use_arrows_always)
	{
    // set previous month 
	  guint *last_day = 0;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
	  if (GTK_CALENDAR (combocal->calendar )->month == 0)
	    {
	    (GTK_CALENDAR (combocal->calendar ))->month  = 11;
	    (GTK_CALENDAR (combocal->calendar ))->year--;
	    }
	  else
	    GTK_CALENDAR (combocal->calendar )->month--;
	  gtk_combocal_get_last_month_day(GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year, &last_day);
	  if ((GTK_CALENDAR (combocal->calendar )->selected_day) > (gint) last_day)
	     GTK_CALENDAR (combocal->calendar )->selected_day = (gint) last_day;
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , GTK_CALENDAR (combocal->calendar )->month, GTK_CALENDAR (combocal->calendar )->year);
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);

          g_signal_handler_unblock ( combocal->entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if ((event->keyval == GDK_Home)
      || (event->keyval == GDK_KP_Home))
    {
      if (combocal->use_arrows_always)
	{
  	  time_t secs;
  	  struct tm *tm;
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
          g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
  	  secs = time (NULL);
  	  tm = localtime (&secs);
  	  GTK_CALENDAR (combocal->calendar )->month = tm->tm_mon;
  	  GTK_CALENDAR (combocal->calendar )->year  = 1900 + tm->tm_year;
          GTK_CALENDAR (combocal->calendar )->selected_day = tm->tm_mday;
	  gtk_combocal_format_text( combocal, GTK_CALENDAR (combocal->calendar )->year,
						GTK_CALENDAR (combocal->calendar )->month,
						GTK_CALENDAR (combocal->calendar )->selected_day ,
						&text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);

          g_signal_handler_unblock ( combocal->entry, combocal->entry_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
          g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
	  if (text) g_free(text);
	  return TRUE;
	}
    }
  else if (event->keyval == GDK_Escape)
    {
    gtk_combocal_popdown_calendar ( combocal );
    if(text) g_free(text);
    return TRUE;
    }
  if(text) g_free(text);
  return FALSE;
}

static gboolean
gtk_combocal_calendar_day_selected_double_click	(GtkCalendar * calendar,
				 GtkCombocal * combocal)
{
  g_return_val_if_fail( combocal != NULL, FALSE );
  g_return_val_if_fail( calendar != NULL, FALSE );

  gtk_combocal_update_entry( combocal );
  gtk_combocal_popdown_calendar ( combocal );
    return TRUE;
}

static gint
gtk_combocal_entry_focus_out (GtkEntry * entry, GdkEventFocus * event, GtkCombocal * combocal)
{
  g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
  g_signal_handler_block ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
  g_signal_handler_block ( combocal->entry, combocal->entry_change_id);
  gtk_combocal_check_date(entry, combocal);
  g_signal_handler_unblock (combocal->entry, combocal->entry_change_id);
  g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_month_change_id);
  g_signal_handler_unblock ( GTK_CALENDAR (combocal->calendar ), combocal->calendar_day_change_id);
  return FALSE;
}
/*
static gint
gtk_combocal_focus_idle (GtkCombocal * combocal)
{
  if (combocal)
    {
      GDK_THREADS_ENTER ();
      gtk_widget_grab_focus (combocal->entry);
      GDK_THREADS_LEAVE ();
    }
  return FALSE;
}
*/
static gint
gtk_combocal_window_key_press (GtkWidget   *window,
			    GdkEventKey *event,
			    GtkCombocal    *combocal)
{
  if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
    {
      if (GTK_WIDGET_VISIBLE (combocal->popwin))
	{
	  gtk_widget_hide (combocal->popwin);
	  
	  if (GTK_WIDGET_HAS_GRAB (combocal->popwin))
	    {
	      gtk_grab_remove (combocal->popwin);
	      gdk_pointer_ungrab (event->time);
	    }
	}

      gtk_signal_emit_stop_by_name (GTK_OBJECT (window), "key_press_event");

      return TRUE;
    }

  return FALSE;
}

static void
gtk_combocal_format_text( GtkCombocal 	*combocal, 
		  	  guint		year,
			  guint		month,
			  guint		day,
			  gchar		**str)
{
  month++;
  g_return_if_fail (IS_GTK_COMBOCAL (combocal));
  g_return_if_fail ( year > 0);
  g_return_if_fail ( month > 0);
  g_return_if_fail ( day > 0);

  switch (combocal->date_format)
    {
    case DDMMYY:
	year = year % 100;
	*str = g_strdup_printf("%02d%c%02d%c%02d", day, combocal->date_separator,
				month, combocal->date_separator, year);
	break;
    case DDMMCCYY:
	*str = g_strdup_printf("%02d%c%02d%c%04d", day, combocal->date_separator,
				month, combocal->date_separator, year);
	break;
    case MMDDYY:
	year = year % 100;
	*str = g_strdup_printf("%02d%c%02d%c%02d", month, combocal->date_separator,
				day, combocal->date_separator, year);
	break;
    case MMDDCCYY:
	*str = g_strdup_printf("%02d%c%02d%c%04d", month, combocal->date_separator,
				day, combocal->date_separator, year);
	break;
    case YYDDMM:
	year = year % 100;
	*str = g_strdup_printf("%02d%c%02d%c%02d", year, combocal->date_separator,
				day, combocal->date_separator, month);
	break;
    case CCYYDDMM:
	*str = g_strdup_printf("%04d%c%02d%c%02d", year, combocal->date_separator,
				day, combocal->date_separator, month);
	break;
    default:
	break;
      }
}

static void
gtk_combocal_get_last_month_day ( guint month, guint year, guint **day)
{
  g_return_if_fail ( month >= 0 );
  g_return_if_fail ( year > 0 );
  
  switch (month)
    {
    case 0: case 2: case 4: case 6: case 7: case 9: case 11:
	(guint) *day = 31;
	break;
    case 3: case 5: case 8: case 10:
	(guint) *day = 30;
	break;
    case 1:
	if (( year % 4 == 0 && year % 100 !=0 ) || year % 400 == 0 )
	  (guint) *day = 29;
	else
	  (guint) *day = 28;
	break;
    default:
	break;
    }
}


static gboolean
gtk_combocal_check_date	( GtkEntry	*entry,
			  GtkCombocal	*combocal)
{
  gchar *text = NULL, **char_array = NULL, *separator = NULL;
  gint day = 0, month = 0, year = 0, date = 0;
  guint *last_day = 0, array_size = 0, i = 0;
  
  g_return_val_if_fail (IS_GTK_COMBOCAL (combocal), FALSE);
  g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);

  separator = g_strdup_printf("%c\n", combocal->date_separator);

  text = g_strstrip( g_strdup (gtk_entry_get_text(entry)));
  if (!strlen(text)) return FALSE;
  // dini contournement bug g_strsplit

  text = g_strdelimit (text, separator, '/');

  char_array = g_strsplit( text, "/", 0);
  while(char_array[array_size])
	array_size++;

  switch (combocal->date_format)
    {
    case DDMMYY:
	while(i<array_size){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 6)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  day = date / 10000;
	  month = (date / 10000)*10000;
	  month = (date - month) / 100;
	  year = (date / 100)*100;
	  year = (date - year);
	  // only valid for Century 2000
	  gtk_combocal_get_last_month_day ( month-1, 2000 + year, &last_day );
	  if(day > (gint) last_day) day = (gint) last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, 2000+year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  }
	break;
    case DDMMCCYY:
	while(i<array_size-1){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 8)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  day = date / 1000000;
	  month = (date / 1000000)*1000000;
	  month = (date - month) / 10000;
	  year = (date / 10000)*10000;
	  year = (date - year);
	  gtk_combocal_get_last_month_day ( month-1, year, &last_day );
	  if(day > (gint)last_day) day = (gint)last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  }
	break;
    case MMDDYY:
	while(i<array_size){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 6)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  month = date / 10000;
	  day = (date / 10000)*10000;
	  day = (date - day) / 100;
	  year = (date / 100)*100;
	  year = (date - year);
	  // only valid for Century 2000
	  gtk_combocal_get_last_month_day ( month-1, 2000 + year, &last_day );
	  if(day > (gint) last_day) day = (gint) last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, 2000+year);
	  }
	break;
    case MMDDCCYY:
	while(i<array_size-1){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 8)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  month = date / 1000000;
	  day = (date / 1000000)*1000000;
	  day = (date - day) / 10000;
	  year = (date / 10000)*10000;
	  year = (date - year);
	  gtk_combocal_get_last_month_day ( month-1, year, &last_day );
	  if(day > (gint)last_day) day = (gint)last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  }
	break;
    case YYDDMM:
	while(i<array_size){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 6)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  year = date / 10000;
	  day = (date / 10000)*10000;
	  day = (date - day) / 100;
	  month = (date / 100)*100;
	  month = (date - month);
	  // only valid for Century 2000
	  gtk_combocal_get_last_month_day ( month-1, 2000 + year, &last_day );
	  if(day > (gint) last_day) day = (gint) last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, 2000+year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  }
	break;
    case CCYYDDMM:
	i = 1;
	while(i<array_size){
  		if(strlen(char_array[i]) == 1) char_array[i] = g_strconcat("0", char_array[i], NULL);
		i++;
	}
	text = g_strjoinv(NULL, char_array);
	if (strlen (text) != 8)
	  {
	  gtk_editable_select_region ( GTK_EDITABLE(combocal->entry), 0, strlen(gtk_entry_get_text(entry)));
	  return FALSE;
	  }
	else
	  {
	  date = g_strtod (text, NULL); 
	  year = date / 10000;
	  day = (date / 100)-(year*100);
	  month = date - (date / 100)*100;
	  gtk_combocal_get_last_month_day ( month-1, year, &last_day );
	  if(day > (gint)last_day) day = (gint)last_day;
	  gtk_combocal_format_text (combocal, year, month-1, day, &text);
	  gtk_entry_set_text ( GTK_ENTRY(combocal->entry), text);
	  gtk_calendar_select_month ( GTK_CALENDAR ( combocal->calendar ) , month-1, year);
	  gtk_calendar_select_day ( GTK_CALENDAR ( combocal->calendar ) , day );
	  }
	break;
    default:
	break;
    }
  if(char_array) g_strfreev(char_array);
  if (separator) g_free(separator);
  if(text) g_free(text);
  char_array = NULL;
  separator = NULL;
  text = NULL;
  day = month = year = 0;
  return TRUE;
}
