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