1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson and Mattias Grönlund
8 * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free
22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
27 * file for a list of people on the GTK+ Team. See the ChangeLog
28 * files for a list of changes. These files are distributed with
29 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #ifdef HAVE_SYS_TIME_H
41 #include "gtkcalendar.h"
42 #include "gdk/gdkkeysyms.h"
44 /***************************************************************************/
45 /* The following date routines are taken from the lib_date package. Keep
46 * them seperate in case we want to update them if a newer lib_date comes
49 typedef unsigned int N_int;
50 typedef unsigned long N_long;
51 typedef signed long Z_long;
52 typedef enum { false = FALSE , true = TRUE } boolean;
54 #define and && /* logical (boolean) operators: lower case */
57 static const N_int month_length[2][13] =
59 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
60 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
63 static const N_int days_in_months[2][14] =
65 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
66 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
69 static Z_long calc_days(N_int year, N_int mm, N_int dd);
70 static N_int day_of_week(N_int year, N_int mm, N_int dd);
71 static Z_long dates_difference(N_int year1, N_int mm1, N_int dd1,
72 N_int year2, N_int mm2, N_int dd2);
73 static N_int weeks_in_year(N_int year);
78 return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
82 day_of_week(N_int year, N_int mm, N_int dd)
86 days = calc_days(year, mm, dd);
93 return( (N_int) days );
96 static N_int weeks_in_year(N_int year)
98 return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
102 check_date(N_int year, N_int mm, N_int dd)
104 if (year < 1) return(false);
105 if ((mm < 1) or (mm > 12)) return(false);
106 if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
111 week_number(N_int year, N_int mm, N_int dd)
115 first = day_of_week(year,1,1) - 1;
116 return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
121 year_to_days(N_int year)
123 return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
128 calc_days(N_int year, N_int mm, N_int dd)
132 if (year < 1) return(0L);
133 if ((mm < 1) or (mm > 12)) return(0L);
134 if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
135 return( year_to_days(--year) + days_in_months[lp][mm] + dd );
139 week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
141 if (check_date(*year,mm,dd))
143 *week = week_number(*year,mm,dd);
145 *week = weeks_in_year(--(*year));
146 else if (*week > weeks_in_year(*year))
157 dates_difference(N_int year1, N_int mm1, N_int dd1,
158 N_int year2, N_int mm2, N_int dd2)
160 return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
163 /*** END OF lib_date routines ********************************************/
165 #define CALENDAR_MARGIN 0
166 #define CALENDAR_YSEP 4
167 #define CALENDAR_XSEP 4
168 #define INNER_BORDER 4
172 #define DAY_XSEP 0 /* not really good for small calendar */
173 #define DAY_YSEP 0 /* not really good for small calendar */
176 #define HEADER_FG_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
177 #define HEADER_BG_COLOR(widget) (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
178 #define DAY_NAME_COLOR(widget) (& (widget)->style->bg[GTK_STATE_SELECTED])
179 #define NORMAL_DAY_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
180 #define SELECTION_FOCUS_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
181 #define SELECTION_NO_FOCUS_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
182 #define PREV_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
183 #define NEXT_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
184 #define MARKED_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
185 #define FOREGROUND_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
186 #define BACKGROUND_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
187 #define HIGHLIGHT_BACK_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
189 #define HEADER_FONT(widget) ((widget)->style->font)
190 #define LABEL_FONT(widget) ((widget)->style->font)
191 #define DAY_FONT(widget) ((widget)->style->font)
207 MONTH_CHANGED_SIGNAL,
209 DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
217 static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 };
219 static GtkWidgetClass *parent_class = NULL;
221 typedef struct _GtkCalendarPrivateData GtkCalendarPrivateData;
222 struct _GtkCalendarPrivateData
224 GdkWindow *header_win;
225 GdkWindow *day_name_win;
228 GdkWindow *arrow_win[4];
234 guint arrow_state[4];
236 guint max_month_width;
237 guint max_year_width;
243 guint max_day_char_width;
244 guint max_day_char_ascent;
245 guint max_day_char_descent;
246 guint max_label_char_ascent;
247 guint max_label_char_descent;
248 guint max_week_char_width;
253 guint dirty_header : 1;
254 guint dirty_day_names : 1;
255 guint dirty_main : 1;
256 guint dirty_week : 1;
259 #define GTK_CALENDAR_PRIVATE_DATA(widget) (((GtkCalendarPrivateData*)(GTK_CALENDAR (widget)->private_data)))
261 typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data);
263 static void gtk_calendar_class_init (GtkCalendarClass *class);
264 static void gtk_calendar_init (GtkCalendar *calendar);
265 static void gtk_calendar_destroy (GtkObject *calendar);
266 static void gtk_calendar_realize (GtkWidget *widget);
267 static void gtk_calendar_unrealize (GtkWidget *widget);
268 static void gtk_calendar_draw_focus (GtkWidget *widget);
269 static void gtk_calendar_size_request (GtkWidget *widget,
270 GtkRequisition *requisition);
271 static void gtk_calendar_size_allocate (GtkWidget *widget,
272 GtkAllocation *allocation);
273 static gint gtk_calendar_expose (GtkWidget *widget,
274 GdkEventExpose *event);
275 static gint gtk_calendar_button_press (GtkWidget *widget,
276 GdkEventButton *event);
277 static void gtk_calendar_main_button (GtkWidget *widget,
278 GdkEventButton *event);
279 static gint gtk_calendar_motion_notify (GtkWidget *widget,
280 GdkEventMotion *event);
281 static gint gtk_calendar_enter_notify (GtkWidget *widget,
282 GdkEventCrossing *event);
283 static gint gtk_calendar_leave_notify (GtkWidget *widget,
284 GdkEventCrossing *event);
285 static gint gtk_calendar_key_press (GtkWidget *widget,
287 static void gtk_calendar_state_changed (GtkWidget *widget,
288 GtkStateType previous_state);
289 static void gtk_calendar_style_set (GtkWidget *widget,
290 GtkStyle *previous_style);
291 static void gtk_calendar_paint_header (GtkWidget *widget);
292 static void gtk_calendar_paint_day_names (GtkWidget *widget);
293 static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
294 static void gtk_calendar_paint_main (GtkWidget *widget);
297 static void gtk_calendar_paint (GtkWidget *widget,
299 static void gtk_calendar_paint_arrow (GtkWidget *widget,
301 static void gtk_calendar_paint_day_num (GtkWidget *widget,
303 static void gtk_calendar_paint_day (GtkWidget *widget,
306 static void gtk_calendar_compute_days (GtkCalendar *calendar);
307 static gint left_x_for_column (GtkCalendar *calendar,
309 static gint top_y_for_row (GtkCalendar *calendar,
312 static char *default_abbreviated_dayname[7];
313 static char *default_monthname[12];
316 gtk_calendar_get_type (void)
318 static GtkType calendar_type = 0;
322 static const GTypeInfo calendar_info =
324 sizeof (GtkCalendarClass),
325 NULL, /* base_init */
326 NULL, /* base_finalize */
327 (GClassInitFunc) gtk_calendar_class_init,
328 NULL, /* class_finalize */
329 NULL, /* class_data */
330 sizeof (GtkCalendar),
331 16, /* n_preallocs */
332 (GInstanceInitFunc) gtk_calendar_init,
335 calendar_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCalendar", &calendar_info, 0);
338 return calendar_type;
342 gtk_calendar_class_init (GtkCalendarClass *class)
344 GtkObjectClass *object_class;
345 GtkWidgetClass *widget_class;
347 object_class = (GtkObjectClass*) class;
348 widget_class = (GtkWidgetClass*) class;
350 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
352 object_class->destroy = gtk_calendar_destroy;
354 widget_class->realize = gtk_calendar_realize;
355 widget_class->unrealize = gtk_calendar_unrealize;
356 widget_class->expose_event = gtk_calendar_expose;
357 widget_class->size_request = gtk_calendar_size_request;
358 widget_class->size_allocate = gtk_calendar_size_allocate;
359 widget_class->button_press_event = gtk_calendar_button_press;
360 widget_class->motion_notify_event = gtk_calendar_motion_notify;
361 widget_class->enter_notify_event = gtk_calendar_enter_notify;
362 widget_class->leave_notify_event = gtk_calendar_leave_notify;
363 widget_class->key_press_event = gtk_calendar_key_press;
364 widget_class->style_set = gtk_calendar_style_set;
365 widget_class->state_changed = gtk_calendar_state_changed;
367 class->month_changed = NULL;
368 class->day_selected = NULL;
369 class->day_selected_double_click = NULL;
370 class->prev_month = NULL;
371 class->next_month = NULL;
372 class->prev_year = NULL;
373 class->next_year = NULL;
375 gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
376 gtk_signal_new ("month_changed",
377 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
378 GTK_SIGNAL_OFFSET (GtkCalendarClass, month_changed),
379 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
380 gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
381 gtk_signal_new ("day_selected",
382 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
383 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected),
384 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
385 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
386 gtk_signal_new ("day_selected_double_click",
387 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
388 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected_double_click),
389 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
390 gtk_calendar_signals[PREV_MONTH_SIGNAL] =
391 gtk_signal_new ("prev_month",
392 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
393 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_month),
394 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
395 gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
396 gtk_signal_new ("next_month",
397 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
398 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_month),
399 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
400 gtk_calendar_signals[PREV_YEAR_SIGNAL] =
401 gtk_signal_new ("prev_year",
402 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
403 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_year),
404 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
405 gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
406 gtk_signal_new ("next_year",
407 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
408 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_year),
409 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
413 gtk_calendar_init (GtkCalendar *calendar)
421 GtkCalendarPrivateData *private_data;
423 widget = GTK_WIDGET (calendar);
424 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
426 calendar->private_data = (gpointer) g_malloc (sizeof (GtkCalendarPrivateData));
427 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
429 if (!default_abbreviated_dayname[0])
432 tmp_time= (i+3)*86400;
433 strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
434 default_abbreviated_dayname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
437 if (!default_monthname[0])
441 strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
442 default_monthname[i] = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
447 tm = localtime (&secs);
448 calendar->month = tm->tm_mon;
449 calendar->year = 1900 + tm->tm_year;
452 calendar->marked_date[i] = FALSE;
453 calendar->num_marked_dates = 0;
454 calendar->selected_day = 1;
456 calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING |
457 GTK_CALENDAR_SHOW_DAY_NAMES );
459 calendar->highlight_row = -1;
460 calendar->highlight_col = -1;
462 calendar->focus_row = -1;
463 calendar->focus_col = -1;
464 calendar->xor_gc = NULL;
466 private_data->max_year_width = 0;
467 private_data->max_month_width = 0;
468 private_data->max_day_char_width = 0;
469 private_data->max_week_char_width = 0;
471 private_data->max_day_char_ascent = 0;
472 private_data->max_day_char_descent = 0;
473 private_data->max_label_char_ascent = 0;
474 private_data->max_label_char_descent = 0;
476 private_data->arrow_width = 10;
478 private_data->freeze_count = 0;
480 private_data->dirty_header = 0;
481 private_data->dirty_day_names = 0;
482 private_data->dirty_week = 0;
483 private_data->dirty_main = 0;
487 gtk_calendar_new (void)
489 return GTK_WIDGET (gtk_type_new (GTK_TYPE_CALENDAR));
492 /* column_from_x: returns the column 0-6 that the
493 * x pixel of the xwindow is in */
495 column_from_x (GtkCalendar *calendar,
499 gint x_left, x_right;
503 for (c = 0; c < 7; c++)
505 x_left = left_x_for_column (calendar, c);
506 x_right = x_left + GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
508 if (event_x >= x_left && event_x < x_right)
519 row_height (GtkCalendar *calendar)
521 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h - CALENDAR_MARGIN
522 - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
523 ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
527 /* row_from_y: returns the row 0-5 that the
528 * y pixel of the xwindow is in */
530 row_from_y (GtkCalendar *calendar,
535 gint y_top, y_bottom;
537 height = row_height (calendar);
540 for (r = 0; r < 6; r++)
542 y_top = top_y_for_row (calendar, r);
543 y_bottom = y_top + height;
545 if (event_y >= y_top && event_y < y_bottom)
555 /* left_x_for_column: returns the x coordinate
556 * for the left of the column */
558 left_x_for_column (GtkCalendar *calendar,
564 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
567 width = GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
568 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
569 x_left = DAY_XSEP + (width + DAY_XSEP) * column;
571 x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
576 /* top_y_for_row: returns the y coordinate
577 * for the top of the row */
579 top_y_for_row (GtkCalendar *calendar,
583 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h
584 - (CALENDAR_MARGIN + (6 - row)
585 * row_height (calendar)));
588 /* This function should be done by the toolkit, but we don't like the
589 * GTK arrows because they don't look good on this widget */
591 draw_arrow_right (GdkWindow *window,
599 for (i = 0; i <= size / 2; i++)
601 gdk_draw_line (window, gc,
609 /* This function should be done by the toolkit, but we don't like the
610 * GTK arrows because they don't look good on this widget */
612 draw_arrow_left (GdkWindow *window,
620 for (i = 0; i <= size / 2; i++)
622 gdk_draw_line (window, gc,
631 gtk_calendar_set_month_prev (GtkCalendar *calendar)
635 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
638 if (calendar->month == 0)
640 calendar->month = 11;
646 month_len = month_length[leap (calendar->year)][calendar->month + 1];
648 gtk_calendar_freeze (calendar);
649 gtk_calendar_compute_days (calendar);
651 gtk_signal_emit (GTK_OBJECT (calendar),
652 gtk_calendar_signals[PREV_MONTH_SIGNAL]);
653 gtk_signal_emit (GTK_OBJECT (calendar),
654 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
656 if (month_len < calendar->selected_day)
658 calendar->selected_day = 0;
659 gtk_calendar_select_day (calendar, month_len);
663 if (calendar->selected_day < 0)
664 calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
665 gtk_calendar_select_day (calendar, calendar->selected_day);
668 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
669 gtk_calendar_thaw (calendar);
674 gtk_calendar_set_month_next (GtkCalendar *calendar)
678 g_return_if_fail (calendar != NULL);
679 g_return_if_fail (GTK_IS_WIDGET (calendar));
681 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
685 if (calendar->month == 11)
693 gtk_calendar_freeze (calendar);
694 gtk_calendar_compute_days (calendar);
695 gtk_signal_emit (GTK_OBJECT (calendar),
696 gtk_calendar_signals[NEXT_MONTH_SIGNAL]);
697 gtk_signal_emit (GTK_OBJECT (calendar),
698 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
700 month_len = month_length[leap (calendar->year)][calendar->month + 1];
702 if (month_len < calendar->selected_day)
704 calendar->selected_day = 0;
705 gtk_calendar_select_day (calendar, month_len);
708 gtk_calendar_select_day (calendar, calendar->selected_day);
710 gtk_calendar_paint (GTK_WIDGET(calendar), NULL);
711 gtk_calendar_thaw (calendar);
715 gtk_calendar_set_year_prev (GtkCalendar *calendar)
719 g_return_if_fail (calendar != NULL);
720 g_return_if_fail (GTK_IS_WIDGET (calendar));
723 gtk_calendar_freeze (calendar);
724 gtk_calendar_compute_days (calendar);
725 gtk_signal_emit (GTK_OBJECT (calendar),
726 gtk_calendar_signals[PREV_YEAR_SIGNAL]);
727 gtk_signal_emit (GTK_OBJECT (calendar),
728 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
730 month_len = month_length[leap (calendar->year)][calendar->month + 1];
732 if (month_len < calendar->selected_day)
734 calendar->selected_day = 0;
735 gtk_calendar_select_day (calendar, month_len);
738 gtk_calendar_select_day (calendar, calendar->selected_day);
740 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
741 gtk_calendar_thaw (calendar);
745 gtk_calendar_set_year_next (GtkCalendar *calendar)
750 g_return_if_fail (calendar != NULL);
751 g_return_if_fail (GTK_IS_WIDGET (calendar));
753 widget = GTK_WIDGET (calendar);
755 gtk_calendar_freeze (calendar);
758 gtk_calendar_compute_days (calendar);
759 gtk_signal_emit (GTK_OBJECT (calendar),
760 gtk_calendar_signals[NEXT_YEAR_SIGNAL]);
761 gtk_signal_emit (GTK_OBJECT (calendar),
762 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
764 month_len = month_length[leap (calendar->year)][calendar->month + 1];
766 if (month_len < calendar->selected_day)
768 calendar->selected_day = 0;
769 gtk_calendar_select_day (calendar, month_len);
772 gtk_calendar_select_day (calendar, calendar->selected_day);
774 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
775 gtk_calendar_thaw (calendar);
779 gtk_calendar_main_button (GtkWidget *widget,
780 GdkEventButton *event)
782 GtkCalendar *calendar;
786 gint old_focus_row, old_focus_col;
788 calendar = GTK_CALENDAR (widget);
790 x = (gint) (event->x);
791 y = (gint) (event->y);
793 row = row_from_y (calendar, y);
794 col = column_from_x (calendar, x);
796 /* If row or column isn't found, just return. */
797 if (row == -1 || col == -1)
800 day_month = calendar->day_month[row][col];
802 if (day_month == MONTH_CURRENT)
804 if (event->type == GDK_2BUTTON_PRESS)
805 gtk_signal_emit (GTK_OBJECT (calendar),
806 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]);
809 if (!GTK_WIDGET_HAS_FOCUS (widget))
810 gtk_widget_grab_focus (widget);
811 old_focus_row = calendar->focus_row;
812 old_focus_col = calendar->focus_col;
813 calendar->focus_row = row;
814 calendar->focus_col = col;
815 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
816 gtk_calendar_select_day (calendar, calendar->day[row][col]);
819 else if (day_month == MONTH_PREV)
820 gtk_calendar_set_month_prev (calendar);
821 else if (day_month == MONTH_NEXT)
822 gtk_calendar_set_month_next (calendar);
826 gtk_calendar_realize_arrows (GtkWidget *widget)
828 GtkCalendar *calendar;
829 GtkCalendarPrivateData *private_data;
830 GdkWindowAttr attributes;
831 gint attributes_mask;
834 g_return_if_fail (widget != NULL);
835 g_return_if_fail (GTK_IS_CALENDAR (widget));
837 calendar = GTK_CALENDAR (widget);
838 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
840 /* Arrow windows ------------------------------------- */
841 if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
842 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
844 attributes.wclass = GDK_INPUT_OUTPUT;
845 attributes.window_type = GDK_WINDOW_CHILD;
846 attributes.visual = gtk_widget_get_visual (widget);
847 attributes.colormap = gtk_widget_get_colormap (widget);
848 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
849 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
850 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
851 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
853 attributes.width = private_data->arrow_width;
854 attributes.height = private_data->header_h - 7;
855 for (i = 0; i < 4; i++)
859 case ARROW_MONTH_LEFT:
862 case ARROW_MONTH_RIGHT:
863 attributes.x = (private_data->arrow_width
864 + private_data->max_month_width);
866 case ARROW_YEAR_LEFT:
867 attributes.x = (widget->allocation.width - 4
868 - (3 + 2*private_data->arrow_width
869 + private_data->max_year_width));
871 case ARROW_YEAR_RIGHT:
872 attributes.x = (widget->allocation.width - 4
873 - 3 - private_data->arrow_width);
876 private_data->arrow_win[i] = gdk_window_new (private_data->header_win,
879 private_data->arrow_state[i] = GTK_STATE_NORMAL;
880 gdk_window_set_background (private_data->arrow_win[i],
881 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
882 gdk_window_show (private_data->arrow_win[i]);
883 gdk_window_set_user_data (private_data->arrow_win[i], widget);
888 for (i = 0; i < 4; i++)
889 private_data->arrow_win[i] = NULL;
894 gtk_calendar_realize_header (GtkWidget *widget)
896 GtkCalendar *calendar;
897 GtkCalendarPrivateData *private_data;
898 GdkWindowAttr attributes;
899 gint attributes_mask;
901 g_return_if_fail (widget != NULL);
902 g_return_if_fail (GTK_IS_CALENDAR (widget));
904 calendar = GTK_CALENDAR (widget);
905 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
907 /* Header window ------------------------------------- */
908 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
910 attributes.wclass = GDK_INPUT_OUTPUT;
911 attributes.window_type = GDK_WINDOW_CHILD;
912 attributes.visual = gtk_widget_get_visual (widget);
913 attributes.colormap = gtk_widget_get_colormap (widget);
914 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
915 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
918 attributes.width = widget->allocation.width - 4;
919 attributes.height = private_data->header_h;
920 private_data->header_win = gdk_window_new (widget->window,
921 &attributes, attributes_mask);
923 gdk_window_set_background (private_data->header_win,
924 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
925 gdk_window_show (private_data->header_win);
926 gdk_window_set_user_data (private_data->header_win, widget);
931 private_data->header_win = NULL;
933 gtk_calendar_realize_arrows (widget);
937 gtk_calendar_realize_day_names (GtkWidget *widget)
939 GtkCalendar *calendar;
940 GtkCalendarPrivateData *private_data;
941 GdkWindowAttr attributes;
942 gint attributes_mask;
944 g_return_if_fail (widget != NULL);
945 g_return_if_fail (GTK_IS_CALENDAR (widget));
947 calendar = GTK_CALENDAR (widget);
948 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
950 /* Day names window --------------------------------- */
951 if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
953 attributes.wclass = GDK_INPUT_OUTPUT;
954 attributes.window_type = GDK_WINDOW_CHILD;
955 attributes.visual = gtk_widget_get_visual (widget);
956 attributes.colormap = gtk_widget_get_colormap (widget);
957 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
958 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
959 attributes.x = (widget->style->xthickness + INNER_BORDER);
960 attributes.y = private_data->header_h + (widget->style->ythickness
962 attributes.width = (widget->allocation.width
963 - (widget->style->xthickness + INNER_BORDER)
965 attributes.height = private_data->day_name_h;
966 private_data->day_name_win = gdk_window_new (widget->window,
969 gdk_window_set_background (private_data->day_name_win,
970 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
971 gdk_window_show (private_data->day_name_win);
972 gdk_window_set_user_data (private_data->day_name_win, widget);
976 private_data->day_name_win = NULL;
981 gtk_calendar_realize_week_numbers (GtkWidget *widget)
983 GtkCalendar *calendar;
984 GtkCalendarPrivateData *private_data;
985 GdkWindowAttr attributes;
986 gint attributes_mask;
988 g_return_if_fail (widget != NULL);
989 g_return_if_fail (GTK_IS_CALENDAR (widget));
991 calendar = GTK_CALENDAR (widget);
992 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
994 /* Week number window -------------------------------- */
995 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
997 attributes.wclass = GDK_INPUT_OUTPUT;
998 attributes.window_type = GDK_WINDOW_CHILD;
999 attributes.visual = gtk_widget_get_visual (widget);
1000 attributes.colormap = gtk_widget_get_colormap (widget);
1001 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1003 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1004 attributes.x = + (widget->style->xthickness + INNER_BORDER);
1005 attributes.y = (private_data->header_h + private_data->day_name_h
1006 + (widget->style->ythickness + INNER_BORDER));
1007 attributes.width = private_data->week_width;
1008 attributes.height = private_data->main_h;
1009 private_data->week_win = gdk_window_new (widget->window,
1010 &attributes, attributes_mask);
1011 gdk_window_set_background (private_data->week_win,
1012 BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1013 gdk_window_show (private_data->week_win);
1014 gdk_window_set_user_data (private_data->week_win, widget);
1018 private_data->week_win = NULL;
1023 gtk_calendar_realize (GtkWidget *widget)
1025 GtkCalendar *calendar;
1026 GtkCalendarPrivateData *private_data;
1027 GdkWindowAttr attributes;
1028 gint attributes_mask;
1031 g_return_if_fail (widget != NULL);
1032 g_return_if_fail (GTK_IS_CALENDAR (widget));
1034 calendar = GTK_CALENDAR (widget);
1035 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1037 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1038 gtk_calendar_compute_days (calendar);
1040 attributes.x = widget->allocation.x;
1041 attributes.y = widget->allocation.y;
1042 attributes.width = widget->allocation.width;
1043 attributes.height = widget->allocation.height;
1044 attributes.wclass = GDK_INPUT_OUTPUT;
1045 attributes.window_type = GDK_WINDOW_CHILD;
1046 attributes.event_mask = (gtk_widget_get_events (widget)
1047 | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK);
1048 attributes.visual = gtk_widget_get_visual (widget);
1049 attributes.colormap = gtk_widget_get_colormap (widget);
1051 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1052 widget->window = gdk_window_new (widget->parent->window,
1053 &attributes, attributes_mask);
1055 widget->style = gtk_style_attach (widget->style, widget->window);
1057 /* Header window ------------------------------------- */
1058 gtk_calendar_realize_header (widget);
1059 /* Day names window --------------------------------- */
1060 gtk_calendar_realize_day_names (widget);
1061 /* Week number window -------------------------------- */
1062 gtk_calendar_realize_week_numbers (widget);
1063 /* Main Window -------------------------------------- */
1064 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1065 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1066 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1068 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1069 attributes.x = private_data->week_width;
1072 attributes.x += (widget->style->xthickness + INNER_BORDER);
1073 attributes.y = (private_data->header_h + private_data->day_name_h
1074 + (widget->style->ythickness + INNER_BORDER));
1075 attributes.width = (widget->allocation.width - attributes.x
1076 - (widget->style->xthickness + INNER_BORDER));
1077 attributes.height = private_data->main_h;
1078 private_data->main_win = gdk_window_new (widget->window,
1079 &attributes, attributes_mask);
1080 gdk_window_set_background (private_data->main_win,
1081 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1082 gdk_window_show (private_data->main_win);
1083 gdk_window_set_user_data (private_data->main_win, widget);
1084 gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1085 gdk_window_show (widget->window);
1086 gdk_window_set_user_data (widget->window, widget);
1088 /* Set widgets gc */
1089 calendar->gc = gdk_gc_new (widget->window);
1091 values.foreground = widget->style->white;
1092 values.function = GDK_XOR;
1093 calendar->xor_gc = gdk_gc_new_with_values (widget->window,
1100 gtk_calendar_unrealize (GtkWidget *widget)
1102 GtkCalendar *calendar;
1103 GtkCalendarPrivateData *private_data;
1106 g_return_if_fail (widget != NULL);
1107 g_return_if_fail (GTK_IS_CALENDAR (widget));
1109 calendar = GTK_CALENDAR (widget);
1110 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1112 if (private_data->header_win)
1114 for (i = 0; i < 4; i++)
1116 if (private_data->arrow_win[i])
1118 gdk_window_set_user_data (private_data->arrow_win[i], NULL);
1119 gdk_window_destroy (private_data->arrow_win[i]);
1120 private_data->arrow_win[i] = NULL;
1123 gdk_window_set_user_data (private_data->header_win, NULL);
1124 gdk_window_destroy (private_data->header_win);
1125 private_data->header_win = NULL;
1128 if (private_data->week_win)
1130 gdk_window_set_user_data (private_data->week_win, NULL);
1131 gdk_window_destroy (private_data->week_win);
1132 private_data->week_win = NULL;
1135 if (private_data->main_win)
1137 gdk_window_set_user_data (private_data->main_win, NULL);
1138 gdk_window_destroy (private_data->main_win);
1139 private_data->main_win = NULL;
1141 if (private_data->day_name_win)
1143 gdk_window_set_user_data (private_data->day_name_win, NULL);
1144 gdk_window_destroy (private_data->day_name_win);
1145 private_data->day_name_win = NULL;
1147 if (calendar->xor_gc)
1148 gdk_gc_unref (calendar->xor_gc);
1150 gdk_gc_unref (calendar->gc);
1152 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1153 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1157 gtk_calendar_size_request (GtkWidget *widget,
1158 GtkRequisition *requisition)
1160 GtkCalendar *calendar;
1161 GtkCalendarPrivateData *private_data;
1162 PangoLayout *layout;
1163 PangoRectangle logical_rect;
1168 gint calendar_margin = CALENDAR_MARGIN;
1169 gint header_width, main_width;
1170 gint max_header_height = 0;
1172 calendar = GTK_CALENDAR (widget);
1173 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1175 layout = gtk_widget_create_pango_layout (widget, NULL);
1178 * Calculate the requisition width for the widget.
1183 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1185 private_data->max_month_width = 0;
1186 for (i = 0; i < 12; i++)
1188 pango_layout_set_text (layout, default_monthname[i], -1);
1189 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1190 private_data->max_month_width = MAX (private_data->max_month_width,
1191 logical_rect.width + 8);
1192 max_header_height = MAX (max_header_height, logical_rect.height);
1194 private_data->max_year_width = 0;
1195 for (i=0; i<10; i++)
1197 sprintf (buffer, "%d%d%d%d", i,i,i,i);
1198 pango_layout_set_text (layout, buffer, -1);
1199 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1200 private_data->max_year_width = MAX (private_data->max_year_width,
1201 logical_rect.width + 8);
1202 max_header_height = MAX (max_header_height, logical_rect.height);
1207 private_data->max_month_width = 0;
1208 private_data->max_year_width = 0;
1211 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1212 header_width = (private_data->max_month_width
1213 + private_data->max_year_width
1216 header_width = (private_data->max_month_width
1217 + private_data->max_year_width
1218 + 4 * private_data->arrow_width + 3 * 3);
1220 /* Mainwindow labels width */
1222 private_data->max_day_char_width = 0;
1223 for (i = 0; i < 9; i++)
1225 sprintf (buffer, "%d%d", i, i);
1226 pango_layout_set_text (layout, buffer, -1);
1227 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1228 private_data->min_day_width = MAX (private_data->max_day_char_width,
1229 logical_rect.width);
1231 private_data->max_day_char_ascent = MAX (private_data->max_label_char_ascent,
1232 PANGO_ASCENT (logical_rect));
1233 private_data->max_day_char_descent = MAX (private_data->max_label_char_descent,
1234 PANGO_DESCENT (logical_rect));
1236 /* We add one to max_day_char_width to be able to make the marked day "bold" */
1237 private_data->max_day_char_width = private_data->min_day_width / 2 +1;
1239 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1240 for (i = 0; i < 7; i++)
1242 pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1243 pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1245 private_data->min_day_width = MAX (private_data->min_day_width, logical_rect.width);
1246 private_data->max_label_char_ascent = MAX (private_data->max_label_char_ascent,
1247 PANGO_ASCENT (logical_rect));
1248 private_data->max_label_char_descent = MAX (private_data->max_label_char_descent,
1249 PANGO_DESCENT (logical_rect));
1252 private_data->max_week_char_width = 0;
1253 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1254 for (i = 0; i < 9; i++)
1256 sprintf (buffer, "%d%d", i, i);
1257 pango_layout_set_text (layout, buffer, -1);
1258 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1259 private_data->max_week_char_width = MAX (private_data->max_week_char_width,
1260 logical_rect.width / 2);
1263 main_width = (7 * (private_data->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1264 + (private_data->max_week_char_width
1265 ? private_data->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2
1269 requisition->width = MAX (header_width+4, main_width + (widget->style->xthickness + INNER_BORDER) *2);
1272 * Calculate the requisition height for the widget.
1275 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1277 private_data->header_h = (max_header_height + CALENDAR_YSEP * 2);
1281 private_data->header_h = 0;
1284 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1286 private_data->day_name_h = (private_data->max_label_char_ascent
1287 + private_data->max_label_char_descent
1288 + 2 * DAY_YPAD + calendar_margin);
1289 calendar_margin = CALENDAR_YSEP;
1293 private_data->day_name_h = 0;
1296 private_data->main_h = (CALENDAR_MARGIN + calendar_margin
1297 + 6 * (private_data->max_day_char_ascent
1298 + private_data->max_day_char_descent
1303 * If we display weeknumbers we need some extra space
1306 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1308 private_data->main_h = MAX (private_data->main_h,
1309 (CALENDAR_MARGIN + calendar_margin
1310 + 6 * (private_data->max_day_char_ascent
1311 + private_data->max_day_char_descent
1316 height = (private_data->header_h + private_data->day_name_h
1317 + private_data->main_h);
1319 requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1321 g_object_unref (G_OBJECT (layout));
1325 gtk_calendar_size_allocate (GtkWidget *widget,
1326 GtkAllocation *allocation)
1328 GtkCalendar *calendar;
1329 GtkCalendarPrivateData *private_data;
1331 g_return_if_fail (widget != NULL);
1332 g_return_if_fail (GTK_IS_CALENDAR (widget));
1333 g_return_if_fail (allocation != NULL);
1335 widget->allocation = *allocation;
1337 calendar = GTK_CALENDAR (widget);
1338 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1340 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1342 private_data->day_width = (private_data->min_day_width
1343 * ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1344 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2))
1345 / (7 * private_data->min_day_width + private_data->max_week_char_width * 2));
1346 private_data->week_width = ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1347 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 )
1348 - private_data->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1352 private_data->day_width = (allocation->width
1353 - (widget->style->xthickness + INNER_BORDER) * 2
1354 - (CALENDAR_MARGIN * 2)
1355 - (DAY_XSEP * 7))/7;
1356 private_data->week_width = 0;
1359 if (GTK_WIDGET_REALIZED (widget))
1361 gdk_window_move_resize (widget->window,
1362 allocation->x, allocation->y,
1363 allocation->width, allocation->height);
1364 if (private_data->header_win)
1365 gdk_window_move_resize (private_data->header_win,
1367 allocation->width-4, private_data->header_h);
1368 if (private_data->arrow_win[ARROW_MONTH_LEFT])
1369 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1371 private_data->arrow_width,
1372 private_data->header_h - 7);
1373 if (private_data->arrow_win[ARROW_MONTH_RIGHT])
1374 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1375 (private_data->arrow_width
1376 + private_data->max_month_width),
1378 private_data->arrow_width,
1379 private_data->header_h - 7);
1380 if (private_data->arrow_win[ARROW_YEAR_LEFT])
1381 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1382 (allocation->width - 4
1383 - (3 + 2*private_data->arrow_width
1384 + private_data->max_year_width)),
1386 private_data->arrow_width,
1387 private_data->header_h - 7);
1388 if (private_data->arrow_win[ARROW_YEAR_RIGHT])
1389 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1390 (allocation->width - 4
1391 - 3 - private_data->arrow_width),
1393 private_data->arrow_width,
1394 private_data->header_h - 7);
1395 if (private_data->day_name_win)
1396 gdk_window_move_resize (private_data->day_name_win,
1397 widget->style->xthickness + INNER_BORDER,
1398 private_data->header_h + (widget->style->ythickness + INNER_BORDER),
1399 allocation->width - (widget->style->xthickness + INNER_BORDER) * 2,
1400 private_data->day_name_h);
1401 if (private_data->week_win)
1402 gdk_window_move_resize (private_data->week_win,
1403 (widget->style->xthickness + INNER_BORDER),
1404 private_data->header_h + private_data->day_name_h
1405 + (widget->style->ythickness + INNER_BORDER),
1406 private_data->week_width,
1407 private_data->main_h);
1408 gdk_window_move_resize (private_data->main_win,
1409 (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1410 + (widget->style->xthickness + INNER_BORDER),
1411 private_data->header_h + private_data->day_name_h
1412 + (widget->style->ythickness + INNER_BORDER),
1414 - (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1415 - (widget->style->xthickness + INNER_BORDER) * 2,
1416 private_data->main_h);
1421 gtk_calendar_draw_focus (GtkWidget *widget)
1423 GtkCalendar *calendar;
1424 GtkCalendarPrivateData *private_data;
1428 g_return_if_fail (widget != NULL);
1429 g_return_if_fail (GTK_IS_CALENDAR (widget));
1431 calendar = GTK_CALENDAR (widget);
1432 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1434 if (GTK_WIDGET_DRAWABLE (widget))
1438 gdk_window_get_size (widget->window, &width, &height);
1439 gdk_window_clear (widget->window);
1441 gdk_draw_rectangle (widget->window,
1442 widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1443 FALSE, x + 2, y + 2, width - 5, height - 5);
1445 gtk_draw_shadow (widget->style, widget->window,
1446 GTK_STATE_NORMAL, GTK_SHADOW_IN,
1447 x, y, width, height);
1453 gtk_calendar_expose (GtkWidget *widget,
1454 GdkEventExpose *event)
1456 GtkCalendar *calendar;
1457 GtkCalendarPrivateData *private_data;
1459 g_return_val_if_fail (widget != NULL, FALSE);
1460 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
1461 g_return_val_if_fail (event != NULL, FALSE);
1463 calendar = GTK_CALENDAR (widget);
1464 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1466 if (GTK_WIDGET_DRAWABLE (widget))
1468 if (event->window == private_data->main_win)
1469 gtk_calendar_paint_main (widget);
1471 if (event->window == private_data->header_win)
1472 gtk_calendar_paint_header (widget);
1474 if (event->window == private_data->day_name_win)
1475 gtk_calendar_paint_day_names (widget);
1477 if (event->window == private_data->week_win)
1478 gtk_calendar_paint_week_numbers (widget);
1479 if (event->window == widget->window)
1480 gtk_calendar_draw_focus (widget);
1487 gtk_calendar_paint (GtkWidget *widget,
1490 GtkCalendar *calendar;
1491 GtkCalendarPrivateData *private_data;
1493 g_return_if_fail (widget != NULL);
1494 g_return_if_fail (widget->window != NULL);
1495 g_return_if_fail (GTK_IS_CALENDAR (widget));
1497 calendar = GTK_CALENDAR (widget);
1498 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1500 if (private_data->main_win != NULL)
1501 gtk_calendar_paint_main (widget);
1503 if (private_data->header_win != NULL)
1504 gtk_calendar_paint_header (widget);
1506 if (private_data->day_name_win != NULL)
1507 gtk_calendar_paint_day_names (widget);
1509 if (private_data->week_win != NULL)
1510 gtk_calendar_paint_week_numbers (widget);
1512 gtk_calendar_draw_focus (widget);
1516 gtk_calendar_paint_header (GtkWidget *widget)
1518 GtkCalendar *calendar;
1522 gint header_width, cal_height;
1523 gint max_month_width;
1524 gint max_year_width;
1525 GtkCalendarPrivateData *private_data;
1526 PangoLayout *layout;
1527 PangoRectangle logical_rect;
1529 calendar = GTK_CALENDAR (widget);
1530 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1532 if (private_data->freeze_count)
1534 private_data->dirty_header = 1;
1537 private_data->dirty_header = 0;
1541 gdk_window_clear (private_data->header_win);
1543 header_width = widget->allocation.width - 4;
1544 cal_height = widget->allocation.height;
1546 max_month_width = private_data->max_month_width;
1547 max_year_width = private_data->max_year_width;
1549 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1550 gtk_draw_shadow (widget->style, private_data->header_win,
1551 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1552 0, 0, header_width, private_data->header_h);
1555 sprintf (buffer, "%d", calendar->year);
1556 layout = gtk_widget_create_pango_layout (widget, buffer);
1557 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1560 y = (private_data->header_h - logical_rect.height) / 2;
1562 /* Draw year and its arrows */
1564 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1565 x = header_width - (3 + max_year_width
1566 - (max_year_width - logical_rect.width)/2);
1568 x = header_width - (3 + private_data->arrow_width + max_year_width
1569 - (max_year_width - logical_rect.width)/2);
1572 gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1573 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1576 sprintf (buffer, "%s", default_monthname[calendar->month]);
1577 pango_layout_set_text (layout, buffer, -1);
1578 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1580 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1581 x = 3 + (max_month_width - logical_rect.width) / 2;
1583 x = 3 + private_data->arrow_width + (max_month_width - logical_rect.width)/2;
1585 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1587 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1589 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
1590 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
1591 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
1592 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
1594 g_object_unref (G_OBJECT (layout));
1598 gtk_calendar_paint_day_names (GtkWidget *widget)
1600 GtkCalendar *calendar;
1604 int day_width, cal_width;
1607 PangoLayout *layout;
1608 PangoRectangle logical_rect;
1609 GtkCalendarPrivateData *private_data;
1611 g_return_if_fail (widget != NULL);
1612 g_return_if_fail (GTK_IS_CALENDAR (widget));
1613 calendar = GTK_CALENDAR (widget);
1614 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1618 * Handle freeze/thaw functionality
1621 if (private_data->freeze_count)
1623 private_data->dirty_day_names = 1;
1626 private_data->dirty_day_names = 0;
1632 gdk_window_clear (private_data->day_name_win);
1634 day_width = private_data->day_width;
1635 cal_width = widget->allocation.width;
1636 cal_height = widget->allocation.height;
1637 day_wid_sep = day_width + DAY_XSEP;
1640 * Draw rectangles as inverted background for the labels.
1643 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1644 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1645 CALENDAR_MARGIN, CALENDAR_MARGIN,
1646 cal_width-CALENDAR_MARGIN * 2,
1647 private_data->day_name_h - CALENDAR_MARGIN);
1649 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1650 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1652 private_data->day_name_h - CALENDAR_YSEP,
1653 private_data->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1660 layout = gtk_widget_create_pango_layout (widget, NULL);
1662 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1663 for (i = 0; i < 7; i++)
1665 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
1669 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1671 sprintf (buffer, "%s", default_abbreviated_dayname[day]);
1673 pango_layout_set_text (layout, buffer, -1);
1674 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1676 gdk_draw_layout (private_data->day_name_win, gc,
1677 ((private_data->week_width ? CALENDAR_XSEP : CALENDAR_MARGIN)
1679 + private_data->week_width
1680 + (day_width - logical_rect.width)/2),
1681 CALENDAR_MARGIN + DAY_YPAD + logical_rect.y,
1685 g_object_unref (G_OBJECT (layout));
1689 gtk_calendar_paint_week_numbers (GtkWidget *widget)
1691 GtkCalendar *calendar;
1693 gint row, week = 0, year;
1696 gint y_loc, day_height;
1697 GtkCalendarPrivateData *private_data;
1698 PangoLayout *layout;
1699 PangoRectangle logical_rect;
1701 g_return_if_fail (widget != NULL);
1702 g_return_if_fail (widget->window != NULL);
1703 g_return_if_fail (GTK_IS_CALENDAR (widget));
1704 calendar = GTK_CALENDAR (widget);
1705 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1709 * Handle freeze/thaw functionality
1712 if (private_data->freeze_count)
1714 private_data->dirty_week = 1;
1717 private_data->dirty_week = 0;
1723 gdk_window_clear (private_data->week_win);
1726 * Draw a rectangle as inverted background for the labels.
1729 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1730 if (private_data->day_name_win)
1731 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1734 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1735 private_data->main_h - CALENDAR_MARGIN);
1737 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1740 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1741 private_data->main_h - 2 * CALENDAR_MARGIN);
1747 layout = gtk_widget_create_pango_layout (widget, NULL);
1749 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1750 day_height = row_height (calendar);
1751 for (row = 0; row < 6; row++)
1753 year = calendar->year;
1754 if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
1757 g_return_if_fail (week_of_year (&week, &year,
1758 ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
1759 + calendar->month) % 12 + 1, calendar->day[row][6]));
1761 sprintf (buffer, "%d", week);
1762 pango_layout_set_text (layout, buffer, -1);
1763 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1765 y_loc = top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
1767 x_loc = (private_data->week_width
1768 - logical_rect.width
1769 - CALENDAR_XSEP - DAY_XPAD);
1771 gdk_draw_layout (private_data->week_win, gc, x_loc, y_loc, layout);
1774 g_object_unref (G_OBJECT (layout));
1778 gtk_calendar_paint_day_num (GtkWidget *widget,
1781 GtkCalendar *calendar;
1782 gint r, c, row, col;
1784 g_return_if_fail (widget != NULL);
1785 g_return_if_fail (GTK_IS_CALENDAR (widget));
1787 calendar = GTK_CALENDAR (widget);
1791 for (r = 0; r < 6; r++)
1792 for (c = 0; c < 7; c++)
1793 if (calendar->day_month[r][c] == MONTH_CURRENT &&
1794 calendar->day[r][c] == day)
1800 g_return_if_fail (row != -1);
1801 g_return_if_fail (col != -1);
1803 gtk_calendar_paint_day (widget, row, col);
1807 gtk_calendar_paint_day (GtkWidget *widget,
1811 GtkCalendar *calendar;
1821 GtkCalendarPrivateData *private_data;
1822 PangoLayout *layout;
1823 PangoRectangle logical_rect;
1825 g_return_if_fail (widget != NULL);
1826 g_return_if_fail (GTK_IS_CALENDAR (widget));
1827 g_return_if_fail (row < 6);
1828 g_return_if_fail (col < 7);
1829 calendar = GTK_CALENDAR (widget);
1830 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1833 * Handle freeze/thaw functionality
1836 if (private_data->freeze_count)
1838 private_data->dirty_main = 1;
1842 day_height = row_height (calendar);
1844 day_xspace = private_data->day_width - private_data->max_day_char_width*2;
1846 day = calendar->day[row][col];
1848 x_left = left_x_for_column (calendar, col);
1849 x_loc = x_left + private_data->day_width / 2 + private_data->max_day_char_width;
1851 y_top = top_y_for_row (calendar, row);
1853 gdk_window_clear_area (private_data->main_win, x_left, y_top,
1854 private_data->day_width, day_height);
1858 if (calendar->day_month[row][col] == MONTH_PREV)
1860 gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar)));
1862 else if (calendar->day_month[row][col] == MONTH_NEXT)
1864 gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar)));
1869 if (calendar->highlight_row == row && calendar->highlight_col == col)
1871 gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar)));
1872 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1873 private_data->day_width, day_height);
1876 if (calendar->selected_day == day)
1878 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->bg[GTK_STATE_SELECTED]));
1879 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1880 private_data->day_width, day_height);
1883 if (calendar->marked_date[day-1])
1884 gdk_gc_set_foreground (gc, MARKED_COLOR (GTK_WIDGET (calendar)));
1886 gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar)));
1888 if (calendar->selected_day == day)
1889 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_STATE_SELECTED]));
1891 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_WIDGET_STATE (calendar)]));
1895 sprintf (buffer, "%d", day);
1896 layout = gtk_widget_create_pango_layout (widget, buffer);
1897 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1899 x_loc -= logical_rect.width;
1901 y_loc = y_top + (day_height - logical_rect.height) / 2;
1902 gdk_draw_layout (private_data->main_win, gc,
1903 x_loc, y_loc, layout);
1904 if (calendar->marked_date[day-1]
1905 && calendar->day_month[row][col] == MONTH_CURRENT)
1906 gdk_draw_layout (private_data->main_win, gc,
1907 x_loc-1, y_loc, layout);
1909 if (GTK_WIDGET_HAS_FOCUS (calendar)
1910 && calendar->focus_row == row && calendar->focus_col == col)
1912 gdk_draw_rectangle (private_data->main_win, calendar->xor_gc,
1913 FALSE, x_left, y_top,
1914 private_data->day_width-1, day_height-1);
1917 g_object_unref (G_OBJECT (layout));
1922 gtk_calendar_paint_main (GtkWidget *widget)
1924 GtkCalendar *calendar;
1925 GtkCalendarPrivateData *private_data;
1928 g_return_if_fail (widget != NULL);
1929 g_return_if_fail (widget->window != NULL);
1930 g_return_if_fail (GTK_IS_CALENDAR (widget));
1932 calendar = GTK_CALENDAR (widget);
1933 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1935 if (private_data->freeze_count)
1937 private_data->dirty_main = 1;
1940 private_data->dirty_main = 0;
1941 gdk_window_clear (private_data->main_win);
1943 /* gtk_calendar_compute_days (calendar); */ /* REMOVE later */
1945 for (col = 0; col < 7; col++)
1946 for (row = 0; row < 6; row++)
1947 gtk_calendar_paint_day (widget, row, col);
1951 gtk_calendar_compute_days (GtkCalendar *calendar)
1955 gint ndays_in_month;
1956 gint ndays_in_prev_month;
1962 g_return_if_fail (calendar != NULL);
1963 g_return_if_fail (GTK_IS_CALENDAR (calendar));
1965 year = calendar->year;
1966 month = calendar->month + 1;
1968 ndays_in_month = month_length[leap (year)][month];
1970 first_day = day_of_week (year, month, 1);
1972 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1978 /* Compute days of previous month */
1980 ndays_in_prev_month = month_length[leap (year)][month-1];
1982 ndays_in_prev_month = month_length[leap (year)][12];
1983 day = ndays_in_prev_month - first_day + 1;
1988 for (col = 0; col < first_day; col++)
1990 calendar->day[row][col] = day;
1991 calendar->day_month[row][col] = MONTH_PREV;
1996 /* Compute days of current month */
1998 for (day = 1; day <= ndays_in_month; day++)
2000 calendar->day[row][col] = day;
2001 calendar->day_month[row][col] = MONTH_CURRENT;
2011 /* Compute days of next month */
2013 for (; row <= 5; row++)
2015 for (; col <= 6; col++)
2017 calendar->day[row][col] = day;
2018 calendar->day_month[row][col] = MONTH_NEXT;
2025 /* ----------------------------------------------------------------------
2026 NAME: gtk_calendar_display_options
2027 DESCRIPTION: Set display options (whether to display the
2028 heading and the month headings)
2030 flags is can be an XOR of:
2031 GTK_CALENDAR_SHOW_HEADING
2032 GTK_CALENDAR_SHOW_DAY_NAMES
2033 GTK_CALENDAR_NO_MONTH_CHANGE
2034 GTK_CALENDAR_SHOW_WEEK_NUMBERS
2035 GTK_CALENDAR_WEEK_START_MONDAY
2036 ---------------------------------------------------------------------- */
2039 gtk_calendar_display_options (GtkCalendar *calendar,
2040 GtkCalendarDisplayOptions flags)
2042 GtkCalendarPrivateData *private_data;
2047 g_return_if_fail (calendar != NULL);
2048 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2050 widget = GTK_WIDGET (calendar);
2051 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2053 if (GTK_WIDGET_REALIZED (widget))
2055 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2058 if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
2059 && (private_data->header_win))
2061 calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
2062 gtk_calendar_realize_arrows (widget);
2066 for (i = 0; i < 4; i++)
2068 if (private_data->arrow_win[i])
2070 gdk_window_set_user_data (private_data->arrow_win[i],
2072 gdk_window_destroy (private_data->arrow_win[i]);
2073 private_data->arrow_win[i] = NULL;
2079 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2083 if (flags & GTK_CALENDAR_SHOW_HEADING)
2085 calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
2086 gtk_calendar_realize_header (widget);
2090 for (i = 0; i < 4; i++)
2092 if (private_data->arrow_win[i])
2094 gdk_window_set_user_data (private_data->arrow_win[i],
2096 gdk_window_destroy (private_data->arrow_win[i]);
2097 private_data->arrow_win[i] = NULL;
2100 gdk_window_set_user_data (private_data->header_win, NULL);
2101 gdk_window_destroy (private_data->header_win);
2102 private_data->header_win = NULL;
2107 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2111 if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
2113 calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
2114 gtk_calendar_realize_day_names (widget);
2118 gdk_window_set_user_data (private_data->day_name_win, NULL);
2119 gdk_window_destroy (private_data->day_name_win);
2120 private_data->day_name_win = NULL;
2124 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2128 if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2130 calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
2131 gtk_calendar_realize_week_numbers (widget);
2135 gdk_window_set_user_data (private_data->week_win, NULL);
2136 gdk_window_destroy (private_data->week_win);
2137 private_data->week_win = NULL;
2141 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
2143 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
2144 calendar->display_flags &= ~GTK_CALENDAR_WEEK_START_MONDAY;
2146 calendar->display_flags |= GTK_CALENDAR_WEEK_START_MONDAY;
2148 gtk_calendar_compute_days (calendar);
2149 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2150 if (private_data->day_name_win)
2151 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2154 calendar->display_flags = flags;
2156 gtk_widget_queue_resize (GTK_WIDGET (calendar));
2160 calendar->display_flags = flags;
2165 gtk_calendar_select_month (GtkCalendar *calendar,
2169 g_return_val_if_fail (calendar != NULL, FALSE);
2170 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2171 g_return_val_if_fail (month <= 11, FALSE);
2173 calendar->month = month;
2174 calendar->year = year;
2176 gtk_calendar_compute_days (calendar);
2178 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2179 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
2181 gtk_signal_emit (GTK_OBJECT (calendar),
2182 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
2187 gtk_calendar_select_day (GtkCalendar *calendar,
2190 g_return_if_fail (calendar != NULL);
2191 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2192 g_return_if_fail (day <= 31);
2194 /* gtk_calendar_compute_days (calendar); */
2196 /* Deselect the old day */
2197 if (calendar->selected_day > 0)
2201 selected_day = calendar->selected_day;
2202 calendar->selected_day = 0;
2203 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2204 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day);
2207 calendar->selected_day = day;
2209 /* Deselect the new day */
2212 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2213 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day);
2216 gtk_signal_emit (GTK_OBJECT (calendar),
2217 gtk_calendar_signals[DAY_SELECTED_SIGNAL]);
2221 gtk_calendar_clear_marks (GtkCalendar *calendar)
2225 g_return_if_fail (calendar != NULL);
2226 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2228 for (day = 0; day < 31; day++)
2230 calendar->marked_date[day] = FALSE;
2233 calendar->num_marked_dates = 0;
2235 if (GTK_WIDGET_DRAWABLE (calendar))
2237 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2242 gtk_calendar_mark_day (GtkCalendar *calendar,
2245 g_return_val_if_fail (calendar != NULL, FALSE);
2246 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2248 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
2250 calendar->marked_date[day - 1] = TRUE;
2251 calendar->num_marked_dates++;
2253 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2255 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2262 gtk_calendar_unmark_day (GtkCalendar *calendar,
2265 g_return_val_if_fail (calendar != NULL, FALSE);
2266 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2268 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
2270 calendar->marked_date[day - 1] = FALSE;
2271 calendar->num_marked_dates--;
2274 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2276 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2283 gtk_calendar_get_date (GtkCalendar *calendar,
2288 g_return_if_fail (calendar != NULL);
2289 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2292 *year = calendar->year;
2295 *month = calendar->month;
2298 *day = calendar->selected_day;
2302 gtk_calendar_button_press (GtkWidget *widget,
2303 GdkEventButton *event)
2305 GtkCalendar *calendar;
2306 GtkCalendarPrivateData *private_data;
2308 void (* action_func) (GtkCalendar *);
2310 g_return_val_if_fail (widget != NULL, FALSE);
2311 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2312 g_return_val_if_fail (event != NULL, FALSE);
2314 calendar = GTK_CALENDAR (widget);
2315 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2317 x = (gint) (event->x);
2318 y = (gint) (event->y);
2320 if (event->window == private_data->main_win)
2321 gtk_calendar_main_button (widget, event);
2325 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2326 action_func = gtk_calendar_set_month_prev;
2327 else if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2328 action_func = gtk_calendar_set_month_next;
2329 else if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2330 action_func = gtk_calendar_set_year_prev;
2331 else if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2332 action_func = gtk_calendar_set_year_next;
2334 /* only call the action on single click, not double */
2335 if (action_func && event->type == GDK_BUTTON_PRESS)
2336 (* action_func) (calendar);
2338 return action_func != NULL;
2342 gtk_calendar_motion_notify (GtkWidget *widget,
2343 GdkEventMotion *event)
2345 GtkCalendar *calendar;
2346 GtkCalendarPrivateData *private_data;
2347 gint event_x, event_y;
2349 gint old_row, old_col;
2351 calendar = GTK_CALENDAR (widget);
2352 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2353 event_x = (gint) (event->x);
2354 event_y = (gint) (event->y);
2356 if (event->window == private_data->main_win)
2359 row = row_from_y (calendar, event_y);
2360 col = column_from_x (calendar, event_x);
2362 if (row != calendar->highlight_row || calendar->highlight_col != col)
2364 old_row = calendar->highlight_row;
2365 old_col = calendar->highlight_col;
2366 if (old_row > -1 && old_col > -1)
2368 calendar->highlight_row = -1;
2369 calendar->highlight_col = -1;
2370 gtk_calendar_paint_day (widget, old_row, old_col);
2373 calendar->highlight_row = row;
2374 calendar->highlight_col = col;
2376 if (row > -1 && col > -1)
2377 gtk_calendar_paint_day (widget, row, col);
2384 gtk_calendar_enter_notify (GtkWidget *widget,
2385 GdkEventCrossing *event)
2387 GtkCalendar *calendar;
2388 GtkCalendarPrivateData *private_data;
2390 g_return_val_if_fail (widget != NULL, FALSE);
2391 g_return_val_if_fail (event != NULL, FALSE);
2393 calendar = GTK_CALENDAR (widget);
2394 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2396 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2398 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2399 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2402 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2404 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2405 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2408 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2410 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2411 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2414 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2416 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2417 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2424 gtk_calendar_leave_notify (GtkWidget *widget,
2425 GdkEventCrossing *event)
2427 GtkCalendar *calendar;
2428 GtkCalendarPrivateData *private_data;
2432 g_return_val_if_fail (widget != NULL, FALSE);
2433 g_return_val_if_fail (event != NULL, FALSE);
2435 calendar = GTK_CALENDAR (widget);
2436 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2438 if (event->window == private_data->main_win)
2440 row = calendar->highlight_row;
2441 col = calendar->highlight_col;
2442 calendar->highlight_row = -1;
2443 calendar->highlight_col = -1;
2444 if (row > -1 && col > -1)
2445 gtk_calendar_paint_day (widget, row, col);
2448 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2450 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2451 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2454 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2456 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2457 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2460 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2462 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2463 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2466 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2468 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2469 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2476 gtk_calendar_paint_arrow (GtkWidget *widget,
2479 GtkCalendarPrivateData *private_data;
2482 GtkCalendar *calendar;
2486 g_return_if_fail (widget != NULL);
2488 calendar = GTK_CALENDAR (widget);
2489 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2491 if (private_data->freeze_count)
2493 private_data->dirty_header = 1;
2496 window = private_data->arrow_win[arrow];
2499 state = private_data->arrow_state[arrow];
2502 gdk_window_clear (window);
2503 gdk_window_set_background (window, &(widget)->style->bg[state]);
2504 gdk_window_get_size (window, &width, &height);
2505 gdk_window_clear_area (window,
2509 gdk_gc_set_foreground (gc, & (widget)->style->fg[state]);
2511 if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2512 draw_arrow_left (window, gc, width/2 - 3, height/2 - 4, 8);
2514 draw_arrow_right (window, gc, width/2 - 2, height/2 - 4, 8);
2520 gtk_calendar_freeze (GtkCalendar *calendar)
2522 g_return_if_fail (calendar != NULL);
2523 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2525 GTK_CALENDAR_PRIVATE_DATA (calendar)->freeze_count++;
2529 gtk_calendar_thaw (GtkCalendar *calendar)
2531 GtkCalendarPrivateData *private_data;
2533 g_return_if_fail (calendar != NULL);
2534 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2536 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2538 if (private_data->freeze_count)
2539 if (!(--private_data->freeze_count))
2541 if (private_data->dirty_header)
2542 if (GTK_WIDGET_DRAWABLE (calendar))
2543 gtk_calendar_paint_header (GTK_WIDGET (calendar));
2545 if (private_data->dirty_day_names)
2546 if (GTK_WIDGET_DRAWABLE (calendar))
2547 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2549 if (private_data->dirty_week)
2550 if (GTK_WIDGET_DRAWABLE (calendar))
2551 gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar));
2553 if (private_data->dirty_main)
2554 if (GTK_WIDGET_DRAWABLE (calendar))
2555 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2560 gtk_calendar_set_background (GtkWidget *widget)
2562 GtkCalendar *calendar;
2563 GtkCalendarPrivateData *private_data;
2566 g_return_if_fail (widget != NULL);
2567 g_return_if_fail (GTK_IS_CALENDAR (widget));
2569 calendar = GTK_CALENDAR (widget);
2570 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2572 if (GTK_WIDGET_REALIZED (widget))
2574 for (i = 0; i < 4; i++)
2576 if (private_data->arrow_win[i])
2577 gdk_window_set_background (private_data->arrow_win[i],
2578 HEADER_BG_COLOR (widget));
2580 if (private_data->header_win)
2581 gdk_window_set_background (private_data->header_win,
2582 HEADER_BG_COLOR (widget));
2583 if (private_data->day_name_win)
2584 gdk_window_set_background (private_data->day_name_win,
2585 BACKGROUND_COLOR (widget));
2586 if (private_data->week_win)
2587 gdk_window_set_background (private_data->week_win,
2588 BACKGROUND_COLOR (widget));
2589 if (private_data->main_win)
2590 gdk_window_set_background (private_data->main_win,
2591 BACKGROUND_COLOR (widget));
2593 gdk_window_set_background (widget->window,
2594 BACKGROUND_COLOR (widget));
2599 gtk_calendar_style_set (GtkWidget *widget,
2600 GtkStyle *previous_style)
2602 g_return_if_fail (widget != NULL);
2603 g_return_if_fail (GTK_IS_CALENDAR (widget));
2605 if (previous_style && GTK_WIDGET_REALIZED (widget))
2606 gtk_calendar_set_background(widget);
2610 gtk_calendar_state_changed (GtkWidget *widget,
2611 GtkStateType previous_state)
2613 g_return_if_fail (widget != NULL);
2614 g_return_if_fail (GTK_IS_CALENDAR (widget));
2616 gtk_calendar_set_background (widget);
2620 gtk_calendar_destroy (GtkObject *object)
2622 GtkCalendarPrivateData *private_data;
2623 private_data = GTK_CALENDAR_PRIVATE_DATA (object);
2624 g_free (private_data);
2625 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2626 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2630 gtk_calendar_key_press (GtkWidget *widget,
2633 GtkCalendar *calendar;
2639 g_return_val_if_fail (widget != NULL, FALSE);
2640 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2641 g_return_val_if_fail (event != NULL, FALSE);
2643 calendar = GTK_CALENDAR (widget);
2646 old_focus_row = calendar->focus_row;
2647 old_focus_col = calendar->focus_col;
2649 switch (event->keyval)
2653 if (event->state & GDK_CONTROL_MASK)
2655 gtk_calendar_set_month_prev (calendar);
2659 if (calendar->focus_col > 0)
2661 calendar->focus_col--;
2663 else if (calendar->focus_row > 0)
2665 calendar->focus_col = 6;
2666 calendar->focus_row--;
2668 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2669 gtk_calendar_paint_day (widget, calendar->focus_row,
2670 calendar->focus_col);
2675 if (event->state & GDK_CONTROL_MASK)
2677 gtk_calendar_set_month_next (calendar);
2681 if (calendar->focus_col < 6)
2683 calendar->focus_col++;
2685 else if (calendar->focus_row < 5)
2687 calendar->focus_col = 0;
2688 calendar->focus_row++;
2690 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2691 gtk_calendar_paint_day (widget, calendar->focus_row,
2692 calendar->focus_col);
2697 if (event->state & GDK_CONTROL_MASK)
2699 gtk_calendar_set_year_prev (calendar);
2703 if (calendar->focus_row > 0)
2705 calendar->focus_row--;
2707 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2708 gtk_calendar_paint_day (widget, calendar->focus_row,
2709 calendar->focus_col);
2714 if (event->state & GDK_CONTROL_MASK)
2716 gtk_calendar_set_year_next (calendar);
2720 if (calendar->focus_row < 5)
2722 calendar->focus_row++;
2724 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2725 gtk_calendar_paint_day (widget, calendar->focus_row,
2726 calendar->focus_col);
2730 row = calendar->focus_row;
2731 col = calendar->focus_col;
2732 day = calendar->day[row][col];
2734 if (row > -1 && col > -1)
2737 gtk_calendar_freeze (calendar);
2739 if (calendar->day_month[row][col] == MONTH_PREV)
2741 gtk_calendar_set_month_prev (calendar);
2743 else if (calendar->day_month[row][col] == MONTH_NEXT)
2745 gtk_calendar_set_month_next (calendar);
2748 gtk_calendar_select_day (calendar, day);
2750 for (row = 0; row < 6; row ++)
2751 for (col = 0; col < 7; col++)
2753 if (calendar->day_month[row][col] == MONTH_CURRENT
2754 && calendar->day[row][col] == day)
2756 calendar->focus_row = row;
2757 calendar->focus_col = col;
2760 gtk_calendar_thaw (calendar);