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 Groenlund
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
37 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
50 #include <glib/gprintf.h>
52 #undef GTK_DISABLE_DEPRECATED
53 #include "gtkcalendar.h"
54 #define GTK_DISABLE_DEPRECATED
59 #include "gtkmarshalers.h"
60 #include "gtkprivate.h"
62 #include "gdk/gdkkeysyms.h"
65 /***************************************************************************/
66 /* The following date routines are taken from the lib_date package. Keep
67 * them separate in case we want to update them if a newer lib_date comes
70 typedef unsigned int N_int;
71 typedef unsigned long N_long;
72 typedef signed long Z_long;
73 typedef enum { false = FALSE , true = TRUE } boolean;
75 #define and && /* logical (boolean) operators: lower case */
78 static const N_int month_length[2][13] =
80 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
81 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
84 static const N_int days_in_months[2][14] =
86 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
87 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
90 static Z_long calc_days(N_int year, N_int mm, N_int dd);
91 static N_int day_of_week(N_int year, N_int mm, N_int dd);
92 static Z_long dates_difference(N_int year1, N_int mm1, N_int dd1,
93 N_int year2, N_int mm2, N_int dd2);
94 static N_int weeks_in_year(N_int year);
99 return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
103 day_of_week(N_int year, N_int mm, N_int dd)
107 days = calc_days(year, mm, dd);
114 return( (N_int) days );
117 static N_int weeks_in_year(N_int year)
119 return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
123 check_date(N_int year, N_int mm, N_int dd)
125 if (year < 1) return(false);
126 if ((mm < 1) or (mm > 12)) return(false);
127 if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
132 week_number(N_int year, N_int mm, N_int dd)
136 first = day_of_week(year,1,1) - 1;
137 return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
142 year_to_days(N_int year)
144 return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
149 calc_days(N_int year, N_int mm, N_int dd)
153 if (year < 1) return(0L);
154 if ((mm < 1) or (mm > 12)) return(0L);
155 if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
156 return( year_to_days(--year) + days_in_months[lp][mm] + dd );
160 week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
162 if (check_date(*year,mm,dd))
164 *week = week_number(*year,mm,dd);
166 *week = weeks_in_year(--(*year));
167 else if (*week > weeks_in_year(*year))
178 dates_difference(N_int year1, N_int mm1, N_int dd1,
179 N_int year2, N_int mm2, N_int dd2)
181 return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
184 /*** END OF lib_date routines ********************************************/
186 /* Spacing around day/week headers and main area, inside those windows */
187 #define CALENDAR_MARGIN 0
188 /* Spacing around day/week headers and main area, outside those windows */
189 #define INNER_BORDER 4
190 /* Separation between day headers and main area */
191 #define CALENDAR_YSEP 4
192 /* Separation between week headers and main area */
193 #define CALENDAR_XSEP 4
195 #define DAY_XSEP 0 /* not really good for small calendar */
196 #define DAY_YSEP 0 /* not really good for small calendar */
199 #define HEADER_FG_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
200 #define HEADER_BG_COLOR(widget) (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
201 #define SELECTED_BG_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE])
202 #define SELECTED_FG_COLOR(widget) (& (widget)->style->text[GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE])
203 #define NORMAL_DAY_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
204 #define PREV_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
205 #define NEXT_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
206 #define MARKED_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
207 #define BACKGROUND_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
208 #define HIGHLIGHT_BACK_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
224 MONTH_CHANGED_SIGNAL,
226 DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
242 PROP_NO_MONTH_CHANGE,
243 PROP_SHOW_WEEK_NUMBERS,
247 static guint gtk_calendar_signals[LAST_SIGNAL] = { 0 };
249 struct _GtkCalendarPrivate
251 GdkWindow *header_win;
252 GdkWindow *day_name_win;
255 GdkWindow *arrow_win[4];
261 guint arrow_state[4];
263 guint max_month_width;
264 guint max_year_width;
270 guint max_day_char_width;
271 guint max_day_char_ascent;
272 guint max_day_char_descent;
273 guint max_label_char_ascent;
274 guint max_label_char_descent;
275 guint max_week_char_width;
278 guint year_before : 1;
280 guint need_timer : 1;
283 guint drag_highlight : 1;
294 #define GTK_CALENDAR_GET_PRIVATE(widget) (GTK_CALENDAR (widget)->priv)
296 static void gtk_calendar_finalize (GObject *calendar);
297 static void gtk_calendar_destroy (GtkObject *calendar);
298 static void gtk_calendar_set_property (GObject *object,
302 static void gtk_calendar_get_property (GObject *object,
307 static void gtk_calendar_realize (GtkWidget *widget);
308 static void gtk_calendar_unrealize (GtkWidget *widget);
309 static void gtk_calendar_size_request (GtkWidget *widget,
310 GtkRequisition *requisition);
311 static void gtk_calendar_size_allocate (GtkWidget *widget,
312 GtkAllocation *allocation);
313 static gboolean gtk_calendar_expose (GtkWidget *widget,
314 GdkEventExpose *event);
315 static gboolean gtk_calendar_button_press (GtkWidget *widget,
316 GdkEventButton *event);
317 static gboolean gtk_calendar_button_release (GtkWidget *widget,
318 GdkEventButton *event);
319 static gboolean gtk_calendar_motion_notify (GtkWidget *widget,
320 GdkEventMotion *event);
321 static gboolean gtk_calendar_enter_notify (GtkWidget *widget,
322 GdkEventCrossing *event);
323 static gboolean gtk_calendar_leave_notify (GtkWidget *widget,
324 GdkEventCrossing *event);
325 static gboolean gtk_calendar_scroll (GtkWidget *widget,
326 GdkEventScroll *event);
327 static gboolean gtk_calendar_key_press (GtkWidget *widget,
329 static gboolean gtk_calendar_focus_out (GtkWidget *widget,
330 GdkEventFocus *event);
331 static void gtk_calendar_grab_notify (GtkWidget *widget,
332 gboolean was_grabbed);
333 static void gtk_calendar_state_changed (GtkWidget *widget,
334 GtkStateType previous_state);
335 static void gtk_calendar_style_set (GtkWidget *widget,
336 GtkStyle *previous_style);
338 static void gtk_calendar_drag_data_get (GtkWidget *widget,
339 GdkDragContext *context,
340 GtkSelectionData *selection_data,
343 static void gtk_calendar_drag_data_received (GtkWidget *widget,
344 GdkDragContext *context,
347 GtkSelectionData *selection_data,
350 static gboolean gtk_calendar_drag_motion (GtkWidget *widget,
351 GdkDragContext *context,
355 static void gtk_calendar_drag_leave (GtkWidget *widget,
356 GdkDragContext *context,
358 static gboolean gtk_calendar_drag_drop (GtkWidget *widget,
359 GdkDragContext *context,
364 static void calendar_start_spinning (GtkCalendar *calendar,
366 static void calendar_stop_spinning (GtkCalendar *calendar);
368 static void calendar_invalidate_day (GtkCalendar *widget,
371 static void calendar_invalidate_day_num (GtkCalendar *widget,
373 static void calendar_invalidate_arrow (GtkCalendar *widget,
376 static void calendar_compute_days (GtkCalendar *calendar);
378 static char *default_abbreviated_dayname[7];
379 static char *default_monthname[12];
381 G_DEFINE_TYPE (GtkCalendar, gtk_calendar, GTK_TYPE_WIDGET)
384 gtk_calendar_class_init (GtkCalendarClass *class)
386 GObjectClass *gobject_class;
387 GtkObjectClass *object_class;
388 GtkWidgetClass *widget_class;
390 gobject_class = (GObjectClass*) class;
391 object_class = (GtkObjectClass*) class;
392 widget_class = (GtkWidgetClass*) class;
394 gobject_class->set_property = gtk_calendar_set_property;
395 gobject_class->get_property = gtk_calendar_get_property;
396 gobject_class->finalize = gtk_calendar_finalize;
398 object_class->destroy = gtk_calendar_destroy;
400 widget_class->realize = gtk_calendar_realize;
401 widget_class->unrealize = gtk_calendar_unrealize;
402 widget_class->expose_event = gtk_calendar_expose;
403 widget_class->size_request = gtk_calendar_size_request;
404 widget_class->size_allocate = gtk_calendar_size_allocate;
405 widget_class->button_press_event = gtk_calendar_button_press;
406 widget_class->button_release_event = gtk_calendar_button_release;
407 widget_class->motion_notify_event = gtk_calendar_motion_notify;
408 widget_class->enter_notify_event = gtk_calendar_enter_notify;
409 widget_class->leave_notify_event = gtk_calendar_leave_notify;
410 widget_class->key_press_event = gtk_calendar_key_press;
411 widget_class->scroll_event = gtk_calendar_scroll;
412 widget_class->style_set = gtk_calendar_style_set;
413 widget_class->state_changed = gtk_calendar_state_changed;
414 widget_class->grab_notify = gtk_calendar_grab_notify;
415 widget_class->focus_out_event = gtk_calendar_focus_out;
417 widget_class->drag_data_get = gtk_calendar_drag_data_get;
418 widget_class->drag_motion = gtk_calendar_drag_motion;
419 widget_class->drag_leave = gtk_calendar_drag_leave;
420 widget_class->drag_drop = gtk_calendar_drag_drop;
421 widget_class->drag_data_received = gtk_calendar_drag_data_received;
423 g_object_class_install_property (gobject_class,
425 g_param_spec_int ("year",
427 P_("The selected year"),
429 GTK_PARAM_READWRITE));
430 g_object_class_install_property (gobject_class,
432 g_param_spec_int ("month",
434 P_("The selected month (as a number between 0 and 11)"),
436 GTK_PARAM_READWRITE));
437 g_object_class_install_property (gobject_class,
439 g_param_spec_int ("day",
441 P_("The selected day (as a number between 1 and 31, or 0 to unselect the currently selected day)"),
443 GTK_PARAM_READWRITE));
446 * GtkCalendar:show-heading:
448 * Determines whether a heading is displayed.
452 g_object_class_install_property (gobject_class,
454 g_param_spec_boolean ("show-heading",
456 P_("If TRUE, a heading is displayed"),
458 GTK_PARAM_READWRITE));
461 * GtkCalendar:show-day-names:
463 * Determines whether day names are displayed.
467 g_object_class_install_property (gobject_class,
469 g_param_spec_boolean ("show-day-names",
470 P_("Show Day Names"),
471 P_("If TRUE, day names are displayed"),
473 GTK_PARAM_READWRITE));
475 * GtkCalendar:no-month-change:
477 * Determines whether the selected month can be changed.
481 g_object_class_install_property (gobject_class,
482 PROP_NO_MONTH_CHANGE,
483 g_param_spec_boolean ("no-month-change",
484 P_("No Month Change"),
485 P_("If TRUE, the selected month cannot be changed"),
487 GTK_PARAM_READWRITE));
490 * GtkCalendar:show-week-numbers:
492 * Determines whether week numbers are displayed.
496 g_object_class_install_property (gobject_class,
497 PROP_SHOW_WEEK_NUMBERS,
498 g_param_spec_boolean ("show-week-numbers",
499 P_("Show Week Numbers"),
500 P_("If TRUE, week numbers are displayed"),
502 GTK_PARAM_READWRITE));
504 gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
505 g_signal_new (I_("month_changed"),
506 G_OBJECT_CLASS_TYPE (gobject_class),
508 G_STRUCT_OFFSET (GtkCalendarClass, month_changed),
510 _gtk_marshal_VOID__VOID,
512 gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
513 g_signal_new (I_("day_selected"),
514 G_OBJECT_CLASS_TYPE (gobject_class),
516 G_STRUCT_OFFSET (GtkCalendarClass, day_selected),
518 _gtk_marshal_VOID__VOID,
520 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
521 g_signal_new (I_("day_selected_double_click"),
522 G_OBJECT_CLASS_TYPE (gobject_class),
524 G_STRUCT_OFFSET (GtkCalendarClass, day_selected_double_click),
526 _gtk_marshal_VOID__VOID,
528 gtk_calendar_signals[PREV_MONTH_SIGNAL] =
529 g_signal_new (I_("prev_month"),
530 G_OBJECT_CLASS_TYPE (gobject_class),
532 G_STRUCT_OFFSET (GtkCalendarClass, prev_month),
534 _gtk_marshal_VOID__VOID,
536 gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
537 g_signal_new (I_("next_month"),
538 G_OBJECT_CLASS_TYPE (gobject_class),
540 G_STRUCT_OFFSET (GtkCalendarClass, next_month),
542 _gtk_marshal_VOID__VOID,
544 gtk_calendar_signals[PREV_YEAR_SIGNAL] =
545 g_signal_new (I_("prev_year"),
546 G_OBJECT_CLASS_TYPE (gobject_class),
548 G_STRUCT_OFFSET (GtkCalendarClass, prev_year),
550 _gtk_marshal_VOID__VOID,
552 gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
553 g_signal_new (I_("next_year"),
554 G_OBJECT_CLASS_TYPE (gobject_class),
556 G_STRUCT_OFFSET (GtkCalendarClass, next_year),
558 _gtk_marshal_VOID__VOID,
561 g_type_class_add_private (gobject_class, sizeof (GtkCalendarPrivate));
565 gtk_calendar_init (GtkCalendar *calendar)
567 GtkWidget *widget = GTK_WIDGET (calendar);
573 wchar_t wbuffer[100];
577 GtkCalendarPrivate *priv;
579 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
581 gint week_1stday = 0;
582 gint first_weekday = 1;
588 priv = calendar->priv = G_TYPE_INSTANCE_GET_PRIVATE (calendar,
592 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
594 if (!default_abbreviated_dayname[0])
598 tmp_time= (i+3)*86400;
599 strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
600 default_abbreviated_dayname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
602 if (G_WIN32_HAVE_WIDECHAR_API ())
604 if (!GetLocaleInfoW (GetThreadLocale (), LOCALE_SABBREVDAYNAME1 + (i+6)%7,
605 wbuffer, G_N_ELEMENTS (wbuffer)))
606 default_abbreviated_dayname[i] = g_strdup_printf ("(%d)", i);
608 default_abbreviated_dayname[i] = g_utf16_to_utf8 (wbuffer, -1, NULL, NULL, NULL);
612 if (!GetLocaleInfoA (GetThreadLocale (),
613 (LOCALE_SABBREVDAYNAME1 + (i+6)%7) | LOCALE_USE_CP_ACP,
614 buffer, G_N_ELEMENTS (buffer)))
615 default_abbreviated_dayname[i] = g_strdup_printf ("(%d)", i);
617 default_abbreviated_dayname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
622 if (!default_monthname[0])
627 strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
628 default_monthname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
630 if (G_WIN32_HAVE_WIDECHAR_API ())
632 if (!GetLocaleInfoW (GetThreadLocale (), LOCALE_SMONTHNAME1 + i,
633 wbuffer, G_N_ELEMENTS (wbuffer)))
634 default_monthname[i] = g_strdup_printf ("(%d)", i);
636 default_monthname[i] = g_utf16_to_utf8 (wbuffer, -1, NULL, NULL, NULL);
640 if (!GetLocaleInfoA (GetThreadLocale (),
641 (LOCALE_SMONTHNAME1 + i) | LOCALE_USE_CP_ACP,
642 buffer, G_N_ELEMENTS (buffer)))
643 default_monthname[i] = g_strdup_printf ("(%d)", i);
645 default_monthname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
652 tm = localtime (&secs);
653 calendar->month = tm->tm_mon;
654 calendar->year = 1900 + tm->tm_year;
657 calendar->marked_date[i] = FALSE;
658 calendar->num_marked_dates = 0;
659 calendar->selected_day = tm->tm_mday;
661 calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING |
662 GTK_CALENDAR_SHOW_DAY_NAMES );
664 calendar->highlight_row = -1;
665 calendar->highlight_col = -1;
667 calendar->focus_row = -1;
668 calendar->focus_col = -1;
670 priv->max_year_width = 0;
671 priv->max_month_width = 0;
672 priv->max_day_char_width = 0;
673 priv->max_week_char_width = 0;
675 priv->max_day_char_ascent = 0;
676 priv->max_day_char_descent = 0;
677 priv->max_label_char_ascent = 0;
678 priv->max_label_char_descent = 0;
680 priv->arrow_width = 10;
682 priv->need_timer = 0;
684 priv->click_child = -1;
687 priv->drag_highlight = 0;
689 gtk_drag_dest_set (widget, 0, NULL, 0, GDK_ACTION_COPY);
690 gtk_drag_dest_add_text_targets (widget);
692 priv->year_before = 0;
694 /* Translate to calendar:YM if you want years to be displayed
695 * before months; otherwise translate to calendar:MY.
696 * Do *not* translate it to anything else, if it
697 * it isn't calendar:YM or calendar:MY it will not work.
699 * Note that this flipping is in top the text direction flipping,
700 * so if you have a default text direction of RTL and YM, then
701 * the year will appear on the right.
703 year_before = _("calendar:MY");
704 if (strcmp (year_before, "calendar:YM") == 0)
705 priv->year_before = 1;
706 else if (strcmp (year_before, "calendar:MY") != 0)
707 g_warning ("Whoever translated calendar:MY did so wrongly.\n");
709 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
710 langinfo = nl_langinfo (_NL_TIME_FIRST_WEEKDAY);
711 first_weekday = langinfo[0];
712 langinfo = nl_langinfo (_NL_TIME_WEEK_1STDAY);
713 week_origin = GPOINTER_TO_INT (langinfo);
714 if (week_origin == 19971130) /* Sunday */
716 else if (week_origin == 19971201) /* Monday */
719 g_warning ("Unknown value of _NL_TIME_WEEK_1STDAY.\n");
721 priv->week_start = (week_1stday + first_weekday - 1) % 7;
723 /* Translate to calendar:week_start:0 if you want Sunday to be the
724 * first day of the week to calendar:week_start:1 if you want Monday
725 * to be the first day of the week, and so on.
727 week_start = _("calendar:week_start:0");
729 if (strncmp (week_start, "calendar:week_start:", 20) == 0)
730 priv->week_start = *(week_start + 20) - '0';
732 priv->week_start = -1;
734 if (priv->week_start < 0 || priv->week_start > 6)
736 g_warning ("Whoever translated calendar:week_start:0 did so wrongly.\n");
737 priv->week_start = 0;
741 calendar_compute_days (calendar);
745 /****************************************
746 * Utility Functions *
747 ****************************************/
750 calendar_set_month_next (GtkCalendar *calendar)
754 g_return_if_fail (GTK_IS_WIDGET (calendar));
756 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
760 if (calendar->month == 11)
768 calendar_compute_days (calendar);
769 g_signal_emit (calendar,
770 gtk_calendar_signals[NEXT_MONTH_SIGNAL],
772 g_signal_emit (calendar,
773 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
776 month_len = month_length[leap (calendar->year)][calendar->month + 1];
778 if (month_len < calendar->selected_day)
780 calendar->selected_day = 0;
781 gtk_calendar_select_day (calendar, month_len);
784 gtk_calendar_select_day (calendar, calendar->selected_day);
786 gtk_widget_queue_draw (GTK_WIDGET (calendar));
790 calendar_set_year_prev (GtkCalendar *calendar)
794 g_return_if_fail (GTK_IS_WIDGET (calendar));
797 calendar_compute_days (calendar);
798 g_signal_emit (calendar,
799 gtk_calendar_signals[PREV_YEAR_SIGNAL],
801 g_signal_emit (calendar,
802 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
805 month_len = month_length[leap (calendar->year)][calendar->month + 1];
807 if (month_len < calendar->selected_day)
809 calendar->selected_day = 0;
810 gtk_calendar_select_day (calendar, month_len);
813 gtk_calendar_select_day (calendar, calendar->selected_day);
815 gtk_widget_queue_draw (GTK_WIDGET (calendar));
819 calendar_set_year_next (GtkCalendar *calendar)
823 g_return_if_fail (GTK_IS_WIDGET (calendar));
826 calendar_compute_days (calendar);
827 g_signal_emit (calendar,
828 gtk_calendar_signals[NEXT_YEAR_SIGNAL],
830 g_signal_emit (calendar,
831 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
834 month_len = month_length[leap (calendar->year)][calendar->month + 1];
836 if (month_len < calendar->selected_day)
838 calendar->selected_day = 0;
839 gtk_calendar_select_day (calendar, month_len);
842 gtk_calendar_select_day (calendar, calendar->selected_day);
844 gtk_widget_queue_draw (GTK_WIDGET (calendar));
848 calendar_compute_days (GtkCalendar *calendar)
850 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (GTK_WIDGET (calendar));
854 gint ndays_in_prev_month;
860 g_return_if_fail (GTK_IS_CALENDAR (calendar));
862 year = calendar->year;
863 month = calendar->month + 1;
865 ndays_in_month = month_length[leap (year)][month];
867 first_day = day_of_week (year, month, 1);
868 first_day = (first_day + 7 - priv->week_start) % 7;
870 /* Compute days of previous month */
872 ndays_in_prev_month = month_length[leap (year)][month-1];
874 ndays_in_prev_month = month_length[leap (year)][12];
875 day = ndays_in_prev_month - first_day + 1;
880 for (col = 0; col < first_day; col++)
882 calendar->day[row][col] = day;
883 calendar->day_month[row][col] = MONTH_PREV;
888 /* Compute days of current month */
890 for (day = 1; day <= ndays_in_month; day++)
892 calendar->day[row][col] = day;
893 calendar->day_month[row][col] = MONTH_CURRENT;
903 /* Compute days of next month */
905 for (; row <= 5; row++)
907 for (; col <= 6; col++)
909 calendar->day[row][col] = day;
910 calendar->day_month[row][col] = MONTH_NEXT;
918 calendar_select_and_focus_day (GtkCalendar *calendar,
921 gint old_focus_row = calendar->focus_row;
922 gint old_focus_col = calendar->focus_col;
926 for (row = 0; row < 6; row ++)
927 for (col = 0; col < 7; col++)
929 if (calendar->day_month[row][col] == MONTH_CURRENT
930 && calendar->day[row][col] == day)
932 calendar->focus_row = row;
933 calendar->focus_col = col;
937 if (old_focus_row != -1 && old_focus_col != -1)
938 calendar_invalidate_day (calendar, old_focus_row, old_focus_col);
940 gtk_calendar_select_day (calendar, day);
944 /****************************************
945 * Layout computation utilities *
946 ****************************************/
949 calendar_row_height (GtkCalendar *calendar)
951 return (GTK_CALENDAR_GET_PRIVATE (calendar)->main_h - CALENDAR_MARGIN
952 - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
953 ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
957 /* calendar_left_x_for_column: returns the x coordinate
958 * for the left of the column */
960 calendar_left_x_for_column (GtkCalendar *calendar,
966 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
969 width = GTK_CALENDAR_GET_PRIVATE (calendar)->day_width;
970 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
971 x_left = CALENDAR_XSEP + (width + DAY_XSEP) * column;
973 x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
978 /* column_from_x: returns the column 0-6 that the
979 * x pixel of the xwindow is in */
981 calendar_column_from_x (GtkCalendar *calendar,
985 gint x_left, x_right;
989 for (c = 0; c < 7; c++)
991 x_left = calendar_left_x_for_column (calendar, c);
992 x_right = x_left + GTK_CALENDAR_GET_PRIVATE (calendar)->day_width;
994 if (event_x >= x_left && event_x < x_right)
1004 /* calendar_top_y_for_row: returns the y coordinate
1005 * for the top of the row */
1007 calendar_top_y_for_row (GtkCalendar *calendar,
1011 return (GTK_CALENDAR_GET_PRIVATE (calendar)->main_h
1012 - (CALENDAR_MARGIN + (6 - row)
1013 * calendar_row_height (calendar)));
1016 /* row_from_y: returns the row 0-5 that the
1017 * y pixel of the xwindow is in */
1019 calendar_row_from_y (GtkCalendar *calendar,
1024 gint y_top, y_bottom;
1026 height = calendar_row_height (calendar);
1029 for (r = 0; r < 6; r++)
1031 y_top = calendar_top_y_for_row (calendar, r);
1032 y_bottom = y_top + height;
1034 if (event_y >= y_top && event_y < y_bottom)
1045 calendar_arrow_rectangle (GtkCalendar *calendar,
1049 GtkWidget *widget = GTK_WIDGET (calendar);
1050 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1053 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1054 year_left = priv->year_before;
1056 year_left = !priv->year_before;
1059 rect->width = priv->arrow_width;
1060 rect->height = priv->header_h - 7;
1064 case ARROW_MONTH_LEFT:
1066 rect->x = (widget->allocation.width - 2 * widget->style->xthickness
1067 - (3 + 2*priv->arrow_width
1068 + priv->max_month_width));
1072 case ARROW_MONTH_RIGHT:
1074 rect->x = (widget->allocation.width - 2 * widget->style->xthickness
1075 - 3 - priv->arrow_width);
1077 rect->x = (priv->arrow_width
1078 + priv->max_month_width);
1080 case ARROW_YEAR_LEFT:
1084 rect->x = (widget->allocation.width - 2 * widget->style->xthickness
1085 - (3 + 2*priv->arrow_width
1086 + priv->max_year_width));
1088 case ARROW_YEAR_RIGHT:
1090 rect->x = (priv->arrow_width
1091 + priv->max_year_width);
1093 rect->x = (widget->allocation.width - 2 * widget->style->xthickness
1094 - 3 - priv->arrow_width);
1100 calendar_day_rectangle (GtkCalendar *calendar,
1105 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1107 rect->x = calendar_left_x_for_column (calendar, col);
1108 rect->y = calendar_top_y_for_row (calendar, row);
1109 rect->height = calendar_row_height (calendar);
1110 rect->width = priv->day_width;
1114 calendar_set_month_prev (GtkCalendar *calendar)
1118 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1121 if (calendar->month == 0)
1123 calendar->month = 11;
1129 month_len = month_length[leap (calendar->year)][calendar->month + 1];
1131 calendar_compute_days (calendar);
1133 g_signal_emit (calendar,
1134 gtk_calendar_signals[PREV_MONTH_SIGNAL],
1136 g_signal_emit (calendar,
1137 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
1140 if (month_len < calendar->selected_day)
1142 calendar->selected_day = 0;
1143 gtk_calendar_select_day (calendar, month_len);
1147 if (calendar->selected_day < 0)
1148 calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
1149 gtk_calendar_select_day (calendar, calendar->selected_day);
1152 gtk_widget_queue_draw (GTK_WIDGET (calendar));
1156 /****************************************
1157 * Basic object methods *
1158 ****************************************/
1161 gtk_calendar_finalize (GObject *object)
1163 (* G_OBJECT_CLASS (gtk_calendar_parent_class)->finalize) (object);
1167 gtk_calendar_destroy (GtkObject *object)
1169 calendar_stop_spinning (GTK_CALENDAR (object));
1171 GTK_OBJECT_CLASS (gtk_calendar_parent_class)->destroy (object);
1176 calendar_set_display_option (GtkCalendar *calendar,
1177 GtkCalendarDisplayOptions flag,
1180 GtkCalendarDisplayOptions flags;
1182 flags = calendar->display_flags | flag;
1184 flags = calendar->display_flags & ~flag;
1185 gtk_calendar_display_options (calendar, flags);
1189 calendar_get_display_option (GtkCalendar *calendar,
1190 GtkCalendarDisplayOptions flag)
1192 return (calendar->display_flags & flag) != 0;
1196 gtk_calendar_set_property (GObject *object,
1198 const GValue *value,
1201 GtkCalendar *calendar;
1203 calendar = GTK_CALENDAR (object);
1208 gtk_calendar_select_month (calendar,
1210 g_value_get_int (value));
1213 gtk_calendar_select_month (calendar,
1214 g_value_get_int (value),
1218 gtk_calendar_select_day (calendar,
1219 g_value_get_int (value));
1221 case PROP_SHOW_HEADING:
1222 calendar_set_display_option (calendar,
1223 GTK_CALENDAR_SHOW_HEADING,
1224 g_value_get_boolean (value));
1226 case PROP_SHOW_DAY_NAMES:
1227 calendar_set_display_option (calendar,
1228 GTK_CALENDAR_SHOW_DAY_NAMES,
1229 g_value_get_boolean (value));
1231 case PROP_NO_MONTH_CHANGE:
1232 calendar_set_display_option (calendar,
1233 GTK_CALENDAR_NO_MONTH_CHANGE,
1234 g_value_get_boolean (value));
1236 case PROP_SHOW_WEEK_NUMBERS:
1237 calendar_set_display_option (calendar,
1238 GTK_CALENDAR_SHOW_WEEK_NUMBERS,
1239 g_value_get_boolean (value));
1242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1248 gtk_calendar_get_property (GObject *object,
1253 GtkCalendar *calendar;
1255 calendar = GTK_CALENDAR (object);
1260 g_value_set_int (value, calendar->year);
1263 g_value_set_int (value, calendar->month);
1266 g_value_set_int (value, calendar->selected_day);
1268 case PROP_SHOW_HEADING:
1269 g_value_set_boolean (value, calendar_get_display_option (calendar,
1270 GTK_CALENDAR_SHOW_HEADING));
1272 case PROP_SHOW_DAY_NAMES:
1273 g_value_set_boolean (value, calendar_get_display_option (calendar,
1274 GTK_CALENDAR_SHOW_DAY_NAMES));
1276 case PROP_NO_MONTH_CHANGE:
1277 g_value_set_boolean (value, calendar_get_display_option (calendar,
1278 GTK_CALENDAR_NO_MONTH_CHANGE));
1280 case PROP_SHOW_WEEK_NUMBERS:
1281 g_value_set_boolean (value, calendar_get_display_option (calendar,
1282 GTK_CALENDAR_SHOW_WEEK_NUMBERS));
1285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1291 /****************************************
1293 ****************************************/
1296 calendar_realize_arrows (GtkCalendar *calendar)
1298 GtkWidget *widget = GTK_WIDGET (calendar);
1299 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1300 GdkWindowAttr attributes;
1301 gint attributes_mask;
1304 /* Arrow windows ------------------------------------- */
1305 if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1306 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
1308 attributes.wclass = GDK_INPUT_OUTPUT;
1309 attributes.window_type = GDK_WINDOW_CHILD;
1310 attributes.visual = gtk_widget_get_visual (widget);
1311 attributes.colormap = gtk_widget_get_colormap (widget);
1312 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1313 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1314 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1315 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1316 for (i = 0; i < 4; i++)
1319 calendar_arrow_rectangle (calendar, i, &rect);
1321 attributes.x = rect.x;
1322 attributes.y = rect.y;
1323 attributes.width = rect.width;
1324 attributes.height = rect.height;
1325 priv->arrow_win[i] = gdk_window_new (priv->header_win,
1328 if (GTK_WIDGET_IS_SENSITIVE (widget))
1329 priv->arrow_state[i] = GTK_STATE_NORMAL;
1331 priv->arrow_state[i] = GTK_STATE_INSENSITIVE;
1332 gdk_window_set_background (priv->arrow_win[i],
1333 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
1334 gdk_window_show (priv->arrow_win[i]);
1335 gdk_window_set_user_data (priv->arrow_win[i], widget);
1340 for (i = 0; i < 4; i++)
1341 priv->arrow_win[i] = NULL;
1346 calendar_realize_header (GtkCalendar *calendar)
1348 GtkWidget *widget = GTK_WIDGET (calendar);
1349 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1350 GdkWindowAttr attributes;
1351 gint attributes_mask;
1353 /* Header window ------------------------------------- */
1354 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1356 attributes.wclass = GDK_INPUT_OUTPUT;
1357 attributes.window_type = GDK_WINDOW_CHILD;
1358 attributes.visual = gtk_widget_get_visual (widget);
1359 attributes.colormap = gtk_widget_get_colormap (widget);
1360 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1361 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1362 attributes.x = widget->style->xthickness;
1363 attributes.y = widget->style->ythickness;
1364 attributes.width = widget->allocation.width - 2 * attributes.x;
1365 attributes.height = priv->header_h - 2 * attributes.y;
1366 priv->header_win = gdk_window_new (widget->window,
1367 &attributes, attributes_mask);
1369 gdk_window_set_background (priv->header_win,
1370 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
1371 gdk_window_show (priv->header_win);
1372 gdk_window_set_user_data (priv->header_win, widget);
1377 priv->header_win = NULL;
1379 calendar_realize_arrows (calendar);
1383 calendar_realize_day_names (GtkCalendar *calendar)
1385 GtkWidget *widget = GTK_WIDGET (calendar);
1386 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1387 GdkWindowAttr attributes;
1388 gint attributes_mask;
1390 /* Day names window --------------------------------- */
1391 if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1393 attributes.wclass = GDK_INPUT_OUTPUT;
1394 attributes.window_type = GDK_WINDOW_CHILD;
1395 attributes.visual = gtk_widget_get_visual (widget);
1396 attributes.colormap = gtk_widget_get_colormap (widget);
1397 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1398 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1399 attributes.x = (widget->style->xthickness + INNER_BORDER);
1400 attributes.y = priv->header_h + (widget->style->ythickness
1402 attributes.width = (widget->allocation.width
1403 - (widget->style->xthickness + INNER_BORDER)
1405 attributes.height = priv->day_name_h;
1406 priv->day_name_win = gdk_window_new (widget->window,
1409 gdk_window_set_background (priv->day_name_win,
1410 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1411 gdk_window_show (priv->day_name_win);
1412 gdk_window_set_user_data (priv->day_name_win, widget);
1416 priv->day_name_win = NULL;
1421 calendar_realize_week_numbers (GtkCalendar *calendar)
1423 GtkWidget *widget = GTK_WIDGET (calendar);
1424 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1425 GdkWindowAttr attributes;
1426 gint attributes_mask;
1428 /* Week number window -------------------------------- */
1429 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1431 attributes.wclass = GDK_INPUT_OUTPUT;
1432 attributes.window_type = GDK_WINDOW_CHILD;
1433 attributes.visual = gtk_widget_get_visual (widget);
1434 attributes.colormap = gtk_widget_get_colormap (widget);
1435 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1437 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1438 attributes.x = widget->style->xthickness + INNER_BORDER;
1439 attributes.y = (priv->header_h + priv->day_name_h
1440 + (widget->style->ythickness + INNER_BORDER));
1441 attributes.width = priv->week_width;
1442 attributes.height = priv->main_h;
1443 priv->week_win = gdk_window_new (widget->window,
1444 &attributes, attributes_mask);
1445 gdk_window_set_background (priv->week_win,
1446 BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1447 gdk_window_show (priv->week_win);
1448 gdk_window_set_user_data (priv->week_win, widget);
1452 priv->week_win = NULL;
1457 gtk_calendar_realize (GtkWidget *widget)
1459 GtkCalendar *calendar = GTK_CALENDAR (widget);
1460 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
1461 GdkWindowAttr attributes;
1462 gint attributes_mask;
1464 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1466 attributes.x = widget->allocation.x;
1467 attributes.y = widget->allocation.y;
1468 attributes.width = widget->allocation.width;
1469 attributes.height = widget->allocation.height;
1470 attributes.wclass = GDK_INPUT_OUTPUT;
1471 attributes.window_type = GDK_WINDOW_CHILD;
1472 attributes.event_mask = (gtk_widget_get_events (widget)
1473 | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK | GDK_SCROLL_MASK);
1474 attributes.visual = gtk_widget_get_visual (widget);
1475 attributes.colormap = gtk_widget_get_colormap (widget);
1477 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1478 widget->window = gdk_window_new (widget->parent->window,
1479 &attributes, attributes_mask);
1481 widget->style = gtk_style_attach (widget->style, widget->window);
1483 /* Header window ------------------------------------- */
1484 calendar_realize_header (calendar);
1485 /* Day names window --------------------------------- */
1486 calendar_realize_day_names (calendar);
1487 /* Week number window -------------------------------- */
1488 calendar_realize_week_numbers (calendar);
1489 /* Main Window -------------------------------------- */
1490 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1491 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1492 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1494 attributes.x = priv->week_width + (widget->style->ythickness + INNER_BORDER);
1495 attributes.y = (priv->header_h + priv->day_name_h
1496 + (widget->style->ythickness + INNER_BORDER));
1497 attributes.width = (widget->allocation.width - attributes.x
1498 - (widget->style->xthickness + INNER_BORDER));
1499 attributes.height = priv->main_h;
1500 priv->main_win = gdk_window_new (widget->window,
1501 &attributes, attributes_mask);
1502 gdk_window_set_background (priv->main_win,
1503 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1504 gdk_window_show (priv->main_win);
1505 gdk_window_set_user_data (priv->main_win, widget);
1506 gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1507 gdk_window_show (widget->window);
1508 gdk_window_set_user_data (widget->window, widget);
1512 gtk_calendar_unrealize (GtkWidget *widget)
1514 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
1517 if (priv->header_win)
1519 for (i = 0; i < 4; i++)
1521 if (priv->arrow_win[i])
1523 gdk_window_set_user_data (priv->arrow_win[i], NULL);
1524 gdk_window_destroy (priv->arrow_win[i]);
1525 priv->arrow_win[i] = NULL;
1528 gdk_window_set_user_data (priv->header_win, NULL);
1529 gdk_window_destroy (priv->header_win);
1530 priv->header_win = NULL;
1535 gdk_window_set_user_data (priv->week_win, NULL);
1536 gdk_window_destroy (priv->week_win);
1537 priv->week_win = NULL;
1542 gdk_window_set_user_data (priv->main_win, NULL);
1543 gdk_window_destroy (priv->main_win);
1544 priv->main_win = NULL;
1546 if (priv->day_name_win)
1548 gdk_window_set_user_data (priv->day_name_win, NULL);
1549 gdk_window_destroy (priv->day_name_win);
1550 priv->day_name_win = NULL;
1553 if (GTK_WIDGET_CLASS (gtk_calendar_parent_class)->unrealize)
1554 (* GTK_WIDGET_CLASS (gtk_calendar_parent_class)->unrealize) (widget);
1558 /****************************************
1559 * Size Request and Allocate *
1560 ****************************************/
1563 gtk_calendar_size_request (GtkWidget *widget,
1564 GtkRequisition *requisition)
1566 GtkCalendar *calendar = GTK_CALENDAR (widget);
1567 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
1568 PangoLayout *layout;
1569 PangoRectangle logical_rect;
1574 gint calendar_margin = CALENDAR_MARGIN;
1575 gint header_width, main_width;
1576 gint max_header_height = 0;
1580 gtk_widget_style_get (GTK_WIDGET (widget),
1581 "focus-line-width", &focus_width,
1582 "focus-padding", &focus_padding,
1585 layout = gtk_widget_create_pango_layout (widget, NULL);
1588 * Calculate the requisition width for the widget.
1593 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1595 priv->max_month_width = 0;
1596 for (i = 0; i < 12; i++)
1598 pango_layout_set_text (layout, default_monthname[i], -1);
1599 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1600 priv->max_month_width = MAX (priv->max_month_width,
1601 logical_rect.width + 8);
1602 max_header_height = MAX (max_header_height, logical_rect.height);
1605 priv->max_year_width = 0;
1606 /* Translators: This is a text measurement template.
1607 * Translate it to the widest year text.
1609 * Don't include the prefix "year measurement template|"
1610 * in the translation.
1612 * If you don't understand this, leave it as "2000"
1614 pango_layout_set_text (layout, Q_("year measurement template|2000"), -1);
1615 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1616 priv->max_year_width = MAX (priv->max_year_width,
1617 logical_rect.width + 8);
1618 max_header_height = MAX (max_header_height, logical_rect.height);
1622 priv->max_month_width = 0;
1623 priv->max_year_width = 0;
1626 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1627 header_width = (priv->max_month_width
1628 + priv->max_year_width
1631 header_width = (priv->max_month_width
1632 + priv->max_year_width
1633 + 4 * priv->arrow_width + 3 * 3);
1635 /* Mainwindow labels width */
1637 priv->max_day_char_width = 0;
1638 priv->min_day_width = 0;
1639 priv->max_label_char_ascent = 0;
1640 priv->max_label_char_descent = 0;
1642 for (i = 0; i < 9; i++)
1644 g_snprintf (buffer, sizeof (buffer), "%d%d", i, i);
1645 pango_layout_set_text (layout, buffer, -1);
1646 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1647 priv->min_day_width = MAX (priv->min_day_width,
1648 logical_rect.width);
1650 priv->max_day_char_ascent = MAX (priv->max_label_char_ascent,
1651 PANGO_ASCENT (logical_rect));
1652 priv->max_day_char_descent = MAX (priv->max_label_char_descent,
1653 PANGO_DESCENT (logical_rect));
1655 /* We add one to max_day_char_width to be able to make the marked day "bold" */
1656 priv->max_day_char_width = priv->min_day_width / 2 + 1;
1658 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1659 for (i = 0; i < 7; i++)
1661 pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1662 pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1664 priv->min_day_width = MAX (priv->min_day_width, logical_rect.width);
1665 priv->max_label_char_ascent = MAX (priv->max_label_char_ascent,
1666 PANGO_ASCENT (logical_rect));
1667 priv->max_label_char_descent = MAX (priv->max_label_char_descent,
1668 PANGO_DESCENT (logical_rect));
1671 priv->max_week_char_width = 0;
1672 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1673 for (i = 0; i < 9; i++)
1675 g_snprintf (buffer, sizeof (buffer), "%d%d", i, i);
1676 pango_layout_set_text (layout, buffer, -1);
1677 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1678 priv->max_week_char_width = MAX (priv->max_week_char_width,
1679 logical_rect.width / 2);
1682 main_width = (7 * (priv->min_day_width + (focus_padding + focus_width) * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1683 + (priv->max_week_char_width
1684 ? priv->max_week_char_width * 2 + (focus_padding + focus_width) * 2 + CALENDAR_XSEP * 2
1688 requisition->width = MAX (header_width, main_width + INNER_BORDER * 2) + widget->style->xthickness * 2;
1691 * Calculate the requisition height for the widget.
1694 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1696 priv->header_h = (max_header_height + CALENDAR_YSEP * 2);
1703 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1705 priv->day_name_h = (priv->max_label_char_ascent
1706 + priv->max_label_char_descent
1707 + 2 * (focus_padding + focus_width) + calendar_margin);
1708 calendar_margin = CALENDAR_YSEP;
1712 priv->day_name_h = 0;
1715 priv->main_h = (CALENDAR_MARGIN + calendar_margin
1716 + 6 * (priv->max_day_char_ascent
1717 + priv->max_day_char_descent
1718 + 2 * (focus_padding + focus_width))
1721 height = (priv->header_h + priv->day_name_h
1724 requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1726 g_object_unref (layout);
1730 gtk_calendar_size_allocate (GtkWidget *widget,
1731 GtkAllocation *allocation)
1733 GtkCalendar *calendar = GTK_CALENDAR (widget);
1734 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
1735 gint xthickness = widget->style->xthickness;
1736 gint ythickness = widget->style->xthickness;
1739 widget->allocation = *allocation;
1741 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1743 priv->day_width = (priv->min_day_width
1744 * ((allocation->width - (xthickness + INNER_BORDER) * 2
1745 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 6) - CALENDAR_XSEP * 2))
1746 / (7 * priv->min_day_width + priv->max_week_char_width * 2));
1747 priv->week_width = ((allocation->width - (xthickness + INNER_BORDER) * 2
1748 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 6) - CALENDAR_XSEP * 2 )
1749 - priv->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1753 priv->day_width = (allocation->width
1754 - (xthickness + INNER_BORDER) * 2
1755 - (CALENDAR_MARGIN * 2)
1756 - (DAY_XSEP * 6))/7;
1757 priv->week_width = 0;
1760 if (GTK_WIDGET_REALIZED (widget))
1762 gdk_window_move_resize (widget->window,
1763 allocation->x, allocation->y,
1764 allocation->width, allocation->height);
1765 if (priv->header_win)
1766 gdk_window_move_resize (priv->header_win,
1767 xthickness, ythickness,
1768 allocation->width - 2 * xthickness, priv->header_h);
1770 for (i = 0 ; i < 4 ; i++)
1772 if (priv->arrow_win[i])
1775 calendar_arrow_rectangle (calendar, i, &rect);
1777 gdk_window_move_resize (priv->arrow_win[i],
1778 rect.x, rect.y, rect.width, rect.height);
1782 if (priv->day_name_win)
1783 gdk_window_move_resize (priv->day_name_win,
1784 xthickness + INNER_BORDER,
1785 priv->header_h + (widget->style->ythickness + INNER_BORDER),
1786 allocation->width - (xthickness + INNER_BORDER) * 2,
1788 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1791 gdk_window_move_resize (priv->week_win,
1792 (xthickness + INNER_BORDER),
1793 priv->header_h + priv->day_name_h
1794 + (widget->style->ythickness + INNER_BORDER),
1797 gdk_window_move_resize (priv->main_win,
1798 priv->week_width + (xthickness + INNER_BORDER),
1799 priv->header_h + priv->day_name_h
1800 + (widget->style->ythickness + INNER_BORDER),
1803 - (xthickness + INNER_BORDER) * 2,
1808 gdk_window_move_resize (priv->main_win,
1809 (xthickness + INNER_BORDER),
1810 priv->header_h + priv->day_name_h
1811 + (widget->style->ythickness + INNER_BORDER),
1814 - (xthickness + INNER_BORDER) * 2,
1817 gdk_window_move_resize (priv->week_win,
1820 - (xthickness + INNER_BORDER),
1821 priv->header_h + priv->day_name_h
1822 + (widget->style->ythickness + INNER_BORDER),
1830 /****************************************
1832 ****************************************/
1835 calendar_paint_header (GtkCalendar *calendar)
1837 GtkWidget *widget = GTK_WIDGET (calendar);
1838 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1843 gint max_month_width;
1844 gint max_year_width;
1845 PangoLayout *layout;
1846 PangoRectangle logical_rect;
1852 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1853 year_left = priv->year_before;
1855 year_left = !priv->year_before;
1857 cr = gdk_cairo_create (priv->header_win);
1859 header_width = widget->allocation.width - 2 * widget->style->xthickness;
1861 max_month_width = priv->max_month_width;
1862 max_year_width = priv->max_year_width;
1864 gtk_paint_shadow (widget->style, priv->header_win,
1865 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1866 NULL, widget, "calendar",
1867 0, 0, header_width, priv->header_h);
1869 tmp_time = 1; /* Jan 1 1970, 00:00:01 UTC */
1870 tm = gmtime (&tmp_time);
1871 tm->tm_year = calendar->year - 1900;
1873 /* Translators: This dictates how the year is displayed in
1874 * gtkcalendar widget. See strftime() manual for the format.
1875 * Use only ASCII in the translation.
1877 * Also look for the msgid "year measurement template|2000".
1878 * Translate that entry to a year with the widest output of this
1881 * Don't include the prefix "calendar year format|" in the
1882 * translation. "%Y" is appropriate for most locales.
1884 strftime (buffer, sizeof (buffer), Q_("calendar year format|%Y"), tm);
1885 str = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
1886 layout = gtk_widget_create_pango_layout (widget, str);
1889 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1892 y = (priv->header_h - logical_rect.height) / 2;
1894 /* Draw year and its arrows */
1896 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1898 x = 3 + (max_year_width - logical_rect.width)/2;
1900 x = header_width - (3 + max_year_width
1901 - (max_year_width - logical_rect.width)/2);
1904 x = 3 + priv->arrow_width + (max_year_width - logical_rect.width)/2;
1906 x = header_width - (3 + priv->arrow_width + max_year_width
1907 - (max_year_width - logical_rect.width)/2);
1910 gdk_cairo_set_source_color (cr, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1911 cairo_move_to (cr, x, y);
1912 pango_cairo_show_layout (cr, layout);
1915 g_snprintf (buffer, sizeof (buffer), "%s", default_monthname[calendar->month]);
1916 pango_layout_set_text (layout, buffer, -1);
1917 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1919 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1921 x = header_width - (3 + max_month_width
1922 - (max_month_width - logical_rect.width)/2);
1924 x = 3 + (max_month_width - logical_rect.width) / 2;
1927 x = header_width - (3 + priv->arrow_width + max_month_width
1928 - (max_month_width - logical_rect.width)/2);
1930 x = 3 + priv->arrow_width + (max_month_width - logical_rect.width)/2;
1932 cairo_move_to (cr, x, y);
1933 pango_cairo_show_layout (cr, layout);
1935 g_object_unref (layout);
1940 calendar_paint_day_names (GtkCalendar *calendar)
1942 GtkWidget *widget = GTK_WIDGET (calendar);
1943 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
1947 int day_width, cal_width;
1949 PangoLayout *layout;
1950 PangoRectangle logical_rect;
1954 cr = gdk_cairo_create (priv->day_name_win);
1956 gtk_widget_style_get (GTK_WIDGET (widget),
1957 "focus-line-width", &focus_width,
1958 "focus-padding", &focus_padding,
1961 day_width = priv->day_width;
1962 cal_width = widget->allocation.width;
1963 day_wid_sep = day_width + DAY_XSEP;
1966 * Draw rectangles as inverted background for the labels.
1969 gdk_cairo_set_source_color (cr, SELECTED_BG_COLOR (widget));
1970 cairo_rectangle (cr,
1971 CALENDAR_MARGIN, CALENDAR_MARGIN,
1972 cal_width-CALENDAR_MARGIN * 2,
1973 priv->day_name_h - CALENDAR_MARGIN);
1976 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1978 cairo_rectangle (cr,
1980 priv->day_name_h - CALENDAR_YSEP,
1981 priv->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1990 layout = gtk_widget_create_pango_layout (widget, NULL);
1992 gdk_cairo_set_source_color (cr, SELECTED_FG_COLOR (widget));
1993 for (i = 0; i < 7; i++)
1995 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
1999 day = (day + priv->week_start) % 7;
2000 g_snprintf (buffer, sizeof (buffer), "%s", default_abbreviated_dayname[day]);
2002 pango_layout_set_text (layout, buffer, -1);
2003 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2007 + (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ?
2008 (priv->week_width + (priv->week_width ? CALENDAR_XSEP : 0))
2011 + (day_width - logical_rect.width)/2),
2012 CALENDAR_MARGIN + focus_width + focus_padding + logical_rect.y);
2013 pango_cairo_show_layout (cr, layout);
2016 g_object_unref (layout);
2021 calendar_paint_week_numbers (GtkCalendar *calendar)
2023 GtkWidget *widget = GTK_WIDGET (calendar);
2024 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2026 gint row, week = 0, year;
2029 gint y_loc, day_height;
2030 PangoLayout *layout;
2031 PangoRectangle logical_rect;
2035 cr = gdk_cairo_create (priv->week_win);
2037 gtk_widget_style_get (GTK_WIDGET (widget),
2038 "focus-line-width", &focus_width,
2039 "focus-padding", &focus_padding,
2043 * Draw a rectangle as inverted background for the labels.
2046 gdk_cairo_set_source_color (cr, SELECTED_BG_COLOR (widget));
2047 if (priv->day_name_win)
2048 cairo_rectangle (cr,
2051 priv->week_width - CALENDAR_MARGIN,
2052 priv->main_h - CALENDAR_MARGIN);
2054 cairo_rectangle (cr,
2057 priv->week_width - CALENDAR_MARGIN,
2058 priv->main_h - 2 * CALENDAR_MARGIN);
2065 layout = gtk_widget_create_pango_layout (widget, NULL);
2067 gdk_cairo_set_source_color (cr, SELECTED_FG_COLOR (widget));
2068 day_height = calendar_row_height (calendar);
2069 for (row = 0; row < 6; row++)
2073 year = calendar->year;
2074 if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
2077 result = week_of_year (&week, &year,
2078 ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
2079 + calendar->month) % 12 + 1, calendar->day[row][6]);
2080 g_return_if_fail (result);
2082 g_snprintf (buffer, sizeof (buffer), "%d", week);
2083 pango_layout_set_text (layout, buffer, -1);
2084 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2086 y_loc = calendar_top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
2088 x_loc = (priv->week_width
2089 - logical_rect.width
2090 - CALENDAR_XSEP - focus_padding - focus_width);
2092 cairo_move_to (cr, x_loc, y_loc);
2093 pango_cairo_show_layout (cr, layout);
2096 g_object_unref (layout);
2101 calendar_invalidate_day_num (GtkCalendar *calendar,
2104 gint r, c, row, col;
2108 for (r = 0; r < 6; r++)
2109 for (c = 0; c < 7; c++)
2110 if (calendar->day_month[r][c] == MONTH_CURRENT &&
2111 calendar->day[r][c] == day)
2117 g_return_if_fail (row != -1);
2118 g_return_if_fail (col != -1);
2120 calendar_invalidate_day (calendar, row, col);
2124 calendar_invalidate_day (GtkCalendar *calendar,
2128 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2132 GdkRectangle day_rect;
2134 calendar_day_rectangle (calendar, row, col, &day_rect);
2135 gdk_window_invalidate_rect (priv->main_win, &day_rect, FALSE);
2140 calendar_paint_day (GtkCalendar *calendar,
2144 GtkWidget *widget = GTK_WIDGET (calendar);
2145 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2147 GdkColor *text_color;
2151 GdkRectangle day_rect;
2153 PangoLayout *layout;
2154 PangoRectangle logical_rect;
2156 g_return_if_fail (row < 6);
2157 g_return_if_fail (col < 7);
2159 cr = gdk_cairo_create (priv->main_win);
2161 day = calendar->day[row][col];
2163 calendar_day_rectangle (calendar, row, col, &day_rect);
2165 if (calendar->day_month[row][col] == MONTH_PREV)
2167 text_color = PREV_MONTH_COLOR (widget);
2169 else if (calendar->day_month[row][col] == MONTH_NEXT)
2171 text_color = NEXT_MONTH_COLOR (widget);
2176 if (calendar->highlight_row == row && calendar->highlight_col == col)
2178 cairo_set_source_color (cr, HIGHLIGHT_BG_COLOR (widget));
2179 gdk_cairo_rectangle (cr, &day_rect);
2183 if (calendar->selected_day == day)
2185 gdk_cairo_set_source_color (cr, SELECTED_BG_COLOR (widget));
2186 gdk_cairo_rectangle (cr, &day_rect);
2189 if (calendar->selected_day == day)
2190 text_color = SELECTED_FG_COLOR (widget);
2191 else if (calendar->marked_date[day-1])
2192 text_color = MARKED_COLOR (widget);
2194 text_color = NORMAL_DAY_COLOR (widget);
2197 g_snprintf (buffer, sizeof (buffer), "%d", day);
2198 layout = gtk_widget_create_pango_layout (widget, buffer);
2199 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2201 x_loc = day_rect.x + day_rect.width / 2 + priv->max_day_char_width;
2202 x_loc -= logical_rect.width;
2203 y_loc = day_rect.y + (day_rect.height - logical_rect.height) / 2;
2205 gdk_cairo_set_source_color (cr, text_color);
2206 cairo_move_to (cr, x_loc, y_loc);
2207 pango_cairo_show_layout (cr, layout);
2209 if (calendar->marked_date[day-1]
2210 && calendar->day_month[row][col] == MONTH_CURRENT)
2212 cairo_move_to (cr, x_loc - 1, y_loc);
2213 pango_cairo_show_layout (cr, layout);
2216 if (GTK_WIDGET_HAS_FOCUS (calendar)
2217 && calendar->focus_row == row && calendar->focus_col == col)
2221 if (calendar->selected_day == day)
2222 state = GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
2224 state = GTK_STATE_NORMAL;
2226 gtk_paint_focus (widget->style,
2230 (calendar->selected_day == day)
2231 ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2233 NULL, widget, "calendar-day",
2234 day_rect.x, day_rect.y,
2235 day_rect.width, day_rect.height);
2238 g_object_unref (layout);
2243 calendar_paint_main (GtkCalendar *calendar)
2247 for (col = 0; col < 7; col++)
2248 for (row = 0; row < 6; row++)
2249 calendar_paint_day (calendar, row, col);
2253 calendar_invalidate_arrow (GtkCalendar *calendar,
2256 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2259 window = priv->arrow_win[arrow];
2261 gdk_window_invalidate_rect (window, NULL, FALSE);
2265 calendar_paint_arrow (GtkCalendar *calendar,
2268 GtkWidget *widget = GTK_WIDGET (calendar);
2269 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2272 window = priv->arrow_win[arrow];
2275 cairo_t *cr = gdk_cairo_create (window);
2279 state = priv->arrow_state[arrow];
2281 gdk_cairo_set_source_color (cr, &widget->style->bg[state]);
2285 gdk_drawable_get_size (window, &width, &height);
2286 if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2287 gtk_paint_arrow (widget->style, window, state,
2288 GTK_SHADOW_OUT, NULL, widget, "calendar",
2289 GTK_ARROW_LEFT, TRUE,
2290 width/2 - 3, height/2 - 4, 8, 8);
2292 gtk_paint_arrow (widget->style, window, state,
2293 GTK_SHADOW_OUT, NULL, widget, "calendar",
2294 GTK_ARROW_RIGHT, TRUE,
2295 width/2 - 2, height/2 - 4, 8, 8);
2300 gtk_calendar_expose (GtkWidget *widget,
2301 GdkEventExpose *event)
2303 GtkCalendar *calendar = GTK_CALENDAR (widget);
2304 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2307 if (GTK_WIDGET_DRAWABLE (widget))
2309 if (event->window == priv->main_win)
2310 calendar_paint_main (calendar);
2312 if (event->window == priv->header_win)
2313 calendar_paint_header (calendar);
2315 for (i = 0; i < 4; i++)
2316 if (event->window == priv->arrow_win[i])
2317 calendar_paint_arrow (calendar, i);
2319 if (event->window == priv->day_name_win)
2320 calendar_paint_day_names (calendar);
2322 if (event->window == priv->week_win)
2323 calendar_paint_week_numbers (calendar);
2324 if (event->window == widget->window)
2326 gtk_paint_shadow (widget->style, widget->window, GTK_WIDGET_STATE (widget),
2327 GTK_SHADOW_IN, NULL, widget, "calendar",
2328 0, 0, widget->allocation.width, widget->allocation.height);
2336 /****************************************
2338 ****************************************/
2341 calendar_arrow_action (GtkCalendar *calendar,
2346 case ARROW_YEAR_LEFT:
2347 calendar_set_year_prev (calendar);
2349 case ARROW_YEAR_RIGHT:
2350 calendar_set_year_next (calendar);
2352 case ARROW_MONTH_LEFT:
2353 calendar_set_month_prev (calendar);
2355 case ARROW_MONTH_RIGHT:
2356 calendar_set_month_next (calendar);
2364 calendar_timer (gpointer data)
2366 GtkCalendar *calendar = data;
2367 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2368 gboolean retval = FALSE;
2370 GDK_THREADS_ENTER ();
2374 calendar_arrow_action (calendar, priv->click_child);
2376 if (priv->need_timer)
2378 GtkSettings *settings;
2381 settings = gtk_widget_get_settings (GTK_WIDGET (calendar));
2382 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2384 priv->need_timer = FALSE;
2385 priv->timer = g_timeout_add (timeout,
2386 (GSourceFunc) calendar_timer,
2387 (gpointer) calendar);
2393 GDK_THREADS_LEAVE ();
2399 calendar_start_spinning (GtkCalendar *calendar,
2402 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2404 priv->click_child = click_child;
2408 GtkSettings *settings;
2411 settings = gtk_widget_get_settings (GTK_WIDGET (calendar));
2412 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
2414 priv->need_timer = TRUE;
2415 priv->timer = g_timeout_add (timeout,
2422 calendar_stop_spinning (GtkCalendar *calendar)
2424 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2428 g_source_remove (priv->timer);
2430 priv->need_timer = FALSE;
2435 calendar_main_button_press (GtkCalendar *calendar,
2436 GdkEventButton *event)
2438 GtkWidget *widget = GTK_WIDGET (calendar);
2439 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
2445 x = (gint) (event->x);
2446 y = (gint) (event->y);
2448 row = calendar_row_from_y (calendar, y);
2449 col = calendar_column_from_x (calendar, x);
2451 /* If row or column isn't found, just return. */
2452 if (row == -1 || col == -1)
2455 day_month = calendar->day_month[row][col];
2457 if (event->type == GDK_BUTTON_PRESS)
2459 day = calendar->day[row][col];
2461 if (day_month == MONTH_PREV)
2462 calendar_set_month_prev (calendar);
2463 else if (day_month == MONTH_NEXT)
2464 calendar_set_month_next (calendar);
2466 if (!GTK_WIDGET_HAS_FOCUS (widget))
2467 gtk_widget_grab_focus (widget);
2469 if (event->button == 1)
2472 priv->drag_start_x = x;
2473 priv->drag_start_y = y;
2476 calendar_select_and_focus_day (calendar, day);
2478 else if (event->type == GDK_2BUTTON_PRESS)
2481 if (day_month == MONTH_CURRENT)
2482 g_signal_emit (calendar,
2483 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL],
2489 gtk_calendar_button_press (GtkWidget *widget,
2490 GdkEventButton *event)
2492 GtkCalendar *calendar = GTK_CALENDAR (widget);
2493 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2496 if (event->window == priv->main_win)
2497 calendar_main_button_press (calendar, event);
2499 if (!GTK_WIDGET_HAS_FOCUS (widget))
2500 gtk_widget_grab_focus (widget);
2502 for (arrow = ARROW_YEAR_LEFT; arrow <= ARROW_MONTH_RIGHT; arrow++)
2504 if (event->window == priv->arrow_win[arrow])
2507 /* only call the action on single click, not double */
2508 if (event->type == GDK_BUTTON_PRESS)
2510 if (event->button == 1)
2511 calendar_start_spinning (calendar, arrow);
2513 calendar_arrow_action (calendar, arrow);
2524 gtk_calendar_button_release (GtkWidget *widget,
2525 GdkEventButton *event)
2527 GtkCalendar *calendar = GTK_CALENDAR (widget);
2528 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2530 if (event->button == 1)
2532 calendar_stop_spinning (calendar);
2542 gtk_calendar_motion_notify (GtkWidget *widget,
2543 GdkEventMotion *event)
2545 GtkCalendar *calendar = GTK_CALENDAR (widget);
2546 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2547 gint event_x, event_y;
2549 gint old_row, old_col;
2551 event_x = (gint) (event->x);
2552 event_y = (gint) (event->y);
2554 if (event->window == priv->main_win)
2559 if (gtk_drag_check_threshold (widget,
2560 priv->drag_start_x, priv->drag_start_y,
2561 event->x, event->y))
2563 GdkDragContext *context;
2564 GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2565 gtk_target_list_add_text_targets (target_list, 0);
2566 context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY,
2567 1, (GdkEvent *)event);
2572 gtk_target_list_unref (target_list);
2573 gtk_drag_set_icon_default (context);
2578 row = calendar_row_from_y (calendar, event_y);
2579 col = calendar_column_from_x (calendar, event_x);
2581 if (row != calendar->highlight_row || calendar->highlight_col != col)
2583 old_row = calendar->highlight_row;
2584 old_col = calendar->highlight_col;
2585 if (old_row > -1 && old_col > -1)
2587 calendar->highlight_row = -1;
2588 calendar->highlight_col = -1;
2589 calendar_invalidate_day (calendar, old_row, old_col);
2592 calendar->highlight_row = row;
2593 calendar->highlight_col = col;
2595 if (row > -1 && col > -1)
2596 calendar_invalidate_day (calendar, row, col);
2604 gtk_calendar_enter_notify (GtkWidget *widget,
2605 GdkEventCrossing *event)
2607 GtkCalendar *calendar = GTK_CALENDAR (widget);
2608 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2610 if (event->window == priv->arrow_win[ARROW_MONTH_LEFT])
2612 priv->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2613 calendar_invalidate_arrow (calendar, ARROW_MONTH_LEFT);
2616 if (event->window == priv->arrow_win[ARROW_MONTH_RIGHT])
2618 priv->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2619 calendar_invalidate_arrow (calendar, ARROW_MONTH_RIGHT);
2622 if (event->window == priv->arrow_win[ARROW_YEAR_LEFT])
2624 priv->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2625 calendar_invalidate_arrow (calendar, ARROW_YEAR_LEFT);
2628 if (event->window == priv->arrow_win[ARROW_YEAR_RIGHT])
2630 priv->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2631 calendar_invalidate_arrow (calendar, ARROW_YEAR_RIGHT);
2638 gtk_calendar_leave_notify (GtkWidget *widget,
2639 GdkEventCrossing *event)
2641 GtkCalendar *calendar = GTK_CALENDAR (widget);
2642 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2646 if (event->window == priv->main_win)
2648 row = calendar->highlight_row;
2649 col = calendar->highlight_col;
2650 calendar->highlight_row = -1;
2651 calendar->highlight_col = -1;
2652 if (row > -1 && col > -1)
2653 calendar_invalidate_day (calendar, row, col);
2656 if (event->window == priv->arrow_win[ARROW_MONTH_LEFT])
2658 priv->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2659 calendar_invalidate_arrow (calendar, ARROW_MONTH_LEFT);
2662 if (event->window == priv->arrow_win[ARROW_MONTH_RIGHT])
2664 priv->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2665 calendar_invalidate_arrow (calendar, ARROW_MONTH_RIGHT);
2668 if (event->window == priv->arrow_win[ARROW_YEAR_LEFT])
2670 priv->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2671 calendar_invalidate_arrow (calendar, ARROW_YEAR_LEFT);
2674 if (event->window == priv->arrow_win[ARROW_YEAR_RIGHT])
2676 priv->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2677 calendar_invalidate_arrow (calendar, ARROW_YEAR_RIGHT);
2684 gtk_calendar_scroll (GtkWidget *widget,
2685 GdkEventScroll *event)
2687 GtkCalendar *calendar = GTK_CALENDAR (widget);
2689 if (event->direction == GDK_SCROLL_UP)
2691 if (!GTK_WIDGET_HAS_FOCUS (widget))
2692 gtk_widget_grab_focus (widget);
2693 calendar_set_month_prev (calendar);
2695 else if (event->direction == GDK_SCROLL_DOWN)
2697 if (!GTK_WIDGET_HAS_FOCUS (widget))
2698 gtk_widget_grab_focus (widget);
2699 calendar_set_month_next (calendar);
2708 /****************************************
2710 ****************************************/
2713 move_focus (GtkCalendar *calendar,
2716 GtkTextDirection text_dir = gtk_widget_get_direction (GTK_WIDGET (calendar));
2718 if ((text_dir == GTK_TEXT_DIR_LTR && direction == -1) ||
2719 (text_dir == GTK_TEXT_DIR_RTL && direction == 1))
2721 if (calendar->focus_col > 0)
2722 calendar->focus_col--;
2723 else if (calendar->focus_row > 0)
2725 calendar->focus_col = 6;
2726 calendar->focus_row--;
2731 if (calendar->focus_col < 6)
2732 calendar->focus_col++;
2733 else if (calendar->focus_row < 5)
2735 calendar->focus_col = 0;
2736 calendar->focus_row++;
2742 gtk_calendar_key_press (GtkWidget *widget,
2745 GtkCalendar *calendar;
2751 calendar = GTK_CALENDAR (widget);
2754 old_focus_row = calendar->focus_row;
2755 old_focus_col = calendar->focus_col;
2757 switch (event->keyval)
2762 if (event->state & GDK_CONTROL_MASK)
2763 calendar_set_month_prev (calendar);
2766 move_focus (calendar, -1);
2767 calendar_invalidate_day (calendar, old_focus_row, old_focus_col);
2768 calendar_invalidate_day (calendar, calendar->focus_row,
2769 calendar->focus_col);
2775 if (event->state & GDK_CONTROL_MASK)
2776 calendar_set_month_next (calendar);
2779 move_focus (calendar, 1);
2780 calendar_invalidate_day (calendar, old_focus_row, old_focus_col);
2781 calendar_invalidate_day (calendar, calendar->focus_row,
2782 calendar->focus_col);
2788 if (event->state & GDK_CONTROL_MASK)
2789 calendar_set_year_prev (calendar);
2792 if (calendar->focus_row > 0)
2793 calendar->focus_row--;
2794 calendar_invalidate_day (calendar, old_focus_row, old_focus_col);
2795 calendar_invalidate_day (calendar, calendar->focus_row,
2796 calendar->focus_col);
2802 if (event->state & GDK_CONTROL_MASK)
2803 calendar_set_year_next (calendar);
2806 if (calendar->focus_row < 5)
2807 calendar->focus_row++;
2808 calendar_invalidate_day (calendar, old_focus_row, old_focus_col);
2809 calendar_invalidate_day (calendar, calendar->focus_row,
2810 calendar->focus_col);
2815 row = calendar->focus_row;
2816 col = calendar->focus_col;
2817 day = calendar->day[row][col];
2819 if (row > -1 && col > -1)
2823 if (calendar->day_month[row][col] == MONTH_PREV)
2824 calendar_set_month_prev (calendar);
2825 else if (calendar->day_month[row][col] == MONTH_NEXT)
2826 calendar_set_month_next (calendar);
2828 calendar_select_and_focus_day (calendar, day);
2836 /****************************************
2837 * Misc widget methods *
2838 ****************************************/
2841 calendar_set_background (GtkWidget *widget)
2843 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2846 if (GTK_WIDGET_REALIZED (widget))
2848 for (i = 0; i < 4; i++)
2850 if (priv->arrow_win[i])
2851 gdk_window_set_background (priv->arrow_win[i],
2852 HEADER_BG_COLOR (widget));
2854 if (priv->header_win)
2855 gdk_window_set_background (priv->header_win,
2856 HEADER_BG_COLOR (widget));
2857 if (priv->day_name_win)
2858 gdk_window_set_background (priv->day_name_win,
2859 BACKGROUND_COLOR (widget));
2861 gdk_window_set_background (priv->week_win,
2862 BACKGROUND_COLOR (widget));
2864 gdk_window_set_background (priv->main_win,
2865 BACKGROUND_COLOR (widget));
2867 gdk_window_set_background (widget->window,
2868 BACKGROUND_COLOR (widget));
2873 gtk_calendar_style_set (GtkWidget *widget,
2874 GtkStyle *previous_style)
2876 if (previous_style && GTK_WIDGET_REALIZED (widget))
2877 calendar_set_background (widget);
2881 gtk_calendar_state_changed (GtkWidget *widget,
2882 GtkStateType previous_state)
2884 GtkCalendar *calendar = GTK_CALENDAR (widget);
2885 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2888 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2891 calendar_stop_spinning (calendar);
2894 for (i = 0; i < 4; i++)
2895 if (GTK_WIDGET_IS_SENSITIVE (widget))
2896 priv->arrow_state[i] = GTK_STATE_NORMAL;
2898 priv->arrow_state[i] = GTK_STATE_INSENSITIVE;
2900 calendar_set_background (widget);
2904 gtk_calendar_grab_notify (GtkWidget *widget,
2905 gboolean was_grabbed)
2908 calendar_stop_spinning (GTK_CALENDAR (widget));
2912 gtk_calendar_focus_out (GtkWidget *widget,
2913 GdkEventFocus *event)
2915 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2917 calendar_stop_spinning (GTK_CALENDAR (widget));
2925 /****************************************
2927 ****************************************/
2930 gtk_calendar_drag_data_get (GtkWidget *widget,
2931 GdkDragContext *context,
2932 GtkSelectionData *selection_data,
2936 GtkCalendar *calendar = GTK_CALENDAR (widget);
2941 date = g_date_new_dmy (calendar->selected_day, calendar->month + 1, calendar->year);
2942 len = g_date_strftime (str, 127, "%x", date);
2943 gtk_selection_data_set_text (selection_data, str, len);
2948 /* Get/set whether drag_motion requested the drag data and
2949 * drag_data_received should thus not actually insert the data,
2950 * since the data doesn't result from a drop.
2953 set_status_pending (GdkDragContext *context,
2954 GdkDragAction suggested_action)
2956 g_object_set_data (G_OBJECT (context),
2957 I_("gtk-calendar-status-pending"),
2958 GINT_TO_POINTER (suggested_action));
2961 static GdkDragAction
2962 get_status_pending (GdkDragContext *context)
2964 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
2965 "gtk-calendar-status-pending"));
2969 gtk_calendar_drag_leave (GtkWidget *widget,
2970 GdkDragContext *context,
2973 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2975 priv->drag_highlight = 0;
2976 gtk_drag_unhighlight (widget);
2981 gtk_calendar_drag_motion (GtkWidget *widget,
2982 GdkDragContext *context,
2987 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (widget);
2990 if (!priv->drag_highlight)
2992 priv->drag_highlight = 1;
2993 gtk_drag_highlight (widget);
2996 target = gtk_drag_dest_find_target (widget, context, NULL);
2997 if (target == GDK_NONE)
2998 gdk_drag_status (context, 0, time);
3001 set_status_pending (context, context->suggested_action);
3002 gtk_drag_get_data (widget, context, target, time);
3009 gtk_calendar_drag_drop (GtkWidget *widget,
3010 GdkDragContext *context,
3017 target = gtk_drag_dest_find_target (widget, context, NULL);
3018 if (target != GDK_NONE)
3020 gtk_drag_get_data (widget, context,
3030 gtk_calendar_drag_data_received (GtkWidget *widget,
3031 GdkDragContext *context,
3034 GtkSelectionData *selection_data,
3038 GtkCalendar *calendar = GTK_CALENDAR (widget);
3039 guint day, month, year;
3042 GdkDragAction suggested_action;
3044 suggested_action = get_status_pending (context);
3046 if (suggested_action)
3048 set_status_pending (context, 0);
3050 /* We are getting this data due to a request in drag_motion,
3051 * rather than due to a request in drag_drop, so we are just
3052 * supposed to call drag_status, not actually paste in the
3055 str = gtk_selection_data_get_text (selection_data);
3058 date = g_date_new ();
3059 g_date_set_parse (date, str);
3060 if (!g_date_valid (date))
3061 suggested_action = 0;
3066 suggested_action = 0;
3068 gdk_drag_status (context, suggested_action, time);
3073 date = g_date_new ();
3074 str = gtk_selection_data_get_text (selection_data);
3077 g_date_set_parse (date, str);
3081 if (!g_date_valid (date))
3083 g_warning ("Received invalid date data\n");
3085 gtk_drag_finish (context, FALSE, FALSE, time);
3089 day = g_date_get_day (date);
3090 month = g_date_get_month (date);
3091 year = g_date_get_year (date);
3094 gtk_drag_finish (context, TRUE, FALSE, time);
3097 g_object_freeze_notify (G_OBJECT (calendar));
3098 if (!(calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
3099 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
3100 gtk_calendar_select_month (calendar, month - 1, year);
3101 gtk_calendar_select_day (calendar, day);
3102 g_object_thaw_notify (G_OBJECT (calendar));
3106 /****************************************
3108 ****************************************/
3113 * Creates a new calendar, with the current date being selected.
3115 * Return value: a newly #GtkCalendar widget
3118 gtk_calendar_new (void)
3120 return g_object_new (GTK_TYPE_CALENDAR, NULL);
3124 * gtk_calendar_display_options:
3125 * @calendar: a #GtkCalendar.
3126 * @flags: the display options to set.
3128 * Sets display options (whether to display the heading and the month headings).
3130 * Deprecated: Use gtk_calendar_set_display_options() instead
3133 gtk_calendar_display_options (GtkCalendar *calendar,
3134 GtkCalendarDisplayOptions flags)
3136 gtk_calendar_set_display_options (calendar, flags);
3140 * gtk_calendar_get_display_options:
3141 * @calendar: a #GtkCalendar
3143 * Returns the current display options of @calendar.
3145 * Return value: the display options.
3149 GtkCalendarDisplayOptions
3150 gtk_calendar_get_display_options (GtkCalendar *calendar)
3152 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), 0);
3154 return calendar->display_flags;
3158 * gtk_calendar_set_display_options:
3159 * @calendar: a #GtkCalendar
3160 * @flags: the display options to set
3162 * Sets display options (whether to display the heading and the month
3168 gtk_calendar_set_display_options (GtkCalendar *calendar,
3169 GtkCalendarDisplayOptions flags)
3171 GtkWidget *widget = GTK_WIDGET (calendar);
3172 GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
3175 GtkCalendarDisplayOptions old_flags;
3177 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3179 old_flags = calendar->display_flags;
3181 if (GTK_WIDGET_REALIZED (widget))
3183 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
3186 if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
3187 && (priv->header_win))
3189 calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
3190 calendar_realize_arrows (calendar);
3194 for (i = 0; i < 4; i++)
3196 if (priv->arrow_win[i])
3198 gdk_window_set_user_data (priv->arrow_win[i],
3200 gdk_window_destroy (priv->arrow_win[i]);
3201 priv->arrow_win[i] = NULL;
3207 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
3211 if (flags & GTK_CALENDAR_SHOW_HEADING)
3213 calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
3214 calendar_realize_header (calendar);
3218 for (i = 0; i < 4; i++)
3220 if (priv->arrow_win[i])
3222 gdk_window_set_user_data (priv->arrow_win[i],
3224 gdk_window_destroy (priv->arrow_win[i]);
3225 priv->arrow_win[i] = NULL;
3228 gdk_window_set_user_data (priv->header_win, NULL);
3229 gdk_window_destroy (priv->header_win);
3230 priv->header_win = NULL;
3235 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
3239 if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
3241 calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
3242 calendar_realize_day_names (calendar);
3246 gdk_window_set_user_data (priv->day_name_win, NULL);
3247 gdk_window_destroy (priv->day_name_win);
3248 priv->day_name_win = NULL;
3252 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
3256 if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
3258 calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
3259 calendar_realize_week_numbers (calendar);
3263 gdk_window_set_user_data (priv->week_win, NULL);
3264 gdk_window_destroy (priv->week_win);
3265 priv->week_win = NULL;
3269 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
3270 g_warning ("GTK_CALENDAR_WEEK_START_MONDAY is ignored; the first day of the week is determined from the locale");
3272 calendar->display_flags = flags;
3274 gtk_widget_queue_resize (GTK_WIDGET (calendar));
3278 calendar->display_flags = flags;
3280 g_object_freeze_notify (G_OBJECT (calendar));
3281 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
3282 g_object_notify (G_OBJECT (calendar), "show-heading");
3283 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
3284 g_object_notify (G_OBJECT (calendar), "show-day-names");
3285 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
3286 g_object_notify (G_OBJECT (calendar), "no-month-change");
3287 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
3288 g_object_notify (G_OBJECT (calendar), "show-week-numbers");
3289 g_object_thaw_notify (G_OBJECT (calendar));
3293 * gtk_calendar_select_month:
3294 * @calendar: a #GtkCalendar
3295 * @month: a month number between 0 and 11.
3296 * @year: the year the month is in.
3298 * Shifts the calendar to a different month.
3300 * Return value: %TRUE, always
3303 gtk_calendar_select_month (GtkCalendar *calendar,
3307 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
3308 g_return_val_if_fail (month <= 11, FALSE);
3310 calendar->month = month;
3311 calendar->year = year;
3313 calendar_compute_days (calendar);
3315 gtk_widget_queue_draw (GTK_WIDGET (calendar));
3317 g_object_freeze_notify (G_OBJECT (calendar));
3318 g_object_notify (G_OBJECT (calendar), "month");
3319 g_object_notify (G_OBJECT (calendar), "year");
3320 g_object_thaw_notify (G_OBJECT (calendar));
3322 g_signal_emit (calendar,
3323 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
3329 * gtk_calendar_select_day:
3330 * @calendar: a #GtkCalendar.
3331 * @day: the day number between 1 and 31, or 0 to unselect
3332 * the currently selected day.
3334 * Selects a day from the current month.
3337 gtk_calendar_select_day (GtkCalendar *calendar,
3340 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3341 g_return_if_fail (day <= 31);
3343 /* Deselect the old day */
3344 if (calendar->selected_day > 0)
3348 selected_day = calendar->selected_day;
3349 calendar->selected_day = 0;
3350 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
3351 calendar_invalidate_day_num (calendar, selected_day);
3354 calendar->selected_day = day;
3356 /* Select the new day */
3359 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
3360 calendar_invalidate_day_num (calendar, day);
3363 g_object_notify (G_OBJECT (calendar), "day");
3365 g_signal_emit (calendar,
3366 gtk_calendar_signals[DAY_SELECTED_SIGNAL],
3371 * gtk_calendar_clear_marks:
3372 * @calendar: a #GtkCalendar
3374 * Remove all visual markers.
3377 gtk_calendar_clear_marks (GtkCalendar *calendar)
3381 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3383 for (day = 0; day < 31; day++)
3385 calendar->marked_date[day] = FALSE;
3388 calendar->num_marked_dates = 0;
3390 gtk_widget_queue_draw (GTK_WIDGET (calendar));
3394 * gtk_calendar_mark_day:
3395 * @calendar: a #GtkCalendar
3396 * @day: the day number to mark between 1 and 31.
3398 * Places a visual marker on a particular day.
3400 * Return value: %TRUE, always
3403 gtk_calendar_mark_day (GtkCalendar *calendar,
3406 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
3408 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
3410 calendar->marked_date[day - 1] = TRUE;
3411 calendar->num_marked_dates++;
3412 calendar_invalidate_day_num (calendar, day);
3419 * gtk_calendar_unmark_day:
3420 * @calendar: a #GtkCalendar.
3421 * @day: the day number to unmark between 1 and 31.
3423 * Removes the visual marker from a particular day.
3425 * Return value: %TRUE, always
3428 gtk_calendar_unmark_day (GtkCalendar *calendar,
3431 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
3433 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
3435 calendar->marked_date[day - 1] = FALSE;
3436 calendar->num_marked_dates--;
3437 calendar_invalidate_day_num (calendar, day);
3444 * gtk_calendar_get_date:
3445 * @calendar: a #GtkCalendar
3446 * @year: location to store the year number, or %NULL
3447 * @month: location to store the month number (between 0 and 11), or %NULL
3448 * @day: location to store the day number (between 1 and 31), or %NULL
3450 * Obtains the selected date from a #GtkCalendar.
3453 gtk_calendar_get_date (GtkCalendar *calendar,
3458 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3461 *year = calendar->year;
3464 *month = calendar->month;
3467 *day = calendar->selected_day;
3471 * gtk_calendar_freeze:
3472 * @calendar: a #GtkCalendar
3474 * Does nothing. Previously locked the display of the calendar until
3475 * it was thawed with gtk_calendar_thaw().
3478 gtk_calendar_freeze (GtkCalendar *calendar)
3480 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3484 * gtk_calendar_thaw:
3485 * @calendar: a #GtkCalendar
3487 * Does nothing. Previously defrosted a calendar; all the changes made
3488 * since the last gtk_calendar_freeze() were displayed.
3491 gtk_calendar_thaw (GtkCalendar *calendar)
3493 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3496 #define __GTK_CALENDAR_C__
3497 #include "gtkaliasdef.c"