]> Pileus Git - ~andy/gtk/blob - gtk/gtkcalendar.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~andy/gtk] / gtk / gtkcalendar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GTK Calendar Widget
5  * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson and Mattias Grönlund
6  * 
7  * lib_date routines
8  * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /*
26  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GTK+ Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
30  */
31
32 #include "config.h"
33
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #endif
37 #include <string.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <stdio.h>
41 #include "gtkcalendar.h"
42 #include "gdk/gdkkeysyms.h"
43
44 /***************************************************************************/
45 /* The following date routines are taken from the lib_date package.  Keep
46  * them seperate in case we want to update them if a newer lib_date comes
47  * out with fixes.  */
48
49 typedef  unsigned   int     N_int;
50 typedef  unsigned   long    N_long;
51 typedef  signed     long    Z_long;
52 typedef enum { false = FALSE , true = TRUE } boolean;
53
54 #define and         &&      /* logical (boolean) operators: lower case */
55 #define or          ||
56
57 static const N_int month_length[2][13] =
58 {
59   { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
60   { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
61 };
62
63 static const N_int days_in_months[2][14] =
64 {
65   { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
66   { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
67 };
68
69 static Z_long  calc_days(N_int year, N_int mm, N_int dd);
70 static N_int   day_of_week(N_int year, N_int mm, N_int dd);
71 static Z_long  dates_difference(N_int year1, N_int mm1, N_int dd1,
72                                 N_int year2, N_int mm2, N_int dd2);
73 static N_int   weeks_in_year(N_int year);
74
75 static boolean 
76 leap(N_int year)
77 {
78   return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
79 }
80
81 static N_int 
82 day_of_week(N_int year, N_int mm, N_int dd)
83 {
84   Z_long  days;
85   
86   days = calc_days(year, mm, dd);
87   if (days > 0L)
88     {
89       days--;
90       days %= 7L;
91       days++;
92     }
93   return( (N_int) days );
94 }
95
96 static N_int weeks_in_year(N_int year)
97 {
98   return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
99 }
100
101 static boolean 
102 check_date(N_int year, N_int mm, N_int dd)
103 {
104   if (year < 1) return(false);
105   if ((mm < 1) or (mm > 12)) return(false);
106   if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
107   return(true);
108 }
109
110 static N_int 
111 week_number(N_int year, N_int mm, N_int dd)
112 {
113   N_int first;
114   
115   first = day_of_week(year,1,1) - 1;
116   return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
117           (first < 4) );
118 }
119
120 static Z_long 
121 year_to_days(N_int year)
122 {
123   return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
124 }
125
126
127 static Z_long 
128 calc_days(N_int year, N_int mm, N_int dd)
129 {
130   boolean lp;
131   
132   if (year < 1) return(0L);
133   if ((mm < 1) or (mm > 12)) return(0L);
134   if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
135   return( year_to_days(--year) + days_in_months[lp][mm] + dd );
136 }
137
138 static boolean 
139 week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
140 {
141   if (check_date(*year,mm,dd))
142     {
143       *week = week_number(*year,mm,dd);
144       if (*week == 0) 
145         *week = weeks_in_year(--(*year));
146       else if (*week > weeks_in_year(*year))
147         {
148           *week = 1;
149           (*year)++;
150         }
151       return(true);
152     }
153   return(false);
154 }
155
156 static Z_long 
157 dates_difference(N_int year1, N_int mm1, N_int dd1,
158                  N_int year2, N_int mm2, N_int dd2)
159 {
160   return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
161 }
162
163 /** END OF lib_date routines ************************************************/
164
165 #define CALENDAR_MARGIN          0
166 #define CALENDAR_YSEP            4
167 #define CALENDAR_XSEP            4
168 #define INNER_BORDER             4
169
170 #define DAY_XPAD                 2
171 #define DAY_YPAD                 2
172 #define DAY_XSEP                 0 /* not really good for small calendar */
173 #define DAY_YSEP                 0 /* not really good for small calendar */
174
175 /* Color usage */
176 #define HEADER_FG_COLOR(widget)          (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
177 #define HEADER_BG_COLOR(widget)          (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
178 #define DAY_NAME_COLOR(widget)           (& (widget)->style->bg[GTK_STATE_SELECTED])
179 #define NORMAL_DAY_COLOR(widget)         (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
180 #define SELECTION_FOCUS_COLOR(widget)    (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
181 #define SELECTION_NO_FOCUS_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
182 #define PREV_MONTH_COLOR(widget)         (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
183 #define NEXT_MONTH_COLOR(widget)         (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
184 #define MARKED_COLOR(widget)             (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
185 #define FOREGROUND_COLOR(widget)         (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
186 #define BACKGROUND_COLOR(widget)         (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
187 #define HIGHLIGHT_BACK_COLOR(widget)     (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
188
189 #define HEADER_FONT(widget) ((widget)->style->font)
190 #define LABEL_FONT(widget)   ((widget)->style->font)
191 #define DAY_FONT(widget)     ((widget)->style->font)
192
193 enum {
194   ARROW_YEAR_LEFT,
195   ARROW_YEAR_RIGHT,
196   ARROW_MONTH_LEFT,
197   ARROW_MONTH_RIGHT
198 };
199
200 enum {
201   MONTH_PREV,
202   MONTH_CURRENT,
203   MONTH_NEXT
204 };
205
206 enum {
207   MONTH_CHANGED_SIGNAL,
208   DAY_SELECTED_SIGNAL,
209   DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
210   PREV_MONTH_SIGNAL,
211   NEXT_MONTH_SIGNAL,
212   PREV_YEAR_SIGNAL,
213   NEXT_YEAR_SIGNAL,
214   LAST_SIGNAL
215 };
216
217 static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 };
218
219 static GtkWidgetClass *parent_class = NULL;
220
221 typedef struct _GtkCalendarPrivateData GtkCalendarPrivateData;
222 struct _GtkCalendarPrivateData
223 {
224   GdkWindow *header_win;
225   GdkWindow *day_name_win;
226   GdkWindow *main_win;
227   GdkWindow *week_win;
228   GdkWindow *arrow_win[4];
229
230   guint header_h;
231   guint day_name_h;
232   guint main_h;
233
234   guint      arrow_state[4];
235   guint      arrow_width;
236   guint      max_month_width;
237   guint      max_year_width;
238   
239   guint day_width;
240   guint week_width;
241
242   guint min_day_width;
243   guint max_day_char_width;
244   guint max_day_char_ascent;
245   guint max_day_char_descent;
246   guint max_label_char_ascent;
247   guint max_label_char_descent;
248   guint max_week_char_width;
249   
250   guint freeze_count;
251
252   /* flags */
253   guint dirty_header : 1;
254   guint dirty_day_names : 1;
255   guint dirty_main : 1;
256   guint dirty_week : 1;
257 };
258
259 #define GTK_CALENDAR_PRIVATE_DATA(widget)  (((GtkCalendarPrivateData*)(GTK_CALENDAR (widget)->private_data)))
260
261 typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data);
262
263 static void gtk_calendar_class_init     (GtkCalendarClass *class);
264 static void gtk_calendar_init           (GtkCalendar *calendar);
265 static void gtk_calendar_realize        (GtkWidget *widget);
266 static void gtk_calendar_unrealize      (GtkWidget *widget);
267 static void gtk_calendar_draw_focus     (GtkWidget *widget);
268 static void gtk_calendar_size_request   (GtkWidget *widget,
269                                          GtkRequisition *requisition);
270 static void gtk_calendar_size_allocate  (GtkWidget *widget,
271                                          GtkAllocation *allocation);
272 static gint gtk_calendar_expose         (GtkWidget *widget,
273                                          GdkEventExpose *event);
274 static gint gtk_calendar_button_press   (GtkWidget *widget,
275                                          GdkEventButton *event);
276 static void gtk_calendar_main_button    (GtkWidget *widget,
277                                          GdkEventButton *event);
278 static gint gtk_calendar_motion_notify  (GtkWidget *widget,
279                                          GdkEventMotion *event);
280 static gint gtk_calendar_enter_notify   (GtkWidget *widget,
281                                          GdkEventCrossing *event);
282 static gint gtk_calendar_leave_notify   (GtkWidget *widget,
283                                          GdkEventCrossing *event);
284 static gint gtk_calendar_key_press      (GtkWidget         *widget,
285                                          GdkEventKey       *event);
286 static gint gtk_calendar_focus_in       (GtkWidget *widget,
287                                          GdkEventFocus *event);
288 static gint gtk_calendar_focus_out      (GtkWidget *widget,
289                                          GdkEventFocus *event);
290 static void gtk_calendar_state_changed  (GtkWidget *widget,
291                                          GtkStateType previous_state);
292 static void gtk_calendar_style_set      (GtkWidget *widget,
293                                          GtkStyle  *previous_style);
294 static void gtk_calendar_paint_header       (GtkWidget *widget);
295 static void gtk_calendar_paint_day_names    (GtkWidget *widget);
296 static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
297 static void gtk_calendar_paint_main         (GtkWidget *widget);
298
299
300 static void gtk_calendar_paint          (GtkWidget    *widget,
301                                          GdkRectangle *area);
302 static void gtk_calendar_paint_arrow    (GtkWidget    *widget,
303                                          guint         arrow);
304 static void gtk_calendar_paint_day_num  (GtkWidget    *widget,
305                                          gint          day);
306 static void gtk_calendar_paint_day      (GtkWidget    *widget,
307                                          gint          row,
308                                          gint          col);
309 static void gtk_calendar_draw           (GtkWidget    *widget,
310                                          GdkRectangle *area);
311 static void gtk_calendar_compute_days   (GtkCalendar  *calendar);
312 static gint left_x_for_column           (GtkCalendar  *calendar,
313                                          gint          column);
314 static gint top_y_for_row               (GtkCalendar  *calendar,
315                                          gint          row);
316
317 static char    *default_abbreviated_dayname[7];
318 static char    *default_monthname[12];
319
320 GtkType
321 gtk_calendar_get_type (void)
322 {
323   static GtkType calendar_type = 0;
324   
325   if (!calendar_type)
326     {
327       static const GTypeInfo calendar_info =
328       {
329         sizeof (GtkCalendarClass),
330         NULL,           /* base_init */
331         NULL,           /* base_finalize */
332         (GClassInitFunc) gtk_calendar_class_init,
333         NULL,           /* class_finalize */
334         NULL,           /* class_data */
335         sizeof (GtkCalendar),
336         16,             /* n_preallocs */
337         (GInstanceInitFunc) gtk_calendar_init,
338       };
339
340       calendar_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCalendar", &calendar_info);
341     }
342   
343   return calendar_type;
344 }
345
346 static void
347 gtk_calendar_class_init (GtkCalendarClass *class)
348 {
349   GtkObjectClass *object_class;
350   GtkWidgetClass *widget_class;
351   
352   object_class = (GtkObjectClass*) class;
353   widget_class = (GtkWidgetClass*) class;
354   
355   parent_class = gtk_type_class (GTK_TYPE_WIDGET);
356   
357   widget_class->realize = gtk_calendar_realize;
358   widget_class->unrealize = gtk_calendar_unrealize;
359   widget_class->expose_event = gtk_calendar_expose;
360   widget_class->draw = gtk_calendar_draw;
361   widget_class->draw_focus = gtk_calendar_draw_focus;
362   widget_class->size_request = gtk_calendar_size_request;
363   widget_class->size_allocate = gtk_calendar_size_allocate;
364   widget_class->button_press_event = gtk_calendar_button_press;
365   widget_class->motion_notify_event = gtk_calendar_motion_notify;
366   widget_class->enter_notify_event = gtk_calendar_enter_notify;
367   widget_class->leave_notify_event = gtk_calendar_leave_notify;
368   widget_class->key_press_event = gtk_calendar_key_press;
369   widget_class->focus_in_event = gtk_calendar_focus_in;
370   widget_class->focus_out_event = gtk_calendar_focus_out;
371   widget_class->style_set = gtk_calendar_style_set;
372   widget_class->state_changed = gtk_calendar_state_changed;
373   
374   gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
375     gtk_signal_new ("month_changed",
376                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
377                     GTK_SIGNAL_OFFSET (GtkCalendarClass, month_changed),
378                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
379   gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
380     gtk_signal_new ("day_selected",
381                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
382                     GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected),
383                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
384   gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
385     gtk_signal_new ("day_selected_double_click",
386                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
387                     GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected_double_click),
388                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
389   gtk_calendar_signals[PREV_MONTH_SIGNAL] =
390     gtk_signal_new ("prev_month",
391                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
392                     GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_month),
393                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
394   gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
395     gtk_signal_new ("next_month",
396                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
397                     GTK_SIGNAL_OFFSET (GtkCalendarClass, next_month),
398                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
399   gtk_calendar_signals[PREV_YEAR_SIGNAL] =
400     gtk_signal_new ("prev_year",
401                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
402                     GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_year),
403                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
404   gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
405     gtk_signal_new ("next_year",
406                     GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
407                     GTK_SIGNAL_OFFSET (GtkCalendarClass, next_year),
408                     gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
409   
410   gtk_object_class_add_signals (object_class, gtk_calendar_signals, LAST_SIGNAL);
411   
412   class->month_changed = NULL;
413   class->day_selected = NULL;
414   class->day_selected_double_click = NULL;
415   class->prev_month = NULL;
416   class->next_month = NULL;
417   class->prev_year = NULL;
418   class->next_year = NULL;
419 }
420
421 static void
422 gtk_calendar_init (GtkCalendar *calendar)
423 {
424   time_t secs;
425   struct tm *tm;
426   gint i;
427   char buffer[255];
428   time_t tmp_time;
429   GtkWidget *widget;
430   GtkCalendarPrivateData *private_data;
431   
432   widget = GTK_WIDGET (calendar);
433   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
434   
435   calendar->private_data = (gpointer) malloc (sizeof (GtkCalendarPrivateData));
436   private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
437
438   if (!default_abbreviated_dayname[0])
439     for (i=0; i<7; i++)
440       {
441         tmp_time= (i+3)*86400;
442         strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
443         default_abbreviated_dayname[i] = g_strdup (buffer);
444       }
445   
446   if (!default_monthname[0])
447     for (i=0; i<12; i++)
448       {
449         tmp_time=i*2764800;
450         strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
451         default_monthname[i] = g_strdup (buffer);
452       }
453   
454   /* Set defaults */
455   secs = time (NULL);
456   tm = localtime (&secs);
457   calendar->month = tm->tm_mon;
458   calendar->year  = 1900 + tm->tm_year;
459   
460   for (i=0;i<31;i++)
461     calendar->marked_date[i] = FALSE;
462   calendar->num_marked_dates = 0;
463   calendar->selected_day = 1;
464   
465   calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING | 
466                               GTK_CALENDAR_SHOW_DAY_NAMES );
467   
468   calendar->highlight_row = -1;
469   calendar->highlight_col = -1;
470   
471   calendar->focus_row = -1;
472   calendar->focus_col = -1;
473   calendar->xor_gc = NULL;
474
475   private_data->max_year_width = 0;
476   private_data->max_month_width = 0;
477   private_data->max_day_char_width = 0;
478   private_data->max_week_char_width = 0;
479
480   private_data->max_day_char_ascent = 0;
481   private_data->max_day_char_descent = 0;
482   private_data->max_label_char_ascent = 0;
483   private_data->max_label_char_descent = 0;
484
485   private_data->arrow_width = 10;
486
487   private_data->freeze_count = 0;
488   
489   private_data->dirty_header = 0;
490   private_data->dirty_day_names = 0;
491   private_data->dirty_week = 0;
492   private_data->dirty_main = 0;
493 }
494
495 GtkWidget*
496 gtk_calendar_new (void)
497 {
498   return GTK_WIDGET (gtk_type_new (GTK_TYPE_CALENDAR));
499 }
500
501 /* column_from_x: returns the column 0-6 that the
502  * x pixel of the xwindow is in */
503 static gint
504 column_from_x (GtkCalendar *calendar,
505                gint         event_x)
506 {
507   gint c, column;
508   gint x_left, x_right;
509   
510   column = -1;
511   
512   for (c = 0; c < 7; c++)
513     {
514       x_left = left_x_for_column (calendar, c);
515       x_right = x_left + GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
516       
517       if (event_x >= x_left && event_x < x_right)
518         {
519           column = c;
520           break;
521         }
522     }
523   
524   return column;
525 }
526
527 static gint
528 row_height (GtkCalendar *calendar)
529 {
530   return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h - CALENDAR_MARGIN
531           - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
532              ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
533 }
534
535
536 /* row_from_y: returns the row 0-5 that the
537  * y pixel of the xwindow is in */
538 static gint
539 row_from_y (GtkCalendar *calendar,
540             gint         event_y)
541 {
542   gint r, row;
543   gint height;
544   gint y_top, y_bottom;
545   
546   height = row_height (calendar);
547   row = -1;
548   
549   for (r = 0; r < 6; r++)
550     {
551       y_top = top_y_for_row (calendar, r);
552       y_bottom = y_top + height;
553       
554       if (event_y >= y_top && event_y < y_bottom)
555         {
556           row = r;
557           break;
558         }
559     }
560   
561   return row;
562 }
563
564 /* left_x_for_column: returns the x coordinate
565  * for the left of the column */
566 static gint
567 left_x_for_column (GtkCalendar *calendar,
568                    gint         column)
569 {
570   gint width;
571   gint x_left;
572   
573   width = GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
574   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
575     x_left =  DAY_XSEP + (width + DAY_XSEP) * column;
576   else
577     x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
578   
579   return x_left;
580 }
581
582 /* top_y_for_row: returns the y coordinate
583  * for the top of the row */
584 static gint
585 top_y_for_row (GtkCalendar *calendar,
586                gint         row)
587 {
588   
589   return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h 
590           - (CALENDAR_MARGIN + (6 - row)
591              * row_height (calendar)));
592 }
593
594 /* This function should be done by the toolkit, but we don't like the
595  * GTK arrows because they don't look good on this widget */
596 static void
597 draw_arrow_right (GdkWindow *window,
598                   GdkGC     *gc,
599                   gint       x,
600                   gint       y,
601                   gint       size)
602 {
603   gint i;
604   
605   for (i = 0; i <= size / 2; i++)
606     {
607       gdk_draw_line (window, gc,
608                      x + i,
609                      y + i,
610                      x + i,
611                      y + size - i);
612     }
613 }
614
615 /* This function should be done by the toolkit, but we don't like the
616  * GTK arrows because they don't look good on this widget */
617 static void
618 draw_arrow_left (GdkWindow *window,
619                  GdkGC     *gc,
620                  gint       x,
621                  gint       y,
622                  gint       size)
623 {
624   gint i;
625   
626   for (i = 0; i <= size / 2; i++)
627     {
628       gdk_draw_line (window, gc,
629                      x + size/2 - i,
630                      y + i,
631                      x + size/2 - i,
632                      y + size - i);
633     }
634 }
635
636 static void
637 gtk_calendar_set_month_prev (GtkCalendar *calendar)
638 {
639   gint month_len;
640   
641   if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
642     return;
643   
644   if (calendar->month == 0)
645     {
646       calendar->month = 11;
647       calendar->year--;
648     } 
649   else 
650     calendar->month--;
651   
652   month_len = month_length[leap (calendar->year)][calendar->month + 1];
653   
654   gtk_calendar_freeze (calendar);
655   gtk_calendar_compute_days (calendar);
656   
657   gtk_signal_emit (GTK_OBJECT (calendar),
658                    gtk_calendar_signals[PREV_MONTH_SIGNAL]);
659   gtk_signal_emit (GTK_OBJECT (calendar),
660                    gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
661   
662   if (month_len < calendar->selected_day)
663     {
664       calendar->selected_day = 0;
665       gtk_calendar_select_day (calendar, month_len);
666     }
667   else
668     {
669       if (calendar->selected_day < 0)
670         calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
671       gtk_calendar_select_day (calendar, calendar->selected_day);
672     }
673   
674   gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
675   gtk_calendar_thaw (calendar);
676 }
677
678
679 static void
680 gtk_calendar_set_month_next (GtkCalendar *calendar)
681 {
682   gint month_len;
683   
684   g_return_if_fail (calendar != NULL);
685   g_return_if_fail (GTK_IS_WIDGET (calendar));
686   
687   if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
688     return;
689   
690   
691   if (calendar->month == 11)
692     {
693       calendar->month = 0;
694       calendar->year++;
695     } 
696   else 
697     calendar->month++;
698   
699   gtk_calendar_freeze (calendar);
700   gtk_calendar_compute_days (calendar);
701   gtk_signal_emit (GTK_OBJECT (calendar),
702                    gtk_calendar_signals[NEXT_MONTH_SIGNAL]);
703   gtk_signal_emit (GTK_OBJECT (calendar),
704                    gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
705   
706   month_len = month_length[leap (calendar->year)][calendar->month + 1];
707   
708   if (month_len < calendar->selected_day)
709     {
710       calendar->selected_day = 0;
711       gtk_calendar_select_day (calendar, month_len);
712     }
713   else
714     gtk_calendar_select_day (calendar, calendar->selected_day);
715   
716   gtk_calendar_paint (GTK_WIDGET(calendar), NULL);
717   gtk_calendar_thaw (calendar);
718 }
719
720 static void
721 gtk_calendar_set_year_prev (GtkCalendar *calendar)
722 {
723   gint month_len;
724   
725   g_return_if_fail (calendar != NULL);
726   g_return_if_fail (GTK_IS_WIDGET (calendar));
727   
728   calendar->year--;
729   gtk_calendar_freeze (calendar);
730   gtk_calendar_compute_days (calendar);
731   gtk_signal_emit (GTK_OBJECT (calendar),
732                    gtk_calendar_signals[PREV_YEAR_SIGNAL]);
733   gtk_signal_emit (GTK_OBJECT (calendar),
734                    gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
735   
736   month_len = month_length[leap (calendar->year)][calendar->month + 1];
737   
738   if (month_len < calendar->selected_day)
739     {
740       calendar->selected_day = 0;
741       gtk_calendar_select_day (calendar, month_len);
742     }
743   else
744     gtk_calendar_select_day (calendar, calendar->selected_day);
745   
746   gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
747   gtk_calendar_thaw (calendar);
748 }
749
750 static void
751 gtk_calendar_set_year_next (GtkCalendar *calendar)
752 {
753   gint month_len;
754   GtkWidget *widget;
755   
756   g_return_if_fail (calendar != NULL);
757   g_return_if_fail (GTK_IS_WIDGET (calendar));
758   
759   widget = GTK_WIDGET (calendar);
760   
761   gtk_calendar_freeze (calendar);
762   
763   calendar->year++;
764   gtk_calendar_compute_days (calendar);
765   gtk_signal_emit (GTK_OBJECT (calendar),
766                    gtk_calendar_signals[NEXT_YEAR_SIGNAL]);
767   gtk_signal_emit (GTK_OBJECT (calendar),
768                    gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
769   
770   month_len = month_length[leap (calendar->year)][calendar->month + 1];
771   
772   if (month_len < calendar->selected_day)
773     {
774       calendar->selected_day = 0;
775       gtk_calendar_select_day (calendar, month_len);
776     }
777   else
778     gtk_calendar_select_day (calendar, calendar->selected_day);
779   
780   gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
781   gtk_calendar_thaw (calendar);
782 }
783
784 static void
785 gtk_calendar_main_button (GtkWidget      *widget,
786                           GdkEventButton *event)
787 {
788   GtkCalendar *calendar;
789   gint x, y;
790   gint row, col;
791   gint day_month;
792   gint old_focus_row, old_focus_col;
793   
794   calendar = GTK_CALENDAR (widget);
795   
796   x = (gint) (event->x);
797   y = (gint) (event->y);
798   
799   row = row_from_y (calendar, y);
800   col = column_from_x (calendar, x);
801
802   /* If row or column isn't found, just return. */
803   if (row == -1 || col == -1)
804     return;
805   
806   day_month = calendar->day_month[row][col];
807   
808   if (day_month == MONTH_CURRENT)
809     {
810       if (event->type == GDK_2BUTTON_PRESS)
811         gtk_signal_emit (GTK_OBJECT (calendar),
812                          gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]);
813       else
814         {
815           if (!GTK_WIDGET_HAS_FOCUS (widget))
816             gtk_widget_grab_focus (widget);
817           old_focus_row = calendar->focus_row;
818           old_focus_col = calendar->focus_col;
819           calendar->focus_row = row;
820           calendar->focus_col = col;
821           gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
822           gtk_calendar_select_day (calendar, calendar->day[row][col]);
823         }
824     }
825   else if (day_month == MONTH_PREV)
826     gtk_calendar_set_month_prev (calendar);
827   else if (day_month == MONTH_NEXT)
828     gtk_calendar_set_month_next (calendar);
829 }
830
831 static void
832 gtk_calendar_realize_arrows (GtkWidget *widget)
833 {
834   GtkCalendar *calendar;
835   GtkCalendarPrivateData *private_data;
836   GdkWindowAttr attributes;
837   gint attributes_mask;
838   gint i;
839   
840   g_return_if_fail (widget != NULL);
841   g_return_if_fail (GTK_IS_CALENDAR (widget));
842   
843   calendar = GTK_CALENDAR (widget);
844   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
845
846   /* Arrow windows ------------------------------------- */
847   if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
848       && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
849     {
850       attributes.wclass = GDK_INPUT_OUTPUT;
851       attributes.window_type = GDK_WINDOW_CHILD;
852       attributes.visual = gtk_widget_get_visual (widget);
853       attributes.colormap = gtk_widget_get_colormap (widget);
854       attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
855                                | GDK_BUTTON_PRESS_MASK  | GDK_BUTTON_RELEASE_MASK
856                                | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
857       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
858       attributes.y = 3;
859       attributes.width = private_data->arrow_width;
860       attributes.height = private_data->header_h - 7;
861       for (i = 0; i < 4; i++)
862         {
863           switch (i)
864             {
865             case ARROW_MONTH_LEFT:
866               attributes.x = 3;
867               break;
868             case ARROW_MONTH_RIGHT:
869               attributes.x = (private_data->arrow_width 
870                               + private_data->max_month_width);
871               break;
872             case ARROW_YEAR_LEFT:
873               attributes.x = (widget->allocation.width - 4
874                               - (3 + 2*private_data->arrow_width 
875                                  + private_data->max_year_width));
876               break;
877             case ARROW_YEAR_RIGHT:
878               attributes.x = (widget->allocation.width - 4 
879                               - 3 - private_data->arrow_width);
880               break;
881             }
882           private_data->arrow_win[i] = gdk_window_new (private_data->header_win,
883                                                        &attributes, 
884                                                        attributes_mask);
885           private_data->arrow_state[i] = GTK_STATE_NORMAL;
886           gdk_window_set_background (private_data->arrow_win[i],
887                                      HEADER_BG_COLOR (GTK_WIDGET (calendar)));
888           gdk_window_show (private_data->arrow_win[i]);
889           gdk_window_set_user_data (private_data->arrow_win[i], widget);
890         }
891     }
892   else
893     {
894       for (i = 0; i < 4; i++)
895         private_data->arrow_win[i] = NULL;
896     }
897 }
898
899 static void
900 gtk_calendar_realize_header (GtkWidget *widget)
901 {
902   GtkCalendar *calendar;
903   GtkCalendarPrivateData *private_data;
904   GdkWindowAttr attributes;
905   gint attributes_mask;
906   
907   g_return_if_fail (widget != NULL);
908   g_return_if_fail (GTK_IS_CALENDAR (widget));
909   
910   calendar = GTK_CALENDAR (widget);
911   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
912
913   /* Header window ------------------------------------- */
914   if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
915     {
916       attributes.wclass = GDK_INPUT_OUTPUT;
917       attributes.window_type = GDK_WINDOW_CHILD;
918       attributes.visual = gtk_widget_get_visual (widget);
919       attributes.colormap = gtk_widget_get_colormap (widget);
920       attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
921       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
922       attributes.x = 2;
923       attributes.y = 2;
924       attributes.width = widget->allocation.width - 4;
925       attributes.height = private_data->header_h;
926       private_data->header_win = gdk_window_new (widget->window,
927                                              &attributes, attributes_mask);
928       
929       gdk_window_set_background (private_data->header_win,
930                                  HEADER_BG_COLOR (GTK_WIDGET (calendar)));
931       gdk_window_show (private_data->header_win);
932       gdk_window_set_user_data (private_data->header_win, widget);
933       
934     }
935   else
936     {
937       private_data->header_win = NULL;
938     }
939   gtk_calendar_realize_arrows (widget);
940 }
941
942 static void
943 gtk_calendar_realize_day_names (GtkWidget *widget)
944 {
945   GtkCalendar *calendar;
946   GtkCalendarPrivateData *private_data;
947   GdkWindowAttr attributes;
948   gint attributes_mask;
949   
950   g_return_if_fail (widget != NULL);
951   g_return_if_fail (GTK_IS_CALENDAR (widget));
952   
953   calendar = GTK_CALENDAR (widget);
954   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
955
956   /* Day names  window --------------------------------- */
957   if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
958     {
959       attributes.wclass = GDK_INPUT_OUTPUT;
960       attributes.window_type = GDK_WINDOW_CHILD;
961       attributes.visual = gtk_widget_get_visual (widget);
962       attributes.colormap = gtk_widget_get_colormap (widget);
963       attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
964       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
965       attributes.x = (widget->style->xthickness + INNER_BORDER);
966       attributes.y = private_data->header_h + (widget->style->ythickness 
967                                            + INNER_BORDER);
968       attributes.width = (widget->allocation.width 
969                           - (widget->style->xthickness + INNER_BORDER) 
970                           * 2);
971       attributes.height = private_data->day_name_h;
972       private_data->day_name_win = gdk_window_new (widget->window,
973                                                    &attributes, 
974                                                    attributes_mask);
975       gdk_window_set_background (private_data->day_name_win, 
976                                  BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
977       gdk_window_show (private_data->day_name_win);
978       gdk_window_set_user_data (private_data->day_name_win, widget);
979     }
980   else
981     {
982       private_data->day_name_win = NULL;
983     }
984 }
985
986 static void
987 gtk_calendar_realize_week_numbers (GtkWidget *widget)
988 {
989   GtkCalendar *calendar;
990   GtkCalendarPrivateData *private_data;
991   GdkWindowAttr attributes;
992   gint attributes_mask;
993   
994   g_return_if_fail (widget != NULL);
995   g_return_if_fail (GTK_IS_CALENDAR (widget));
996   
997   calendar = GTK_CALENDAR (widget);
998   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
999
1000   /* Week number window -------------------------------- */
1001   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1002     {
1003       attributes.wclass = GDK_INPUT_OUTPUT;
1004       attributes.window_type = GDK_WINDOW_CHILD;
1005       attributes.visual = gtk_widget_get_visual (widget);
1006       attributes.colormap = gtk_widget_get_colormap (widget);
1007       attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1008       
1009       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1010       attributes.x = + (widget->style->xthickness + INNER_BORDER);
1011       attributes.y = (private_data->header_h + private_data->day_name_h 
1012                       + (widget->style->ythickness + INNER_BORDER));
1013       attributes.width = private_data->week_width;
1014       attributes.height = private_data->main_h;
1015       private_data->week_win = gdk_window_new (widget->window,
1016                                                &attributes, attributes_mask);
1017       gdk_window_set_background (private_data->week_win,  
1018                                  BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1019       gdk_window_show (private_data->week_win);
1020       gdk_window_set_user_data (private_data->week_win, widget);
1021     } 
1022   else
1023     {
1024       private_data->week_win = NULL;
1025     }
1026 }
1027
1028 static void
1029 gtk_calendar_realize (GtkWidget *widget)
1030 {
1031   GtkCalendar *calendar;
1032   GtkCalendarPrivateData *private_data;
1033   GdkWindowAttr attributes;
1034   gint attributes_mask;
1035   GdkGCValues values;
1036
1037   g_return_if_fail (widget != NULL);
1038   g_return_if_fail (GTK_IS_CALENDAR (widget));
1039   
1040   calendar = GTK_CALENDAR (widget);
1041   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1042   
1043   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1044   gtk_calendar_compute_days (calendar);
1045   
1046   attributes.x = widget->allocation.x;
1047   attributes.y = widget->allocation.y;
1048   attributes.width = widget->allocation.width;
1049   attributes.height = widget->allocation.height;
1050   attributes.wclass = GDK_INPUT_OUTPUT;
1051   attributes.window_type = GDK_WINDOW_CHILD;
1052   attributes.event_mask =  (gtk_widget_get_events (widget) 
1053                             | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK);
1054   attributes.visual = gtk_widget_get_visual (widget);
1055   attributes.colormap = gtk_widget_get_colormap (widget);
1056   
1057   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1058   widget->window = gdk_window_new (widget->parent->window,
1059                                    &attributes, attributes_mask);
1060   
1061   widget->style = gtk_style_attach (widget->style, widget->window);
1062   
1063   /* Header window ------------------------------------- */
1064   gtk_calendar_realize_header (widget);
1065   /* Day names  window --------------------------------- */
1066   gtk_calendar_realize_day_names (widget);
1067   /* Week number window -------------------------------- */
1068   gtk_calendar_realize_week_numbers (widget);
1069   /* Main Window --------------------------------------  */
1070   attributes.event_mask =  (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1071                             | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1072                             | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1073   
1074   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1075     attributes.x = private_data->week_width;
1076   else
1077     attributes.x = 0;
1078   attributes.x += (widget->style->xthickness + INNER_BORDER);
1079   attributes.y = (private_data->header_h + private_data->day_name_h 
1080                   + (widget->style->ythickness + INNER_BORDER));
1081   attributes.width = (widget->allocation.width - attributes.x 
1082                       - (widget->style->xthickness + INNER_BORDER));
1083   attributes.height = private_data->main_h;
1084   private_data->main_win = gdk_window_new (widget->window,
1085                                            &attributes, attributes_mask);
1086   gdk_window_set_background (private_data->main_win, 
1087                              BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1088   gdk_window_show (private_data->main_win);
1089   gdk_window_set_user_data (private_data->main_win, widget);
1090   gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1091   gdk_window_show (widget->window);
1092   gdk_window_set_user_data (widget->window, widget);
1093   
1094   /* Set widgets gc */
1095   calendar->gc = gdk_gc_new (widget->window);
1096
1097   values.foreground = widget->style->white;
1098   values.function = GDK_XOR;
1099   calendar->xor_gc = gdk_gc_new_with_values (widget->window,
1100                                              &values,
1101                                              GDK_GC_FOREGROUND |
1102                                              GDK_GC_FUNCTION);
1103 }
1104
1105 static void
1106 gtk_calendar_unrealize (GtkWidget *widget)
1107 {
1108   GtkCalendar *calendar;
1109   GtkCalendarPrivateData *private_data;
1110   gint i;
1111   
1112   g_return_if_fail (widget != NULL);
1113   g_return_if_fail (GTK_IS_CALENDAR (widget));
1114   
1115   calendar = GTK_CALENDAR (widget);
1116   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1117   
1118   if (private_data->header_win)
1119     {
1120       for (i = 0; i < 4; i++)
1121         {
1122           if (private_data->arrow_win[i])
1123             {
1124               gdk_window_set_user_data (private_data->arrow_win[i], NULL);
1125               gdk_window_destroy (private_data->arrow_win[i]);
1126               private_data->arrow_win[i] = NULL;
1127             }
1128         }
1129       gdk_window_set_user_data (private_data->header_win, NULL);
1130       gdk_window_destroy (private_data->header_win);
1131       private_data->header_win = NULL;
1132     }
1133   
1134   if (private_data->week_win)
1135     {
1136       gdk_window_set_user_data (private_data->week_win, NULL);
1137       gdk_window_destroy (private_data->week_win);
1138       private_data->week_win = NULL;      
1139     }
1140   
1141   if (private_data->main_win)
1142     {
1143       gdk_window_set_user_data (private_data->main_win, NULL);
1144       gdk_window_destroy (private_data->main_win);
1145       private_data->main_win = NULL;      
1146     }
1147   
1148   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1149     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1150 }
1151
1152 static void
1153 gtk_calendar_size_request (GtkWidget      *widget,
1154                            GtkRequisition *requisition)
1155 {
1156   GtkCalendar *calendar;
1157   GtkCalendarPrivateData *private_data;
1158   PangoLayout *layout;
1159   PangoRectangle logical_rect;
1160
1161   gint height;
1162   gint i;
1163   gchar buffer[255];
1164   gint calendar_margin = CALENDAR_MARGIN;
1165   gint header_width, main_width;
1166   gint max_header_height = 0;
1167   
1168   calendar = GTK_CALENDAR (widget);
1169   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1170
1171   layout = gtk_widget_create_pango_layout (widget, NULL);
1172   
1173   /*
1174    * Calculate the requisition  width for the widget.
1175    */
1176   
1177   /* Header width */
1178   
1179   if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1180     {
1181       private_data->max_month_width = 0;
1182       for (i = 0; i < 12; i++)
1183         {
1184           pango_layout_set_text (layout, default_monthname[i], -1);
1185           pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1186           private_data->max_month_width = MAX (private_data->max_month_width,
1187                                                logical_rect.width + 8);
1188           max_header_height = MAX (max_header_height, logical_rect.height); 
1189         }
1190       private_data->max_year_width = 0;
1191       for (i=0; i<10; i++)
1192         {
1193           sprintf (buffer, "%d%d%d%d", i,i,i,i);
1194           pango_layout_set_text (layout, buffer, -1);     
1195           pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1196           private_data->max_year_width = MAX (private_data->max_year_width,
1197                                               logical_rect.width + 8);
1198           max_header_height = MAX (max_header_height, logical_rect.height); 
1199         }
1200     } 
1201   else 
1202     {
1203       private_data->max_month_width = 0;
1204       private_data->max_year_width = 0;
1205     }
1206   
1207   if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1208     header_width = (private_data->max_month_width 
1209                     + private_data->max_year_width
1210                     + 3 * 3);
1211   else
1212     header_width = (private_data->max_month_width 
1213                     + private_data->max_year_width
1214                     + 4 * private_data->arrow_width + 3 * 3);
1215
1216   /* Mainwindow labels width */
1217   
1218   private_data->max_day_char_width = 0;
1219   for (i = 0; i < 9; i++)
1220     {
1221       sprintf (buffer, "%d%d", i, i);
1222       pango_layout_set_text (layout, buffer, -1);         
1223       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1224       private_data->min_day_width = MAX (private_data->max_day_char_width,
1225                                          logical_rect.width);
1226
1227       private_data->max_day_char_ascent = MAX (private_data->max_label_char_ascent,
1228                                                PANGO_ASCENT (logical_rect));
1229       private_data->max_day_char_descent = MAX (private_data->max_label_char_descent, 
1230                                                 PANGO_DESCENT (logical_rect));
1231     }
1232   /* We add one to max_day_char_width to be able to make the marked day "bold" */
1233   private_data->max_day_char_width = private_data->min_day_width / 2 +1;
1234   
1235   if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1236     for (i = 0; i < 7; i++)
1237       {
1238         pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1239         pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1240
1241         private_data->min_day_width = MAX (private_data->min_day_width, logical_rect.width);
1242         private_data->max_label_char_ascent = MAX (private_data->max_label_char_ascent,
1243                                                    PANGO_ASCENT (logical_rect));
1244         private_data->max_label_char_descent = MAX (private_data->max_label_char_descent, 
1245                                                     PANGO_DESCENT (logical_rect));
1246       }
1247   
1248   private_data->max_week_char_width = 0;
1249   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1250     for (i = 0; i < 9; i++)
1251       {
1252         sprintf (buffer, "%d%d", i, i);
1253         pango_layout_set_text (layout, buffer, -1);       
1254         pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1255         private_data->max_week_char_width = MAX (private_data->max_week_char_width,
1256                                                  logical_rect.width / 2);
1257       }
1258   
1259   main_width = (7 * (private_data->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1260                 + (private_data->max_week_char_width
1261                    ? private_data->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2
1262                    : 0));
1263   
1264   
1265   requisition->width = MAX (header_width+4, main_width + (widget->style->xthickness + INNER_BORDER) *2);
1266   
1267   /*
1268    * Calculate the requisition height for the widget.
1269    */
1270   
1271   if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1272     {
1273       private_data->header_h = (max_header_height + CALENDAR_YSEP * 2);
1274     }
1275   else
1276     {
1277       private_data->header_h = 0;
1278     }
1279   
1280   if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1281     {
1282       private_data->day_name_h = (private_data->max_label_char_ascent
1283                                   + private_data->max_label_char_descent
1284                                   + 2 * DAY_YPAD + calendar_margin);
1285       calendar_margin = CALENDAR_YSEP;
1286     } 
1287   else
1288     {
1289       private_data->day_name_h = 0;
1290     }
1291
1292   private_data->main_h = (CALENDAR_MARGIN + calendar_margin
1293                           + 6 * (private_data->max_day_char_ascent
1294                                  + private_data->max_day_char_descent 
1295                                  + DAY_YPAD * 2)
1296                           + DAY_YSEP * 5);
1297   
1298   /* 
1299    * If we display weeknumbers we need some extra space 
1300    */
1301   
1302   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1303     {
1304       private_data->main_h = MAX (private_data->main_h,
1305                                   (CALENDAR_MARGIN + calendar_margin
1306                                    + 6 * (private_data->max_day_char_ascent 
1307                                           + private_data->max_day_char_descent 
1308                                           + DAY_YPAD * 2)
1309                                    + DAY_YSEP * 5));
1310     }
1311   
1312   height = (private_data->header_h + private_data->day_name_h 
1313             + private_data->main_h);
1314   
1315   requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1316
1317   g_object_unref (G_OBJECT (layout));
1318 }
1319
1320 static void
1321 gtk_calendar_size_allocate (GtkWidget     *widget,
1322                             GtkAllocation *allocation)
1323 {
1324   GtkCalendar *calendar;
1325   GtkCalendarPrivateData *private_data;
1326   
1327   g_return_if_fail (widget != NULL);
1328   g_return_if_fail (GTK_IS_CALENDAR (widget));
1329   g_return_if_fail (allocation != NULL);
1330   
1331   widget->allocation = *allocation;
1332   
1333   calendar = GTK_CALENDAR (widget);
1334   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1335   
1336   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1337     {
1338       private_data->day_width = (private_data->min_day_width
1339                              * ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1340                                  - (CALENDAR_MARGIN * 2) -  (DAY_XSEP * 7) - CALENDAR_XSEP * 2))
1341                              / (7 * private_data->min_day_width + private_data->max_week_char_width * 2));
1342       private_data->week_width = ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1343                                - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 )
1344                               - private_data->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1345     } 
1346   else 
1347     {
1348       private_data->day_width = (allocation->width
1349                              - (widget->style->xthickness + INNER_BORDER) * 2
1350                              - (CALENDAR_MARGIN * 2)
1351                              - (DAY_XSEP * 7))/7;
1352       private_data->week_width = 0;
1353     }
1354   
1355   if (GTK_WIDGET_REALIZED (widget))
1356     {
1357       gdk_window_move_resize (widget->window,
1358                               allocation->x, allocation->y,
1359                               allocation->width, allocation->height);
1360       if (private_data->header_win)
1361         gdk_window_move_resize (private_data->header_win,
1362                                 2, 2,
1363                                 allocation->width-4, private_data->header_h);
1364       if (private_data->arrow_win[ARROW_MONTH_LEFT])
1365         gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1366                                 3, 3,
1367                                 private_data->arrow_width,
1368                                 private_data->header_h - 7);
1369       if (private_data->arrow_win[ARROW_MONTH_RIGHT])
1370         gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1371                                 (private_data->arrow_width 
1372                                  + private_data->max_month_width), 
1373                                 3,
1374                                 private_data->arrow_width,
1375                                 private_data->header_h - 7);
1376       if (private_data->arrow_win[ARROW_YEAR_LEFT])
1377         gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1378                                 (allocation->width - 4
1379                                  - (3 + 2*private_data->arrow_width 
1380                                     + private_data->max_year_width)),
1381                                 3,
1382                                 private_data->arrow_width,
1383                                 private_data->header_h - 7);
1384       if (private_data->arrow_win[ARROW_YEAR_RIGHT])
1385         gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1386                                 (allocation->width - 4 
1387                                  - 3 - private_data->arrow_width), 
1388                                 3,
1389                                 private_data->arrow_width,
1390                                 private_data->header_h - 7);
1391       if (private_data->day_name_win)
1392         gdk_window_move_resize (private_data->day_name_win,
1393                                 widget->style->xthickness + INNER_BORDER,
1394                                 private_data->header_h + (widget->style->ythickness + INNER_BORDER),
1395                                 allocation->width - (widget->style->xthickness + INNER_BORDER) * 2,
1396                                 private_data->day_name_h);
1397       if (private_data->week_win)
1398         gdk_window_move_resize (private_data->week_win,
1399                                 (widget->style->xthickness + INNER_BORDER),
1400                                 private_data->header_h + private_data->day_name_h
1401                                 + (widget->style->ythickness + INNER_BORDER),
1402                                 private_data->week_width,
1403                                 private_data->main_h);
1404       gdk_window_move_resize (private_data->main_win,
1405                               (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0) 
1406                               + (widget->style->xthickness + INNER_BORDER),
1407                               private_data->header_h + private_data->day_name_h
1408                               + (widget->style->ythickness + INNER_BORDER),
1409                               allocation->width 
1410                               - (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0) 
1411                               - (widget->style->xthickness + INNER_BORDER) * 2,
1412                               private_data->main_h);
1413     }
1414 }
1415
1416 static void
1417 gtk_calendar_draw_focus (GtkWidget *widget)
1418 {
1419   GtkCalendar *calendar;
1420   GtkCalendarPrivateData *private_data;
1421   gint width, height;
1422   gint x, y;
1423   
1424   g_return_if_fail (widget != NULL);
1425   g_return_if_fail (GTK_IS_CALENDAR (widget));
1426
1427   calendar = GTK_CALENDAR (widget);
1428   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1429   
1430   if (GTK_WIDGET_DRAWABLE (widget))
1431     {
1432       x = 0;
1433       y = 0;
1434       gdk_window_get_size (widget->window, &width, &height);
1435       gdk_window_clear (widget->window);
1436       
1437       gdk_draw_rectangle (widget->window, 
1438                           widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1439                           FALSE, x + 2, y + 2, width - 5, height - 5);
1440       
1441       gtk_draw_shadow (widget->style, widget->window,
1442                        GTK_STATE_NORMAL, GTK_SHADOW_IN,
1443                        x, y, width, height);
1444       
1445     }
1446 }
1447
1448 static gint
1449 gtk_calendar_expose (GtkWidget      *widget,
1450                      GdkEventExpose *event)
1451 {
1452   GtkCalendar *calendar;
1453   GtkCalendarPrivateData *private_data;
1454
1455   g_return_val_if_fail (widget != NULL, FALSE);
1456   g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
1457   g_return_val_if_fail (event != NULL, FALSE);
1458   
1459   calendar = GTK_CALENDAR (widget);
1460   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1461   
1462   if (GTK_WIDGET_DRAWABLE (widget))
1463     {
1464       if (event->window == private_data->main_win)
1465         gtk_calendar_paint_main (widget);
1466       
1467       if (event->window == private_data->header_win)
1468         gtk_calendar_paint_header (widget);
1469       
1470       if (event->window == private_data->day_name_win)
1471         gtk_calendar_paint_day_names (widget);
1472       
1473       if (event->window == private_data->week_win)
1474         gtk_calendar_paint_week_numbers (widget);
1475       if (event->window == widget->window)
1476         gtk_widget_draw_focus (widget);
1477     }
1478   
1479   return FALSE;
1480 }
1481
1482 static void
1483 gtk_calendar_draw (GtkWidget    *widget,
1484                    GdkRectangle *area)
1485 {
1486   g_return_if_fail (widget != NULL);
1487   g_return_if_fail (GTK_IS_CALENDAR (widget));
1488   g_return_if_fail (area != NULL);
1489   
1490   if (GTK_WIDGET_DRAWABLE (widget))
1491     gtk_calendar_paint (widget, area);
1492   
1493 }
1494
1495 static void
1496 gtk_calendar_paint (GtkWidget    *widget,
1497                     GdkRectangle *area)
1498 {
1499   GtkCalendar *calendar;
1500   GtkCalendarPrivateData *private_data;
1501
1502   g_return_if_fail (widget != NULL);
1503   g_return_if_fail (widget->window != NULL);
1504   g_return_if_fail (GTK_IS_CALENDAR (widget));
1505   
1506   calendar = GTK_CALENDAR (widget);
1507   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1508   
1509   if (private_data->main_win != NULL)
1510     gtk_calendar_paint_main (widget);
1511   
1512   if (private_data->header_win != NULL)
1513     gtk_calendar_paint_header (widget);
1514   
1515   if (private_data->day_name_win != NULL)
1516     gtk_calendar_paint_day_names (widget);
1517   
1518   if (private_data->week_win != NULL)
1519     gtk_calendar_paint_week_numbers (widget);
1520   
1521   gtk_widget_draw_focus (widget);
1522 }
1523
1524 static void
1525 gtk_calendar_paint_header (GtkWidget *widget)
1526 {
1527   GtkCalendar *calendar;
1528   GdkGC *gc;
1529   char buffer[255];
1530   int x, y;
1531   gint header_width, cal_height;
1532   gint max_month_width;
1533   gint max_year_width;
1534   GtkCalendarPrivateData *private_data;
1535   PangoLayout *layout;
1536   PangoRectangle logical_rect;
1537
1538   calendar = GTK_CALENDAR (widget);
1539   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1540
1541   if (private_data->freeze_count)
1542     {
1543       private_data->dirty_header = 1;
1544       return;
1545     }
1546   private_data->dirty_header = 0;
1547   gc = calendar->gc;
1548   
1549   /* Clear window */
1550   gdk_window_clear (private_data->header_win);
1551   
1552   header_width = widget->allocation.width - 4;
1553   cal_height = widget->allocation.height;
1554   
1555   max_month_width = private_data->max_month_width;
1556   max_year_width = private_data->max_year_width;
1557   
1558   gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1559   gtk_draw_shadow (widget->style, private_data->header_win,
1560                    GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1561                    0, 0, header_width, private_data->header_h);
1562   
1563   
1564   sprintf (buffer, "%d", calendar->year);
1565   layout = gtk_widget_create_pango_layout (widget, buffer);
1566   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1567   
1568   /* Draw title */
1569   y = (private_data->header_h - logical_rect.height) / 2;
1570   
1571   /* Draw year and its arrows */
1572   
1573   if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1574     x = header_width - (3 + max_year_width
1575                         - (max_year_width - logical_rect.width)/2);
1576   else
1577     x = header_width - (3 + private_data->arrow_width + max_year_width
1578                         - (max_year_width - logical_rect.width)/2);
1579     
1580   
1581   gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1582   gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1583   
1584   /* Draw month */
1585   sprintf (buffer, "%s", default_monthname[calendar->month]);
1586   pango_layout_set_text (layout, buffer, -1);
1587   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1588
1589   if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1590     x = 3 + (max_month_width - logical_rect.width) / 2;
1591   else
1592     x = 3 + private_data->arrow_width + (max_month_width - logical_rect.width)/2;
1593
1594   gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1595   
1596   gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1597   
1598   gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
1599   gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
1600   gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
1601   gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
1602
1603   g_object_unref (G_OBJECT (layout));
1604 }
1605
1606 static void
1607 gtk_calendar_paint_day_names (GtkWidget *widget)
1608 {
1609   GtkCalendar *calendar;
1610   GdkGC *gc;
1611   char buffer[255];
1612   int day,i;
1613   int day_width, cal_width;
1614   gint cal_height;
1615   int day_wid_sep;
1616   PangoLayout *layout;
1617   PangoRectangle logical_rect;
1618   GtkCalendarPrivateData *private_data;
1619
1620   g_return_if_fail (widget != NULL);
1621   g_return_if_fail (GTK_IS_CALENDAR (widget));
1622   calendar = GTK_CALENDAR (widget);
1623   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1624   gc = calendar->gc;
1625   
1626   /*
1627    * Handle freeze/thaw functionality
1628    */
1629   
1630   if (private_data->freeze_count)
1631     {
1632       private_data->dirty_day_names = 1;
1633       return;
1634     }
1635   private_data->dirty_day_names = 0;
1636   
1637   /*
1638    * Clear the window
1639    */
1640   
1641   gdk_window_clear (private_data->day_name_win);
1642   
1643   day_width = private_data->day_width;
1644   cal_width = widget->allocation.width;
1645   cal_height = widget->allocation.height;
1646   day_wid_sep = day_width + DAY_XSEP;
1647   
1648   /*
1649    * Draw rectangles as inverted background for the labels.
1650    */
1651   
1652   gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1653   gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1654                       CALENDAR_MARGIN, CALENDAR_MARGIN,
1655                       cal_width-CALENDAR_MARGIN * 2,
1656                       private_data->day_name_h - CALENDAR_MARGIN);
1657   
1658   if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1659     gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1660                         CALENDAR_MARGIN,
1661                         private_data->day_name_h - CALENDAR_YSEP,
1662                         private_data->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1663                         CALENDAR_YSEP);
1664   
1665   /*
1666    * Write the labels
1667    */
1668
1669   layout = gtk_widget_create_pango_layout (widget, NULL);
1670   
1671   gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1672   for (i = 0; i < 7; i++)
1673     {
1674       day=i;
1675       if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1676         day= (day+1)%7;
1677       sprintf (buffer, "%s", default_abbreviated_dayname[day]);
1678
1679       pango_layout_set_text (layout, buffer, -1);
1680       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1681
1682       gdk_draw_layout (private_data->day_name_win, gc, 
1683                        ((private_data->week_width ? CALENDAR_XSEP : CALENDAR_MARGIN)
1684                         + day_wid_sep * i
1685                         + private_data->week_width
1686                         + (day_width - logical_rect.width)/2),
1687                        CALENDAR_MARGIN + DAY_YPAD + private_data->max_label_char_ascent + logical_rect.y,
1688                        layout);
1689     }
1690   
1691   g_object_unref (G_OBJECT (layout));
1692 }
1693
1694 static void
1695 gtk_calendar_paint_week_numbers (GtkWidget *widget)
1696 {
1697   GtkCalendar *calendar;
1698   GdkGC *gc;
1699   gint row, week = 0, year;
1700   gint x_loc;
1701   char buffer[3];
1702   gint y_loc, day_height;
1703   GtkCalendarPrivateData *private_data;
1704   PangoLayout *layout;
1705   PangoRectangle logical_rect;
1706   
1707   g_return_if_fail (widget != NULL);
1708   g_return_if_fail (widget->window != NULL);
1709   g_return_if_fail (GTK_IS_CALENDAR (widget));
1710   calendar = GTK_CALENDAR (widget);
1711   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1712   gc = calendar->gc;
1713   
1714   /*
1715    * Handle freeze/thaw functionality
1716    */
1717   
1718   if (private_data->freeze_count)
1719     {
1720       private_data->dirty_week = 1;
1721       return;
1722     }
1723   private_data->dirty_week = 0;
1724   
1725   /*
1726    * Clear the window
1727    */
1728   
1729   gdk_window_clear (private_data->week_win);
1730   
1731   /*
1732    * Draw a rectangle as inverted background for the labels.
1733    */
1734   
1735   gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1736   if (private_data->day_name_win)
1737     gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1738                         CALENDAR_MARGIN,
1739                         0,
1740                         private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1741                         private_data->main_h - CALENDAR_MARGIN);
1742   else
1743     gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1744                         CALENDAR_MARGIN,
1745                         CALENDAR_MARGIN,
1746                         private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1747                         private_data->main_h - 2 * CALENDAR_MARGIN);
1748   
1749   /*
1750    * Write the labels
1751    */
1752   
1753   layout = gtk_widget_create_pango_layout (widget, NULL);
1754   
1755   gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1756   day_height = row_height (calendar);
1757   for (row = 0; row < 6; row++)
1758     {
1759       year = calendar->year;
1760       if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
1761         year++;
1762
1763       g_return_if_fail (week_of_year (&week, &year,             
1764                                       ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
1765                                        + calendar->month) % 12 + 1, calendar->day[row][6]));
1766
1767       sprintf (buffer, "%d", week);
1768       pango_layout_set_text (layout, buffer, -1);
1769       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1770
1771       y_loc = top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
1772
1773       x_loc = (private_data->week_width
1774                - logical_rect.width
1775                - CALENDAR_XSEP - DAY_XPAD);
1776
1777       gdk_draw_layout (private_data->week_win, gc, x_loc, y_loc, layout);
1778     }
1779   
1780   g_object_unref (G_OBJECT (layout));
1781 }
1782
1783 static void
1784 gtk_calendar_paint_day_num (GtkWidget *widget,
1785                             gint       day)
1786 {
1787   GtkCalendar *calendar;
1788   gint r, c, row, col;
1789   
1790   g_return_if_fail (widget != NULL);
1791   g_return_if_fail (GTK_IS_CALENDAR (widget));
1792   
1793   calendar = GTK_CALENDAR (widget);
1794   
1795   row = -1;
1796   col = -1;
1797   for (r = 0; r < 6; r++)
1798     for (c = 0; c < 7; c++)
1799       if (calendar->day_month[r][c] == MONTH_CURRENT &&
1800           calendar->day[r][c] == day)
1801         {
1802           row = r;
1803           col = c;
1804         }
1805   
1806   g_return_if_fail (row != -1);
1807   g_return_if_fail (col != -1);
1808   
1809   gtk_calendar_paint_day (widget, row, col);
1810 }
1811
1812 static void
1813 gtk_calendar_paint_day (GtkWidget *widget,
1814                         gint       row,
1815                         gint       col)
1816 {
1817   GtkCalendar *calendar;
1818   GdkGC *gc;
1819   gchar buffer[255];
1820   gint day;
1821   gint day_height;
1822   gint x_left;
1823   gint x_loc;
1824   gint y_top;
1825   gint y_loc;
1826   gint day_xspace;
1827   GtkCalendarPrivateData *private_data;
1828   PangoLayout *layout;
1829   PangoRectangle logical_rect;
1830   
1831   g_return_if_fail (widget != NULL);
1832   g_return_if_fail (GTK_IS_CALENDAR (widget));
1833   g_return_if_fail (row < 6);
1834   g_return_if_fail (col < 7);
1835   calendar = GTK_CALENDAR (widget);
1836   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1837
1838   /*
1839    * Handle freeze/thaw functionality
1840    */
1841   
1842   if (private_data->freeze_count)
1843     {
1844       private_data->dirty_main = 1;
1845       return;
1846     }
1847   
1848   day_height = row_height (calendar);
1849   
1850   day_xspace = private_data->day_width - private_data->max_day_char_width*2;
1851   
1852   day = calendar->day[row][col];
1853   
1854   x_left = left_x_for_column (calendar, col);
1855   x_loc = x_left + private_data->day_width / 2 + private_data->max_day_char_width;
1856   
1857   y_top = top_y_for_row (calendar, row);
1858   
1859   gdk_window_clear_area (private_data->main_win, x_left, y_top,
1860                          private_data->day_width, day_height);
1861   
1862   gc = calendar->gc;
1863   
1864   if (calendar->day_month[row][col] == MONTH_PREV)
1865     {
1866       gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar)));
1867     } 
1868   else if (calendar->day_month[row][col] == MONTH_NEXT)
1869     {
1870       gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar)));
1871     } 
1872   else 
1873     {
1874       /*
1875       if (calendar->highlight_row == row && calendar->highlight_col == col)
1876         {
1877           gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar)));
1878           gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1879                               private_data->day_width, day_height);
1880         }
1881       */
1882       if (calendar->selected_day == day)
1883         {
1884           gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->bg[GTK_STATE_SELECTED]));
1885           gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1886                               private_data->day_width, day_height);
1887         }
1888       
1889       if (calendar->marked_date[day-1])
1890         gdk_gc_set_foreground (gc, MARKED_COLOR  (GTK_WIDGET (calendar)));
1891       else
1892         gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar)));
1893   
1894       if (calendar->selected_day == day)
1895         gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_STATE_SELECTED]));
1896       else
1897         gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_WIDGET_STATE (calendar)]));
1898     }
1899     
1900
1901   sprintf (buffer, "%d", day);
1902   layout = gtk_widget_create_pango_layout (widget, buffer);
1903   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1904   
1905   x_loc -= logical_rect.width;
1906
1907   y_loc = y_top + (day_height - logical_rect.height) / 2;
1908   gdk_draw_layout (private_data->main_win, gc,
1909                    x_loc, y_loc, layout);
1910   if (calendar->marked_date[day-1]
1911       && calendar->day_month[row][col] == MONTH_CURRENT)
1912     gdk_draw_layout (private_data->main_win, gc,
1913                      x_loc-1, y_loc, layout);
1914
1915   if (GTK_WIDGET_HAS_FOCUS (calendar) 
1916       && calendar->focus_row == row && calendar->focus_col == col)
1917     {
1918       gdk_draw_rectangle (private_data->main_win, calendar->xor_gc, 
1919                           FALSE, x_left, y_top,
1920                           private_data->day_width-1, day_height-1);
1921     }
1922
1923   g_object_unref (G_OBJECT (layout));
1924 }
1925
1926
1927 static void
1928 gtk_calendar_paint_main (GtkWidget *widget)
1929 {
1930   GtkCalendar *calendar;
1931   GtkCalendarPrivateData *private_data;
1932   gint row, col;
1933   
1934   g_return_if_fail (widget != NULL);
1935   g_return_if_fail (widget->window != NULL);
1936   g_return_if_fail (GTK_IS_CALENDAR (widget));
1937   
1938   calendar = GTK_CALENDAR (widget);
1939   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1940
1941   if (private_data->freeze_count)
1942     {
1943       private_data->dirty_main = 1;
1944       return;
1945     }
1946   private_data->dirty_main = 0;
1947   gdk_window_clear (private_data->main_win);
1948   
1949   /* gtk_calendar_compute_days (calendar); */ /* REMOVE later */
1950   
1951   for (col = 0; col < 7; col++)
1952     for (row = 0; row < 6; row++)
1953       gtk_calendar_paint_day (widget, row, col);
1954 }
1955
1956 static void
1957 gtk_calendar_compute_days (GtkCalendar *calendar)
1958 {
1959   gint month;
1960   gint year;
1961   gint ndays_in_month;
1962   gint ndays_in_prev_month;
1963   gint first_day;
1964   gint row;
1965   gint col;
1966   gint day;
1967   
1968   g_return_if_fail (calendar != NULL);
1969   g_return_if_fail (GTK_IS_CALENDAR (calendar));
1970   
1971   year = calendar->year;
1972   month = calendar->month + 1;
1973   
1974   ndays_in_month = month_length[leap (year)][month];
1975   
1976   first_day = day_of_week (year, month, 1);
1977   
1978   if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1979     first_day--;
1980   else
1981     first_day %= 7;
1982   
1983   
1984   /* Compute days of previous month */
1985   if (month > 1)
1986     ndays_in_prev_month = month_length[leap (year)][month-1];
1987   else
1988     ndays_in_prev_month = month_length[leap (year)][12];
1989   day = ndays_in_prev_month - first_day + 1;
1990   
1991   row = 0;
1992   if (first_day > 0)
1993     {
1994       for (col = 0; col < first_day; col++)
1995         {
1996           calendar->day[row][col] = day;
1997           calendar->day_month[row][col] = MONTH_PREV;
1998           day++;
1999         }
2000     }
2001   
2002   /* Compute days of current month */
2003   col = first_day;
2004   for (day = 1; day <= ndays_in_month; day++)
2005     {
2006       calendar->day[row][col] = day;
2007       calendar->day_month[row][col] = MONTH_CURRENT;
2008       
2009       col++;
2010       if (col == 7)
2011         {
2012           row++;
2013           col = 0;
2014         }
2015     }
2016   
2017   /* Compute days of next month */
2018   day = 1;
2019   for (; row <= 5; row++)
2020     {
2021       for (; col <= 6; col++)
2022         {
2023           calendar->day[row][col] = day;
2024           calendar->day_month[row][col] = MONTH_NEXT;
2025           day++;
2026         }
2027       col = 0;
2028     }
2029 }
2030
2031 /* ----------------------------------------------------------------------
2032    NAME:        gtk_calendar_display_options
2033    DESCRIPTION: Set display options (whether to display the
2034    heading and the month headings)
2035    
2036    flags is can be an XOR of:
2037    GTK_CALENDAR_SHOW_HEADING
2038    GTK_CALENDAR_SHOW_DAY_NAMES
2039    GTK_CALENDAR_NO_MONTH_CHANGE
2040    GTK_CALENDAR_SHOW_WEEK_NUMBERS
2041    GTK_CALENDAR_WEEK_START_MONDAY
2042    ---------------------------------------------------------------------- */
2043
2044 void
2045 gtk_calendar_display_options (GtkCalendar              *calendar,
2046                               GtkCalendarDisplayOptions flags)
2047 {
2048   GtkCalendarPrivateData *private_data;
2049   gint resize = 0;
2050   GtkWidget *widget;
2051   gint i;
2052   
2053   g_return_if_fail (calendar != NULL);
2054   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2055   
2056   widget = GTK_WIDGET (calendar);
2057   private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2058   
2059   if (GTK_WIDGET_REALIZED (widget))
2060     {
2061       if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2062         {
2063           resize ++;
2064           if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
2065               && (private_data->header_win))
2066             {
2067               calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
2068               gtk_calendar_realize_arrows (widget);
2069             }
2070           else
2071             {
2072               for (i = 0; i < 4; i++)
2073                 {
2074                   if (private_data->arrow_win[i])
2075                     {
2076                       gdk_window_set_user_data (private_data->arrow_win[i], 
2077                                                 NULL);
2078                       gdk_window_destroy (private_data->arrow_win[i]);
2079                       private_data->arrow_win[i] = NULL;
2080                     }
2081                 }
2082             }
2083         }
2084       
2085       if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2086         {
2087           resize++;
2088           
2089           if (flags & GTK_CALENDAR_SHOW_HEADING)
2090             {
2091               calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
2092               gtk_calendar_realize_header (widget);
2093             }
2094           else
2095             {
2096               for (i = 0; i < 4; i++)
2097                 {
2098                   if (private_data->arrow_win[i])
2099                     {
2100                       gdk_window_set_user_data (private_data->arrow_win[i], 
2101                                                 NULL);
2102                       gdk_window_destroy (private_data->arrow_win[i]);
2103                       private_data->arrow_win[i] = NULL;
2104                     }
2105                 }
2106               gdk_window_set_user_data (private_data->header_win, NULL);
2107               gdk_window_destroy (private_data->header_win);
2108               private_data->header_win = NULL;
2109             }
2110         }
2111       
2112       
2113       if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2114         {
2115           resize++;
2116           
2117           if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
2118             {
2119               calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
2120               gtk_calendar_realize_day_names (widget);
2121             }
2122           else
2123             {
2124               gdk_window_set_user_data (private_data->day_name_win, NULL);
2125               gdk_window_destroy (private_data->day_name_win);
2126               private_data->day_name_win = NULL;
2127             }
2128         }
2129       
2130       if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2131         {
2132           resize++;
2133           
2134           if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2135             {
2136               calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
2137               gtk_calendar_realize_week_numbers (widget);
2138             }
2139           else
2140             {
2141               gdk_window_set_user_data (private_data->week_win, NULL);
2142               gdk_window_destroy (private_data->week_win);
2143               private_data->week_win = NULL;
2144             }
2145         }
2146       
2147       if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
2148         {
2149           if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
2150             calendar->display_flags &= ~GTK_CALENDAR_WEEK_START_MONDAY;
2151           else
2152             calendar->display_flags |= GTK_CALENDAR_WEEK_START_MONDAY;
2153           
2154           gtk_calendar_compute_days (calendar);
2155           gtk_calendar_paint_main (GTK_WIDGET (calendar));
2156           if (private_data->day_name_win)
2157             gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2158         }
2159       
2160       calendar->display_flags = flags;
2161       if (resize)
2162         gtk_widget_queue_resize (GTK_WIDGET (calendar));
2163       
2164     } 
2165   else
2166     calendar->display_flags = flags;
2167   
2168 }
2169
2170 gint
2171 gtk_calendar_select_month (GtkCalendar *calendar,
2172                            guint        month,
2173                            guint        year)
2174 {
2175   g_return_val_if_fail (calendar != NULL, FALSE);
2176   g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2177   g_return_val_if_fail (month <= 11, FALSE);
2178   
2179   calendar->month = month;
2180   calendar->year  = year;
2181   
2182   gtk_calendar_compute_days (calendar);
2183   
2184   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2185     gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
2186   
2187   gtk_signal_emit (GTK_OBJECT (calendar),
2188                    gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
2189   return TRUE;
2190 }
2191
2192 void
2193 gtk_calendar_select_day (GtkCalendar *calendar,
2194                          guint        day)
2195 {
2196   g_return_if_fail (calendar != NULL);
2197   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2198   g_return_if_fail (day <= 31);
2199   
2200   /* gtk_calendar_compute_days (calendar); */
2201   
2202   /* Deselect the old day */
2203   if (calendar->selected_day > 0)
2204     {
2205       gint selected_day;
2206       
2207       selected_day = calendar->selected_day;
2208       calendar->selected_day = 0;
2209       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2210         gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day);
2211     }
2212   
2213   calendar->selected_day = day;
2214   
2215   /* Deselect the new day */
2216   if (day != 0)
2217     {
2218       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2219         gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day);
2220     }
2221   
2222   gtk_signal_emit (GTK_OBJECT (calendar),
2223                    gtk_calendar_signals[DAY_SELECTED_SIGNAL]);
2224 }
2225
2226 void
2227 gtk_calendar_clear_marks (GtkCalendar *calendar)
2228 {
2229   guint day;
2230   
2231   g_return_if_fail (calendar != NULL);
2232   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2233   
2234   for (day = 0; day < 31; day++)
2235     {
2236       calendar->marked_date[day] = FALSE;
2237     }
2238  
2239   calendar->num_marked_dates = 0;
2240  
2241   if (GTK_WIDGET_DRAWABLE (calendar))
2242     {
2243       gtk_calendar_paint_main (GTK_WIDGET (calendar));
2244     }
2245 }
2246
2247 gint
2248 gtk_calendar_mark_day (GtkCalendar *calendar,
2249                        guint        day)
2250 {
2251   g_return_val_if_fail (calendar != NULL, FALSE);
2252   g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2253   
2254   if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
2255     {
2256       calendar->marked_date[day - 1] = TRUE;
2257       calendar->num_marked_dates++;
2258     }
2259   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2260     {
2261       gtk_calendar_paint_main (GTK_WIDGET (calendar));
2262     }
2263   
2264   return TRUE;
2265 }
2266
2267 gint
2268 gtk_calendar_unmark_day (GtkCalendar *calendar,
2269                          guint        day)
2270 {
2271   g_return_val_if_fail (calendar != NULL, FALSE);
2272   g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2273   
2274   if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
2275     {
2276       calendar->marked_date[day - 1] = FALSE;
2277       calendar->num_marked_dates--;
2278     }
2279   
2280   if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2281     {
2282       gtk_calendar_paint_main (GTK_WIDGET (calendar));
2283     }
2284   
2285   return TRUE;
2286 }
2287
2288 void
2289 gtk_calendar_get_date (GtkCalendar *calendar,
2290                        guint       *year,
2291                        guint       *month,
2292                        guint       *day)
2293 {
2294   g_return_if_fail (calendar != NULL);
2295   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2296   
2297   if (year)
2298     *year = calendar->year;
2299   
2300   if (month)
2301     *month = calendar->month;
2302   
2303   if (day)
2304     *day = calendar->selected_day;
2305 }
2306
2307 static gint
2308 gtk_calendar_button_press (GtkWidget      *widget,
2309                            GdkEventButton *event)
2310 {
2311   GtkCalendar *calendar;
2312   GtkCalendarPrivateData *private_data;
2313   gint x, y;
2314   
2315   g_return_val_if_fail (widget != NULL, FALSE);
2316   g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2317   g_return_val_if_fail (event != NULL, FALSE);
2318   
2319   calendar = GTK_CALENDAR (widget);
2320   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2321   
2322   x = (gint) (event->x);
2323   y = (gint) (event->y);
2324   
2325   if (event->window == private_data->main_win)
2326     gtk_calendar_main_button (widget, event);
2327   
2328   if (event->type != GDK_BUTTON_PRESS)
2329     return FALSE; /* Double-clicks? Triple-clicks? No thanks! */
2330
2331   if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2332     gtk_calendar_set_month_prev (calendar);
2333   
2334   if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2335     gtk_calendar_set_month_next (calendar);
2336   
2337   if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2338     gtk_calendar_set_year_prev (calendar);
2339   
2340   if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2341     gtk_calendar_set_year_next (calendar);
2342   
2343   return FALSE;
2344 }
2345
2346 static gint
2347 gtk_calendar_motion_notify (GtkWidget      *widget,
2348                             GdkEventMotion *event)
2349 {
2350   GtkCalendar *calendar;
2351   GtkCalendarPrivateData *private_data;
2352   gint event_x, event_y;
2353   gint row, col;
2354   gint old_row, old_col;
2355   
2356   calendar = GTK_CALENDAR (widget);
2357   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2358   event_x = (gint) (event->x);
2359   event_y = (gint) (event->y);
2360   
2361   if (event->window == private_data->main_win)
2362     {
2363       
2364       row = row_from_y (calendar, event_y);
2365       col = column_from_x (calendar, event_x);
2366       
2367       if (row != calendar->highlight_row || calendar->highlight_col != col)
2368         {
2369           old_row = calendar->highlight_row;
2370           old_col = calendar->highlight_col;
2371           if (old_row > -1 && old_col > -1)
2372             {
2373               calendar->highlight_row = -1;
2374               calendar->highlight_col = -1;
2375               gtk_calendar_paint_day (widget, old_row, old_col);
2376             }
2377           
2378           calendar->highlight_row = row;
2379           calendar->highlight_col = col;
2380           
2381           if (row > -1 && col > -1)
2382             gtk_calendar_paint_day (widget, row, col);
2383         }
2384     }
2385   return TRUE;
2386 }
2387
2388 static gint
2389 gtk_calendar_enter_notify (GtkWidget        *widget,
2390                            GdkEventCrossing *event)
2391 {
2392   GtkCalendar *calendar;
2393   GtkCalendarPrivateData *private_data;
2394   
2395   g_return_val_if_fail (widget != NULL, FALSE);
2396   g_return_val_if_fail (event != NULL, FALSE);
2397   
2398   calendar = GTK_CALENDAR (widget);
2399   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2400   
2401   if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2402     {
2403       private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2404       gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2405     }
2406   
2407   if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2408     {
2409       private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2410       gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2411     }
2412   
2413   if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2414     {
2415       private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2416       gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2417     }
2418   
2419   if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2420     {
2421       private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2422       gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2423     }
2424   
2425   return TRUE;
2426 }
2427
2428 static gint
2429 gtk_calendar_leave_notify (GtkWidget        *widget,
2430                            GdkEventCrossing *event)
2431 {
2432   GtkCalendar *calendar;
2433   GtkCalendarPrivateData *private_data;
2434   gint row;
2435   gint col;
2436   
2437   g_return_val_if_fail (widget != NULL, FALSE);
2438   g_return_val_if_fail (event != NULL, FALSE);
2439   
2440   calendar = GTK_CALENDAR (widget);
2441   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2442   
2443   if (event->window == private_data->main_win)
2444     {
2445       row = calendar->highlight_row;
2446       col = calendar->highlight_col;
2447       calendar->highlight_row = -1;
2448       calendar->highlight_col = -1;
2449       if (row > -1 && col > -1)
2450         gtk_calendar_paint_day (widget, row, col);
2451     }
2452   
2453   if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2454     {
2455       private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2456       gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2457     }
2458   
2459   if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2460     {
2461       private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2462       gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2463     }
2464   
2465   if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2466     {
2467       private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2468       gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2469     }
2470   
2471   if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2472     {
2473       private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2474       gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2475     }
2476   
2477   return TRUE;
2478 }
2479
2480 static void
2481 gtk_calendar_paint_arrow (GtkWidget *widget,
2482                           guint      arrow)
2483 {
2484   GtkCalendarPrivateData *private_data;
2485   GdkWindow *window;
2486   GdkGC *gc;
2487   GtkCalendar *calendar;
2488   gint state;
2489   gint width, height;
2490   
2491   g_return_if_fail (widget != NULL);
2492   
2493   calendar = GTK_CALENDAR (widget);
2494   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2495
2496   if (private_data->freeze_count)
2497     {
2498       private_data->dirty_header = 1;
2499       return;
2500     }
2501   window = private_data->arrow_win[arrow];
2502   if (window)
2503     {
2504       state = private_data->arrow_state[arrow];
2505       gc = calendar->gc;
2506       
2507       gdk_window_clear (window);
2508       gdk_window_set_background (window, &(widget)->style->bg[state]);
2509       gdk_window_get_size (window, &width, &height);
2510       gdk_window_clear_area (window,
2511                              0,0,
2512                              width,height);
2513       
2514       gdk_gc_set_foreground (gc, & (widget)->style->fg[state]);
2515       
2516       if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2517         draw_arrow_left (window, gc, width/2 - 3, height/2 - 4, 8);
2518       else 
2519         draw_arrow_right (window, gc, width/2 - 2, height/2 - 4, 8);
2520       return;
2521     }
2522 }
2523
2524 void
2525 gtk_calendar_freeze (GtkCalendar *calendar)
2526 {
2527   g_return_if_fail (calendar != NULL);
2528   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2529   
2530   GTK_CALENDAR_PRIVATE_DATA (calendar)->freeze_count++;
2531 }
2532
2533 void
2534 gtk_calendar_thaw (GtkCalendar *calendar)
2535 {
2536   GtkCalendarPrivateData *private_data;
2537
2538   g_return_if_fail (calendar != NULL);
2539   g_return_if_fail (GTK_IS_CALENDAR (calendar));
2540   
2541   private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2542   
2543   if (private_data->freeze_count)
2544     if (!(--private_data->freeze_count))
2545       {
2546         if (private_data->dirty_header)
2547           if (GTK_WIDGET_DRAWABLE (calendar))
2548             gtk_calendar_paint_header (GTK_WIDGET (calendar));
2549         
2550         if (private_data->dirty_day_names)
2551           if (GTK_WIDGET_DRAWABLE (calendar))
2552             gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2553         
2554         if (private_data->dirty_week)
2555           if (GTK_WIDGET_DRAWABLE (calendar))
2556             gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar));
2557         
2558         if (private_data->dirty_main)
2559           if (GTK_WIDGET_DRAWABLE (calendar))
2560             gtk_calendar_paint_main (GTK_WIDGET (calendar));
2561       }
2562 }
2563
2564 static void
2565 gtk_calendar_set_background (GtkWidget *widget)
2566 {
2567   GtkCalendar *calendar;
2568   GtkCalendarPrivateData *private_data;
2569   gint i;
2570   
2571   g_return_if_fail (widget != NULL);
2572   g_return_if_fail (GTK_IS_CALENDAR (widget));
2573   
2574   calendar = GTK_CALENDAR (widget);
2575   private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2576
2577   if (GTK_WIDGET_REALIZED (widget))
2578     {
2579       for (i = 0; i < 4; i++)
2580         {
2581           if (private_data->arrow_win[i])
2582             gdk_window_set_background (private_data->arrow_win[i], 
2583                                        HEADER_BG_COLOR (widget));
2584         }
2585       if (private_data->header_win)
2586         gdk_window_set_background (private_data->header_win, 
2587                                    HEADER_BG_COLOR (widget));
2588       if (private_data->day_name_win)
2589         gdk_window_set_background (private_data->day_name_win, 
2590                                    BACKGROUND_COLOR (widget));
2591       if (private_data->week_win)
2592         gdk_window_set_background (private_data->week_win,
2593                                    BACKGROUND_COLOR (widget));
2594       if (private_data->main_win)
2595         gdk_window_set_background (private_data->main_win,
2596                                    BACKGROUND_COLOR (widget));
2597       if (widget->window)
2598         gdk_window_set_background (widget->window,
2599                                    BACKGROUND_COLOR (widget)); 
2600     }
2601 }
2602
2603 static void
2604 gtk_calendar_style_set (GtkWidget *widget,
2605                         GtkStyle  *previous_style)
2606 {
2607   g_return_if_fail (widget != NULL);
2608   g_return_if_fail (GTK_IS_CALENDAR (widget));
2609   
2610   if (previous_style && GTK_WIDGET_REALIZED (widget))
2611     gtk_calendar_set_background(widget);
2612 }
2613
2614 static void
2615 gtk_calendar_state_changed (GtkWidget      *widget,
2616                             GtkStateType    previous_state)
2617 {
2618   g_return_if_fail (widget != NULL);
2619   g_return_if_fail (GTK_IS_CALENDAR (widget));
2620   
2621   gtk_calendar_set_background (widget);
2622 }
2623
2624 static gint
2625 gtk_calendar_focus_in (GtkWidget         *widget,
2626                        GdkEventFocus     *event)
2627 {
2628   GtkCalendar *calendar;
2629   
2630   g_return_val_if_fail (widget != NULL, FALSE);
2631   g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2632   g_return_val_if_fail (event != NULL, FALSE);
2633   
2634   calendar = GTK_CALENDAR (widget);
2635   
2636   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2637   gtk_widget_draw_focus (widget);
2638   gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2639   
2640   return FALSE;
2641 }
2642
2643 static gint
2644 gtk_calendar_focus_out (GtkWidget         *widget,
2645                         GdkEventFocus     *event)
2646 {
2647   GtkCalendar *calendar;
2648   
2649   g_return_val_if_fail (widget != NULL, FALSE);
2650   g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2651   g_return_val_if_fail (event != NULL, FALSE);
2652   
2653   calendar = GTK_CALENDAR (widget);
2654   
2655   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2656   gtk_widget_draw_focus (widget);
2657   gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2658   
2659   return FALSE;
2660 }
2661
2662 static gint
2663 gtk_calendar_key_press (GtkWidget   *widget,
2664                         GdkEventKey *event)
2665 {
2666   GtkCalendar *calendar;
2667   gint return_val;
2668   gint old_focus_row;
2669   gint old_focus_col;
2670   gint row, col, day;
2671
2672   g_return_val_if_fail (widget != NULL, FALSE);
2673   g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2674   g_return_val_if_fail (event != NULL, FALSE);
2675   
2676   calendar = GTK_CALENDAR (widget);
2677   return_val = FALSE;
2678   
2679   old_focus_row = calendar->focus_row;
2680   old_focus_col = calendar->focus_col;
2681
2682   switch (event->keyval)
2683     {
2684     case GDK_Left:
2685       return_val = TRUE;
2686       if (event->state & GDK_CONTROL_MASK)
2687         {
2688           gtk_calendar_set_month_prev (calendar);
2689         }
2690       else
2691         {
2692           if (calendar->focus_col > 0)
2693             {
2694               calendar->focus_col--;
2695             }
2696           else if (calendar->focus_row > 0)
2697             {
2698               calendar->focus_col = 6;
2699               calendar->focus_row--;
2700             }
2701           gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2702           gtk_calendar_paint_day (widget, calendar->focus_row,
2703                                   calendar->focus_col);
2704         }
2705       break;
2706     case GDK_Right:
2707       return_val = TRUE;
2708       if (event->state & GDK_CONTROL_MASK)
2709         {
2710         gtk_calendar_set_month_next (calendar);
2711         }
2712       else
2713         {
2714           if (calendar->focus_col < 6)
2715             {
2716               calendar->focus_col++;
2717             }
2718           else if (calendar->focus_row < 5)
2719             {
2720               calendar->focus_col = 0;
2721               calendar->focus_row++;
2722             }
2723           gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2724           gtk_calendar_paint_day (widget, calendar->focus_row,
2725                                   calendar->focus_col);
2726         }
2727       break;
2728     case GDK_Up:
2729       return_val = TRUE;
2730       if (event->state & GDK_CONTROL_MASK)
2731         {
2732           gtk_calendar_set_year_prev (calendar);
2733         }
2734       else
2735         {
2736           if (calendar->focus_row > 0)
2737             {
2738               calendar->focus_row--;
2739             }
2740           gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2741           gtk_calendar_paint_day (widget, calendar->focus_row,
2742                                   calendar->focus_col);
2743         }
2744       break;
2745     case GDK_Down:
2746       return_val = TRUE;
2747       if (event->state & GDK_CONTROL_MASK)
2748         {
2749           gtk_calendar_set_year_next (calendar);
2750         }
2751       else
2752         {
2753           if (calendar->focus_row < 5)
2754             {
2755               calendar->focus_row++;
2756             }
2757           gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2758           gtk_calendar_paint_day (widget, calendar->focus_row,
2759                                   calendar->focus_col);
2760         }
2761       break;
2762     case GDK_space:
2763       row = calendar->focus_row;
2764       col = calendar->focus_col;
2765       day = calendar->day[row][col];
2766       
2767       if (row > -1 && col > -1)
2768         {
2769           gtk_calendar_freeze (calendar);         
2770
2771           if (calendar->day_month[row][col] == MONTH_PREV)
2772             {
2773               gtk_calendar_set_month_prev (calendar);
2774             }
2775           else if (calendar->day_month[row][col] == MONTH_NEXT)
2776             {
2777               gtk_calendar_set_month_next (calendar);
2778             }
2779
2780           gtk_calendar_select_day (calendar, day);
2781           
2782           for (row = 0; row < 6; row ++)
2783             for (col = 0; col < 7; col++)
2784               {
2785                 if (calendar->day_month[row][col] == MONTH_CURRENT 
2786                     && calendar->day[row][col] == day)
2787                   {
2788                     calendar->focus_row = row;
2789                     calendar->focus_col = col;
2790                   }
2791               }
2792           gtk_calendar_thaw (calendar);   
2793         }
2794     }   
2795   
2796   return return_val;
2797 }