Index: gtk/gtkcalendar.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcalendar.c,v
retrieving revision 1.51
diff -u -p -r1.51 gtkcalendar.c
--- gtk/gtkcalendar.c	3 Jul 2003 01:02:03 -0000	1.51
+++ gtk/gtkcalendar.c	12 Jul 2003 22:56:49 -0000
@@ -40,6 +40,7 @@
 #include <glib/gprintf.h>
 
 #include "gtkcalendar.h"
+#include "gtkdnd.h"
 #include "gtkintl.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
@@ -270,9 +271,14 @@ struct _GtkCalendarPrivateData
   guint dirty_week : 1;
 
   guint need_timer  : 1;
+  
+  guint in_drag : 1;
 
   guint32 timer;
   gint click_child;
+
+  gint drag_start_x;
+  gint drag_start_y;
 };
 
 #define GTK_CALENDAR_PRIVATE_DATA(widget)  (((GtkCalendarPrivateData*)(GTK_CALENDAR (widget)->private_data)))
@@ -340,6 +346,19 @@ static gint left_x_for_column		(GtkCalen
 static gint top_y_for_row		(GtkCalendar  *calendar,
 					 gint	       row);
 
+static void gtk_calendar_drag_data_get (GtkWidget        *widget,
+					GdkDragContext   *context,
+					GtkSelectionData *selection_data,
+					guint             info,
+					guint             time);
+static void gtk_calendar_drag_data_received (GtkWidget        *widget,
+					     GdkDragContext   *context,
+					     gint              x,
+					     gint              y,
+					     GtkSelectionData *selection_data,
+					     guint             info,
+					     guint             time);
+
 static char    *default_abbreviated_dayname[7];
 static char    *default_monthname[12];
 
@@ -403,6 +422,9 @@ gtk_calendar_class_init (GtkCalendarClas
   widget_class->style_set = gtk_calendar_style_set;
   widget_class->state_changed = gtk_calendar_state_changed;
   widget_class->grab_notify = gtk_calendar_grab_notify;
+
+  widget_class->drag_data_get = gtk_calendar_drag_data_get;
+  widget_class->drag_data_received = gtk_calendar_drag_data_received;
   
   class->month_changed = NULL;
   class->day_selected = NULL;
@@ -567,6 +589,10 @@ gtk_calendar_class_init (GtkCalendarClas
 		  G_TYPE_NONE, 0);
 }
 
+static const GtkTargetEntry drop_target_table[] = {
+  { "application/x-date", 0, 0 },
+};
+
 static void
 gtk_calendar_init (GtkCalendar *calendar)
 {
@@ -643,6 +669,15 @@ gtk_calendar_init (GtkCalendar *calendar
   private_data->need_timer = 0;
   private_data->timer = 0;
   private_data->click_child = -1;
+  
+  private_data->in_drag = 0;
+
+  gtk_drag_dest_set (widget,
+                     GTK_DEST_DEFAULT_HIGHLIGHT | 
+                     GTK_DEST_DEFAULT_MOTION |
+                     GTK_DEST_DEFAULT_DROP,
+                     drop_target_table, G_N_ELEMENTS (drop_target_table),
+                     GDK_ACTION_COPY);
 }
 
 GtkWidget*
@@ -945,12 +980,14 @@ gtk_calendar_main_button (GtkWidget	 *wi
 			  GdkEventButton *event)
 {
   GtkCalendar *calendar;
+  GtkCalendarPrivateData *private_data;
   gint x, y;
   gint row, col;
   gint day_month;
   gint day;
   
   calendar = GTK_CALENDAR (widget);
+  private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
   
   x = (gint) (event->x);
   y = (gint) (event->y);
@@ -978,6 +1015,9 @@ gtk_calendar_main_button (GtkWidget	 *wi
 	  
       gtk_calendar_select_and_focus_day (calendar, day);
 
+      private_data->in_drag = 1;
+      private_data->drag_start_x = x;
+      private_data->drag_start_y = y;
     }
   else if (event->type == GDK_2BUTTON_PRESS)
     {
@@ -985,6 +1025,7 @@ gtk_calendar_main_button (GtkWidget	 *wi
 	g_signal_emit (calendar,
 		       gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL],
 		       0);
+      private_data->in_drag = 0;
     }
 }
 
@@ -2615,12 +2656,26 @@ static gboolean
 gtk_calendar_button_release (GtkWidget	  *widget,
 			     GdkEventButton *event)
 {
+  GtkCalendar *calendar;
+  GtkCalendarPrivateData *private_data;
+
+  calendar = GTK_CALENDAR (widget);
+  private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
+
   if (event->button == 1) 
     stop_spinning (widget);
 
+  if (private_data->in_drag)
+    private_data->in_drag = 0;
+
   return TRUE;
 }
 
+static const GtkTargetEntry target_table[] = {
+  { "application/x-date", 0, 0 },
+  { "TEXT",               0, 0 },
+};
+
 static gboolean
 gtk_calendar_motion_notify (GtkWidget	   *widget,
 			    GdkEventMotion *event)
@@ -2639,25 +2694,46 @@ gtk_calendar_motion_notify (GtkWidget	  
   if (event->window == private_data->main_win)
     {
       
-      row = row_from_y (calendar, event_y);
-      col = column_from_x (calendar, event_x);
-      
-      if (row != calendar->highlight_row || calendar->highlight_col != col)
+      if (private_data->in_drag) 
 	{
-	  old_row = calendar->highlight_row;
-	  old_col = calendar->highlight_col;
-	  if (old_row > -1 && old_col > -1)
-	    {
-	      calendar->highlight_row = -1;
-	      calendar->highlight_col = -1;
-	      gtk_calendar_paint_day (widget, old_row, old_col);
-	    }
+	  if (gtk_drag_check_threshold (widget,
+					private_data->drag_start_x, private_data->drag_start_y,
+					event->x, event->y))
+	    {
+	      GdkDragContext *context;
+	      GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
+	      context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY,
+					1, (GdkEvent *)event);
+
 	  
-	  calendar->highlight_row = row;
-	  calendar->highlight_col = col;
+	      private_data->in_drag = 0;
+	      
+	      gtk_target_list_unref (target_list);
+	      gtk_drag_set_icon_default (context);
+	    }
+	}
+      else 
+	{
+	  row = row_from_y (calendar, event_y);
+	  col = column_from_x (calendar, event_x);
 	  
-	  if (row > -1 && col > -1)
-	    gtk_calendar_paint_day (widget, row, col);
+	  if (row != calendar->highlight_row || calendar->highlight_col != col)
+	    {
+	      old_row = calendar->highlight_row;
+	      old_col = calendar->highlight_col;
+	      if (old_row > -1 && old_col > -1)
+		{
+		  calendar->highlight_row = -1;
+		  calendar->highlight_col = -1;
+		  gtk_calendar_paint_day (widget, old_row, old_col);
+		}
+	      
+	      calendar->highlight_row = row;
+	      calendar->highlight_col = col;
+	      
+	      if (row > -1 && col > -1)
+		gtk_calendar_paint_day (widget, row, col);
+	    }
 	}
     }
   return TRUE;
@@ -3148,4 +3224,67 @@ gtk_calendar_get_property (GObject      
       break;
     }
 
+}
+
+static void
+gtk_calendar_drag_data_get (GtkWidget        *widget,
+			    GdkDragContext   *context,
+			    GtkSelectionData *selection_data,
+			    guint             info,
+			    guint             time)
+{
+  GtkCalendar *calendar = GTK_CALENDAR (widget);
+
+  if (selection_data->target == gdk_atom_intern ("application/x-date", FALSE))
+    {
+      /* provide the selected date in DMY format */
+      guint16 vals[3];
+      vals[0] = calendar->selected_day;
+      vals[1] = calendar->month;
+      vals[2] = calendar->year;
+
+      gtk_selection_data_set (selection_data, selection_data->target, 16, (gpointer)vals, 6);
+    }
+  else
+    {
+      GDate *date = g_date_new_dmy (calendar->selected_day, calendar->month, calendar->year);
+      gchar str[128];
+      gsize len = g_date_strftime (str, 127, "%F", date);
+      gtk_selection_data_set_text (selection_data, str, len);
+
+      g_free (date);
+    }
+}
+
+static void
+gtk_calendar_drag_data_received (GtkWidget        *widget,
+				 GdkDragContext   *context,
+				 gint              x,
+				 gint              y,
+				 GtkSelectionData *selection_data,
+				 guint             info,
+				 guint             time)
+{
+  GtkCalendar *calendar = GTK_CALENDAR (widget);
+  guint16 *vals;
+  guint day, month, year;
+
+  if (selection_data->format != 16 || selection_data->length != 6)
+    {
+      g_warning ("Received invalid data data\n");
+      return;
+    }
+  
+  vals = (guint16 *)selection_data->data;
+  
+  day   = vals[0];
+  month = vals[1];
+  year  = vals[2];
+
+  g_object_freeze_notify (G_OBJECT (calendar));
+  if (!(calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
+      && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
+    gtk_calendar_select_month (calendar, month, year);
+  gtk_calendar_select_day (calendar, day);
+  g_object_thaw_notify (G_OBJECT (calendar));
 }
