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