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