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
40 #include <glib/gprintf.h>
42 #include "gtkcalendar.h"
46 #include "gtkmarshalers.h"
48 #include "gdk/gdkkeysyms.h"
50 /***************************************************************************/
51 /* The following date routines are taken from the lib_date package. Keep
52 * them separate in case we want to update them if a newer lib_date comes
55 typedef unsigned int N_int;
56 typedef unsigned long N_long;
57 typedef signed long Z_long;
58 typedef enum { false = FALSE , true = TRUE } boolean;
60 #define and && /* logical (boolean) operators: lower case */
63 static const N_int month_length[2][13] =
65 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
66 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
69 static const N_int days_in_months[2][14] =
71 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
72 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
75 static Z_long calc_days(N_int year, N_int mm, N_int dd);
76 static N_int day_of_week(N_int year, N_int mm, N_int dd);
77 static Z_long dates_difference(N_int year1, N_int mm1, N_int dd1,
78 N_int year2, N_int mm2, N_int dd2);
79 static N_int weeks_in_year(N_int year);
84 return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
88 day_of_week(N_int year, N_int mm, N_int dd)
92 days = calc_days(year, mm, dd);
99 return( (N_int) days );
102 static N_int weeks_in_year(N_int year)
104 return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
108 check_date(N_int year, N_int mm, N_int dd)
110 if (year < 1) return(false);
111 if ((mm < 1) or (mm > 12)) return(false);
112 if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
117 week_number(N_int year, N_int mm, N_int dd)
121 first = day_of_week(year,1,1) - 1;
122 return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
127 year_to_days(N_int year)
129 return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
134 calc_days(N_int year, N_int mm, N_int dd)
138 if (year < 1) return(0L);
139 if ((mm < 1) or (mm > 12)) return(0L);
140 if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
141 return( year_to_days(--year) + days_in_months[lp][mm] + dd );
145 week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
147 if (check_date(*year,mm,dd))
149 *week = week_number(*year,mm,dd);
151 *week = weeks_in_year(--(*year));
152 else if (*week > weeks_in_year(*year))
163 dates_difference(N_int year1, N_int mm1, N_int dd1,
164 N_int year2, N_int mm2, N_int dd2)
166 return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
169 /*** END OF lib_date routines ********************************************/
171 /* Spacing around day/week headers and main area, inside those windows */
172 #define CALENDAR_MARGIN 0
173 /* Spacing around day/week headers and main area, outside those windows */
174 #define INNER_BORDER 4
175 /* Separation between day headers and main area */
176 #define CALENDAR_YSEP 4
177 /* Separation between week headers and main area */
178 #define CALENDAR_XSEP 4
180 #define DAY_XSEP 0 /* not really good for small calendar */
181 #define DAY_YSEP 0 /* not really good for small calendar */
184 #define HEADER_FG_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
185 #define HEADER_BG_COLOR(widget) (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
186 #define SELECTED_BG_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE])
187 #define SELECTED_FG_COLOR(widget) (& (widget)->style->text[GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE])
188 #define NORMAL_DAY_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
189 #define PREV_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
190 #define NEXT_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
191 #define MARKED_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
192 #define BACKGROUND_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
193 #define HIGHLIGHT_BACK_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
209 MONTH_CHANGED_SIGNAL,
211 DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
227 PROP_NO_MONTH_CHANGE,
228 PROP_SHOW_WEEK_NUMBERS,
232 static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 };
234 static GtkWidgetClass *parent_class = NULL;
236 typedef struct _GtkCalendarPrivateData GtkCalendarPrivateData;
237 struct _GtkCalendarPrivateData
239 GdkWindow *header_win;
240 GdkWindow *day_name_win;
243 GdkWindow *arrow_win[4];
249 guint arrow_state[4];
251 guint max_month_width;
252 guint max_year_width;
258 guint max_day_char_width;
259 guint max_day_char_ascent;
260 guint max_day_char_descent;
261 guint max_label_char_ascent;
262 guint max_label_char_descent;
263 guint max_week_char_width;
268 guint dirty_header : 1;
269 guint dirty_day_names : 1;
270 guint dirty_main : 1;
271 guint dirty_week : 1;
273 guint year_before : 1;
275 guint need_timer : 1;
278 guint drag_highlight : 1;
289 #define GTK_CALENDAR_PRIVATE_DATA(widget) (((GtkCalendarPrivateData*)(GTK_CALENDAR (widget)->private_data)))
291 typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data);
293 static void gtk_calendar_class_init (GtkCalendarClass *class);
294 static void gtk_calendar_init (GtkCalendar *calendar);
295 static void gtk_calendar_finalize (GObject *calendar);
296 static void gtk_calendar_destroy (GtkObject *calendar);
297 static void gtk_calendar_set_property (GObject *object,
301 static void gtk_calendar_get_property (GObject *object,
305 static void gtk_calendar_realize (GtkWidget *widget);
306 static void gtk_calendar_unrealize (GtkWidget *widget);
307 static void gtk_calendar_size_request (GtkWidget *widget,
308 GtkRequisition *requisition);
309 static void gtk_calendar_size_allocate (GtkWidget *widget,
310 GtkAllocation *allocation);
311 static gint gtk_calendar_expose (GtkWidget *widget,
312 GdkEventExpose *event);
313 static gint gtk_calendar_button_press (GtkWidget *widget,
314 GdkEventButton *event);
315 static gint gtk_calendar_button_release (GtkWidget *widget,
316 GdkEventButton *event);
317 static void gtk_calendar_main_button (GtkWidget *widget,
318 GdkEventButton *event);
319 static gint gtk_calendar_motion_notify (GtkWidget *widget,
320 GdkEventMotion *event);
321 static gint gtk_calendar_enter_notify (GtkWidget *widget,
322 GdkEventCrossing *event);
323 static gint gtk_calendar_leave_notify (GtkWidget *widget,
324 GdkEventCrossing *event);
325 static gint gtk_calendar_key_press (GtkWidget *widget,
327 static gint gtk_calendar_scroll (GtkWidget *widget,
328 GdkEventScroll *event);
329 static void gtk_calendar_grab_notify (GtkWidget *widget,
330 gboolean was_grabbed);
331 static gboolean gtk_calendar_focus_out (GtkWidget *widget,
332 GdkEventFocus *event);
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);
337 static void gtk_calendar_paint_header (GtkWidget *widget);
338 static void gtk_calendar_paint_day_names (GtkWidget *widget);
339 static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
340 static void gtk_calendar_paint_main (GtkWidget *widget);
342 static void gtk_calendar_select_and_focus_day (GtkCalendar *calendar,
345 static void gtk_calendar_paint_arrow (GtkWidget *widget,
347 static void gtk_calendar_paint_day_num (GtkWidget *widget,
349 static void gtk_calendar_paint_day (GtkWidget *widget,
352 static void gtk_calendar_compute_days (GtkCalendar *calendar);
353 static gint left_x_for_column (GtkCalendar *calendar,
355 static gint top_y_for_row (GtkCalendar *calendar,
358 static void gtk_calendar_drag_data_get (GtkWidget *widget,
359 GdkDragContext *context,
360 GtkSelectionData *selection_data,
363 static void gtk_calendar_drag_data_received (GtkWidget *widget,
364 GdkDragContext *context,
367 GtkSelectionData *selection_data,
370 static gboolean gtk_calendar_drag_motion (GtkWidget *widget,
371 GdkDragContext *context,
375 static void gtk_calendar_drag_leave (GtkWidget *widget,
376 GdkDragContext *context,
378 static gboolean gtk_calendar_drag_drop (GtkWidget *widget,
379 GdkDragContext *context,
384 static char *default_abbreviated_dayname[7];
385 static char *default_monthname[12];
388 gtk_calendar_get_type (void)
390 static GType calendar_type = 0;
394 static const GTypeInfo calendar_info =
396 sizeof (GtkCalendarClass),
397 NULL, /* base_init */
398 NULL, /* base_finalize */
399 (GClassInitFunc) gtk_calendar_class_init,
400 NULL, /* class_finalize */
401 NULL, /* class_data */
402 sizeof (GtkCalendar),
404 (GInstanceInitFunc) gtk_calendar_init,
407 calendar_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCalendar",
411 return calendar_type;
415 gtk_calendar_class_init (GtkCalendarClass *class)
417 GObjectClass *gobject_class;
418 GtkObjectClass *object_class;
419 GtkWidgetClass *widget_class;
421 gobject_class = (GObjectClass*) class;
422 object_class = (GtkObjectClass*) class;
423 widget_class = (GtkWidgetClass*) class;
425 parent_class = g_type_class_peek_parent (class);
427 gobject_class->set_property = gtk_calendar_set_property;
428 gobject_class->get_property = gtk_calendar_get_property;
429 gobject_class->finalize = gtk_calendar_finalize;
431 object_class->destroy = gtk_calendar_destroy;
433 widget_class->realize = gtk_calendar_realize;
434 widget_class->unrealize = gtk_calendar_unrealize;
435 widget_class->expose_event = gtk_calendar_expose;
436 widget_class->size_request = gtk_calendar_size_request;
437 widget_class->size_allocate = gtk_calendar_size_allocate;
438 widget_class->button_press_event = gtk_calendar_button_press;
439 widget_class->button_release_event = gtk_calendar_button_release;
440 widget_class->motion_notify_event = gtk_calendar_motion_notify;
441 widget_class->enter_notify_event = gtk_calendar_enter_notify;
442 widget_class->leave_notify_event = gtk_calendar_leave_notify;
443 widget_class->key_press_event = gtk_calendar_key_press;
444 widget_class->scroll_event = gtk_calendar_scroll;
445 widget_class->style_set = gtk_calendar_style_set;
446 widget_class->state_changed = gtk_calendar_state_changed;
447 widget_class->grab_notify = gtk_calendar_grab_notify;
448 widget_class->focus_out_event = gtk_calendar_focus_out;
450 widget_class->drag_data_get = gtk_calendar_drag_data_get;
451 widget_class->drag_motion = gtk_calendar_drag_motion;
452 widget_class->drag_leave = gtk_calendar_drag_leave;
453 widget_class->drag_drop = gtk_calendar_drag_drop;
454 widget_class->drag_data_received = gtk_calendar_drag_data_received;
456 class->month_changed = NULL;
457 class->day_selected = NULL;
458 class->day_selected_double_click = NULL;
459 class->prev_month = NULL;
460 class->next_month = NULL;
461 class->prev_year = NULL;
462 class->next_year = NULL;
464 g_object_class_install_property (gobject_class,
466 g_param_spec_int ("year",
468 P_("The selected year"),
471 g_object_class_install_property (gobject_class,
473 g_param_spec_int ("month",
475 P_("The selected month (as a number between 0 and 11)"),
478 g_object_class_install_property (gobject_class,
480 g_param_spec_int ("day",
482 P_("The selected day (as a number between 1 and 31, or 0 to unselect the currently selected day)"),
487 * GtkCalendar:show-heading:
489 * Determines whether a heading is displayed.
493 g_object_class_install_property (gobject_class,
495 g_param_spec_boolean ("show_heading",
497 P_("If TRUE, a heading is displayed"),
502 * GtkCalendar:show-day-names:
504 * Determines whether day names are displayed.
508 g_object_class_install_property (gobject_class,
510 g_param_spec_boolean ("show_day_names",
511 P_("Show Day Names"),
512 P_("If TRUE, day names are displayed"),
516 * GtkCalendar:no-month-change:
518 * Determines whether the selected month can be changed.
522 g_object_class_install_property (gobject_class,
523 PROP_NO_MONTH_CHANGE,
524 g_param_spec_boolean ("no_month_change",
525 P_("No Month Change"),
526 P_("If TRUE, the selected month cannot be changed"),
531 * GtkCalendar:show-week-numbers:
533 * Determines whether week numbers are displayed.
537 g_object_class_install_property (gobject_class,
538 PROP_SHOW_WEEK_NUMBERS,
539 g_param_spec_boolean ("show_week_numbers",
540 P_("Show Week Numbers"),
541 P_("If TRUE, week numbers are displayed"),
545 gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
546 g_signal_new ("month_changed",
547 G_OBJECT_CLASS_TYPE (gobject_class),
549 G_STRUCT_OFFSET (GtkCalendarClass, month_changed),
551 _gtk_marshal_VOID__VOID,
553 gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
554 g_signal_new ("day_selected",
555 G_OBJECT_CLASS_TYPE (gobject_class),
557 G_STRUCT_OFFSET (GtkCalendarClass, day_selected),
559 _gtk_marshal_VOID__VOID,
561 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
562 g_signal_new ("day_selected_double_click",
563 G_OBJECT_CLASS_TYPE (gobject_class),
565 G_STRUCT_OFFSET (GtkCalendarClass, day_selected_double_click),
567 _gtk_marshal_VOID__VOID,
569 gtk_calendar_signals[PREV_MONTH_SIGNAL] =
570 g_signal_new ("prev_month",
571 G_OBJECT_CLASS_TYPE (gobject_class),
573 G_STRUCT_OFFSET (GtkCalendarClass, prev_month),
575 _gtk_marshal_VOID__VOID,
577 gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
578 g_signal_new ("next_month",
579 G_OBJECT_CLASS_TYPE (gobject_class),
581 G_STRUCT_OFFSET (GtkCalendarClass, next_month),
583 _gtk_marshal_VOID__VOID,
585 gtk_calendar_signals[PREV_YEAR_SIGNAL] =
586 g_signal_new ("prev_year",
587 G_OBJECT_CLASS_TYPE (gobject_class),
589 G_STRUCT_OFFSET (GtkCalendarClass, prev_year),
591 _gtk_marshal_VOID__VOID,
593 gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
594 g_signal_new ("next_year",
595 G_OBJECT_CLASS_TYPE (gobject_class),
597 G_STRUCT_OFFSET (GtkCalendarClass, next_year),
599 _gtk_marshal_VOID__VOID,
608 static const GtkTargetEntry target_table[] = {
609 { "TEXT", 0, TARGET_TEXT },
610 { "STRING", 0, TARGET_TEXT },
611 { "UTF8_STRING", 0, TARGET_TEXT }
615 gtk_calendar_init (GtkCalendar *calendar)
623 GtkCalendarPrivateData *private_data;
627 widget = GTK_WIDGET (calendar);
628 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
630 calendar->private_data = g_malloc (sizeof (GtkCalendarPrivateData));
631 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
633 if (!default_abbreviated_dayname[0])
636 tmp_time= (i+3)*86400;
637 strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
638 default_abbreviated_dayname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
641 if (!default_monthname[0])
645 strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
646 default_monthname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
651 tm = localtime (&secs);
652 calendar->month = tm->tm_mon;
653 calendar->year = 1900 + tm->tm_year;
656 calendar->marked_date[i] = FALSE;
657 calendar->num_marked_dates = 0;
658 calendar->selected_day = tm->tm_mday;
660 calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING |
661 GTK_CALENDAR_SHOW_DAY_NAMES );
663 calendar->highlight_row = -1;
664 calendar->highlight_col = -1;
666 calendar->focus_row = -1;
667 calendar->focus_col = -1;
668 calendar->xor_gc = NULL;
670 private_data->max_year_width = 0;
671 private_data->max_month_width = 0;
672 private_data->max_day_char_width = 0;
673 private_data->max_week_char_width = 0;
675 private_data->max_day_char_ascent = 0;
676 private_data->max_day_char_descent = 0;
677 private_data->max_label_char_ascent = 0;
678 private_data->max_label_char_descent = 0;
680 private_data->arrow_width = 10;
682 private_data->freeze_count = 0;
684 private_data->dirty_header = 0;
685 private_data->dirty_day_names = 0;
686 private_data->dirty_week = 0;
687 private_data->dirty_main = 0;
689 private_data->need_timer = 0;
690 private_data->timer = 0;
691 private_data->click_child = -1;
693 private_data->in_drag = 0;
694 private_data->drag_highlight = 0;
696 gtk_drag_dest_set (widget,
698 target_table, G_N_ELEMENTS (target_table),
701 private_data->year_before = 0;
703 /* Translate to calendar:YM if you want years to be displayed
704 * before months; otherwise translate to calendar:MY.
705 * Do *not* translate it to anything else, if it
706 * it isn't calendar:YM or calendar:MY it will not work.
708 * Note that this flipping is in top the text direction flipping,
709 * so if you have a default text direction of RTL and YM, then
710 * the year will appear on the right.
712 year_before = _("calendar:MY");
713 if (strcmp (year_before, "calendar:YM") == 0)
714 private_data->year_before = 1;
715 else if (strcmp (year_before, "calendar:MY") != 0)
716 g_warning ("Whoever translated calendar:MY did so wrongly.\n");
718 /* Translate to calendar:week_start:0 if you want Sunday to be the
719 * first day of the week to calendar:week_start:1 if you want Monday
720 * to be the first day of the week, and so on.
722 week_start = _("calendar:week_start:0");
724 if (strncmp (week_start, "calendar:week_start:", 20) == 0)
725 private_data->week_start = *(week_start + 20) - '0';
727 private_data->week_start = -1;
729 if (private_data->week_start < 0 || private_data->week_start > 6)
731 g_warning ("Whoever translated calendar:week_start:0 did so wrongly.\n");
732 private_data->week_start = 0;
737 gtk_calendar_new (void)
739 return g_object_new (GTK_TYPE_CALENDAR, NULL);
742 /* column_from_x: returns the column 0-6 that the
743 * x pixel of the xwindow is in */
745 column_from_x (GtkCalendar *calendar,
749 gint x_left, x_right;
753 for (c = 0; c < 7; c++)
755 x_left = left_x_for_column (calendar, c);
756 x_right = x_left + GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
758 if (event_x >= x_left && event_x < x_right)
769 row_height (GtkCalendar *calendar)
771 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h - CALENDAR_MARGIN
772 - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
773 ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
777 /* row_from_y: returns the row 0-5 that the
778 * y pixel of the xwindow is in */
780 row_from_y (GtkCalendar *calendar,
785 gint y_top, y_bottom;
787 height = row_height (calendar);
790 for (r = 0; r < 6; r++)
792 y_top = top_y_for_row (calendar, r);
793 y_bottom = y_top + height;
795 if (event_y >= y_top && event_y < y_bottom)
803 }/* left_x_for_column: returns the x coordinate
804 * for the left of the column */
806 left_x_for_column (GtkCalendar *calendar,
812 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
815 width = GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
816 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
817 x_left = CALENDAR_XSEP + (width + DAY_XSEP) * column;
819 x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
824 /* top_y_for_row: returns the y coordinate
825 * for the top of the row */
827 top_y_for_row (GtkCalendar *calendar,
831 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h
832 - (CALENDAR_MARGIN + (6 - row)
833 * row_height (calendar)));
837 gtk_calendar_set_month_prev (GtkCalendar *calendar)
841 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
844 if (calendar->month == 0)
846 calendar->month = 11;
852 month_len = month_length[leap (calendar->year)][calendar->month + 1];
854 gtk_calendar_freeze (calendar);
855 gtk_calendar_compute_days (calendar);
857 g_signal_emit (calendar,
858 gtk_calendar_signals[PREV_MONTH_SIGNAL],
860 g_signal_emit (calendar,
861 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
864 if (month_len < calendar->selected_day)
866 calendar->selected_day = 0;
867 gtk_calendar_select_day (calendar, month_len);
871 if (calendar->selected_day < 0)
872 calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
873 gtk_calendar_select_day (calendar, calendar->selected_day);
876 gtk_widget_queue_draw (GTK_WIDGET (calendar));
877 gtk_calendar_thaw (calendar);
882 gtk_calendar_set_month_next (GtkCalendar *calendar)
886 g_return_if_fail (GTK_IS_WIDGET (calendar));
888 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
892 if (calendar->month == 11)
900 gtk_calendar_freeze (calendar);
901 gtk_calendar_compute_days (calendar);
902 g_signal_emit (calendar,
903 gtk_calendar_signals[NEXT_MONTH_SIGNAL],
905 g_signal_emit (calendar,
906 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
909 month_len = month_length[leap (calendar->year)][calendar->month + 1];
911 if (month_len < calendar->selected_day)
913 calendar->selected_day = 0;
914 gtk_calendar_select_day (calendar, month_len);
917 gtk_calendar_select_day (calendar, calendar->selected_day);
919 gtk_widget_queue_draw (GTK_WIDGET (calendar));
920 gtk_calendar_thaw (calendar);
924 gtk_calendar_set_year_prev (GtkCalendar *calendar)
928 g_return_if_fail (GTK_IS_WIDGET (calendar));
931 gtk_calendar_freeze (calendar);
932 gtk_calendar_compute_days (calendar);
933 g_signal_emit (calendar,
934 gtk_calendar_signals[PREV_YEAR_SIGNAL],
936 g_signal_emit (calendar,
937 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
940 month_len = month_length[leap (calendar->year)][calendar->month + 1];
942 if (month_len < calendar->selected_day)
944 calendar->selected_day = 0;
945 gtk_calendar_select_day (calendar, month_len);
948 gtk_calendar_select_day (calendar, calendar->selected_day);
950 gtk_widget_queue_draw (GTK_WIDGET (calendar));
951 gtk_calendar_thaw (calendar);
955 gtk_calendar_set_year_next (GtkCalendar *calendar)
960 g_return_if_fail (GTK_IS_WIDGET (calendar));
962 widget = GTK_WIDGET (calendar);
964 gtk_calendar_freeze (calendar);
967 gtk_calendar_compute_days (calendar);
968 g_signal_emit (calendar,
969 gtk_calendar_signals[NEXT_YEAR_SIGNAL],
971 g_signal_emit (calendar,
972 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
975 month_len = month_length[leap (calendar->year)][calendar->month + 1];
977 if (month_len < calendar->selected_day)
979 calendar->selected_day = 0;
980 gtk_calendar_select_day (calendar, month_len);
983 gtk_calendar_select_day (calendar, calendar->selected_day);
985 gtk_widget_queue_draw (GTK_WIDGET (calendar));
986 gtk_calendar_thaw (calendar);
990 gtk_calendar_main_button (GtkWidget *widget,
991 GdkEventButton *event)
993 GtkCalendar *calendar;
994 GtkCalendarPrivateData *private_data;
1000 calendar = GTK_CALENDAR (widget);
1001 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1003 x = (gint) (event->x);
1004 y = (gint) (event->y);
1006 row = row_from_y (calendar, y);
1007 col = column_from_x (calendar, x);
1009 /* If row or column isn't found, just return. */
1010 if (row == -1 || col == -1)
1013 day_month = calendar->day_month[row][col];
1015 if (event->type == GDK_BUTTON_PRESS)
1017 day = calendar->day[row][col];
1019 if (day_month == MONTH_PREV)
1020 gtk_calendar_set_month_prev (calendar);
1021 else if (day_month == MONTH_NEXT)
1022 gtk_calendar_set_month_next (calendar);
1024 if (!GTK_WIDGET_HAS_FOCUS (widget))
1025 gtk_widget_grab_focus (widget);
1027 private_data->in_drag = 1;
1028 private_data->drag_start_x = x;
1029 private_data->drag_start_y = y;
1031 gtk_calendar_select_and_focus_day (calendar, day);
1033 else if (event->type == GDK_2BUTTON_PRESS)
1035 private_data->in_drag = 0;
1036 if (day_month == MONTH_CURRENT)
1037 g_signal_emit (calendar,
1038 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL],
1044 gtk_calendar_realize_arrows (GtkWidget *widget)
1046 GtkCalendar *calendar;
1047 GtkCalendarPrivateData *private_data;
1048 GdkWindowAttr attributes;
1049 gint attributes_mask;
1053 g_return_if_fail (GTK_IS_CALENDAR (widget));
1055 calendar = GTK_CALENDAR (widget);
1056 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1058 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1059 year_left = private_data->year_before;
1061 year_left = !private_data->year_before;
1063 /* Arrow windows ------------------------------------- */
1064 if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1065 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
1067 attributes.wclass = GDK_INPUT_OUTPUT;
1068 attributes.window_type = GDK_WINDOW_CHILD;
1069 attributes.visual = gtk_widget_get_visual (widget);
1070 attributes.colormap = gtk_widget_get_colormap (widget);
1071 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1072 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1073 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1074 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1076 attributes.width = private_data->arrow_width;
1077 attributes.height = private_data->header_h - 7;
1078 for (i = 0; i < 4; i++)
1082 case ARROW_MONTH_LEFT:
1084 attributes.x = (widget->allocation.width - 2 * widget->style->xthickness
1085 - (3 + 2*private_data->arrow_width
1086 + private_data->max_month_width));
1090 case ARROW_MONTH_RIGHT:
1092 attributes.x = (widget->allocation.width - 2 * widget->style->xthickness
1093 - 3 - private_data->arrow_width);
1095 attributes.x = (private_data->arrow_width
1096 + private_data->max_month_width);
1098 case ARROW_YEAR_LEFT:
1102 attributes.x = (widget->allocation.width - 2 * widget->style->xthickness
1103 - (3 + 2*private_data->arrow_width
1104 + private_data->max_year_width));
1106 case ARROW_YEAR_RIGHT:
1108 attributes.x = (private_data->arrow_width
1109 + private_data->max_year_width);
1111 attributes.x = (widget->allocation.width - 2 * widget->style->xthickness
1112 - 3 - private_data->arrow_width);
1115 private_data->arrow_win[i] = gdk_window_new (private_data->header_win,
1118 if (GTK_WIDGET_IS_SENSITIVE (widget))
1119 private_data->arrow_state[i] = GTK_STATE_NORMAL;
1121 private_data->arrow_state[i] = GTK_STATE_INSENSITIVE;
1122 gdk_window_set_background (private_data->arrow_win[i],
1123 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
1124 gdk_window_show (private_data->arrow_win[i]);
1125 gdk_window_set_user_data (private_data->arrow_win[i], widget);
1130 for (i = 0; i < 4; i++)
1131 private_data->arrow_win[i] = NULL;
1136 gtk_calendar_realize_header (GtkWidget *widget)
1138 GtkCalendar *calendar;
1139 GtkCalendarPrivateData *private_data;
1140 GdkWindowAttr attributes;
1141 gint attributes_mask;
1143 g_return_if_fail (GTK_IS_CALENDAR (widget));
1145 calendar = GTK_CALENDAR (widget);
1146 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1148 /* Header window ------------------------------------- */
1149 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1151 attributes.wclass = GDK_INPUT_OUTPUT;
1152 attributes.window_type = GDK_WINDOW_CHILD;
1153 attributes.visual = gtk_widget_get_visual (widget);
1154 attributes.colormap = gtk_widget_get_colormap (widget);
1155 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1156 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1157 attributes.x = widget->style->xthickness;
1158 attributes.y = widget->style->ythickness;
1159 attributes.width = widget->allocation.width - 2 * attributes.x;
1160 attributes.height = private_data->header_h - 2 * attributes.y;
1161 private_data->header_win = gdk_window_new (widget->window,
1162 &attributes, attributes_mask);
1164 gdk_window_set_background (private_data->header_win,
1165 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
1166 gdk_window_show (private_data->header_win);
1167 gdk_window_set_user_data (private_data->header_win, widget);
1172 private_data->header_win = NULL;
1174 gtk_calendar_realize_arrows (widget);
1178 gtk_calendar_realize_day_names (GtkWidget *widget)
1180 GtkCalendar *calendar;
1181 GtkCalendarPrivateData *private_data;
1182 GdkWindowAttr attributes;
1183 gint attributes_mask;
1185 g_return_if_fail (GTK_IS_CALENDAR (widget));
1187 calendar = GTK_CALENDAR (widget);
1188 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1190 /* Day names window --------------------------------- */
1191 if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1193 attributes.wclass = GDK_INPUT_OUTPUT;
1194 attributes.window_type = GDK_WINDOW_CHILD;
1195 attributes.visual = gtk_widget_get_visual (widget);
1196 attributes.colormap = gtk_widget_get_colormap (widget);
1197 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1198 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1199 attributes.x = (widget->style->xthickness + INNER_BORDER);
1200 attributes.y = private_data->header_h + (widget->style->ythickness
1202 attributes.width = (widget->allocation.width
1203 - (widget->style->xthickness + INNER_BORDER)
1205 attributes.height = private_data->day_name_h;
1206 private_data->day_name_win = gdk_window_new (widget->window,
1209 gdk_window_set_background (private_data->day_name_win,
1210 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1211 gdk_window_show (private_data->day_name_win);
1212 gdk_window_set_user_data (private_data->day_name_win, widget);
1216 private_data->day_name_win = NULL;
1221 gtk_calendar_realize_week_numbers (GtkWidget *widget)
1223 GtkCalendar *calendar;
1224 GtkCalendarPrivateData *private_data;
1225 GdkWindowAttr attributes;
1226 gint attributes_mask;
1228 g_return_if_fail (GTK_IS_CALENDAR (widget));
1230 calendar = GTK_CALENDAR (widget);
1231 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1233 /* Week number window -------------------------------- */
1234 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1236 attributes.wclass = GDK_INPUT_OUTPUT;
1237 attributes.window_type = GDK_WINDOW_CHILD;
1238 attributes.visual = gtk_widget_get_visual (widget);
1239 attributes.colormap = gtk_widget_get_colormap (widget);
1240 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1242 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1243 attributes.x = widget->style->xthickness + INNER_BORDER;
1244 attributes.y = (private_data->header_h + private_data->day_name_h
1245 + (widget->style->ythickness + INNER_BORDER));
1246 attributes.width = private_data->week_width;
1247 attributes.height = private_data->main_h;
1248 private_data->week_win = gdk_window_new (widget->window,
1249 &attributes, attributes_mask);
1250 gdk_window_set_background (private_data->week_win,
1251 BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1252 gdk_window_show (private_data->week_win);
1253 gdk_window_set_user_data (private_data->week_win, widget);
1257 private_data->week_win = NULL;
1262 gtk_calendar_realize (GtkWidget *widget)
1264 GtkCalendar *calendar;
1265 GtkCalendarPrivateData *private_data;
1266 GdkWindowAttr attributes;
1267 gint attributes_mask;
1270 calendar = GTK_CALENDAR (widget);
1271 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1273 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1274 gtk_calendar_compute_days (calendar);
1276 attributes.x = widget->allocation.x;
1277 attributes.y = widget->allocation.y;
1278 attributes.width = widget->allocation.width;
1279 attributes.height = widget->allocation.height;
1280 attributes.wclass = GDK_INPUT_OUTPUT;
1281 attributes.window_type = GDK_WINDOW_CHILD;
1282 attributes.event_mask = (gtk_widget_get_events (widget)
1283 | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK | GDK_SCROLL_MASK);
1284 attributes.visual = gtk_widget_get_visual (widget);
1285 attributes.colormap = gtk_widget_get_colormap (widget);
1287 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1288 widget->window = gdk_window_new (widget->parent->window,
1289 &attributes, attributes_mask);
1291 widget->style = gtk_style_attach (widget->style, widget->window);
1293 /* Header window ------------------------------------- */
1294 gtk_calendar_realize_header (widget);
1295 /* Day names window --------------------------------- */
1296 gtk_calendar_realize_day_names (widget);
1297 /* Week number window -------------------------------- */
1298 gtk_calendar_realize_week_numbers (widget);
1299 /* Main Window -------------------------------------- */
1300 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1301 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1302 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1304 attributes.x = private_data->week_width + (widget->style->ythickness + INNER_BORDER);
1305 attributes.y = (private_data->header_h + private_data->day_name_h
1306 + (widget->style->ythickness + INNER_BORDER));
1307 attributes.width = (widget->allocation.width - attributes.x
1308 - (widget->style->xthickness + INNER_BORDER));
1309 attributes.height = private_data->main_h;
1310 private_data->main_win = gdk_window_new (widget->window,
1311 &attributes, attributes_mask);
1312 gdk_window_set_background (private_data->main_win,
1313 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1314 gdk_window_show (private_data->main_win);
1315 gdk_window_set_user_data (private_data->main_win, widget);
1316 gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1317 gdk_window_show (widget->window);
1318 gdk_window_set_user_data (widget->window, widget);
1320 /* Set widgets gc */
1321 calendar->gc = gdk_gc_new (widget->window);
1323 values.foreground = widget->style->white;
1324 values.function = GDK_XOR;
1325 calendar->xor_gc = gdk_gc_new_with_values (widget->window,
1332 gtk_calendar_unrealize (GtkWidget *widget)
1334 GtkCalendar *calendar;
1335 GtkCalendarPrivateData *private_data;
1338 calendar = GTK_CALENDAR (widget);
1339 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1341 if (private_data->header_win)
1343 for (i = 0; i < 4; i++)
1345 if (private_data->arrow_win[i])
1347 gdk_window_set_user_data (private_data->arrow_win[i], NULL);
1348 gdk_window_destroy (private_data->arrow_win[i]);
1349 private_data->arrow_win[i] = NULL;
1352 gdk_window_set_user_data (private_data->header_win, NULL);
1353 gdk_window_destroy (private_data->header_win);
1354 private_data->header_win = NULL;
1357 if (private_data->week_win)
1359 gdk_window_set_user_data (private_data->week_win, NULL);
1360 gdk_window_destroy (private_data->week_win);
1361 private_data->week_win = NULL;
1364 if (private_data->main_win)
1366 gdk_window_set_user_data (private_data->main_win, NULL);
1367 gdk_window_destroy (private_data->main_win);
1368 private_data->main_win = NULL;
1370 if (private_data->day_name_win)
1372 gdk_window_set_user_data (private_data->day_name_win, NULL);
1373 gdk_window_destroy (private_data->day_name_win);
1374 private_data->day_name_win = NULL;
1376 if (calendar->xor_gc)
1377 g_object_unref (calendar->xor_gc);
1379 g_object_unref (calendar->gc);
1381 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1382 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1386 gtk_calendar_size_request (GtkWidget *widget,
1387 GtkRequisition *requisition)
1389 GtkCalendar *calendar;
1390 GtkCalendarPrivateData *private_data;
1391 PangoLayout *layout;
1392 PangoRectangle logical_rect;
1397 gint calendar_margin = CALENDAR_MARGIN;
1398 gint header_width, main_width;
1399 gint max_header_height = 0;
1403 calendar = GTK_CALENDAR (widget);
1404 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1405 gtk_widget_style_get (GTK_WIDGET (widget),
1406 "focus-line-width", &focus_width,
1407 "focus-padding", &focus_padding,
1410 layout = gtk_widget_create_pango_layout (widget, NULL);
1413 * Calculate the requisition width for the widget.
1418 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1420 private_data->max_month_width = 0;
1421 for (i = 0; i < 12; i++)
1423 pango_layout_set_text (layout, default_monthname[i], -1);
1424 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1425 private_data->max_month_width = MAX (private_data->max_month_width,
1426 logical_rect.width + 8);
1427 max_header_height = MAX (max_header_height, logical_rect.height);
1429 private_data->max_year_width = 0;
1430 for (i=0; i<10; i++)
1432 g_snprintf (buffer, sizeof (buffer), "%d%d%d%d", i,i,i,i);
1433 pango_layout_set_text (layout, buffer, -1);
1434 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1435 private_data->max_year_width = MAX (private_data->max_year_width,
1436 logical_rect.width + 8);
1437 max_header_height = MAX (max_header_height, logical_rect.height);
1442 private_data->max_month_width = 0;
1443 private_data->max_year_width = 0;
1446 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1447 header_width = (private_data->max_month_width
1448 + private_data->max_year_width
1451 header_width = (private_data->max_month_width
1452 + private_data->max_year_width
1453 + 4 * private_data->arrow_width + 3 * 3);
1455 /* Mainwindow labels width */
1457 private_data->max_day_char_width = 0;
1458 private_data->min_day_width = 0;
1459 private_data->max_label_char_ascent = 0;
1460 private_data->max_label_char_descent = 0;
1462 for (i = 0; i < 9; i++)
1464 g_snprintf (buffer, sizeof (buffer), "%d%d", i, i);
1465 pango_layout_set_text (layout, buffer, -1);
1466 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1467 private_data->min_day_width = MAX (private_data->min_day_width,
1468 logical_rect.width);
1470 private_data->max_day_char_ascent = MAX (private_data->max_label_char_ascent,
1471 PANGO_ASCENT (logical_rect));
1472 private_data->max_day_char_descent = MAX (private_data->max_label_char_descent,
1473 PANGO_DESCENT (logical_rect));
1475 /* We add one to max_day_char_width to be able to make the marked day "bold" */
1476 private_data->max_day_char_width = private_data->min_day_width / 2 + 1;
1478 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1479 for (i = 0; i < 7; i++)
1481 pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1482 pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1484 private_data->min_day_width = MAX (private_data->min_day_width, logical_rect.width);
1485 private_data->max_label_char_ascent = MAX (private_data->max_label_char_ascent,
1486 PANGO_ASCENT (logical_rect));
1487 private_data->max_label_char_descent = MAX (private_data->max_label_char_descent,
1488 PANGO_DESCENT (logical_rect));
1491 private_data->max_week_char_width = 0;
1492 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1493 for (i = 0; i < 9; i++)
1495 g_snprintf (buffer, sizeof (buffer), "%d%d", i, i);
1496 pango_layout_set_text (layout, buffer, -1);
1497 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1498 private_data->max_week_char_width = MAX (private_data->max_week_char_width,
1499 logical_rect.width / 2);
1502 main_width = (7 * (private_data->min_day_width + (focus_padding + focus_width) * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1503 + (private_data->max_week_char_width
1504 ? private_data->max_week_char_width * 2 + (focus_padding + focus_width) * 2 + CALENDAR_XSEP * 2
1508 requisition->width = MAX (header_width, main_width + INNER_BORDER * 2) + widget->style->xthickness * 2;
1511 * Calculate the requisition height for the widget.
1514 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1516 private_data->header_h = (max_header_height + CALENDAR_YSEP * 2);
1520 private_data->header_h = 0;
1523 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1525 private_data->day_name_h = (private_data->max_label_char_ascent
1526 + private_data->max_label_char_descent
1527 + 2 * (focus_padding + focus_width) + calendar_margin);
1528 calendar_margin = CALENDAR_YSEP;
1532 private_data->day_name_h = 0;
1535 private_data->main_h = (CALENDAR_MARGIN + calendar_margin
1536 + 6 * (private_data->max_day_char_ascent
1537 + private_data->max_day_char_descent
1538 + 2 * (focus_padding + focus_width))
1541 height = (private_data->header_h + private_data->day_name_h
1542 + private_data->main_h);
1544 requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1546 g_object_unref (layout);
1550 gtk_calendar_size_allocate (GtkWidget *widget,
1551 GtkAllocation *allocation)
1553 GtkCalendar *calendar;
1554 GtkCalendarPrivateData *private_data;
1555 gint xthickness = widget->style->xthickness;
1556 gint ythickness = widget->style->xthickness;
1559 widget->allocation = *allocation;
1561 calendar = GTK_CALENDAR (widget);
1562 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1564 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1565 year_left = private_data->year_before;
1567 year_left = !private_data->year_before;
1569 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1571 private_data->day_width = (private_data->min_day_width
1572 * ((allocation->width - (xthickness + INNER_BORDER) * 2
1573 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 6) - CALENDAR_XSEP * 2))
1574 / (7 * private_data->min_day_width + private_data->max_week_char_width * 2));
1575 private_data->week_width = ((allocation->width - (xthickness + INNER_BORDER) * 2
1576 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 6) - CALENDAR_XSEP * 2 )
1577 - private_data->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1581 private_data->day_width = (allocation->width
1582 - (xthickness + INNER_BORDER) * 2
1583 - (CALENDAR_MARGIN * 2)
1584 - (DAY_XSEP * 6))/7;
1585 private_data->week_width = 0;
1588 if (GTK_WIDGET_REALIZED (widget))
1590 gdk_window_move_resize (widget->window,
1591 allocation->x, allocation->y,
1592 allocation->width, allocation->height);
1593 if (private_data->header_win)
1594 gdk_window_move_resize (private_data->header_win,
1595 xthickness, ythickness,
1596 allocation->width - 2 * xthickness, private_data->header_h);
1597 if (private_data->arrow_win[ARROW_MONTH_LEFT])
1600 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1601 (allocation->width - 2 * xthickness
1602 - (3 + 2*private_data->arrow_width
1603 + private_data->max_month_width)),
1605 private_data->arrow_width,
1606 private_data->header_h - 7);
1608 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1610 private_data->arrow_width,
1611 private_data->header_h - 7);
1613 if (private_data->arrow_win[ARROW_MONTH_RIGHT])
1616 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1617 (allocation->width - 2 * xthickness
1618 - 3 - private_data->arrow_width),
1620 private_data->arrow_width,
1621 private_data->header_h - 7);
1623 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1624 (private_data->arrow_width
1625 + private_data->max_month_width),
1627 private_data->arrow_width,
1628 private_data->header_h - 7);
1630 if (private_data->arrow_win[ARROW_YEAR_LEFT])
1633 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1635 private_data->arrow_width,
1636 private_data->header_h - 7);
1638 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1639 (allocation->width - 2 * xthickness
1640 - (3 + 2*private_data->arrow_width
1641 + private_data->max_year_width)),
1643 private_data->arrow_width,
1644 private_data->header_h - 7);
1646 if (private_data->arrow_win[ARROW_YEAR_RIGHT])
1649 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1650 (private_data->arrow_width
1651 + private_data->max_year_width),
1653 private_data->arrow_width,
1654 private_data->header_h - 7);
1656 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1657 (allocation->width - 2 * xthickness
1658 - 3 - private_data->arrow_width),
1660 private_data->arrow_width,
1661 private_data->header_h - 7);
1663 if (private_data->day_name_win)
1664 gdk_window_move_resize (private_data->day_name_win,
1665 xthickness + INNER_BORDER,
1666 private_data->header_h + (widget->style->ythickness + INNER_BORDER),
1667 allocation->width - (xthickness + INNER_BORDER) * 2,
1668 private_data->day_name_h);
1669 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1671 if (private_data->week_win)
1672 gdk_window_move_resize (private_data->week_win,
1673 (xthickness + INNER_BORDER),
1674 private_data->header_h + private_data->day_name_h
1675 + (widget->style->ythickness + INNER_BORDER),
1676 private_data->week_width,
1677 private_data->main_h);
1678 gdk_window_move_resize (private_data->main_win,
1679 private_data->week_width + (xthickness + INNER_BORDER),
1680 private_data->header_h + private_data->day_name_h
1681 + (widget->style->ythickness + INNER_BORDER),
1683 - private_data->week_width
1684 - (xthickness + INNER_BORDER) * 2,
1685 private_data->main_h);
1689 gdk_window_move_resize (private_data->main_win,
1690 (xthickness + INNER_BORDER),
1691 private_data->header_h + private_data->day_name_h
1692 + (widget->style->ythickness + INNER_BORDER),
1694 - private_data->week_width
1695 - (xthickness + INNER_BORDER) * 2,
1696 private_data->main_h);
1697 if (private_data->week_win)
1698 gdk_window_move_resize (private_data->week_win,
1700 - private_data->week_width
1701 - (xthickness + INNER_BORDER),
1702 private_data->header_h + private_data->day_name_h
1703 + (widget->style->ythickness + INNER_BORDER),
1704 private_data->week_width,
1705 private_data->main_h);
1711 gtk_calendar_expose (GtkWidget *widget,
1712 GdkEventExpose *event)
1714 GtkCalendar *calendar;
1715 GtkCalendarPrivateData *private_data;
1717 calendar = GTK_CALENDAR (widget);
1718 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1720 if (GTK_WIDGET_DRAWABLE (widget))
1722 if (event->window == private_data->main_win)
1723 gtk_calendar_paint_main (widget);
1725 if (event->window == private_data->header_win)
1726 gtk_calendar_paint_header (widget);
1728 if (event->window == private_data->day_name_win)
1729 gtk_calendar_paint_day_names (widget);
1731 if (event->window == private_data->week_win)
1732 gtk_calendar_paint_week_numbers (widget);
1733 if (event->window == widget->window)
1735 gtk_paint_shadow (widget->style, widget->window, GTK_WIDGET_STATE (widget),
1736 GTK_SHADOW_IN, NULL, widget, "calendar",
1737 0, 0, widget->allocation.width, widget->allocation.height);
1745 gtk_calendar_paint_header (GtkWidget *widget)
1747 GtkCalendar *calendar;
1751 gint header_width, cal_height;
1752 gint max_month_width;
1753 gint max_year_width;
1754 GtkCalendarPrivateData *private_data;
1755 PangoLayout *layout;
1756 PangoRectangle logical_rect;
1759 calendar = GTK_CALENDAR (widget);
1760 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1762 if (private_data->freeze_count)
1764 private_data->dirty_header = 1;
1768 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1769 year_left = private_data->year_before;
1771 year_left = !private_data->year_before;
1773 private_data->dirty_header = 0;
1777 gdk_window_clear (private_data->header_win);
1779 header_width = widget->allocation.width - 2 * widget->style->xthickness;
1780 cal_height = widget->allocation.height;
1782 max_month_width = private_data->max_month_width;
1783 max_year_width = private_data->max_year_width;
1785 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1786 gtk_paint_shadow (widget->style, private_data->header_win,
1787 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1788 NULL, widget, "calendar",
1789 0, 0, header_width, private_data->header_h);
1792 g_snprintf (buffer, sizeof (buffer), "%d", calendar->year);
1793 layout = gtk_widget_create_pango_layout (widget, buffer);
1794 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1797 y = (private_data->header_h - logical_rect.height) / 2;
1799 /* Draw year and its arrows */
1801 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1803 x = 3 + (max_year_width - logical_rect.width)/2;
1805 x = header_width - (3 + max_year_width
1806 - (max_year_width - logical_rect.width)/2);
1809 x = 3 + private_data->arrow_width + (max_year_width - logical_rect.width)/2;
1811 x = header_width - (3 + private_data->arrow_width + max_year_width
1812 - (max_year_width - logical_rect.width)/2);
1815 gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1816 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1819 g_snprintf (buffer, sizeof (buffer), "%s", default_monthname[calendar->month]);
1820 pango_layout_set_text (layout, buffer, -1);
1821 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1823 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1825 x = header_width - (3 + max_month_width
1826 - (max_month_width - logical_rect.width)/2);
1828 x = 3 + (max_month_width - logical_rect.width) / 2;
1831 x = header_width - (3 + private_data->arrow_width + max_month_width
1832 - (max_month_width - logical_rect.width)/2);
1834 x = 3 + private_data->arrow_width + (max_month_width - logical_rect.width)/2;
1836 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1838 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1840 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
1841 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
1842 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
1843 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
1845 g_object_unref (layout);
1849 gtk_calendar_paint_day_names (GtkWidget *widget)
1851 GtkCalendar *calendar;
1855 int day_width, cal_width;
1858 PangoLayout *layout;
1859 PangoRectangle logical_rect;
1860 GtkCalendarPrivateData *private_data;
1864 g_return_if_fail (GTK_IS_CALENDAR (widget));
1865 calendar = GTK_CALENDAR (widget);
1866 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1869 gtk_widget_style_get (GTK_WIDGET (widget),
1870 "focus-line-width", &focus_width,
1871 "focus-padding", &focus_padding,
1874 * Handle freeze/thaw functionality
1877 if (private_data->freeze_count)
1879 private_data->dirty_day_names = 1;
1882 private_data->dirty_day_names = 0;
1888 gdk_window_clear (private_data->day_name_win);
1890 day_width = private_data->day_width;
1891 cal_width = widget->allocation.width;
1892 cal_height = widget->allocation.height;
1893 day_wid_sep = day_width + DAY_XSEP;
1896 * Draw rectangles as inverted background for the labels.
1899 gdk_gc_set_foreground (gc, SELECTED_BG_COLOR (widget));
1900 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1901 CALENDAR_MARGIN, CALENDAR_MARGIN,
1902 cal_width-CALENDAR_MARGIN * 2,
1903 private_data->day_name_h - CALENDAR_MARGIN);
1905 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1906 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1908 private_data->day_name_h - CALENDAR_YSEP,
1909 private_data->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1916 layout = gtk_widget_create_pango_layout (widget, NULL);
1918 gdk_gc_set_foreground (gc, SELECTED_FG_COLOR (widget));
1919 for (i = 0; i < 7; i++)
1921 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
1925 day = (day + private_data->week_start) % 7;
1926 g_snprintf (buffer, sizeof (buffer), "%s", default_abbreviated_dayname[day]);
1928 pango_layout_set_text (layout, buffer, -1);
1929 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1931 gdk_draw_layout (private_data->day_name_win, gc,
1933 + (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ?
1934 (private_data->week_width + (private_data->week_width ? CALENDAR_XSEP : 0))
1937 + (day_width - logical_rect.width)/2),
1938 CALENDAR_MARGIN + focus_width + focus_padding + logical_rect.y,
1942 g_object_unref (layout);
1946 gtk_calendar_paint_week_numbers (GtkWidget *widget)
1948 GtkCalendar *calendar;
1950 gint row, week = 0, year;
1953 gint y_loc, day_height;
1954 GtkCalendarPrivateData *private_data;
1955 PangoLayout *layout;
1956 PangoRectangle logical_rect;
1960 g_return_if_fail (GTK_IS_CALENDAR (widget));
1961 g_return_if_fail (widget->window != NULL);
1962 calendar = GTK_CALENDAR (widget);
1963 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1967 * Handle freeze/thaw functionality
1970 if (private_data->freeze_count)
1972 private_data->dirty_week = 1;
1975 private_data->dirty_week = 0;
1977 gtk_widget_style_get (GTK_WIDGET (widget),
1978 "focus-line-width", &focus_width,
1979 "focus-padding", &focus_padding,
1986 gdk_window_clear (private_data->week_win);
1989 * Draw a rectangle as inverted background for the labels.
1992 gdk_gc_set_foreground (gc, SELECTED_BG_COLOR (widget));
1993 if (private_data->day_name_win)
1994 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1997 private_data->week_width - CALENDAR_MARGIN,
1998 private_data->main_h - CALENDAR_MARGIN);
2000 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
2003 private_data->week_width - CALENDAR_MARGIN,
2004 private_data->main_h - 2 * CALENDAR_MARGIN);
2010 layout = gtk_widget_create_pango_layout (widget, NULL);
2012 gdk_gc_set_foreground (gc, SELECTED_FG_COLOR (widget));
2013 day_height = row_height (calendar);
2014 for (row = 0; row < 6; row++)
2016 year = calendar->year;
2017 if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
2020 g_return_if_fail (week_of_year (&week, &year,
2021 ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
2022 + calendar->month) % 12 + 1, calendar->day[row][6]));
2024 g_snprintf (buffer, sizeof (buffer), "%d", week);
2025 pango_layout_set_text (layout, buffer, -1);
2026 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2028 y_loc = top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
2030 x_loc = (private_data->week_width
2031 - logical_rect.width
2032 - CALENDAR_XSEP - focus_padding - focus_width);
2034 gdk_draw_layout (private_data->week_win, gc, x_loc, y_loc, layout);
2037 g_object_unref (layout);
2041 gtk_calendar_paint_day_num (GtkWidget *widget,
2044 GtkCalendar *calendar;
2045 gint r, c, row, col;
2047 g_return_if_fail (GTK_IS_CALENDAR (widget));
2049 calendar = GTK_CALENDAR (widget);
2053 for (r = 0; r < 6; r++)
2054 for (c = 0; c < 7; c++)
2055 if (calendar->day_month[r][c] == MONTH_CURRENT &&
2056 calendar->day[r][c] == day)
2062 g_return_if_fail (row != -1);
2063 g_return_if_fail (col != -1);
2065 gtk_calendar_paint_day (widget, row, col);
2069 gtk_calendar_paint_day (GtkWidget *widget,
2073 GtkCalendar *calendar;
2085 GtkCalendarPrivateData *private_data;
2086 PangoLayout *layout;
2087 PangoRectangle logical_rect;
2089 g_return_if_fail (GTK_IS_CALENDAR (widget));
2090 g_return_if_fail (row < 6);
2091 g_return_if_fail (col < 7);
2092 calendar = GTK_CALENDAR (widget);
2093 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2096 * Handle freeze/thaw functionality
2099 if (private_data->freeze_count)
2101 private_data->dirty_main = 1;
2105 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2107 day_height = row_height (calendar);
2109 day_xspace = private_data->day_width - private_data->max_day_char_width*2;
2111 day = calendar->day[row][col];
2113 x_left = left_x_for_column (calendar, col);
2114 x_loc = x_left + private_data->day_width / 2 + private_data->max_day_char_width;
2116 y_top = top_y_for_row (calendar, row);
2118 gdk_window_clear_area (private_data->main_win, x_left, y_top,
2119 private_data->day_width, day_height);
2123 if (calendar->day_month[row][col] == MONTH_PREV)
2125 gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar)));
2127 else if (calendar->day_month[row][col] == MONTH_NEXT)
2129 gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar)));
2134 if (calendar->highlight_row == row && calendar->highlight_col == col)
2136 gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar)));
2137 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
2138 private_data->day_width, day_height);
2141 if (calendar->selected_day == day)
2143 gdk_gc_set_foreground (gc, SELECTED_BG_COLOR (GTK_WIDGET (calendar)));
2144 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
2145 private_data->day_width, day_height);
2148 if (calendar->marked_date[day-1])
2149 gdk_gc_set_foreground (gc, MARKED_COLOR (GTK_WIDGET (calendar)));
2151 gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar)));
2153 if (calendar->selected_day == day)
2154 gdk_gc_set_foreground (gc, SELECTED_FG_COLOR (GTK_WIDGET (calendar)));
2156 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_WIDGET_STATE (calendar)]));
2160 g_snprintf (buffer, sizeof (buffer), "%d", day);
2161 layout = gtk_widget_create_pango_layout (widget, buffer);
2162 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2164 x_loc -= logical_rect.width;
2166 y_loc = y_top + (day_height - logical_rect.height) / 2;
2167 gdk_draw_layout (private_data->main_win, gc,
2168 x_loc, y_loc, layout);
2169 if (calendar->marked_date[day-1]
2170 && calendar->day_month[row][col] == MONTH_CURRENT)
2171 gdk_draw_layout (private_data->main_win, gc,
2172 x_loc-1, y_loc, layout);
2174 if (GTK_WIDGET_HAS_FOCUS (calendar)
2175 && calendar->focus_row == row && calendar->focus_col == col)
2179 if (calendar->selected_day == day)
2180 state = GTK_WIDGET_HAS_FOCUS (widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
2182 state = GTK_STATE_NORMAL;
2184 gtk_paint_focus (widget->style,
2185 private_data->main_win,
2186 (calendar->selected_day == day)
2187 ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2188 NULL, widget, "calendar-day",
2190 private_data->day_width,
2194 g_object_unref (layout);
2199 gtk_calendar_paint_main (GtkWidget *widget)
2201 GtkCalendar *calendar;
2202 GtkCalendarPrivateData *private_data;
2205 g_return_if_fail (GTK_IS_CALENDAR (widget));
2206 g_return_if_fail (widget->window != NULL);
2208 calendar = GTK_CALENDAR (widget);
2209 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2211 if (private_data->freeze_count)
2213 private_data->dirty_main = 1;
2216 private_data->dirty_main = 0;
2217 gdk_window_clear (private_data->main_win);
2219 /* gtk_calendar_compute_days (calendar); */ /* REMOVE later */
2221 for (col = 0; col < 7; col++)
2222 for (row = 0; row < 6; row++)
2223 gtk_calendar_paint_day (widget, row, col);
2227 gtk_calendar_compute_days (GtkCalendar *calendar)
2229 GtkCalendarPrivateData *private_data;
2232 gint ndays_in_month;
2233 gint ndays_in_prev_month;
2239 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2241 private_data = GTK_CALENDAR_PRIVATE_DATA (GTK_WIDGET (calendar));
2243 year = calendar->year;
2244 month = calendar->month + 1;
2246 ndays_in_month = month_length[leap (year)][month];
2248 first_day = day_of_week (year, month, 1);
2249 first_day = (first_day + 7 - private_data->week_start) % 7;
2251 /* Compute days of previous month */
2253 ndays_in_prev_month = month_length[leap (year)][month-1];
2255 ndays_in_prev_month = month_length[leap (year)][12];
2256 day = ndays_in_prev_month - first_day + 1;
2261 for (col = 0; col < first_day; col++)
2263 calendar->day[row][col] = day;
2264 calendar->day_month[row][col] = MONTH_PREV;
2269 /* Compute days of current month */
2271 for (day = 1; day <= ndays_in_month; day++)
2273 calendar->day[row][col] = day;
2274 calendar->day_month[row][col] = MONTH_CURRENT;
2284 /* Compute days of next month */
2286 for (; row <= 5; row++)
2288 for (; col <= 6; col++)
2290 calendar->day[row][col] = day;
2291 calendar->day_month[row][col] = MONTH_NEXT;
2299 gtk_calendar_display_options (GtkCalendar *calendar,
2300 GtkCalendarDisplayOptions flags)
2302 gtk_calendar_set_display_options (calendar, flags);
2306 * gtk_calendar_get_display_options:
2307 * @calendar: a #GtkCalendar
2309 * Returns the current display options of @calendar.
2311 * Return value: the display options.
2315 GtkCalendarDisplayOptions
2316 gtk_calendar_get_display_options (GtkCalendar *calendar)
2318 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), 0);
2320 return calendar->display_flags;
2324 * gtk_calendar_set_display_options:
2325 * @calendar: a #GtkCalendar
2326 * @flags: the display options to set
2328 * Sets display options (whether to display the heading and the month
2334 gtk_calendar_set_display_options (GtkCalendar *calendar,
2335 GtkCalendarDisplayOptions flags)
2337 GtkCalendarPrivateData *private_data;
2341 GtkCalendarDisplayOptions old_flags;
2343 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2345 widget = GTK_WIDGET (calendar);
2346 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2347 old_flags = calendar->display_flags;
2349 if (GTK_WIDGET_REALIZED (widget))
2351 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2354 if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
2355 && (private_data->header_win))
2357 calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
2358 gtk_calendar_realize_arrows (widget);
2362 for (i = 0; i < 4; i++)
2364 if (private_data->arrow_win[i])
2366 gdk_window_set_user_data (private_data->arrow_win[i],
2368 gdk_window_destroy (private_data->arrow_win[i]);
2369 private_data->arrow_win[i] = NULL;
2375 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2379 if (flags & GTK_CALENDAR_SHOW_HEADING)
2381 calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
2382 gtk_calendar_realize_header (widget);
2386 for (i = 0; i < 4; i++)
2388 if (private_data->arrow_win[i])
2390 gdk_window_set_user_data (private_data->arrow_win[i],
2392 gdk_window_destroy (private_data->arrow_win[i]);
2393 private_data->arrow_win[i] = NULL;
2396 gdk_window_set_user_data (private_data->header_win, NULL);
2397 gdk_window_destroy (private_data->header_win);
2398 private_data->header_win = NULL;
2403 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2407 if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
2409 calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
2410 gtk_calendar_realize_day_names (widget);
2414 gdk_window_set_user_data (private_data->day_name_win, NULL);
2415 gdk_window_destroy (private_data->day_name_win);
2416 private_data->day_name_win = NULL;
2420 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2424 if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2426 calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
2427 gtk_calendar_realize_week_numbers (widget);
2431 gdk_window_set_user_data (private_data->week_win, NULL);
2432 gdk_window_destroy (private_data->week_win);
2433 private_data->week_win = NULL;
2437 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
2438 g_warning ("GTK_CALENDAR_WEEK_START_MONDAY is ignored; the first day of the week is determined from the locale");
2440 calendar->display_flags = flags;
2442 gtk_widget_queue_resize (GTK_WIDGET (calendar));
2446 calendar->display_flags = flags;
2448 g_object_freeze_notify (G_OBJECT (calendar));
2449 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2450 g_object_notify (G_OBJECT (calendar), "show_heading");
2451 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2452 g_object_notify (G_OBJECT (calendar), "show_day_names");
2453 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2454 g_object_notify (G_OBJECT (calendar), "no_month_change");
2455 if ((old_flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2456 g_object_notify (G_OBJECT (calendar), "show_week_numbers");
2457 g_object_thaw_notify (G_OBJECT (calendar));
2461 gtk_calendar_select_month (GtkCalendar *calendar,
2465 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2466 g_return_val_if_fail (month <= 11, FALSE);
2468 calendar->month = month;
2469 calendar->year = year;
2471 gtk_calendar_compute_days (calendar);
2473 gtk_widget_queue_draw (GTK_WIDGET (calendar));
2475 g_object_freeze_notify (G_OBJECT (calendar));
2476 g_object_notify (G_OBJECT (calendar), "month");
2477 g_object_notify (G_OBJECT (calendar), "year");
2478 g_object_thaw_notify (G_OBJECT (calendar));
2480 g_signal_emit (calendar,
2481 gtk_calendar_signals[MONTH_CHANGED_SIGNAL],
2487 gtk_calendar_select_day (GtkCalendar *calendar,
2490 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2491 g_return_if_fail (day <= 31);
2493 /* gtk_calendar_compute_days (calendar); */
2495 /* Deselect the old day */
2496 if (calendar->selected_day > 0)
2500 selected_day = calendar->selected_day;
2501 calendar->selected_day = 0;
2502 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2503 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day);
2506 calendar->selected_day = day;
2508 /* Select the new day */
2511 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2512 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day);
2515 g_object_notify (G_OBJECT (calendar), "day");
2517 g_signal_emit (calendar,
2518 gtk_calendar_signals[DAY_SELECTED_SIGNAL],
2523 gtk_calendar_select_and_focus_day (GtkCalendar *calendar,
2526 gint old_focus_row = calendar->focus_row;
2527 gint old_focus_col = calendar->focus_col;
2531 for (row = 0; row < 6; row ++)
2532 for (col = 0; col < 7; col++)
2534 if (calendar->day_month[row][col] == MONTH_CURRENT
2535 && calendar->day[row][col] == day)
2537 calendar->focus_row = row;
2538 calendar->focus_col = col;
2542 if (old_focus_row != -1 && old_focus_col != -1)
2543 gtk_calendar_paint_day (GTK_WIDGET (calendar), old_focus_row, old_focus_col);
2545 gtk_calendar_select_day (calendar, day);
2549 gtk_calendar_clear_marks (GtkCalendar *calendar)
2553 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2555 for (day = 0; day < 31; day++)
2557 calendar->marked_date[day] = FALSE;
2560 calendar->num_marked_dates = 0;
2562 if (GTK_WIDGET_DRAWABLE (calendar))
2564 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2569 gtk_calendar_mark_day (GtkCalendar *calendar,
2572 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2574 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
2576 calendar->marked_date[day - 1] = TRUE;
2577 calendar->num_marked_dates++;
2579 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2581 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2588 gtk_calendar_unmark_day (GtkCalendar *calendar,
2591 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2593 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
2595 calendar->marked_date[day - 1] = FALSE;
2596 calendar->num_marked_dates--;
2599 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2601 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2608 gtk_calendar_get_date (GtkCalendar *calendar,
2613 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2616 *year = calendar->year;
2619 *month = calendar->month;
2622 *day = calendar->selected_day;
2625 #define CALENDAR_INITIAL_TIMER_DELAY 200
2626 #define CALENDAR_TIMER_DELAY 20
2629 arrow_action (GtkCalendar *calendar,
2634 case ARROW_YEAR_LEFT:
2635 gtk_calendar_set_year_prev (calendar);
2637 case ARROW_YEAR_RIGHT:
2638 gtk_calendar_set_year_next (calendar);
2640 case ARROW_MONTH_LEFT:
2641 gtk_calendar_set_month_prev (calendar);
2643 case ARROW_MONTH_RIGHT:
2644 gtk_calendar_set_month_next (calendar);
2652 calendar_timer (gpointer data)
2654 GtkCalendar *calendar = data;
2655 GtkCalendarPrivateData *private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2656 gboolean retval = FALSE;
2658 GDK_THREADS_ENTER ();
2660 if (private_data->timer)
2662 arrow_action (calendar, private_data->click_child);
2664 if (private_data->need_timer)
2666 private_data->need_timer = FALSE;
2667 private_data->timer = g_timeout_add (CALENDAR_TIMER_DELAY,
2668 (GSourceFunc) calendar_timer,
2669 (gpointer) calendar);
2675 GDK_THREADS_LEAVE ();
2681 start_spinning (GtkWidget *widget,
2684 GtkCalendarPrivateData *private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2686 private_data->click_child = click_child;
2688 if (!private_data->timer)
2690 private_data->need_timer = TRUE;
2691 private_data->timer = g_timeout_add (CALENDAR_INITIAL_TIMER_DELAY,
2698 stop_spinning (GtkWidget *widget)
2700 GtkCalendarPrivateData *private_data;
2702 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2704 if (private_data->timer)
2706 g_source_remove (private_data->timer);
2707 private_data->timer = 0;
2708 private_data->need_timer = FALSE;
2713 gtk_calendar_destroy (GtkObject *object)
2715 stop_spinning (GTK_WIDGET (object));
2717 GTK_OBJECT_CLASS (parent_class)->destroy (object);
2721 gtk_calendar_grab_notify (GtkWidget *widget,
2722 gboolean was_grabbed)
2725 stop_spinning (widget);
2729 gtk_calendar_focus_out (GtkWidget *widget,
2730 GdkEventFocus *event)
2732 GtkCalendarPrivateData *private_data;
2734 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2736 stop_spinning (widget);
2738 private_data->in_drag = 0;
2744 gtk_calendar_button_press (GtkWidget *widget,
2745 GdkEventButton *event)
2747 GtkCalendar *calendar;
2748 GtkCalendarPrivateData *private_data;
2751 calendar = GTK_CALENDAR (widget);
2752 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2754 if (event->window == private_data->main_win)
2755 gtk_calendar_main_button (widget, event);
2757 if (!GTK_WIDGET_HAS_FOCUS (widget))
2758 gtk_widget_grab_focus (widget);
2760 for (arrow = ARROW_YEAR_LEFT; arrow <= ARROW_MONTH_RIGHT; arrow++)
2762 if (event->window == private_data->arrow_win[arrow])
2765 /* only call the action on single click, not double */
2766 if (event->type == GDK_BUTTON_PRESS)
2768 if (event->button == 1)
2769 start_spinning (widget, arrow);
2771 arrow_action (calendar, arrow);
2782 gtk_calendar_button_release (GtkWidget *widget,
2783 GdkEventButton *event)
2785 GtkCalendar *calendar;
2786 GtkCalendarPrivateData *private_data;
2788 calendar = GTK_CALENDAR (widget);
2789 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2791 if (event->button == 1)
2793 stop_spinning (widget);
2795 if (private_data->in_drag)
2796 private_data->in_drag = 0;
2803 gtk_calendar_motion_notify (GtkWidget *widget,
2804 GdkEventMotion *event)
2806 GtkCalendar *calendar;
2807 GtkCalendarPrivateData *private_data;
2808 gint event_x, event_y;
2810 gint old_row, old_col;
2812 calendar = GTK_CALENDAR (widget);
2813 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2814 event_x = (gint) (event->x);
2815 event_y = (gint) (event->y);
2817 if (event->window == private_data->main_win)
2820 if (private_data->in_drag)
2822 if (gtk_drag_check_threshold (widget,
2823 private_data->drag_start_x, private_data->drag_start_y,
2824 event->x, event->y))
2826 GdkDragContext *context;
2827 GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
2828 context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY,
2829 1, (GdkEvent *)event);
2832 private_data->in_drag = 0;
2834 gtk_target_list_unref (target_list);
2835 gtk_drag_set_icon_default (context);
2840 row = row_from_y (calendar, event_y);
2841 col = column_from_x (calendar, event_x);
2843 if (row != calendar->highlight_row || calendar->highlight_col != col)
2845 old_row = calendar->highlight_row;
2846 old_col = calendar->highlight_col;
2847 if (old_row > -1 && old_col > -1)
2849 calendar->highlight_row = -1;
2850 calendar->highlight_col = -1;
2851 gtk_calendar_paint_day (widget, old_row, old_col);
2854 calendar->highlight_row = row;
2855 calendar->highlight_col = col;
2857 if (row > -1 && col > -1)
2858 gtk_calendar_paint_day (widget, row, col);
2866 gtk_calendar_enter_notify (GtkWidget *widget,
2867 GdkEventCrossing *event)
2869 GtkCalendar *calendar;
2870 GtkCalendarPrivateData *private_data;
2872 calendar = GTK_CALENDAR (widget);
2873 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2875 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2877 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2878 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2881 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2883 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2884 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2887 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2889 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2890 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2893 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2895 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2896 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2903 gtk_calendar_leave_notify (GtkWidget *widget,
2904 GdkEventCrossing *event)
2906 GtkCalendar *calendar;
2907 GtkCalendarPrivateData *private_data;
2911 calendar = GTK_CALENDAR (widget);
2912 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2914 if (event->window == private_data->main_win)
2916 row = calendar->highlight_row;
2917 col = calendar->highlight_col;
2918 calendar->highlight_row = -1;
2919 calendar->highlight_col = -1;
2920 if (row > -1 && col > -1)
2921 gtk_calendar_paint_day (widget, row, col);
2924 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2926 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2927 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2930 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2932 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2933 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2936 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2938 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2939 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2942 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2944 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2945 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2952 gtk_calendar_paint_arrow (GtkWidget *widget,
2955 GtkCalendarPrivateData *private_data;
2958 GtkCalendar *calendar;
2962 calendar = GTK_CALENDAR (widget);
2963 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2965 if (private_data->freeze_count)
2967 private_data->dirty_header = 1;
2970 window = private_data->arrow_win[arrow];
2973 state = private_data->arrow_state[arrow];
2976 gdk_window_clear (window);
2977 gdk_window_set_background (window, &(widget)->style->bg[state]);
2978 gdk_drawable_get_size (window, &width, &height);
2979 gdk_window_clear_area (window,
2982 if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2983 gtk_paint_arrow (widget->style, window, state,
2984 GTK_SHADOW_OUT, NULL, widget, "calendar",
2985 GTK_ARROW_LEFT, TRUE,
2986 width/2 - 3, height/2 - 4, 8, 8);
2988 gtk_paint_arrow (widget->style, window, state,
2989 GTK_SHADOW_OUT, NULL, widget, "calendar",
2990 GTK_ARROW_RIGHT, TRUE,
2991 width/2 - 2, height/2 - 4, 8, 8);
2996 gtk_calendar_freeze (GtkCalendar *calendar)
2998 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3000 GTK_CALENDAR_PRIVATE_DATA (calendar)->freeze_count++;
3004 gtk_calendar_thaw (GtkCalendar *calendar)
3006 GtkCalendarPrivateData *private_data;
3008 g_return_if_fail (GTK_IS_CALENDAR (calendar));
3010 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
3012 if (private_data->freeze_count)
3013 if (!(--private_data->freeze_count))
3015 if (private_data->dirty_header)
3016 if (GTK_WIDGET_DRAWABLE (calendar))
3017 gtk_calendar_paint_header (GTK_WIDGET (calendar));
3019 if (private_data->dirty_day_names)
3020 if (GTK_WIDGET_DRAWABLE (calendar))
3021 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
3023 if (private_data->dirty_week)
3024 if (GTK_WIDGET_DRAWABLE (calendar))
3025 gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar));
3027 if (private_data->dirty_main)
3028 if (GTK_WIDGET_DRAWABLE (calendar))
3029 gtk_calendar_paint_main (GTK_WIDGET (calendar));
3034 gtk_calendar_set_background (GtkWidget *widget)
3036 GtkCalendar *calendar;
3037 GtkCalendarPrivateData *private_data;
3040 calendar = GTK_CALENDAR (widget);
3041 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
3043 if (GTK_WIDGET_REALIZED (widget))
3045 for (i = 0; i < 4; i++)
3047 if (private_data->arrow_win[i])
3048 gdk_window_set_background (private_data->arrow_win[i],
3049 HEADER_BG_COLOR (widget));
3051 if (private_data->header_win)
3052 gdk_window_set_background (private_data->header_win,
3053 HEADER_BG_COLOR (widget));
3054 if (private_data->day_name_win)
3055 gdk_window_set_background (private_data->day_name_win,
3056 BACKGROUND_COLOR (widget));
3057 if (private_data->week_win)
3058 gdk_window_set_background (private_data->week_win,
3059 BACKGROUND_COLOR (widget));
3060 if (private_data->main_win)
3061 gdk_window_set_background (private_data->main_win,
3062 BACKGROUND_COLOR (widget));
3064 gdk_window_set_background (widget->window,
3065 BACKGROUND_COLOR (widget));
3070 gtk_calendar_style_set (GtkWidget *widget,
3071 GtkStyle *previous_style)
3073 if (previous_style && GTK_WIDGET_REALIZED (widget))
3074 gtk_calendar_set_background(widget);
3078 gtk_calendar_state_changed (GtkWidget *widget,
3079 GtkStateType previous_state)
3081 GtkCalendarPrivateData *private_data;
3084 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
3086 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3088 private_data->in_drag = 0;
3089 stop_spinning (widget);
3092 for (i = 0; i < 4; i++)
3093 if (GTK_WIDGET_IS_SENSITIVE (widget))
3094 private_data->arrow_state[i] = GTK_STATE_NORMAL;
3096 private_data->arrow_state[i] = GTK_STATE_INSENSITIVE;
3098 gtk_calendar_set_background (widget);
3102 gtk_calendar_finalize (GObject *object)
3104 GtkCalendarPrivateData *private_data;
3105 private_data = GTK_CALENDAR_PRIVATE_DATA (object);
3107 g_free (private_data);
3109 if (G_OBJECT_CLASS (parent_class)->finalize)
3110 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
3114 gtk_calendar_scroll (GtkWidget *widget,
3115 GdkEventScroll *event)
3117 GtkCalendar *calendar = GTK_CALENDAR (widget);
3119 if (event->direction == GDK_SCROLL_UP)
3121 if (!GTK_WIDGET_HAS_FOCUS (widget))
3122 gtk_widget_grab_focus (widget);
3123 gtk_calendar_set_month_prev (calendar);
3125 else if (event->direction == GDK_SCROLL_DOWN)
3127 if (!GTK_WIDGET_HAS_FOCUS (widget))
3128 gtk_widget_grab_focus (widget);
3129 gtk_calendar_set_month_next (calendar);
3138 move_focus (GtkCalendar *calendar,
3141 GtkTextDirection text_dir = gtk_widget_get_direction (GTK_WIDGET (calendar));
3143 if ((text_dir == GTK_TEXT_DIR_LTR && direction == -1) ||
3144 (text_dir == GTK_TEXT_DIR_RTL && direction == 1))
3146 if (calendar->focus_col > 0)
3147 calendar->focus_col--;
3148 else if (calendar->focus_row > 0)
3150 calendar->focus_col = 6;
3151 calendar->focus_row--;
3156 if (calendar->focus_col < 6)
3157 calendar->focus_col++;
3158 else if (calendar->focus_row < 5)
3160 calendar->focus_col = 0;
3161 calendar->focus_row++;
3167 gtk_calendar_key_press (GtkWidget *widget,
3170 GtkCalendar *calendar;
3176 calendar = GTK_CALENDAR (widget);
3179 old_focus_row = calendar->focus_row;
3180 old_focus_col = calendar->focus_col;
3182 switch (event->keyval)
3187 if (event->state & GDK_CONTROL_MASK)
3188 gtk_calendar_set_month_prev (calendar);
3191 move_focus (calendar, -1);
3192 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
3193 gtk_calendar_paint_day (widget, calendar->focus_row,
3194 calendar->focus_col);
3200 if (event->state & GDK_CONTROL_MASK)
3201 gtk_calendar_set_month_next (calendar);
3204 move_focus (calendar, 1);
3205 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
3206 gtk_calendar_paint_day (widget, calendar->focus_row,
3207 calendar->focus_col);
3213 if (event->state & GDK_CONTROL_MASK)
3214 gtk_calendar_set_year_prev (calendar);
3217 if (calendar->focus_row > 0)
3218 calendar->focus_row--;
3219 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
3220 gtk_calendar_paint_day (widget, calendar->focus_row,
3221 calendar->focus_col);
3227 if (event->state & GDK_CONTROL_MASK)
3228 gtk_calendar_set_year_next (calendar);
3231 if (calendar->focus_row < 5)
3232 calendar->focus_row++;
3233 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
3234 gtk_calendar_paint_day (widget, calendar->focus_row,
3235 calendar->focus_col);
3240 row = calendar->focus_row;
3241 col = calendar->focus_col;
3242 day = calendar->day[row][col];
3244 if (row > -1 && col > -1)
3247 gtk_calendar_freeze (calendar);
3249 if (calendar->day_month[row][col] == MONTH_PREV)
3250 gtk_calendar_set_month_prev (calendar);
3251 else if (calendar->day_month[row][col] == MONTH_NEXT)
3252 gtk_calendar_set_month_next (calendar);
3254 gtk_calendar_select_and_focus_day (calendar, day);
3256 gtk_calendar_thaw (calendar);
3264 gtk_calendar_set_display_option (GtkCalendar *calendar,
3265 GtkCalendarDisplayOptions flag,
3268 GtkCalendarDisplayOptions flags;
3270 flags = calendar->display_flags | flag;
3272 flags = calendar->display_flags & ~flag;
3273 gtk_calendar_display_options (calendar, flags);
3277 gtk_calendar_get_display_option (GtkCalendar *calendar,
3278 GtkCalendarDisplayOptions flag)
3280 return (calendar->display_flags & flag) != 0;
3285 gtk_calendar_set_property (GObject *object,
3287 const GValue *value,
3290 GtkCalendar *calendar;
3292 calendar = GTK_CALENDAR (object);
3297 gtk_calendar_select_month (calendar,
3299 g_value_get_int (value));
3302 gtk_calendar_select_month (calendar,
3303 g_value_get_int (value),
3307 gtk_calendar_select_day (calendar,
3308 g_value_get_int (value));
3310 case PROP_SHOW_HEADING:
3311 gtk_calendar_set_display_option (calendar,
3312 GTK_CALENDAR_SHOW_HEADING,
3313 g_value_get_boolean (value));
3315 case PROP_SHOW_DAY_NAMES:
3316 gtk_calendar_set_display_option (calendar,
3317 GTK_CALENDAR_SHOW_DAY_NAMES,
3318 g_value_get_boolean (value));
3320 case PROP_NO_MONTH_CHANGE:
3321 gtk_calendar_set_display_option (calendar,
3322 GTK_CALENDAR_NO_MONTH_CHANGE,
3323 g_value_get_boolean (value));
3325 case PROP_SHOW_WEEK_NUMBERS:
3326 gtk_calendar_set_display_option (calendar,
3327 GTK_CALENDAR_SHOW_WEEK_NUMBERS,
3328 g_value_get_boolean (value));
3331 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3337 gtk_calendar_get_property (GObject *object,
3342 GtkCalendar *calendar;
3344 calendar = GTK_CALENDAR (object);
3349 g_value_set_int (value, calendar->year);
3352 g_value_set_int (value, calendar->month);
3355 g_value_set_int (value, calendar->selected_day);
3357 case PROP_SHOW_HEADING:
3358 g_value_set_boolean (value, gtk_calendar_get_display_option (calendar,
3359 GTK_CALENDAR_SHOW_HEADING));
3361 case PROP_SHOW_DAY_NAMES:
3362 g_value_set_boolean (value, gtk_calendar_get_display_option (calendar,
3363 GTK_CALENDAR_SHOW_DAY_NAMES));
3365 case PROP_NO_MONTH_CHANGE:
3366 g_value_set_boolean (value, gtk_calendar_get_display_option (calendar,
3367 GTK_CALENDAR_NO_MONTH_CHANGE));
3369 case PROP_SHOW_WEEK_NUMBERS:
3370 g_value_set_boolean (value, gtk_calendar_get_display_option (calendar,
3371 GTK_CALENDAR_SHOW_WEEK_NUMBERS));
3374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3381 gtk_calendar_drag_data_get (GtkWidget *widget,
3382 GdkDragContext *context,
3383 GtkSelectionData *selection_data,
3387 GtkCalendar *calendar = GTK_CALENDAR (widget);
3392 date = g_date_new_dmy (calendar->selected_day, calendar->month + 1, calendar->year);
3393 len = g_date_strftime (str, 127, "%x", date);
3394 gtk_selection_data_set_text (selection_data, str, len);
3399 /* Get/set whether drag_motion requested the drag data and
3400 * drag_data_received should thus not actually insert the data,
3401 * since the data doesn't result from a drop.
3404 set_status_pending (GdkDragContext *context,
3405 GdkDragAction suggested_action)
3407 g_object_set_data (G_OBJECT (context),
3408 "gtk-calendar-status-pending",
3409 GINT_TO_POINTER (suggested_action));
3412 static GdkDragAction
3413 get_status_pending (GdkDragContext *context)
3415 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
3416 "gtk-calendar-status-pending"));
3420 gtk_calendar_drag_leave (GtkWidget *widget,
3421 GdkDragContext *context,
3424 GtkCalendarPrivateData *private_data;
3426 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
3427 private_data->drag_highlight = 0;
3428 gtk_drag_unhighlight (widget);
3433 gtk_calendar_drag_motion (GtkWidget *widget,
3434 GdkDragContext *context,
3439 GtkCalendarPrivateData *private_data;
3442 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
3444 if (!private_data->drag_highlight)
3446 private_data->drag_highlight = 1;
3447 gtk_drag_highlight (widget);
3450 target = gtk_drag_dest_find_target (widget, context, NULL);
3451 if (target == GDK_NONE)
3452 gdk_drag_status (context, 0, time);
3454 set_status_pending (context, context->suggested_action);
3455 gtk_drag_get_data (widget, context, target, time);
3462 gtk_calendar_drag_drop (GtkWidget *widget,
3463 GdkDragContext *context,
3470 target = gtk_drag_dest_find_target (widget, context, NULL);
3471 if (target != GDK_NONE)
3473 gtk_drag_get_data (widget, context,
3483 gtk_calendar_drag_data_received (GtkWidget *widget,
3484 GdkDragContext *context,
3487 GtkSelectionData *selection_data,
3491 GtkCalendar *calendar = GTK_CALENDAR (widget);
3492 guint day, month, year;
3495 GdkDragAction suggested_action;
3497 suggested_action = get_status_pending (context);
3499 if (suggested_action)
3501 set_status_pending (context, 0);
3503 /* We are getting this data due to a request in drag_motion,
3504 * rather than due to a request in drag_drop, so we are just
3505 * supposed to call drag_status, not actually paste in the
3508 str = gtk_selection_data_get_text (selection_data);
3511 date = g_date_new ();
3512 g_date_set_parse (date, str);
3513 if (!g_date_valid (date))
3514 suggested_action = 0;
3519 suggested_action = 0;
3521 gdk_drag_status (context, suggested_action, time);
3526 date = g_date_new ();
3527 str = gtk_selection_data_get_text (selection_data);
3530 g_date_set_parse (date, str);
3534 if (!g_date_valid (date))
3536 g_warning ("Received invalid date data\n");
3538 gtk_drag_finish (context, FALSE, FALSE, time);
3542 day = g_date_get_day (date);
3543 month = g_date_get_month (date);
3544 year = g_date_get_year (date);
3547 gtk_drag_finish (context, TRUE, FALSE, time);
3550 g_object_freeze_notify (G_OBJECT (calendar));
3551 if (!(calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
3552 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
3553 gtk_calendar_select_month (calendar, month - 1, year);
3554 gtk_calendar_select_day (calendar, day);
3555 g_object_thaw_notify (G_OBJECT (calendar));