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