1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson and Mattias Grönlund
8 * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer
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.
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.
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.
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/.
34 #ifdef HAVE_SYS_TIME_H
41 #include "gtkcalendar.h"
42 #include "gdk/gdkkeysyms.h"
44 /***************************************************************************/
45 /* The following date routines are taken from the lib_date package. Keep
46 * them seperate in case we want to update them if a newer lib_date comes
49 typedef unsigned int N_int;
50 typedef unsigned long N_long;
51 typedef signed long Z_long;
52 typedef enum { false = FALSE , true = TRUE } boolean;
54 #define and && /* logical (boolean) operators: lower case */
57 static const N_int month_length[2][13] =
59 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
60 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
63 static const N_int days_in_months[2][14] =
65 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
66 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
69 static Z_long calc_days(N_int year, N_int mm, N_int dd);
70 static N_int day_of_week(N_int year, N_int mm, N_int dd);
71 static Z_long dates_difference(N_int year1, N_int mm1, N_int dd1,
72 N_int year2, N_int mm2, N_int dd2);
73 static N_int weeks_in_year(N_int year);
78 return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
82 day_of_week(N_int year, N_int mm, N_int dd)
86 days = calc_days(year, mm, dd);
93 return( (N_int) days );
96 static N_int weeks_in_year(N_int year)
98 return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
102 check_date(N_int year, N_int mm, N_int dd)
104 if (year < 1) return(false);
105 if ((mm < 1) or (mm > 12)) return(false);
106 if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
111 week_number(N_int year, N_int mm, N_int dd)
115 first = day_of_week(year,1,1) - 1;
116 return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
121 year_to_days(N_int year)
123 return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
128 calc_days(N_int year, N_int mm, N_int dd)
132 if (year < 1) return(0L);
133 if ((mm < 1) or (mm > 12)) return(0L);
134 if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
135 return( year_to_days(--year) + days_in_months[lp][mm] + dd );
139 week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
141 if (check_date(*year,mm,dd))
143 *week = week_number(*year,mm,dd);
145 *week = weeks_in_year(--(*year));
146 else if (*week > weeks_in_year(*year))
157 dates_difference(N_int year1, N_int mm1, N_int dd1,
158 N_int year2, N_int mm2, N_int dd2)
160 return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
163 /** END OF lib_date routines ************************************************/
165 #define CALENDAR_MARGIN 0
166 #define CALENDAR_YSEP 4
167 #define CALENDAR_XSEP 4
168 #define INNER_BORDER 4
172 #define DAY_XSEP 0 /* not really good for small calendar */
173 #define DAY_YSEP 0 /* not really good for small calendar */
176 #define HEADER_FG_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
177 #define HEADER_BG_COLOR(widget) (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
178 #define DAY_NAME_COLOR(widget) (& (widget)->style->bg[GTK_STATE_SELECTED])
179 #define NORMAL_DAY_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
180 #define SELECTION_FOCUS_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
181 #define SELECTION_NO_FOCUS_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
182 #define PREV_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
183 #define NEXT_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
184 #define MARKED_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
185 #define FOREGROUND_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
186 #define BACKGROUND_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
187 #define HIGHLIGHT_BACK_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
189 #define HEADER_FONT(widget) ((widget)->style->font)
190 #define LABEL_FONT(widget) ((widget)->style->font)
191 #define DAY_FONT(widget) ((widget)->style->font)
207 MONTH_CHANGED_SIGNAL,
209 DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
217 static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 };
219 static GtkWidgetClass *parent_class = NULL;
221 typedef struct _GtkCalendarPrivateData GtkCalendarPrivateData;
222 struct _GtkCalendarPrivateData
224 GdkWindow *header_win;
225 GdkWindow *day_name_win;
228 GdkWindow *arrow_win[4];
234 guint arrow_state[4];
236 guint max_month_width;
237 guint max_year_width;
243 guint max_day_char_width;
244 guint max_day_char_ascent;
245 guint max_day_char_descent;
246 guint max_label_char_ascent;
247 guint max_label_char_descent;
248 guint max_week_char_width;
253 guint dirty_header : 1;
254 guint dirty_day_names : 1;
255 guint dirty_main : 1;
256 guint dirty_week : 1;
259 #define GTK_CALENDAR_PRIVATE_DATA(widget) (((GtkCalendarPrivateData*)(GTK_CALENDAR (widget)->private_data)))
261 typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data);
263 static void gtk_calendar_class_init (GtkCalendarClass *class);
264 static void gtk_calendar_init (GtkCalendar *calendar);
265 static void gtk_calendar_realize (GtkWidget *widget);
266 static void gtk_calendar_unrealize (GtkWidget *widget);
267 static void gtk_calendar_draw_focus (GtkWidget *widget);
268 static void gtk_calendar_size_request (GtkWidget *widget,
269 GtkRequisition *requisition);
270 static void gtk_calendar_size_allocate (GtkWidget *widget,
271 GtkAllocation *allocation);
272 static gint gtk_calendar_expose (GtkWidget *widget,
273 GdkEventExpose *event);
274 static gint gtk_calendar_button_press (GtkWidget *widget,
275 GdkEventButton *event);
276 static void gtk_calendar_main_button (GtkWidget *widget,
277 GdkEventButton *event);
278 static gint gtk_calendar_motion_notify (GtkWidget *widget,
279 GdkEventMotion *event);
280 static gint gtk_calendar_enter_notify (GtkWidget *widget,
281 GdkEventCrossing *event);
282 static gint gtk_calendar_leave_notify (GtkWidget *widget,
283 GdkEventCrossing *event);
284 static gint gtk_calendar_key_press (GtkWidget *widget,
286 static gint gtk_calendar_focus_in (GtkWidget *widget,
287 GdkEventFocus *event);
288 static gint gtk_calendar_focus_out (GtkWidget *widget,
289 GdkEventFocus *event);
290 static void gtk_calendar_state_changed (GtkWidget *widget,
291 GtkStateType previous_state);
292 static void gtk_calendar_style_set (GtkWidget *widget,
293 GtkStyle *previous_style);
294 static void gtk_calendar_paint_header (GtkWidget *widget);
295 static void gtk_calendar_paint_day_names (GtkWidget *widget);
296 static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
297 static void gtk_calendar_paint_main (GtkWidget *widget);
300 static void gtk_calendar_paint (GtkWidget *widget,
302 static void gtk_calendar_paint_arrow (GtkWidget *widget,
304 static void gtk_calendar_paint_day_num (GtkWidget *widget,
306 static void gtk_calendar_paint_day (GtkWidget *widget,
309 static void gtk_calendar_draw (GtkWidget *widget,
311 static void gtk_calendar_compute_days (GtkCalendar *calendar);
312 static gint left_x_for_column (GtkCalendar *calendar,
314 static gint top_y_for_row (GtkCalendar *calendar,
317 static char *default_abbreviated_dayname[7];
318 static char *default_monthname[12];
321 gtk_calendar_get_type (void)
323 static GtkType calendar_type = 0;
327 static const GTypeInfo calendar_info =
329 sizeof (GtkCalendarClass),
330 NULL, /* base_init */
331 NULL, /* base_finalize */
332 (GClassInitFunc) gtk_calendar_class_init,
333 NULL, /* class_finalize */
334 NULL, /* class_data */
335 sizeof (GtkCalendar),
336 16, /* n_preallocs */
337 (GInstanceInitFunc) gtk_calendar_init,
340 calendar_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCalendar", &calendar_info);
343 return calendar_type;
347 gtk_calendar_class_init (GtkCalendarClass *class)
349 GtkObjectClass *object_class;
350 GtkWidgetClass *widget_class;
352 object_class = (GtkObjectClass*) class;
353 widget_class = (GtkWidgetClass*) class;
355 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
357 widget_class->realize = gtk_calendar_realize;
358 widget_class->unrealize = gtk_calendar_unrealize;
359 widget_class->expose_event = gtk_calendar_expose;
360 widget_class->draw = gtk_calendar_draw;
361 widget_class->draw_focus = gtk_calendar_draw_focus;
362 widget_class->size_request = gtk_calendar_size_request;
363 widget_class->size_allocate = gtk_calendar_size_allocate;
364 widget_class->button_press_event = gtk_calendar_button_press;
365 widget_class->motion_notify_event = gtk_calendar_motion_notify;
366 widget_class->enter_notify_event = gtk_calendar_enter_notify;
367 widget_class->leave_notify_event = gtk_calendar_leave_notify;
368 widget_class->key_press_event = gtk_calendar_key_press;
369 widget_class->focus_in_event = gtk_calendar_focus_in;
370 widget_class->focus_out_event = gtk_calendar_focus_out;
371 widget_class->style_set = gtk_calendar_style_set;
372 widget_class->state_changed = gtk_calendar_state_changed;
374 gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
375 gtk_signal_new ("month_changed",
376 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
377 GTK_SIGNAL_OFFSET (GtkCalendarClass, month_changed),
378 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
379 gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
380 gtk_signal_new ("day_selected",
381 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
382 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected),
383 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
384 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
385 gtk_signal_new ("day_selected_double_click",
386 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
387 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected_double_click),
388 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
389 gtk_calendar_signals[PREV_MONTH_SIGNAL] =
390 gtk_signal_new ("prev_month",
391 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
392 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_month),
393 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
394 gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
395 gtk_signal_new ("next_month",
396 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
397 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_month),
398 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
399 gtk_calendar_signals[PREV_YEAR_SIGNAL] =
400 gtk_signal_new ("prev_year",
401 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
402 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_year),
403 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
404 gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
405 gtk_signal_new ("next_year",
406 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
407 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_year),
408 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
410 gtk_object_class_add_signals (object_class, gtk_calendar_signals, LAST_SIGNAL);
412 class->month_changed = NULL;
413 class->day_selected = NULL;
414 class->day_selected_double_click = NULL;
415 class->prev_month = NULL;
416 class->next_month = NULL;
417 class->prev_year = NULL;
418 class->next_year = NULL;
422 gtk_calendar_init (GtkCalendar *calendar)
430 GtkCalendarPrivateData *private_data;
432 widget = GTK_WIDGET (calendar);
433 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
435 calendar->private_data = (gpointer) malloc (sizeof (GtkCalendarPrivateData));
436 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
438 if (!default_abbreviated_dayname[0])
441 tmp_time= (i+3)*86400;
442 strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
443 default_abbreviated_dayname[i] = g_strdup (buffer);
446 if (!default_monthname[0])
450 strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
451 default_monthname[i] = g_strdup (buffer);
456 tm = localtime (&secs);
457 calendar->month = tm->tm_mon;
458 calendar->year = 1900 + tm->tm_year;
461 calendar->marked_date[i] = FALSE;
462 calendar->num_marked_dates = 0;
463 calendar->selected_day = 1;
465 calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING |
466 GTK_CALENDAR_SHOW_DAY_NAMES );
468 calendar->highlight_row = -1;
469 calendar->highlight_col = -1;
471 calendar->focus_row = -1;
472 calendar->focus_col = -1;
473 calendar->xor_gc = NULL;
475 private_data->max_year_width = 0;
476 private_data->max_month_width = 0;
477 private_data->max_day_char_width = 0;
478 private_data->max_week_char_width = 0;
480 private_data->max_day_char_ascent = 0;
481 private_data->max_day_char_descent = 0;
482 private_data->max_label_char_ascent = 0;
483 private_data->max_label_char_descent = 0;
485 private_data->arrow_width = 10;
487 private_data->freeze_count = 0;
489 private_data->dirty_header = 0;
490 private_data->dirty_day_names = 0;
491 private_data->dirty_week = 0;
492 private_data->dirty_main = 0;
496 gtk_calendar_new (void)
498 return GTK_WIDGET (gtk_type_new (GTK_TYPE_CALENDAR));
501 /* column_from_x: returns the column 0-6 that the
502 * x pixel of the xwindow is in */
504 column_from_x (GtkCalendar *calendar,
508 gint x_left, x_right;
512 for (c = 0; c < 7; c++)
514 x_left = left_x_for_column (calendar, c);
515 x_right = x_left + GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
517 if (event_x >= x_left && event_x < x_right)
528 row_height (GtkCalendar *calendar)
530 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h - CALENDAR_MARGIN
531 - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
532 ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
536 /* row_from_y: returns the row 0-5 that the
537 * y pixel of the xwindow is in */
539 row_from_y (GtkCalendar *calendar,
544 gint y_top, y_bottom;
546 height = row_height (calendar);
549 for (r = 0; r < 6; r++)
551 y_top = top_y_for_row (calendar, r);
552 y_bottom = y_top + height;
554 if (event_y >= y_top && event_y < y_bottom)
564 /* left_x_for_column: returns the x coordinate
565 * for the left of the column */
567 left_x_for_column (GtkCalendar *calendar,
573 width = GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
574 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
575 x_left = DAY_XSEP + (width + DAY_XSEP) * column;
577 x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
582 /* top_y_for_row: returns the y coordinate
583 * for the top of the row */
585 top_y_for_row (GtkCalendar *calendar,
589 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h
590 - (CALENDAR_MARGIN + (6 - row)
591 * row_height (calendar)));
594 /* This function should be done by the toolkit, but we don't like the
595 * GTK arrows because they don't look good on this widget */
597 draw_arrow_right (GdkWindow *window,
605 for (i = 0; i <= size / 2; i++)
607 gdk_draw_line (window, gc,
615 /* This function should be done by the toolkit, but we don't like the
616 * GTK arrows because they don't look good on this widget */
618 draw_arrow_left (GdkWindow *window,
626 for (i = 0; i <= size / 2; i++)
628 gdk_draw_line (window, gc,
637 gtk_calendar_set_month_prev (GtkCalendar *calendar)
641 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
644 if (calendar->month == 0)
646 calendar->month = 11;
652 month_len = month_length[leap (calendar->year)][calendar->month + 1];
654 gtk_calendar_freeze (calendar);
655 gtk_calendar_compute_days (calendar);
657 gtk_signal_emit (GTK_OBJECT (calendar),
658 gtk_calendar_signals[PREV_MONTH_SIGNAL]);
659 gtk_signal_emit (GTK_OBJECT (calendar),
660 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
662 if (month_len < calendar->selected_day)
664 calendar->selected_day = 0;
665 gtk_calendar_select_day (calendar, month_len);
669 if (calendar->selected_day < 0)
670 calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
671 gtk_calendar_select_day (calendar, calendar->selected_day);
674 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
675 gtk_calendar_thaw (calendar);
680 gtk_calendar_set_month_next (GtkCalendar *calendar)
684 g_return_if_fail (calendar != NULL);
685 g_return_if_fail (GTK_IS_WIDGET (calendar));
687 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
691 if (calendar->month == 11)
699 gtk_calendar_freeze (calendar);
700 gtk_calendar_compute_days (calendar);
701 gtk_signal_emit (GTK_OBJECT (calendar),
702 gtk_calendar_signals[NEXT_MONTH_SIGNAL]);
703 gtk_signal_emit (GTK_OBJECT (calendar),
704 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
706 month_len = month_length[leap (calendar->year)][calendar->month + 1];
708 if (month_len < calendar->selected_day)
710 calendar->selected_day = 0;
711 gtk_calendar_select_day (calendar, month_len);
714 gtk_calendar_select_day (calendar, calendar->selected_day);
716 gtk_calendar_paint (GTK_WIDGET(calendar), NULL);
717 gtk_calendar_thaw (calendar);
721 gtk_calendar_set_year_prev (GtkCalendar *calendar)
725 g_return_if_fail (calendar != NULL);
726 g_return_if_fail (GTK_IS_WIDGET (calendar));
729 gtk_calendar_freeze (calendar);
730 gtk_calendar_compute_days (calendar);
731 gtk_signal_emit (GTK_OBJECT (calendar),
732 gtk_calendar_signals[PREV_YEAR_SIGNAL]);
733 gtk_signal_emit (GTK_OBJECT (calendar),
734 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
736 month_len = month_length[leap (calendar->year)][calendar->month + 1];
738 if (month_len < calendar->selected_day)
740 calendar->selected_day = 0;
741 gtk_calendar_select_day (calendar, month_len);
744 gtk_calendar_select_day (calendar, calendar->selected_day);
746 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
747 gtk_calendar_thaw (calendar);
751 gtk_calendar_set_year_next (GtkCalendar *calendar)
756 g_return_if_fail (calendar != NULL);
757 g_return_if_fail (GTK_IS_WIDGET (calendar));
759 widget = GTK_WIDGET (calendar);
761 gtk_calendar_freeze (calendar);
764 gtk_calendar_compute_days (calendar);
765 gtk_signal_emit (GTK_OBJECT (calendar),
766 gtk_calendar_signals[NEXT_YEAR_SIGNAL]);
767 gtk_signal_emit (GTK_OBJECT (calendar),
768 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
770 month_len = month_length[leap (calendar->year)][calendar->month + 1];
772 if (month_len < calendar->selected_day)
774 calendar->selected_day = 0;
775 gtk_calendar_select_day (calendar, month_len);
778 gtk_calendar_select_day (calendar, calendar->selected_day);
780 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
781 gtk_calendar_thaw (calendar);
785 gtk_calendar_main_button (GtkWidget *widget,
786 GdkEventButton *event)
788 GtkCalendar *calendar;
792 gint old_focus_row, old_focus_col;
794 calendar = GTK_CALENDAR (widget);
796 x = (gint) (event->x);
797 y = (gint) (event->y);
799 row = row_from_y (calendar, y);
800 col = column_from_x (calendar, x);
802 /* If row or column isn't found, just return. */
803 if (row == -1 || col == -1)
806 day_month = calendar->day_month[row][col];
808 if (day_month == MONTH_CURRENT)
810 if (event->type == GDK_2BUTTON_PRESS)
811 gtk_signal_emit (GTK_OBJECT (calendar),
812 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]);
815 if (!GTK_WIDGET_HAS_FOCUS (widget))
816 gtk_widget_grab_focus (widget);
817 old_focus_row = calendar->focus_row;
818 old_focus_col = calendar->focus_col;
819 calendar->focus_row = row;
820 calendar->focus_col = col;
821 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
822 gtk_calendar_select_day (calendar, calendar->day[row][col]);
825 else if (day_month == MONTH_PREV)
826 gtk_calendar_set_month_prev (calendar);
827 else if (day_month == MONTH_NEXT)
828 gtk_calendar_set_month_next (calendar);
832 gtk_calendar_realize_arrows (GtkWidget *widget)
834 GtkCalendar *calendar;
835 GtkCalendarPrivateData *private_data;
836 GdkWindowAttr attributes;
837 gint attributes_mask;
840 g_return_if_fail (widget != NULL);
841 g_return_if_fail (GTK_IS_CALENDAR (widget));
843 calendar = GTK_CALENDAR (widget);
844 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
846 /* Arrow windows ------------------------------------- */
847 if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
848 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
850 attributes.wclass = GDK_INPUT_OUTPUT;
851 attributes.window_type = GDK_WINDOW_CHILD;
852 attributes.visual = gtk_widget_get_visual (widget);
853 attributes.colormap = gtk_widget_get_colormap (widget);
854 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
855 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
856 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
857 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
859 attributes.width = private_data->arrow_width;
860 attributes.height = private_data->header_h - 7;
861 for (i = 0; i < 4; i++)
865 case ARROW_MONTH_LEFT:
868 case ARROW_MONTH_RIGHT:
869 attributes.x = (private_data->arrow_width
870 + private_data->max_month_width);
872 case ARROW_YEAR_LEFT:
873 attributes.x = (widget->allocation.width - 4
874 - (3 + 2*private_data->arrow_width
875 + private_data->max_year_width));
877 case ARROW_YEAR_RIGHT:
878 attributes.x = (widget->allocation.width - 4
879 - 3 - private_data->arrow_width);
882 private_data->arrow_win[i] = gdk_window_new (private_data->header_win,
885 private_data->arrow_state[i] = GTK_STATE_NORMAL;
886 gdk_window_set_background (private_data->arrow_win[i],
887 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
888 gdk_window_show (private_data->arrow_win[i]);
889 gdk_window_set_user_data (private_data->arrow_win[i], widget);
894 for (i = 0; i < 4; i++)
895 private_data->arrow_win[i] = NULL;
900 gtk_calendar_realize_header (GtkWidget *widget)
902 GtkCalendar *calendar;
903 GtkCalendarPrivateData *private_data;
904 GdkWindowAttr attributes;
905 gint attributes_mask;
907 g_return_if_fail (widget != NULL);
908 g_return_if_fail (GTK_IS_CALENDAR (widget));
910 calendar = GTK_CALENDAR (widget);
911 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
913 /* Header window ------------------------------------- */
914 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
916 attributes.wclass = GDK_INPUT_OUTPUT;
917 attributes.window_type = GDK_WINDOW_CHILD;
918 attributes.visual = gtk_widget_get_visual (widget);
919 attributes.colormap = gtk_widget_get_colormap (widget);
920 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
921 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
924 attributes.width = widget->allocation.width - 4;
925 attributes.height = private_data->header_h;
926 private_data->header_win = gdk_window_new (widget->window,
927 &attributes, attributes_mask);
929 gdk_window_set_background (private_data->header_win,
930 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
931 gdk_window_show (private_data->header_win);
932 gdk_window_set_user_data (private_data->header_win, widget);
937 private_data->header_win = NULL;
939 gtk_calendar_realize_arrows (widget);
943 gtk_calendar_realize_day_names (GtkWidget *widget)
945 GtkCalendar *calendar;
946 GtkCalendarPrivateData *private_data;
947 GdkWindowAttr attributes;
948 gint attributes_mask;
950 g_return_if_fail (widget != NULL);
951 g_return_if_fail (GTK_IS_CALENDAR (widget));
953 calendar = GTK_CALENDAR (widget);
954 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
956 /* Day names window --------------------------------- */
957 if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
959 attributes.wclass = GDK_INPUT_OUTPUT;
960 attributes.window_type = GDK_WINDOW_CHILD;
961 attributes.visual = gtk_widget_get_visual (widget);
962 attributes.colormap = gtk_widget_get_colormap (widget);
963 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
964 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
965 attributes.x = (widget->style->xthickness + INNER_BORDER);
966 attributes.y = private_data->header_h + (widget->style->ythickness
968 attributes.width = (widget->allocation.width
969 - (widget->style->xthickness + INNER_BORDER)
971 attributes.height = private_data->day_name_h;
972 private_data->day_name_win = gdk_window_new (widget->window,
975 gdk_window_set_background (private_data->day_name_win,
976 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
977 gdk_window_show (private_data->day_name_win);
978 gdk_window_set_user_data (private_data->day_name_win, widget);
982 private_data->day_name_win = NULL;
987 gtk_calendar_realize_week_numbers (GtkWidget *widget)
989 GtkCalendar *calendar;
990 GtkCalendarPrivateData *private_data;
991 GdkWindowAttr attributes;
992 gint attributes_mask;
994 g_return_if_fail (widget != NULL);
995 g_return_if_fail (GTK_IS_CALENDAR (widget));
997 calendar = GTK_CALENDAR (widget);
998 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1000 /* Week number window -------------------------------- */
1001 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1003 attributes.wclass = GDK_INPUT_OUTPUT;
1004 attributes.window_type = GDK_WINDOW_CHILD;
1005 attributes.visual = gtk_widget_get_visual (widget);
1006 attributes.colormap = gtk_widget_get_colormap (widget);
1007 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1009 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1010 attributes.x = + (widget->style->xthickness + INNER_BORDER);
1011 attributes.y = (private_data->header_h + private_data->day_name_h
1012 + (widget->style->ythickness + INNER_BORDER));
1013 attributes.width = private_data->week_width;
1014 attributes.height = private_data->main_h;
1015 private_data->week_win = gdk_window_new (widget->window,
1016 &attributes, attributes_mask);
1017 gdk_window_set_background (private_data->week_win,
1018 BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1019 gdk_window_show (private_data->week_win);
1020 gdk_window_set_user_data (private_data->week_win, widget);
1024 private_data->week_win = NULL;
1029 gtk_calendar_realize (GtkWidget *widget)
1031 GtkCalendar *calendar;
1032 GtkCalendarPrivateData *private_data;
1033 GdkWindowAttr attributes;
1034 gint attributes_mask;
1037 g_return_if_fail (widget != NULL);
1038 g_return_if_fail (GTK_IS_CALENDAR (widget));
1040 calendar = GTK_CALENDAR (widget);
1041 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1043 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1044 gtk_calendar_compute_days (calendar);
1046 attributes.x = widget->allocation.x;
1047 attributes.y = widget->allocation.y;
1048 attributes.width = widget->allocation.width;
1049 attributes.height = widget->allocation.height;
1050 attributes.wclass = GDK_INPUT_OUTPUT;
1051 attributes.window_type = GDK_WINDOW_CHILD;
1052 attributes.event_mask = (gtk_widget_get_events (widget)
1053 | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK);
1054 attributes.visual = gtk_widget_get_visual (widget);
1055 attributes.colormap = gtk_widget_get_colormap (widget);
1057 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1058 widget->window = gdk_window_new (widget->parent->window,
1059 &attributes, attributes_mask);
1061 widget->style = gtk_style_attach (widget->style, widget->window);
1063 /* Header window ------------------------------------- */
1064 gtk_calendar_realize_header (widget);
1065 /* Day names window --------------------------------- */
1066 gtk_calendar_realize_day_names (widget);
1067 /* Week number window -------------------------------- */
1068 gtk_calendar_realize_week_numbers (widget);
1069 /* Main Window -------------------------------------- */
1070 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1071 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1072 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1074 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1075 attributes.x = private_data->week_width;
1078 attributes.x += (widget->style->xthickness + INNER_BORDER);
1079 attributes.y = (private_data->header_h + private_data->day_name_h
1080 + (widget->style->ythickness + INNER_BORDER));
1081 attributes.width = (widget->allocation.width - attributes.x
1082 - (widget->style->xthickness + INNER_BORDER));
1083 attributes.height = private_data->main_h;
1084 private_data->main_win = gdk_window_new (widget->window,
1085 &attributes, attributes_mask);
1086 gdk_window_set_background (private_data->main_win,
1087 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1088 gdk_window_show (private_data->main_win);
1089 gdk_window_set_user_data (private_data->main_win, widget);
1090 gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1091 gdk_window_show (widget->window);
1092 gdk_window_set_user_data (widget->window, widget);
1094 /* Set widgets gc */
1095 calendar->gc = gdk_gc_new (widget->window);
1097 values.foreground = widget->style->white;
1098 values.function = GDK_XOR;
1099 calendar->xor_gc = gdk_gc_new_with_values (widget->window,
1106 gtk_calendar_unrealize (GtkWidget *widget)
1108 GtkCalendar *calendar;
1109 GtkCalendarPrivateData *private_data;
1112 g_return_if_fail (widget != NULL);
1113 g_return_if_fail (GTK_IS_CALENDAR (widget));
1115 calendar = GTK_CALENDAR (widget);
1116 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1118 if (private_data->header_win)
1120 for (i = 0; i < 4; i++)
1122 if (private_data->arrow_win[i])
1124 gdk_window_set_user_data (private_data->arrow_win[i], NULL);
1125 gdk_window_destroy (private_data->arrow_win[i]);
1126 private_data->arrow_win[i] = NULL;
1129 gdk_window_set_user_data (private_data->header_win, NULL);
1130 gdk_window_destroy (private_data->header_win);
1131 private_data->header_win = NULL;
1134 if (private_data->week_win)
1136 gdk_window_set_user_data (private_data->week_win, NULL);
1137 gdk_window_destroy (private_data->week_win);
1138 private_data->week_win = NULL;
1141 if (private_data->main_win)
1143 gdk_window_set_user_data (private_data->main_win, NULL);
1144 gdk_window_destroy (private_data->main_win);
1145 private_data->main_win = NULL;
1148 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1149 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1153 gtk_calendar_size_request (GtkWidget *widget,
1154 GtkRequisition *requisition)
1156 GtkCalendar *calendar;
1157 GtkCalendarPrivateData *private_data;
1158 PangoLayout *layout;
1159 PangoRectangle logical_rect;
1164 gint calendar_margin = CALENDAR_MARGIN;
1165 gint header_width, main_width;
1166 gint max_header_height = 0;
1168 calendar = GTK_CALENDAR (widget);
1169 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1171 layout = gtk_widget_create_pango_layout (widget, NULL);
1174 * Calculate the requisition width for the widget.
1179 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1181 private_data->max_month_width = 0;
1182 for (i = 0; i < 12; i++)
1184 pango_layout_set_text (layout, default_monthname[i], -1);
1185 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1186 private_data->max_month_width = MAX (private_data->max_month_width,
1187 logical_rect.width + 8);
1188 max_header_height = MAX (max_header_height, logical_rect.height);
1190 private_data->max_year_width = 0;
1191 for (i=0; i<10; i++)
1193 sprintf (buffer, "%d%d%d%d", i,i,i,i);
1194 pango_layout_set_text (layout, buffer, -1);
1195 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1196 private_data->max_year_width = MAX (private_data->max_year_width,
1197 logical_rect.width + 8);
1198 max_header_height = MAX (max_header_height, logical_rect.height);
1203 private_data->max_month_width = 0;
1204 private_data->max_year_width = 0;
1207 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1208 header_width = (private_data->max_month_width
1209 + private_data->max_year_width
1212 header_width = (private_data->max_month_width
1213 + private_data->max_year_width
1214 + 4 * private_data->arrow_width + 3 * 3);
1216 /* Mainwindow labels width */
1218 private_data->max_day_char_width = 0;
1219 for (i = 0; i < 9; i++)
1221 sprintf (buffer, "%d%d", i, i);
1222 pango_layout_set_text (layout, buffer, -1);
1223 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1224 private_data->min_day_width = MAX (private_data->max_day_char_width,
1225 logical_rect.width);
1227 private_data->max_day_char_ascent = MAX (private_data->max_label_char_ascent,
1228 PANGO_ASCENT (logical_rect));
1229 private_data->max_day_char_descent = MAX (private_data->max_label_char_descent,
1230 PANGO_DESCENT (logical_rect));
1232 /* We add one to max_day_char_width to be able to make the marked day "bold" */
1233 private_data->max_day_char_width = private_data->min_day_width / 2 +1;
1235 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1236 for (i = 0; i < 7; i++)
1238 pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1239 pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1241 private_data->min_day_width = MAX (private_data->min_day_width, logical_rect.width);
1242 private_data->max_label_char_ascent = MAX (private_data->max_label_char_ascent,
1243 PANGO_ASCENT (logical_rect));
1244 private_data->max_label_char_descent = MAX (private_data->max_label_char_descent,
1245 PANGO_DESCENT (logical_rect));
1248 private_data->max_week_char_width = 0;
1249 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1250 for (i = 0; i < 9; i++)
1252 sprintf (buffer, "%d%d", i, i);
1253 pango_layout_set_text (layout, buffer, -1);
1254 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1255 private_data->max_week_char_width = MAX (private_data->max_week_char_width,
1256 logical_rect.width / 2);
1259 main_width = (7 * (private_data->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1260 + (private_data->max_week_char_width
1261 ? private_data->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2
1265 requisition->width = MAX (header_width+4, main_width + (widget->style->xthickness + INNER_BORDER) *2);
1268 * Calculate the requisition height for the widget.
1271 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1273 private_data->header_h = (max_header_height + CALENDAR_YSEP * 2);
1277 private_data->header_h = 0;
1280 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1282 private_data->day_name_h = (private_data->max_label_char_ascent
1283 + private_data->max_label_char_descent
1284 + 2 * DAY_YPAD + calendar_margin);
1285 calendar_margin = CALENDAR_YSEP;
1289 private_data->day_name_h = 0;
1292 private_data->main_h = (CALENDAR_MARGIN + calendar_margin
1293 + 6 * (private_data->max_day_char_ascent
1294 + private_data->max_day_char_descent
1299 * If we display weeknumbers we need some extra space
1302 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1304 private_data->main_h = MAX (private_data->main_h,
1305 (CALENDAR_MARGIN + calendar_margin
1306 + 6 * (private_data->max_day_char_ascent
1307 + private_data->max_day_char_descent
1312 height = (private_data->header_h + private_data->day_name_h
1313 + private_data->main_h);
1315 requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1317 g_object_unref (G_OBJECT (layout));
1321 gtk_calendar_size_allocate (GtkWidget *widget,
1322 GtkAllocation *allocation)
1324 GtkCalendar *calendar;
1325 GtkCalendarPrivateData *private_data;
1327 g_return_if_fail (widget != NULL);
1328 g_return_if_fail (GTK_IS_CALENDAR (widget));
1329 g_return_if_fail (allocation != NULL);
1331 widget->allocation = *allocation;
1333 calendar = GTK_CALENDAR (widget);
1334 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1336 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1338 private_data->day_width = (private_data->min_day_width
1339 * ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1340 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2))
1341 / (7 * private_data->min_day_width + private_data->max_week_char_width * 2));
1342 private_data->week_width = ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1343 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 )
1344 - private_data->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1348 private_data->day_width = (allocation->width
1349 - (widget->style->xthickness + INNER_BORDER) * 2
1350 - (CALENDAR_MARGIN * 2)
1351 - (DAY_XSEP * 7))/7;
1352 private_data->week_width = 0;
1355 if (GTK_WIDGET_REALIZED (widget))
1357 gdk_window_move_resize (widget->window,
1358 allocation->x, allocation->y,
1359 allocation->width, allocation->height);
1360 if (private_data->header_win)
1361 gdk_window_move_resize (private_data->header_win,
1363 allocation->width-4, private_data->header_h);
1364 if (private_data->arrow_win[ARROW_MONTH_LEFT])
1365 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1367 private_data->arrow_width,
1368 private_data->header_h - 7);
1369 if (private_data->arrow_win[ARROW_MONTH_RIGHT])
1370 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1371 (private_data->arrow_width
1372 + private_data->max_month_width),
1374 private_data->arrow_width,
1375 private_data->header_h - 7);
1376 if (private_data->arrow_win[ARROW_YEAR_LEFT])
1377 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1378 (allocation->width - 4
1379 - (3 + 2*private_data->arrow_width
1380 + private_data->max_year_width)),
1382 private_data->arrow_width,
1383 private_data->header_h - 7);
1384 if (private_data->arrow_win[ARROW_YEAR_RIGHT])
1385 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1386 (allocation->width - 4
1387 - 3 - private_data->arrow_width),
1389 private_data->arrow_width,
1390 private_data->header_h - 7);
1391 if (private_data->day_name_win)
1392 gdk_window_move_resize (private_data->day_name_win,
1393 widget->style->xthickness + INNER_BORDER,
1394 private_data->header_h + (widget->style->ythickness + INNER_BORDER),
1395 allocation->width - (widget->style->xthickness + INNER_BORDER) * 2,
1396 private_data->day_name_h);
1397 if (private_data->week_win)
1398 gdk_window_move_resize (private_data->week_win,
1399 (widget->style->xthickness + INNER_BORDER),
1400 private_data->header_h + private_data->day_name_h
1401 + (widget->style->ythickness + INNER_BORDER),
1402 private_data->week_width,
1403 private_data->main_h);
1404 gdk_window_move_resize (private_data->main_win,
1405 (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1406 + (widget->style->xthickness + INNER_BORDER),
1407 private_data->header_h + private_data->day_name_h
1408 + (widget->style->ythickness + INNER_BORDER),
1410 - (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1411 - (widget->style->xthickness + INNER_BORDER) * 2,
1412 private_data->main_h);
1417 gtk_calendar_draw_focus (GtkWidget *widget)
1419 GtkCalendar *calendar;
1420 GtkCalendarPrivateData *private_data;
1424 g_return_if_fail (widget != NULL);
1425 g_return_if_fail (GTK_IS_CALENDAR (widget));
1427 calendar = GTK_CALENDAR (widget);
1428 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1430 if (GTK_WIDGET_DRAWABLE (widget))
1434 gdk_window_get_size (widget->window, &width, &height);
1435 gdk_window_clear (widget->window);
1437 gdk_draw_rectangle (widget->window,
1438 widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1439 FALSE, x + 2, y + 2, width - 5, height - 5);
1441 gtk_draw_shadow (widget->style, widget->window,
1442 GTK_STATE_NORMAL, GTK_SHADOW_IN,
1443 x, y, width, height);
1449 gtk_calendar_expose (GtkWidget *widget,
1450 GdkEventExpose *event)
1452 GtkCalendar *calendar;
1453 GtkCalendarPrivateData *private_data;
1455 g_return_val_if_fail (widget != NULL, FALSE);
1456 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
1457 g_return_val_if_fail (event != NULL, FALSE);
1459 calendar = GTK_CALENDAR (widget);
1460 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1462 if (GTK_WIDGET_DRAWABLE (widget))
1464 if (event->window == private_data->main_win)
1465 gtk_calendar_paint_main (widget);
1467 if (event->window == private_data->header_win)
1468 gtk_calendar_paint_header (widget);
1470 if (event->window == private_data->day_name_win)
1471 gtk_calendar_paint_day_names (widget);
1473 if (event->window == private_data->week_win)
1474 gtk_calendar_paint_week_numbers (widget);
1475 if (event->window == widget->window)
1476 gtk_widget_draw_focus (widget);
1483 gtk_calendar_draw (GtkWidget *widget,
1486 g_return_if_fail (widget != NULL);
1487 g_return_if_fail (GTK_IS_CALENDAR (widget));
1488 g_return_if_fail (area != NULL);
1490 if (GTK_WIDGET_DRAWABLE (widget))
1491 gtk_calendar_paint (widget, area);
1496 gtk_calendar_paint (GtkWidget *widget,
1499 GtkCalendar *calendar;
1500 GtkCalendarPrivateData *private_data;
1502 g_return_if_fail (widget != NULL);
1503 g_return_if_fail (widget->window != NULL);
1504 g_return_if_fail (GTK_IS_CALENDAR (widget));
1506 calendar = GTK_CALENDAR (widget);
1507 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1509 if (private_data->main_win != NULL)
1510 gtk_calendar_paint_main (widget);
1512 if (private_data->header_win != NULL)
1513 gtk_calendar_paint_header (widget);
1515 if (private_data->day_name_win != NULL)
1516 gtk_calendar_paint_day_names (widget);
1518 if (private_data->week_win != NULL)
1519 gtk_calendar_paint_week_numbers (widget);
1521 gtk_widget_draw_focus (widget);
1525 gtk_calendar_paint_header (GtkWidget *widget)
1527 GtkCalendar *calendar;
1531 gint header_width, cal_height;
1532 gint max_month_width;
1533 gint max_year_width;
1534 GtkCalendarPrivateData *private_data;
1535 PangoLayout *layout;
1536 PangoRectangle logical_rect;
1538 calendar = GTK_CALENDAR (widget);
1539 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1541 if (private_data->freeze_count)
1543 private_data->dirty_header = 1;
1546 private_data->dirty_header = 0;
1550 gdk_window_clear (private_data->header_win);
1552 header_width = widget->allocation.width - 4;
1553 cal_height = widget->allocation.height;
1555 max_month_width = private_data->max_month_width;
1556 max_year_width = private_data->max_year_width;
1558 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1559 gtk_draw_shadow (widget->style, private_data->header_win,
1560 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1561 0, 0, header_width, private_data->header_h);
1564 sprintf (buffer, "%d", calendar->year);
1565 layout = gtk_widget_create_pango_layout (widget, buffer);
1566 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1569 y = (private_data->header_h - logical_rect.height) / 2;
1571 /* Draw year and its arrows */
1573 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1574 x = header_width - (3 + max_year_width
1575 - (max_year_width - logical_rect.width)/2);
1577 x = header_width - (3 + private_data->arrow_width + max_year_width
1578 - (max_year_width - logical_rect.width)/2);
1581 gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1582 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1585 sprintf (buffer, "%s", default_monthname[calendar->month]);
1586 pango_layout_set_text (layout, buffer, -1);
1587 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1589 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1590 x = 3 + (max_month_width - logical_rect.width) / 2;
1592 x = 3 + private_data->arrow_width + (max_month_width - logical_rect.width)/2;
1594 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1596 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1598 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
1599 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
1600 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
1601 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
1603 g_object_unref (G_OBJECT (layout));
1607 gtk_calendar_paint_day_names (GtkWidget *widget)
1609 GtkCalendar *calendar;
1613 int day_width, cal_width;
1616 PangoLayout *layout;
1617 PangoRectangle logical_rect;
1618 GtkCalendarPrivateData *private_data;
1620 g_return_if_fail (widget != NULL);
1621 g_return_if_fail (GTK_IS_CALENDAR (widget));
1622 calendar = GTK_CALENDAR (widget);
1623 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1627 * Handle freeze/thaw functionality
1630 if (private_data->freeze_count)
1632 private_data->dirty_day_names = 1;
1635 private_data->dirty_day_names = 0;
1641 gdk_window_clear (private_data->day_name_win);
1643 day_width = private_data->day_width;
1644 cal_width = widget->allocation.width;
1645 cal_height = widget->allocation.height;
1646 day_wid_sep = day_width + DAY_XSEP;
1649 * Draw rectangles as inverted background for the labels.
1652 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1653 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1654 CALENDAR_MARGIN, CALENDAR_MARGIN,
1655 cal_width-CALENDAR_MARGIN * 2,
1656 private_data->day_name_h - CALENDAR_MARGIN);
1658 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1659 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1661 private_data->day_name_h - CALENDAR_YSEP,
1662 private_data->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1669 layout = gtk_widget_create_pango_layout (widget, NULL);
1671 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1672 for (i = 0; i < 7; i++)
1675 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1677 sprintf (buffer, "%s", default_abbreviated_dayname[day]);
1679 pango_layout_set_text (layout, buffer, -1);
1680 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1682 gdk_draw_layout (private_data->day_name_win, gc,
1683 ((private_data->week_width ? CALENDAR_XSEP : CALENDAR_MARGIN)
1685 + private_data->week_width
1686 + (day_width - logical_rect.width)/2),
1687 CALENDAR_MARGIN + DAY_YPAD + private_data->max_label_char_ascent + logical_rect.y,
1691 g_object_unref (G_OBJECT (layout));
1695 gtk_calendar_paint_week_numbers (GtkWidget *widget)
1697 GtkCalendar *calendar;
1699 gint row, week = 0, year;
1702 gint y_loc, day_height;
1703 GtkCalendarPrivateData *private_data;
1704 PangoLayout *layout;
1705 PangoRectangle logical_rect;
1707 g_return_if_fail (widget != NULL);
1708 g_return_if_fail (widget->window != NULL);
1709 g_return_if_fail (GTK_IS_CALENDAR (widget));
1710 calendar = GTK_CALENDAR (widget);
1711 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1715 * Handle freeze/thaw functionality
1718 if (private_data->freeze_count)
1720 private_data->dirty_week = 1;
1723 private_data->dirty_week = 0;
1729 gdk_window_clear (private_data->week_win);
1732 * Draw a rectangle as inverted background for the labels.
1735 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1736 if (private_data->day_name_win)
1737 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1740 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1741 private_data->main_h - CALENDAR_MARGIN);
1743 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1746 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1747 private_data->main_h - 2 * CALENDAR_MARGIN);
1753 layout = gtk_widget_create_pango_layout (widget, NULL);
1755 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1756 day_height = row_height (calendar);
1757 for (row = 0; row < 6; row++)
1759 year = calendar->year;
1760 if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
1763 g_return_if_fail (week_of_year (&week, &year,
1764 ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
1765 + calendar->month) % 12 + 1, calendar->day[row][6]));
1767 sprintf (buffer, "%d", week);
1768 pango_layout_set_text (layout, buffer, -1);
1769 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1771 y_loc = top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
1773 x_loc = (private_data->week_width
1774 - logical_rect.width
1775 - CALENDAR_XSEP - DAY_XPAD);
1777 gdk_draw_layout (private_data->week_win, gc, x_loc, y_loc, layout);
1780 g_object_unref (G_OBJECT (layout));
1784 gtk_calendar_paint_day_num (GtkWidget *widget,
1787 GtkCalendar *calendar;
1788 gint r, c, row, col;
1790 g_return_if_fail (widget != NULL);
1791 g_return_if_fail (GTK_IS_CALENDAR (widget));
1793 calendar = GTK_CALENDAR (widget);
1797 for (r = 0; r < 6; r++)
1798 for (c = 0; c < 7; c++)
1799 if (calendar->day_month[r][c] == MONTH_CURRENT &&
1800 calendar->day[r][c] == day)
1806 g_return_if_fail (row != -1);
1807 g_return_if_fail (col != -1);
1809 gtk_calendar_paint_day (widget, row, col);
1813 gtk_calendar_paint_day (GtkWidget *widget,
1817 GtkCalendar *calendar;
1827 GtkCalendarPrivateData *private_data;
1828 PangoLayout *layout;
1829 PangoRectangle logical_rect;
1831 g_return_if_fail (widget != NULL);
1832 g_return_if_fail (GTK_IS_CALENDAR (widget));
1833 g_return_if_fail (row < 6);
1834 g_return_if_fail (col < 7);
1835 calendar = GTK_CALENDAR (widget);
1836 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1839 * Handle freeze/thaw functionality
1842 if (private_data->freeze_count)
1844 private_data->dirty_main = 1;
1848 day_height = row_height (calendar);
1850 day_xspace = private_data->day_width - private_data->max_day_char_width*2;
1852 day = calendar->day[row][col];
1854 x_left = left_x_for_column (calendar, col);
1855 x_loc = x_left + private_data->day_width / 2 + private_data->max_day_char_width;
1857 y_top = top_y_for_row (calendar, row);
1859 gdk_window_clear_area (private_data->main_win, x_left, y_top,
1860 private_data->day_width, day_height);
1864 if (calendar->day_month[row][col] == MONTH_PREV)
1866 gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar)));
1868 else if (calendar->day_month[row][col] == MONTH_NEXT)
1870 gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar)));
1875 if (calendar->highlight_row == row && calendar->highlight_col == col)
1877 gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar)));
1878 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1879 private_data->day_width, day_height);
1882 if (calendar->selected_day == day)
1884 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->bg[GTK_STATE_SELECTED]));
1885 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1886 private_data->day_width, day_height);
1889 if (calendar->marked_date[day-1])
1890 gdk_gc_set_foreground (gc, MARKED_COLOR (GTK_WIDGET (calendar)));
1892 gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar)));
1894 if (calendar->selected_day == day)
1895 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_STATE_SELECTED]));
1897 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_WIDGET_STATE (calendar)]));
1901 sprintf (buffer, "%d", day);
1902 layout = gtk_widget_create_pango_layout (widget, buffer);
1903 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1905 x_loc -= logical_rect.width;
1907 y_loc = y_top + (day_height - logical_rect.height) / 2;
1908 gdk_draw_layout (private_data->main_win, gc,
1909 x_loc, y_loc, layout);
1910 if (calendar->marked_date[day-1]
1911 && calendar->day_month[row][col] == MONTH_CURRENT)
1912 gdk_draw_layout (private_data->main_win, gc,
1913 x_loc-1, y_loc, layout);
1915 if (GTK_WIDGET_HAS_FOCUS (calendar)
1916 && calendar->focus_row == row && calendar->focus_col == col)
1918 gdk_draw_rectangle (private_data->main_win, calendar->xor_gc,
1919 FALSE, x_left, y_top,
1920 private_data->day_width-1, day_height-1);
1923 g_object_unref (G_OBJECT (layout));
1928 gtk_calendar_paint_main (GtkWidget *widget)
1930 GtkCalendar *calendar;
1931 GtkCalendarPrivateData *private_data;
1934 g_return_if_fail (widget != NULL);
1935 g_return_if_fail (widget->window != NULL);
1936 g_return_if_fail (GTK_IS_CALENDAR (widget));
1938 calendar = GTK_CALENDAR (widget);
1939 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1941 if (private_data->freeze_count)
1943 private_data->dirty_main = 1;
1946 private_data->dirty_main = 0;
1947 gdk_window_clear (private_data->main_win);
1949 /* gtk_calendar_compute_days (calendar); */ /* REMOVE later */
1951 for (col = 0; col < 7; col++)
1952 for (row = 0; row < 6; row++)
1953 gtk_calendar_paint_day (widget, row, col);
1957 gtk_calendar_compute_days (GtkCalendar *calendar)
1961 gint ndays_in_month;
1962 gint ndays_in_prev_month;
1968 g_return_if_fail (calendar != NULL);
1969 g_return_if_fail (GTK_IS_CALENDAR (calendar));
1971 year = calendar->year;
1972 month = calendar->month + 1;
1974 ndays_in_month = month_length[leap (year)][month];
1976 first_day = day_of_week (year, month, 1);
1978 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1984 /* Compute days of previous month */
1986 ndays_in_prev_month = month_length[leap (year)][month-1];
1988 ndays_in_prev_month = month_length[leap (year)][12];
1989 day = ndays_in_prev_month - first_day + 1;
1994 for (col = 0; col < first_day; col++)
1996 calendar->day[row][col] = day;
1997 calendar->day_month[row][col] = MONTH_PREV;
2002 /* Compute days of current month */
2004 for (day = 1; day <= ndays_in_month; day++)
2006 calendar->day[row][col] = day;
2007 calendar->day_month[row][col] = MONTH_CURRENT;
2017 /* Compute days of next month */
2019 for (; row <= 5; row++)
2021 for (; col <= 6; col++)
2023 calendar->day[row][col] = day;
2024 calendar->day_month[row][col] = MONTH_NEXT;
2031 /* ----------------------------------------------------------------------
2032 NAME: gtk_calendar_display_options
2033 DESCRIPTION: Set display options (whether to display the
2034 heading and the month headings)
2036 flags is can be an XOR of:
2037 GTK_CALENDAR_SHOW_HEADING
2038 GTK_CALENDAR_SHOW_DAY_NAMES
2039 GTK_CALENDAR_NO_MONTH_CHANGE
2040 GTK_CALENDAR_SHOW_WEEK_NUMBERS
2041 GTK_CALENDAR_WEEK_START_MONDAY
2042 ---------------------------------------------------------------------- */
2045 gtk_calendar_display_options (GtkCalendar *calendar,
2046 GtkCalendarDisplayOptions flags)
2048 GtkCalendarPrivateData *private_data;
2053 g_return_if_fail (calendar != NULL);
2054 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2056 widget = GTK_WIDGET (calendar);
2057 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2059 if (GTK_WIDGET_REALIZED (widget))
2061 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2064 if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
2065 && (private_data->header_win))
2067 calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
2068 gtk_calendar_realize_arrows (widget);
2072 for (i = 0; i < 4; i++)
2074 if (private_data->arrow_win[i])
2076 gdk_window_set_user_data (private_data->arrow_win[i],
2078 gdk_window_destroy (private_data->arrow_win[i]);
2079 private_data->arrow_win[i] = NULL;
2085 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2089 if (flags & GTK_CALENDAR_SHOW_HEADING)
2091 calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
2092 gtk_calendar_realize_header (widget);
2096 for (i = 0; i < 4; i++)
2098 if (private_data->arrow_win[i])
2100 gdk_window_set_user_data (private_data->arrow_win[i],
2102 gdk_window_destroy (private_data->arrow_win[i]);
2103 private_data->arrow_win[i] = NULL;
2106 gdk_window_set_user_data (private_data->header_win, NULL);
2107 gdk_window_destroy (private_data->header_win);
2108 private_data->header_win = NULL;
2113 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2117 if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
2119 calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
2120 gtk_calendar_realize_day_names (widget);
2124 gdk_window_set_user_data (private_data->day_name_win, NULL);
2125 gdk_window_destroy (private_data->day_name_win);
2126 private_data->day_name_win = NULL;
2130 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2134 if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2136 calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
2137 gtk_calendar_realize_week_numbers (widget);
2141 gdk_window_set_user_data (private_data->week_win, NULL);
2142 gdk_window_destroy (private_data->week_win);
2143 private_data->week_win = NULL;
2147 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
2149 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
2150 calendar->display_flags &= ~GTK_CALENDAR_WEEK_START_MONDAY;
2152 calendar->display_flags |= GTK_CALENDAR_WEEK_START_MONDAY;
2154 gtk_calendar_compute_days (calendar);
2155 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2156 if (private_data->day_name_win)
2157 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2160 calendar->display_flags = flags;
2162 gtk_widget_queue_resize (GTK_WIDGET (calendar));
2166 calendar->display_flags = flags;
2171 gtk_calendar_select_month (GtkCalendar *calendar,
2175 g_return_val_if_fail (calendar != NULL, FALSE);
2176 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2177 g_return_val_if_fail (month <= 11, FALSE);
2179 calendar->month = month;
2180 calendar->year = year;
2182 gtk_calendar_compute_days (calendar);
2184 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2185 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
2187 gtk_signal_emit (GTK_OBJECT (calendar),
2188 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
2193 gtk_calendar_select_day (GtkCalendar *calendar,
2196 g_return_if_fail (calendar != NULL);
2197 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2198 g_return_if_fail (day <= 31);
2200 /* gtk_calendar_compute_days (calendar); */
2202 /* Deselect the old day */
2203 if (calendar->selected_day > 0)
2207 selected_day = calendar->selected_day;
2208 calendar->selected_day = 0;
2209 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2210 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day);
2213 calendar->selected_day = day;
2215 /* Deselect the new day */
2218 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2219 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day);
2222 gtk_signal_emit (GTK_OBJECT (calendar),
2223 gtk_calendar_signals[DAY_SELECTED_SIGNAL]);
2227 gtk_calendar_clear_marks (GtkCalendar *calendar)
2231 g_return_if_fail (calendar != NULL);
2232 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2234 for (day = 0; day < 31; day++)
2236 calendar->marked_date[day] = FALSE;
2239 calendar->num_marked_dates = 0;
2241 if (GTK_WIDGET_DRAWABLE (calendar))
2243 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2248 gtk_calendar_mark_day (GtkCalendar *calendar,
2251 g_return_val_if_fail (calendar != NULL, FALSE);
2252 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2254 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
2256 calendar->marked_date[day - 1] = TRUE;
2257 calendar->num_marked_dates++;
2259 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2261 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2268 gtk_calendar_unmark_day (GtkCalendar *calendar,
2271 g_return_val_if_fail (calendar != NULL, FALSE);
2272 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2274 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
2276 calendar->marked_date[day - 1] = FALSE;
2277 calendar->num_marked_dates--;
2280 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2282 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2289 gtk_calendar_get_date (GtkCalendar *calendar,
2294 g_return_if_fail (calendar != NULL);
2295 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2298 *year = calendar->year;
2301 *month = calendar->month;
2304 *day = calendar->selected_day;
2308 gtk_calendar_button_press (GtkWidget *widget,
2309 GdkEventButton *event)
2311 GtkCalendar *calendar;
2312 GtkCalendarPrivateData *private_data;
2315 g_return_val_if_fail (widget != NULL, FALSE);
2316 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2317 g_return_val_if_fail (event != NULL, FALSE);
2319 calendar = GTK_CALENDAR (widget);
2320 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2322 x = (gint) (event->x);
2323 y = (gint) (event->y);
2325 if (event->window == private_data->main_win)
2326 gtk_calendar_main_button (widget, event);
2328 if (event->type != GDK_BUTTON_PRESS)
2329 return FALSE; /* Double-clicks? Triple-clicks? No thanks! */
2331 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2332 gtk_calendar_set_month_prev (calendar);
2334 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2335 gtk_calendar_set_month_next (calendar);
2337 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2338 gtk_calendar_set_year_prev (calendar);
2340 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2341 gtk_calendar_set_year_next (calendar);
2347 gtk_calendar_motion_notify (GtkWidget *widget,
2348 GdkEventMotion *event)
2350 GtkCalendar *calendar;
2351 GtkCalendarPrivateData *private_data;
2352 gint event_x, event_y;
2354 gint old_row, old_col;
2356 calendar = GTK_CALENDAR (widget);
2357 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2358 event_x = (gint) (event->x);
2359 event_y = (gint) (event->y);
2361 if (event->window == private_data->main_win)
2364 row = row_from_y (calendar, event_y);
2365 col = column_from_x (calendar, event_x);
2367 if (row != calendar->highlight_row || calendar->highlight_col != col)
2369 old_row = calendar->highlight_row;
2370 old_col = calendar->highlight_col;
2371 if (old_row > -1 && old_col > -1)
2373 calendar->highlight_row = -1;
2374 calendar->highlight_col = -1;
2375 gtk_calendar_paint_day (widget, old_row, old_col);
2378 calendar->highlight_row = row;
2379 calendar->highlight_col = col;
2381 if (row > -1 && col > -1)
2382 gtk_calendar_paint_day (widget, row, col);
2389 gtk_calendar_enter_notify (GtkWidget *widget,
2390 GdkEventCrossing *event)
2392 GtkCalendar *calendar;
2393 GtkCalendarPrivateData *private_data;
2395 g_return_val_if_fail (widget != NULL, FALSE);
2396 g_return_val_if_fail (event != NULL, FALSE);
2398 calendar = GTK_CALENDAR (widget);
2399 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2401 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2403 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2404 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2407 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2409 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2410 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2413 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2415 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2416 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2419 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2421 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2422 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2429 gtk_calendar_leave_notify (GtkWidget *widget,
2430 GdkEventCrossing *event)
2432 GtkCalendar *calendar;
2433 GtkCalendarPrivateData *private_data;
2437 g_return_val_if_fail (widget != NULL, FALSE);
2438 g_return_val_if_fail (event != NULL, FALSE);
2440 calendar = GTK_CALENDAR (widget);
2441 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2443 if (event->window == private_data->main_win)
2445 row = calendar->highlight_row;
2446 col = calendar->highlight_col;
2447 calendar->highlight_row = -1;
2448 calendar->highlight_col = -1;
2449 if (row > -1 && col > -1)
2450 gtk_calendar_paint_day (widget, row, col);
2453 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2455 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2456 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2459 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2461 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2462 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2465 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2467 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2468 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2471 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2473 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2474 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2481 gtk_calendar_paint_arrow (GtkWidget *widget,
2484 GtkCalendarPrivateData *private_data;
2487 GtkCalendar *calendar;
2491 g_return_if_fail (widget != NULL);
2493 calendar = GTK_CALENDAR (widget);
2494 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2496 if (private_data->freeze_count)
2498 private_data->dirty_header = 1;
2501 window = private_data->arrow_win[arrow];
2504 state = private_data->arrow_state[arrow];
2507 gdk_window_clear (window);
2508 gdk_window_set_background (window, &(widget)->style->bg[state]);
2509 gdk_window_get_size (window, &width, &height);
2510 gdk_window_clear_area (window,
2514 gdk_gc_set_foreground (gc, & (widget)->style->fg[state]);
2516 if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2517 draw_arrow_left (window, gc, width/2 - 3, height/2 - 4, 8);
2519 draw_arrow_right (window, gc, width/2 - 2, height/2 - 4, 8);
2525 gtk_calendar_freeze (GtkCalendar *calendar)
2527 g_return_if_fail (calendar != NULL);
2528 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2530 GTK_CALENDAR_PRIVATE_DATA (calendar)->freeze_count++;
2534 gtk_calendar_thaw (GtkCalendar *calendar)
2536 GtkCalendarPrivateData *private_data;
2538 g_return_if_fail (calendar != NULL);
2539 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2541 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2543 if (private_data->freeze_count)
2544 if (!(--private_data->freeze_count))
2546 if (private_data->dirty_header)
2547 if (GTK_WIDGET_DRAWABLE (calendar))
2548 gtk_calendar_paint_header (GTK_WIDGET (calendar));
2550 if (private_data->dirty_day_names)
2551 if (GTK_WIDGET_DRAWABLE (calendar))
2552 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2554 if (private_data->dirty_week)
2555 if (GTK_WIDGET_DRAWABLE (calendar))
2556 gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar));
2558 if (private_data->dirty_main)
2559 if (GTK_WIDGET_DRAWABLE (calendar))
2560 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2565 gtk_calendar_set_background (GtkWidget *widget)
2567 GtkCalendar *calendar;
2568 GtkCalendarPrivateData *private_data;
2571 g_return_if_fail (widget != NULL);
2572 g_return_if_fail (GTK_IS_CALENDAR (widget));
2574 calendar = GTK_CALENDAR (widget);
2575 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2577 if (GTK_WIDGET_REALIZED (widget))
2579 for (i = 0; i < 4; i++)
2581 if (private_data->arrow_win[i])
2582 gdk_window_set_background (private_data->arrow_win[i],
2583 HEADER_BG_COLOR (widget));
2585 if (private_data->header_win)
2586 gdk_window_set_background (private_data->header_win,
2587 HEADER_BG_COLOR (widget));
2588 if (private_data->day_name_win)
2589 gdk_window_set_background (private_data->day_name_win,
2590 BACKGROUND_COLOR (widget));
2591 if (private_data->week_win)
2592 gdk_window_set_background (private_data->week_win,
2593 BACKGROUND_COLOR (widget));
2594 if (private_data->main_win)
2595 gdk_window_set_background (private_data->main_win,
2596 BACKGROUND_COLOR (widget));
2598 gdk_window_set_background (widget->window,
2599 BACKGROUND_COLOR (widget));
2604 gtk_calendar_style_set (GtkWidget *widget,
2605 GtkStyle *previous_style)
2607 g_return_if_fail (widget != NULL);
2608 g_return_if_fail (GTK_IS_CALENDAR (widget));
2610 if (previous_style && GTK_WIDGET_REALIZED (widget))
2611 gtk_calendar_set_background(widget);
2615 gtk_calendar_state_changed (GtkWidget *widget,
2616 GtkStateType previous_state)
2618 g_return_if_fail (widget != NULL);
2619 g_return_if_fail (GTK_IS_CALENDAR (widget));
2621 gtk_calendar_set_background (widget);
2625 gtk_calendar_focus_in (GtkWidget *widget,
2626 GdkEventFocus *event)
2628 GtkCalendar *calendar;
2630 g_return_val_if_fail (widget != NULL, FALSE);
2631 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2632 g_return_val_if_fail (event != NULL, FALSE);
2634 calendar = GTK_CALENDAR (widget);
2636 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2637 gtk_widget_draw_focus (widget);
2638 gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2644 gtk_calendar_focus_out (GtkWidget *widget,
2645 GdkEventFocus *event)
2647 GtkCalendar *calendar;
2649 g_return_val_if_fail (widget != NULL, FALSE);
2650 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2651 g_return_val_if_fail (event != NULL, FALSE);
2653 calendar = GTK_CALENDAR (widget);
2655 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2656 gtk_widget_draw_focus (widget);
2657 gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2663 gtk_calendar_key_press (GtkWidget *widget,
2666 GtkCalendar *calendar;
2672 g_return_val_if_fail (widget != NULL, FALSE);
2673 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2674 g_return_val_if_fail (event != NULL, FALSE);
2676 calendar = GTK_CALENDAR (widget);
2679 old_focus_row = calendar->focus_row;
2680 old_focus_col = calendar->focus_col;
2682 switch (event->keyval)
2686 if (event->state & GDK_CONTROL_MASK)
2688 gtk_calendar_set_month_prev (calendar);
2692 if (calendar->focus_col > 0)
2694 calendar->focus_col--;
2696 else if (calendar->focus_row > 0)
2698 calendar->focus_col = 6;
2699 calendar->focus_row--;
2701 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2702 gtk_calendar_paint_day (widget, calendar->focus_row,
2703 calendar->focus_col);
2708 if (event->state & GDK_CONTROL_MASK)
2710 gtk_calendar_set_month_next (calendar);
2714 if (calendar->focus_col < 6)
2716 calendar->focus_col++;
2718 else if (calendar->focus_row < 5)
2720 calendar->focus_col = 0;
2721 calendar->focus_row++;
2723 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2724 gtk_calendar_paint_day (widget, calendar->focus_row,
2725 calendar->focus_col);
2730 if (event->state & GDK_CONTROL_MASK)
2732 gtk_calendar_set_year_prev (calendar);
2736 if (calendar->focus_row > 0)
2738 calendar->focus_row--;
2740 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2741 gtk_calendar_paint_day (widget, calendar->focus_row,
2742 calendar->focus_col);
2747 if (event->state & GDK_CONTROL_MASK)
2749 gtk_calendar_set_year_next (calendar);
2753 if (calendar->focus_row < 5)
2755 calendar->focus_row++;
2757 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2758 gtk_calendar_paint_day (widget, calendar->focus_row,
2759 calendar->focus_col);
2763 row = calendar->focus_row;
2764 col = calendar->focus_col;
2765 day = calendar->day[row][col];
2767 if (row > -1 && col > -1)
2769 gtk_calendar_freeze (calendar);
2771 if (calendar->day_month[row][col] == MONTH_PREV)
2773 gtk_calendar_set_month_prev (calendar);
2775 else if (calendar->day_month[row][col] == MONTH_NEXT)
2777 gtk_calendar_set_month_next (calendar);
2780 gtk_calendar_select_day (calendar, day);
2782 for (row = 0; row < 6; row ++)
2783 for (col = 0; col < 7; col++)
2785 if (calendar->day_month[row][col] == MONTH_CURRENT
2786 && calendar->day[row][col] == day)
2788 calendar->focus_row = row;
2789 calendar->focus_col = col;
2792 gtk_calendar_thaw (calendar);