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 gint gtk_calendar_focus_in (GtkWidget *widget,
288 GdkEventFocus *event);
289 static gint gtk_calendar_focus_out (GtkWidget *widget,
290 GdkEventFocus *event);
291 static void gtk_calendar_state_changed (GtkWidget *widget,
292 GtkStateType previous_state);
293 static void gtk_calendar_style_set (GtkWidget *widget,
294 GtkStyle *previous_style);
295 static void gtk_calendar_paint_header (GtkWidget *widget);
296 static void gtk_calendar_paint_day_names (GtkWidget *widget);
297 static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
298 static void gtk_calendar_paint_main (GtkWidget *widget);
301 static void gtk_calendar_paint (GtkWidget *widget,
303 static void gtk_calendar_paint_arrow (GtkWidget *widget,
305 static void gtk_calendar_paint_day_num (GtkWidget *widget,
307 static void gtk_calendar_paint_day (GtkWidget *widget,
310 static void gtk_calendar_compute_days (GtkCalendar *calendar);
311 static gint left_x_for_column (GtkCalendar *calendar,
313 static gint top_y_for_row (GtkCalendar *calendar,
316 static char *default_abbreviated_dayname[7];
317 static char *default_monthname[12];
320 gtk_calendar_get_type (void)
322 static GtkType calendar_type = 0;
326 static const GTypeInfo calendar_info =
328 sizeof (GtkCalendarClass),
329 NULL, /* base_init */
330 NULL, /* base_finalize */
331 (GClassInitFunc) gtk_calendar_class_init,
332 NULL, /* class_finalize */
333 NULL, /* class_data */
334 sizeof (GtkCalendar),
335 16, /* n_preallocs */
336 (GInstanceInitFunc) gtk_calendar_init,
339 calendar_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCalendar", &calendar_info, 0);
342 return calendar_type;
346 gtk_calendar_class_init (GtkCalendarClass *class)
348 GtkObjectClass *object_class;
349 GtkWidgetClass *widget_class;
351 object_class = (GtkObjectClass*) class;
352 widget_class = (GtkWidgetClass*) class;
354 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
356 widget_class->realize = gtk_calendar_realize;
357 widget_class->unrealize = gtk_calendar_unrealize;
358 widget_class->expose_event = gtk_calendar_expose;
359 widget_class->draw_focus = gtk_calendar_draw_focus;
360 widget_class->size_request = gtk_calendar_size_request;
361 widget_class->size_allocate = gtk_calendar_size_allocate;
362 widget_class->button_press_event = gtk_calendar_button_press;
363 widget_class->motion_notify_event = gtk_calendar_motion_notify;
364 widget_class->enter_notify_event = gtk_calendar_enter_notify;
365 widget_class->leave_notify_event = gtk_calendar_leave_notify;
366 widget_class->key_press_event = gtk_calendar_key_press;
367 widget_class->focus_in_event = gtk_calendar_focus_in;
368 widget_class->focus_out_event = gtk_calendar_focus_out;
369 widget_class->style_set = gtk_calendar_style_set;
370 widget_class->state_changed = gtk_calendar_state_changed;
371 object_class->destroy = gtk_calendar_destroy;
373 gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
374 gtk_signal_new ("month_changed",
375 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
376 GTK_SIGNAL_OFFSET (GtkCalendarClass, month_changed),
377 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
378 gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
379 gtk_signal_new ("day_selected",
380 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
381 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected),
382 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
383 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
384 gtk_signal_new ("day_selected_double_click",
385 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
386 GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected_double_click),
387 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
388 gtk_calendar_signals[PREV_MONTH_SIGNAL] =
389 gtk_signal_new ("prev_month",
390 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
391 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_month),
392 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
393 gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
394 gtk_signal_new ("next_month",
395 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
396 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_month),
397 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
398 gtk_calendar_signals[PREV_YEAR_SIGNAL] =
399 gtk_signal_new ("prev_year",
400 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
401 GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_year),
402 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
403 gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
404 gtk_signal_new ("next_year",
405 GTK_RUN_FIRST, GTK_CLASS_TYPE (object_class),
406 GTK_SIGNAL_OFFSET (GtkCalendarClass, next_year),
407 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
409 gtk_object_class_add_signals (object_class, gtk_calendar_signals, LAST_SIGNAL);
411 class->month_changed = NULL;
412 class->day_selected = NULL;
413 class->day_selected_double_click = NULL;
414 class->prev_month = NULL;
415 class->next_month = NULL;
416 class->prev_year = NULL;
417 class->next_year = NULL;
421 gtk_calendar_init (GtkCalendar *calendar)
429 GtkCalendarPrivateData *private_data;
431 widget = GTK_WIDGET (calendar);
432 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
434 calendar->private_data = (gpointer) malloc (sizeof (GtkCalendarPrivateData));
435 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
437 if (!default_abbreviated_dayname[0])
440 tmp_time= (i+3)*86400;
441 strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
442 default_abbreviated_dayname[i] = g_locale_to_utf8 (buffer, NULL);
445 if (!default_monthname[0])
449 strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
450 default_monthname[i] = g_locale_to_utf8 (buffer, NULL);
455 tm = localtime (&secs);
456 calendar->month = tm->tm_mon;
457 calendar->year = 1900 + tm->tm_year;
460 calendar->marked_date[i] = FALSE;
461 calendar->num_marked_dates = 0;
462 calendar->selected_day = 1;
464 calendar->display_flags = ( GTK_CALENDAR_SHOW_HEADING |
465 GTK_CALENDAR_SHOW_DAY_NAMES );
467 calendar->highlight_row = -1;
468 calendar->highlight_col = -1;
470 calendar->focus_row = -1;
471 calendar->focus_col = -1;
472 calendar->xor_gc = NULL;
474 private_data->max_year_width = 0;
475 private_data->max_month_width = 0;
476 private_data->max_day_char_width = 0;
477 private_data->max_week_char_width = 0;
479 private_data->max_day_char_ascent = 0;
480 private_data->max_day_char_descent = 0;
481 private_data->max_label_char_ascent = 0;
482 private_data->max_label_char_descent = 0;
484 private_data->arrow_width = 10;
486 private_data->freeze_count = 0;
488 private_data->dirty_header = 0;
489 private_data->dirty_day_names = 0;
490 private_data->dirty_week = 0;
491 private_data->dirty_main = 0;
495 gtk_calendar_new (void)
497 return GTK_WIDGET (gtk_type_new (GTK_TYPE_CALENDAR));
500 /* column_from_x: returns the column 0-6 that the
501 * x pixel of the xwindow is in */
503 column_from_x (GtkCalendar *calendar,
507 gint x_left, x_right;
511 for (c = 0; c < 7; c++)
513 x_left = left_x_for_column (calendar, c);
514 x_right = x_left + GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
516 if (event_x >= x_left && event_x < x_right)
527 row_height (GtkCalendar *calendar)
529 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h - CALENDAR_MARGIN
530 - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
531 ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
535 /* row_from_y: returns the row 0-5 that the
536 * y pixel of the xwindow is in */
538 row_from_y (GtkCalendar *calendar,
543 gint y_top, y_bottom;
545 height = row_height (calendar);
548 for (r = 0; r < 6; r++)
550 y_top = top_y_for_row (calendar, r);
551 y_bottom = y_top + height;
553 if (event_y >= y_top && event_y < y_bottom)
563 /* left_x_for_column: returns the x coordinate
564 * for the left of the column */
566 left_x_for_column (GtkCalendar *calendar,
572 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
575 width = GTK_CALENDAR_PRIVATE_DATA (calendar)->day_width;
576 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
577 x_left = DAY_XSEP + (width + DAY_XSEP) * column;
579 x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
584 /* top_y_for_row: returns the y coordinate
585 * for the top of the row */
587 top_y_for_row (GtkCalendar *calendar,
591 return (GTK_CALENDAR_PRIVATE_DATA (calendar)->main_h
592 - (CALENDAR_MARGIN + (6 - row)
593 * row_height (calendar)));
596 /* This function should be done by the toolkit, but we don't like the
597 * GTK arrows because they don't look good on this widget */
599 draw_arrow_right (GdkWindow *window,
607 for (i = 0; i <= size / 2; i++)
609 gdk_draw_line (window, gc,
617 /* This function should be done by the toolkit, but we don't like the
618 * GTK arrows because they don't look good on this widget */
620 draw_arrow_left (GdkWindow *window,
628 for (i = 0; i <= size / 2; i++)
630 gdk_draw_line (window, gc,
639 gtk_calendar_set_month_prev (GtkCalendar *calendar)
643 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
646 if (calendar->month == 0)
648 calendar->month = 11;
654 month_len = month_length[leap (calendar->year)][calendar->month + 1];
656 gtk_calendar_freeze (calendar);
657 gtk_calendar_compute_days (calendar);
659 gtk_signal_emit (GTK_OBJECT (calendar),
660 gtk_calendar_signals[PREV_MONTH_SIGNAL]);
661 gtk_signal_emit (GTK_OBJECT (calendar),
662 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
664 if (month_len < calendar->selected_day)
666 calendar->selected_day = 0;
667 gtk_calendar_select_day (calendar, month_len);
671 if (calendar->selected_day < 0)
672 calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
673 gtk_calendar_select_day (calendar, calendar->selected_day);
676 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
677 gtk_calendar_thaw (calendar);
682 gtk_calendar_set_month_next (GtkCalendar *calendar)
686 g_return_if_fail (calendar != NULL);
687 g_return_if_fail (GTK_IS_WIDGET (calendar));
689 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
693 if (calendar->month == 11)
701 gtk_calendar_freeze (calendar);
702 gtk_calendar_compute_days (calendar);
703 gtk_signal_emit (GTK_OBJECT (calendar),
704 gtk_calendar_signals[NEXT_MONTH_SIGNAL]);
705 gtk_signal_emit (GTK_OBJECT (calendar),
706 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
708 month_len = month_length[leap (calendar->year)][calendar->month + 1];
710 if (month_len < calendar->selected_day)
712 calendar->selected_day = 0;
713 gtk_calendar_select_day (calendar, month_len);
716 gtk_calendar_select_day (calendar, calendar->selected_day);
718 gtk_calendar_paint (GTK_WIDGET(calendar), NULL);
719 gtk_calendar_thaw (calendar);
723 gtk_calendar_set_year_prev (GtkCalendar *calendar)
727 g_return_if_fail (calendar != NULL);
728 g_return_if_fail (GTK_IS_WIDGET (calendar));
731 gtk_calendar_freeze (calendar);
732 gtk_calendar_compute_days (calendar);
733 gtk_signal_emit (GTK_OBJECT (calendar),
734 gtk_calendar_signals[PREV_YEAR_SIGNAL]);
735 gtk_signal_emit (GTK_OBJECT (calendar),
736 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
738 month_len = month_length[leap (calendar->year)][calendar->month + 1];
740 if (month_len < calendar->selected_day)
742 calendar->selected_day = 0;
743 gtk_calendar_select_day (calendar, month_len);
746 gtk_calendar_select_day (calendar, calendar->selected_day);
748 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
749 gtk_calendar_thaw (calendar);
753 gtk_calendar_set_year_next (GtkCalendar *calendar)
758 g_return_if_fail (calendar != NULL);
759 g_return_if_fail (GTK_IS_WIDGET (calendar));
761 widget = GTK_WIDGET (calendar);
763 gtk_calendar_freeze (calendar);
766 gtk_calendar_compute_days (calendar);
767 gtk_signal_emit (GTK_OBJECT (calendar),
768 gtk_calendar_signals[NEXT_YEAR_SIGNAL]);
769 gtk_signal_emit (GTK_OBJECT (calendar),
770 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
772 month_len = month_length[leap (calendar->year)][calendar->month + 1];
774 if (month_len < calendar->selected_day)
776 calendar->selected_day = 0;
777 gtk_calendar_select_day (calendar, month_len);
780 gtk_calendar_select_day (calendar, calendar->selected_day);
782 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
783 gtk_calendar_thaw (calendar);
787 gtk_calendar_main_button (GtkWidget *widget,
788 GdkEventButton *event)
790 GtkCalendar *calendar;
794 gint old_focus_row, old_focus_col;
796 calendar = GTK_CALENDAR (widget);
798 x = (gint) (event->x);
799 y = (gint) (event->y);
801 row = row_from_y (calendar, y);
802 col = column_from_x (calendar, x);
804 /* If row or column isn't found, just return. */
805 if (row == -1 || col == -1)
808 day_month = calendar->day_month[row][col];
810 if (day_month == MONTH_CURRENT)
812 if (event->type == GDK_2BUTTON_PRESS)
813 gtk_signal_emit (GTK_OBJECT (calendar),
814 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]);
817 if (!GTK_WIDGET_HAS_FOCUS (widget))
818 gtk_widget_grab_focus (widget);
819 old_focus_row = calendar->focus_row;
820 old_focus_col = calendar->focus_col;
821 calendar->focus_row = row;
822 calendar->focus_col = col;
823 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
824 gtk_calendar_select_day (calendar, calendar->day[row][col]);
827 else if (day_month == MONTH_PREV)
828 gtk_calendar_set_month_prev (calendar);
829 else if (day_month == MONTH_NEXT)
830 gtk_calendar_set_month_next (calendar);
834 gtk_calendar_realize_arrows (GtkWidget *widget)
836 GtkCalendar *calendar;
837 GtkCalendarPrivateData *private_data;
838 GdkWindowAttr attributes;
839 gint attributes_mask;
842 g_return_if_fail (widget != NULL);
843 g_return_if_fail (GTK_IS_CALENDAR (widget));
845 calendar = GTK_CALENDAR (widget);
846 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
848 /* Arrow windows ------------------------------------- */
849 if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
850 && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
852 attributes.wclass = GDK_INPUT_OUTPUT;
853 attributes.window_type = GDK_WINDOW_CHILD;
854 attributes.visual = gtk_widget_get_visual (widget);
855 attributes.colormap = gtk_widget_get_colormap (widget);
856 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
857 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
858 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
859 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
861 attributes.width = private_data->arrow_width;
862 attributes.height = private_data->header_h - 7;
863 for (i = 0; i < 4; i++)
867 case ARROW_MONTH_LEFT:
870 case ARROW_MONTH_RIGHT:
871 attributes.x = (private_data->arrow_width
872 + private_data->max_month_width);
874 case ARROW_YEAR_LEFT:
875 attributes.x = (widget->allocation.width - 4
876 - (3 + 2*private_data->arrow_width
877 + private_data->max_year_width));
879 case ARROW_YEAR_RIGHT:
880 attributes.x = (widget->allocation.width - 4
881 - 3 - private_data->arrow_width);
884 private_data->arrow_win[i] = gdk_window_new (private_data->header_win,
887 private_data->arrow_state[i] = GTK_STATE_NORMAL;
888 gdk_window_set_background (private_data->arrow_win[i],
889 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
890 gdk_window_show (private_data->arrow_win[i]);
891 gdk_window_set_user_data (private_data->arrow_win[i], widget);
896 for (i = 0; i < 4; i++)
897 private_data->arrow_win[i] = NULL;
902 gtk_calendar_realize_header (GtkWidget *widget)
904 GtkCalendar *calendar;
905 GtkCalendarPrivateData *private_data;
906 GdkWindowAttr attributes;
907 gint attributes_mask;
909 g_return_if_fail (widget != NULL);
910 g_return_if_fail (GTK_IS_CALENDAR (widget));
912 calendar = GTK_CALENDAR (widget);
913 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
915 /* Header window ------------------------------------- */
916 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
918 attributes.wclass = GDK_INPUT_OUTPUT;
919 attributes.window_type = GDK_WINDOW_CHILD;
920 attributes.visual = gtk_widget_get_visual (widget);
921 attributes.colormap = gtk_widget_get_colormap (widget);
922 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
923 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
926 attributes.width = widget->allocation.width - 4;
927 attributes.height = private_data->header_h;
928 private_data->header_win = gdk_window_new (widget->window,
929 &attributes, attributes_mask);
931 gdk_window_set_background (private_data->header_win,
932 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
933 gdk_window_show (private_data->header_win);
934 gdk_window_set_user_data (private_data->header_win, widget);
939 private_data->header_win = NULL;
941 gtk_calendar_realize_arrows (widget);
945 gtk_calendar_realize_day_names (GtkWidget *widget)
947 GtkCalendar *calendar;
948 GtkCalendarPrivateData *private_data;
949 GdkWindowAttr attributes;
950 gint attributes_mask;
952 g_return_if_fail (widget != NULL);
953 g_return_if_fail (GTK_IS_CALENDAR (widget));
955 calendar = GTK_CALENDAR (widget);
956 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
958 /* Day names window --------------------------------- */
959 if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
961 attributes.wclass = GDK_INPUT_OUTPUT;
962 attributes.window_type = GDK_WINDOW_CHILD;
963 attributes.visual = gtk_widget_get_visual (widget);
964 attributes.colormap = gtk_widget_get_colormap (widget);
965 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
966 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
967 attributes.x = (widget->style->xthickness + INNER_BORDER);
968 attributes.y = private_data->header_h + (widget->style->ythickness
970 attributes.width = (widget->allocation.width
971 - (widget->style->xthickness + INNER_BORDER)
973 attributes.height = private_data->day_name_h;
974 private_data->day_name_win = gdk_window_new (widget->window,
977 gdk_window_set_background (private_data->day_name_win,
978 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
979 gdk_window_show (private_data->day_name_win);
980 gdk_window_set_user_data (private_data->day_name_win, widget);
984 private_data->day_name_win = NULL;
989 gtk_calendar_realize_week_numbers (GtkWidget *widget)
991 GtkCalendar *calendar;
992 GtkCalendarPrivateData *private_data;
993 GdkWindowAttr attributes;
994 gint attributes_mask;
996 g_return_if_fail (widget != NULL);
997 g_return_if_fail (GTK_IS_CALENDAR (widget));
999 calendar = GTK_CALENDAR (widget);
1000 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1002 /* Week number window -------------------------------- */
1003 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1005 attributes.wclass = GDK_INPUT_OUTPUT;
1006 attributes.window_type = GDK_WINDOW_CHILD;
1007 attributes.visual = gtk_widget_get_visual (widget);
1008 attributes.colormap = gtk_widget_get_colormap (widget);
1009 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1011 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1012 attributes.x = + (widget->style->xthickness + INNER_BORDER);
1013 attributes.y = (private_data->header_h + private_data->day_name_h
1014 + (widget->style->ythickness + INNER_BORDER));
1015 attributes.width = private_data->week_width;
1016 attributes.height = private_data->main_h;
1017 private_data->week_win = gdk_window_new (widget->window,
1018 &attributes, attributes_mask);
1019 gdk_window_set_background (private_data->week_win,
1020 BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1021 gdk_window_show (private_data->week_win);
1022 gdk_window_set_user_data (private_data->week_win, widget);
1026 private_data->week_win = NULL;
1031 gtk_calendar_realize (GtkWidget *widget)
1033 GtkCalendar *calendar;
1034 GtkCalendarPrivateData *private_data;
1035 GdkWindowAttr attributes;
1036 gint attributes_mask;
1039 g_return_if_fail (widget != NULL);
1040 g_return_if_fail (GTK_IS_CALENDAR (widget));
1042 calendar = GTK_CALENDAR (widget);
1043 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1045 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1046 gtk_calendar_compute_days (calendar);
1048 attributes.x = widget->allocation.x;
1049 attributes.y = widget->allocation.y;
1050 attributes.width = widget->allocation.width;
1051 attributes.height = widget->allocation.height;
1052 attributes.wclass = GDK_INPUT_OUTPUT;
1053 attributes.window_type = GDK_WINDOW_CHILD;
1054 attributes.event_mask = (gtk_widget_get_events (widget)
1055 | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK);
1056 attributes.visual = gtk_widget_get_visual (widget);
1057 attributes.colormap = gtk_widget_get_colormap (widget);
1059 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1060 widget->window = gdk_window_new (widget->parent->window,
1061 &attributes, attributes_mask);
1063 widget->style = gtk_style_attach (widget->style, widget->window);
1065 /* Header window ------------------------------------- */
1066 gtk_calendar_realize_header (widget);
1067 /* Day names window --------------------------------- */
1068 gtk_calendar_realize_day_names (widget);
1069 /* Week number window -------------------------------- */
1070 gtk_calendar_realize_week_numbers (widget);
1071 /* Main Window -------------------------------------- */
1072 attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
1073 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1074 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1076 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1077 attributes.x = private_data->week_width;
1080 attributes.x += (widget->style->xthickness + INNER_BORDER);
1081 attributes.y = (private_data->header_h + private_data->day_name_h
1082 + (widget->style->ythickness + INNER_BORDER));
1083 attributes.width = (widget->allocation.width - attributes.x
1084 - (widget->style->xthickness + INNER_BORDER));
1085 attributes.height = private_data->main_h;
1086 private_data->main_win = gdk_window_new (widget->window,
1087 &attributes, attributes_mask);
1088 gdk_window_set_background (private_data->main_win,
1089 BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
1090 gdk_window_show (private_data->main_win);
1091 gdk_window_set_user_data (private_data->main_win, widget);
1092 gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
1093 gdk_window_show (widget->window);
1094 gdk_window_set_user_data (widget->window, widget);
1096 /* Set widgets gc */
1097 calendar->gc = gdk_gc_new (widget->window);
1099 values.foreground = widget->style->white;
1100 values.function = GDK_XOR;
1101 calendar->xor_gc = gdk_gc_new_with_values (widget->window,
1108 gtk_calendar_unrealize (GtkWidget *widget)
1110 GtkCalendar *calendar;
1111 GtkCalendarPrivateData *private_data;
1114 g_return_if_fail (widget != NULL);
1115 g_return_if_fail (GTK_IS_CALENDAR (widget));
1117 calendar = GTK_CALENDAR (widget);
1118 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1120 if (private_data->header_win)
1122 for (i = 0; i < 4; i++)
1124 if (private_data->arrow_win[i])
1126 gdk_window_set_user_data (private_data->arrow_win[i], NULL);
1127 gdk_window_destroy (private_data->arrow_win[i]);
1128 private_data->arrow_win[i] = NULL;
1131 gdk_window_set_user_data (private_data->header_win, NULL);
1132 gdk_window_destroy (private_data->header_win);
1133 private_data->header_win = NULL;
1136 if (private_data->week_win)
1138 gdk_window_set_user_data (private_data->week_win, NULL);
1139 gdk_window_destroy (private_data->week_win);
1140 private_data->week_win = NULL;
1143 if (private_data->main_win)
1145 gdk_window_set_user_data (private_data->main_win, NULL);
1146 gdk_window_destroy (private_data->main_win);
1147 private_data->main_win = NULL;
1149 if (private_data->day_name_win)
1151 gdk_window_set_user_data (private_data->day_name_win, NULL);
1152 gdk_window_destroy (private_data->day_name_win);
1153 private_data->day_name_win = NULL;
1155 if (calendar->xor_gc)
1156 gdk_gc_unref (calendar->xor_gc);
1158 gdk_gc_unref (calendar->gc);
1160 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1161 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1165 gtk_calendar_size_request (GtkWidget *widget,
1166 GtkRequisition *requisition)
1168 GtkCalendar *calendar;
1169 GtkCalendarPrivateData *private_data;
1170 PangoLayout *layout;
1171 PangoRectangle logical_rect;
1176 gint calendar_margin = CALENDAR_MARGIN;
1177 gint header_width, main_width;
1178 gint max_header_height = 0;
1180 calendar = GTK_CALENDAR (widget);
1181 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1183 layout = gtk_widget_create_pango_layout (widget, NULL);
1186 * Calculate the requisition width for the widget.
1191 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1193 private_data->max_month_width = 0;
1194 for (i = 0; i < 12; i++)
1196 pango_layout_set_text (layout, default_monthname[i], -1);
1197 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1198 private_data->max_month_width = MAX (private_data->max_month_width,
1199 logical_rect.width + 8);
1200 max_header_height = MAX (max_header_height, logical_rect.height);
1202 private_data->max_year_width = 0;
1203 for (i=0; i<10; i++)
1205 sprintf (buffer, "%d%d%d%d", i,i,i,i);
1206 pango_layout_set_text (layout, buffer, -1);
1207 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1208 private_data->max_year_width = MAX (private_data->max_year_width,
1209 logical_rect.width + 8);
1210 max_header_height = MAX (max_header_height, logical_rect.height);
1215 private_data->max_month_width = 0;
1216 private_data->max_year_width = 0;
1219 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1220 header_width = (private_data->max_month_width
1221 + private_data->max_year_width
1224 header_width = (private_data->max_month_width
1225 + private_data->max_year_width
1226 + 4 * private_data->arrow_width + 3 * 3);
1228 /* Mainwindow labels width */
1230 private_data->max_day_char_width = 0;
1231 for (i = 0; i < 9; i++)
1233 sprintf (buffer, "%d%d", i, i);
1234 pango_layout_set_text (layout, buffer, -1);
1235 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1236 private_data->min_day_width = MAX (private_data->max_day_char_width,
1237 logical_rect.width);
1239 private_data->max_day_char_ascent = MAX (private_data->max_label_char_ascent,
1240 PANGO_ASCENT (logical_rect));
1241 private_data->max_day_char_descent = MAX (private_data->max_label_char_descent,
1242 PANGO_DESCENT (logical_rect));
1244 /* We add one to max_day_char_width to be able to make the marked day "bold" */
1245 private_data->max_day_char_width = private_data->min_day_width / 2 +1;
1247 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1248 for (i = 0; i < 7; i++)
1250 pango_layout_set_text (layout, default_abbreviated_dayname[i], -1);
1251 pango_layout_line_get_pixel_extents (pango_layout_get_lines (layout)->data, NULL, &logical_rect);
1253 private_data->min_day_width = MAX (private_data->min_day_width, logical_rect.width);
1254 private_data->max_label_char_ascent = MAX (private_data->max_label_char_ascent,
1255 PANGO_ASCENT (logical_rect));
1256 private_data->max_label_char_descent = MAX (private_data->max_label_char_descent,
1257 PANGO_DESCENT (logical_rect));
1260 private_data->max_week_char_width = 0;
1261 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1262 for (i = 0; i < 9; i++)
1264 sprintf (buffer, "%d%d", i, i);
1265 pango_layout_set_text (layout, buffer, -1);
1266 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1267 private_data->max_week_char_width = MAX (private_data->max_week_char_width,
1268 logical_rect.width / 2);
1271 main_width = (7 * (private_data->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
1272 + (private_data->max_week_char_width
1273 ? private_data->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2
1277 requisition->width = MAX (header_width+4, main_width + (widget->style->xthickness + INNER_BORDER) *2);
1280 * Calculate the requisition height for the widget.
1283 if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
1285 private_data->header_h = (max_header_height + CALENDAR_YSEP * 2);
1289 private_data->header_h = 0;
1292 if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
1294 private_data->day_name_h = (private_data->max_label_char_ascent
1295 + private_data->max_label_char_descent
1296 + 2 * DAY_YPAD + calendar_margin);
1297 calendar_margin = CALENDAR_YSEP;
1301 private_data->day_name_h = 0;
1304 private_data->main_h = (CALENDAR_MARGIN + calendar_margin
1305 + 6 * (private_data->max_day_char_ascent
1306 + private_data->max_day_char_descent
1311 * If we display weeknumbers we need some extra space
1314 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1316 private_data->main_h = MAX (private_data->main_h,
1317 (CALENDAR_MARGIN + calendar_margin
1318 + 6 * (private_data->max_day_char_ascent
1319 + private_data->max_day_char_descent
1324 height = (private_data->header_h + private_data->day_name_h
1325 + private_data->main_h);
1327 requisition->height = height + (widget->style->ythickness + INNER_BORDER) * 2;
1329 g_object_unref (G_OBJECT (layout));
1333 gtk_calendar_size_allocate (GtkWidget *widget,
1334 GtkAllocation *allocation)
1336 GtkCalendar *calendar;
1337 GtkCalendarPrivateData *private_data;
1339 g_return_if_fail (widget != NULL);
1340 g_return_if_fail (GTK_IS_CALENDAR (widget));
1341 g_return_if_fail (allocation != NULL);
1343 widget->allocation = *allocation;
1345 calendar = GTK_CALENDAR (widget);
1346 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1348 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1350 private_data->day_width = (private_data->min_day_width
1351 * ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1352 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2))
1353 / (7 * private_data->min_day_width + private_data->max_week_char_width * 2));
1354 private_data->week_width = ((allocation->width - (widget->style->xthickness + INNER_BORDER) * 2
1355 - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 )
1356 - private_data->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
1360 private_data->day_width = (allocation->width
1361 - (widget->style->xthickness + INNER_BORDER) * 2
1362 - (CALENDAR_MARGIN * 2)
1363 - (DAY_XSEP * 7))/7;
1364 private_data->week_width = 0;
1367 if (GTK_WIDGET_REALIZED (widget))
1369 gdk_window_move_resize (widget->window,
1370 allocation->x, allocation->y,
1371 allocation->width, allocation->height);
1372 if (private_data->header_win)
1373 gdk_window_move_resize (private_data->header_win,
1375 allocation->width-4, private_data->header_h);
1376 if (private_data->arrow_win[ARROW_MONTH_LEFT])
1377 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_LEFT],
1379 private_data->arrow_width,
1380 private_data->header_h - 7);
1381 if (private_data->arrow_win[ARROW_MONTH_RIGHT])
1382 gdk_window_move_resize (private_data->arrow_win[ARROW_MONTH_RIGHT],
1383 (private_data->arrow_width
1384 + private_data->max_month_width),
1386 private_data->arrow_width,
1387 private_data->header_h - 7);
1388 if (private_data->arrow_win[ARROW_YEAR_LEFT])
1389 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_LEFT],
1390 (allocation->width - 4
1391 - (3 + 2*private_data->arrow_width
1392 + private_data->max_year_width)),
1394 private_data->arrow_width,
1395 private_data->header_h - 7);
1396 if (private_data->arrow_win[ARROW_YEAR_RIGHT])
1397 gdk_window_move_resize (private_data->arrow_win[ARROW_YEAR_RIGHT],
1398 (allocation->width - 4
1399 - 3 - private_data->arrow_width),
1401 private_data->arrow_width,
1402 private_data->header_h - 7);
1403 if (private_data->day_name_win)
1404 gdk_window_move_resize (private_data->day_name_win,
1405 widget->style->xthickness + INNER_BORDER,
1406 private_data->header_h + (widget->style->ythickness + INNER_BORDER),
1407 allocation->width - (widget->style->xthickness + INNER_BORDER) * 2,
1408 private_data->day_name_h);
1409 if (private_data->week_win)
1410 gdk_window_move_resize (private_data->week_win,
1411 (widget->style->xthickness + INNER_BORDER),
1412 private_data->header_h + private_data->day_name_h
1413 + (widget->style->ythickness + INNER_BORDER),
1414 private_data->week_width,
1415 private_data->main_h);
1416 gdk_window_move_resize (private_data->main_win,
1417 (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1418 + (widget->style->xthickness + INNER_BORDER),
1419 private_data->header_h + private_data->day_name_h
1420 + (widget->style->ythickness + INNER_BORDER),
1422 - (private_data->week_width ? private_data->week_width + CALENDAR_XSEP :0)
1423 - (widget->style->xthickness + INNER_BORDER) * 2,
1424 private_data->main_h);
1429 gtk_calendar_draw_focus (GtkWidget *widget)
1431 GtkCalendar *calendar;
1432 GtkCalendarPrivateData *private_data;
1436 g_return_if_fail (widget != NULL);
1437 g_return_if_fail (GTK_IS_CALENDAR (widget));
1439 calendar = GTK_CALENDAR (widget);
1440 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1442 if (GTK_WIDGET_DRAWABLE (widget))
1446 gdk_window_get_size (widget->window, &width, &height);
1447 gdk_window_clear (widget->window);
1449 gdk_draw_rectangle (widget->window,
1450 widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1451 FALSE, x + 2, y + 2, width - 5, height - 5);
1453 gtk_draw_shadow (widget->style, widget->window,
1454 GTK_STATE_NORMAL, GTK_SHADOW_IN,
1455 x, y, width, height);
1461 gtk_calendar_expose (GtkWidget *widget,
1462 GdkEventExpose *event)
1464 GtkCalendar *calendar;
1465 GtkCalendarPrivateData *private_data;
1467 g_return_val_if_fail (widget != NULL, FALSE);
1468 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
1469 g_return_val_if_fail (event != NULL, FALSE);
1471 calendar = GTK_CALENDAR (widget);
1472 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1474 if (GTK_WIDGET_DRAWABLE (widget))
1476 if (event->window == private_data->main_win)
1477 gtk_calendar_paint_main (widget);
1479 if (event->window == private_data->header_win)
1480 gtk_calendar_paint_header (widget);
1482 if (event->window == private_data->day_name_win)
1483 gtk_calendar_paint_day_names (widget);
1485 if (event->window == private_data->week_win)
1486 gtk_calendar_paint_week_numbers (widget);
1487 if (event->window == widget->window)
1488 gtk_widget_draw_focus (widget);
1495 gtk_calendar_paint (GtkWidget *widget,
1498 GtkCalendar *calendar;
1499 GtkCalendarPrivateData *private_data;
1501 g_return_if_fail (widget != NULL);
1502 g_return_if_fail (widget->window != NULL);
1503 g_return_if_fail (GTK_IS_CALENDAR (widget));
1505 calendar = GTK_CALENDAR (widget);
1506 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1508 if (private_data->main_win != NULL)
1509 gtk_calendar_paint_main (widget);
1511 if (private_data->header_win != NULL)
1512 gtk_calendar_paint_header (widget);
1514 if (private_data->day_name_win != NULL)
1515 gtk_calendar_paint_day_names (widget);
1517 if (private_data->week_win != NULL)
1518 gtk_calendar_paint_week_numbers (widget);
1520 gtk_widget_draw_focus (widget);
1524 gtk_calendar_paint_header (GtkWidget *widget)
1526 GtkCalendar *calendar;
1530 gint header_width, cal_height;
1531 gint max_month_width;
1532 gint max_year_width;
1533 GtkCalendarPrivateData *private_data;
1534 PangoLayout *layout;
1535 PangoRectangle logical_rect;
1537 calendar = GTK_CALENDAR (widget);
1538 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1540 if (private_data->freeze_count)
1542 private_data->dirty_header = 1;
1545 private_data->dirty_header = 0;
1549 gdk_window_clear (private_data->header_win);
1551 header_width = widget->allocation.width - 4;
1552 cal_height = widget->allocation.height;
1554 max_month_width = private_data->max_month_width;
1555 max_year_width = private_data->max_year_width;
1557 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1558 gtk_draw_shadow (widget->style, private_data->header_win,
1559 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1560 0, 0, header_width, private_data->header_h);
1563 sprintf (buffer, "%d", calendar->year);
1564 layout = gtk_widget_create_pango_layout (widget, buffer);
1565 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1568 y = (private_data->header_h - logical_rect.height) / 2;
1570 /* Draw year and its arrows */
1572 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1573 x = header_width - (3 + max_year_width
1574 - (max_year_width - logical_rect.width)/2);
1576 x = header_width - (3 + private_data->arrow_width + max_year_width
1577 - (max_year_width - logical_rect.width)/2);
1580 gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar)));
1581 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1584 sprintf (buffer, "%s", default_monthname[calendar->month]);
1585 pango_layout_set_text (layout, buffer, -1);
1586 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1588 if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
1589 x = 3 + (max_month_width - logical_rect.width) / 2;
1591 x = 3 + private_data->arrow_width + (max_month_width - logical_rect.width)/2;
1593 gdk_draw_layout (private_data->header_win, gc, x, y, layout);
1595 gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar)));
1597 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
1598 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
1599 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
1600 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
1602 g_object_unref (G_OBJECT (layout));
1606 gtk_calendar_paint_day_names (GtkWidget *widget)
1608 GtkCalendar *calendar;
1612 int day_width, cal_width;
1615 PangoLayout *layout;
1616 PangoRectangle logical_rect;
1617 GtkCalendarPrivateData *private_data;
1619 g_return_if_fail (widget != NULL);
1620 g_return_if_fail (GTK_IS_CALENDAR (widget));
1621 calendar = GTK_CALENDAR (widget);
1622 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1626 * Handle freeze/thaw functionality
1629 if (private_data->freeze_count)
1631 private_data->dirty_day_names = 1;
1634 private_data->dirty_day_names = 0;
1640 gdk_window_clear (private_data->day_name_win);
1642 day_width = private_data->day_width;
1643 cal_width = widget->allocation.width;
1644 cal_height = widget->allocation.height;
1645 day_wid_sep = day_width + DAY_XSEP;
1648 * Draw rectangles as inverted background for the labels.
1651 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1652 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1653 CALENDAR_MARGIN, CALENDAR_MARGIN,
1654 cal_width-CALENDAR_MARGIN * 2,
1655 private_data->day_name_h - CALENDAR_MARGIN);
1657 if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
1658 gdk_draw_rectangle (private_data->day_name_win, gc, TRUE,
1660 private_data->day_name_h - CALENDAR_YSEP,
1661 private_data->week_width - CALENDAR_YSEP - CALENDAR_MARGIN,
1668 layout = gtk_widget_create_pango_layout (widget, NULL);
1670 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1671 for (i = 0; i < 7; i++)
1673 if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
1677 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1679 sprintf (buffer, "%s", default_abbreviated_dayname[day]);
1681 pango_layout_set_text (layout, buffer, -1);
1682 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1684 gdk_draw_layout (private_data->day_name_win, gc,
1685 ((private_data->week_width ? CALENDAR_XSEP : CALENDAR_MARGIN)
1687 + private_data->week_width
1688 + (day_width - logical_rect.width)/2),
1689 CALENDAR_MARGIN + DAY_YPAD + logical_rect.y,
1693 g_object_unref (G_OBJECT (layout));
1697 gtk_calendar_paint_week_numbers (GtkWidget *widget)
1699 GtkCalendar *calendar;
1701 gint row, week = 0, year;
1704 gint y_loc, day_height;
1705 GtkCalendarPrivateData *private_data;
1706 PangoLayout *layout;
1707 PangoRectangle logical_rect;
1709 g_return_if_fail (widget != NULL);
1710 g_return_if_fail (widget->window != NULL);
1711 g_return_if_fail (GTK_IS_CALENDAR (widget));
1712 calendar = GTK_CALENDAR (widget);
1713 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1717 * Handle freeze/thaw functionality
1720 if (private_data->freeze_count)
1722 private_data->dirty_week = 1;
1725 private_data->dirty_week = 0;
1731 gdk_window_clear (private_data->week_win);
1734 * Draw a rectangle as inverted background for the labels.
1737 gdk_gc_set_foreground (gc, &widget->style->bg[GTK_STATE_SELECTED]);
1738 if (private_data->day_name_win)
1739 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1742 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1743 private_data->main_h - CALENDAR_MARGIN);
1745 gdk_draw_rectangle (private_data->week_win, gc, TRUE,
1748 private_data->week_width - CALENDAR_MARGIN - CALENDAR_XSEP,
1749 private_data->main_h - 2 * CALENDAR_MARGIN);
1755 layout = gtk_widget_create_pango_layout (widget, NULL);
1757 gdk_gc_set_foreground (gc, &widget->style->fg[GTK_STATE_SELECTED]);
1758 day_height = row_height (calendar);
1759 for (row = 0; row < 6; row++)
1761 year = calendar->year;
1762 if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11)
1765 g_return_if_fail (week_of_year (&week, &year,
1766 ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0)
1767 + calendar->month) % 12 + 1, calendar->day[row][6]));
1769 sprintf (buffer, "%d", week);
1770 pango_layout_set_text (layout, buffer, -1);
1771 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1773 y_loc = top_y_for_row (calendar, row) + (day_height - logical_rect.height) / 2;
1775 x_loc = (private_data->week_width
1776 - logical_rect.width
1777 - CALENDAR_XSEP - DAY_XPAD);
1779 gdk_draw_layout (private_data->week_win, gc, x_loc, y_loc, layout);
1782 g_object_unref (G_OBJECT (layout));
1786 gtk_calendar_paint_day_num (GtkWidget *widget,
1789 GtkCalendar *calendar;
1790 gint r, c, row, col;
1792 g_return_if_fail (widget != NULL);
1793 g_return_if_fail (GTK_IS_CALENDAR (widget));
1795 calendar = GTK_CALENDAR (widget);
1799 for (r = 0; r < 6; r++)
1800 for (c = 0; c < 7; c++)
1801 if (calendar->day_month[r][c] == MONTH_CURRENT &&
1802 calendar->day[r][c] == day)
1808 g_return_if_fail (row != -1);
1809 g_return_if_fail (col != -1);
1811 gtk_calendar_paint_day (widget, row, col);
1815 gtk_calendar_paint_day (GtkWidget *widget,
1819 GtkCalendar *calendar;
1829 GtkCalendarPrivateData *private_data;
1830 PangoLayout *layout;
1831 PangoRectangle logical_rect;
1833 g_return_if_fail (widget != NULL);
1834 g_return_if_fail (GTK_IS_CALENDAR (widget));
1835 g_return_if_fail (row < 6);
1836 g_return_if_fail (col < 7);
1837 calendar = GTK_CALENDAR (widget);
1838 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1841 * Handle freeze/thaw functionality
1844 if (private_data->freeze_count)
1846 private_data->dirty_main = 1;
1850 day_height = row_height (calendar);
1852 day_xspace = private_data->day_width - private_data->max_day_char_width*2;
1854 day = calendar->day[row][col];
1856 x_left = left_x_for_column (calendar, col);
1857 x_loc = x_left + private_data->day_width / 2 + private_data->max_day_char_width;
1859 y_top = top_y_for_row (calendar, row);
1861 gdk_window_clear_area (private_data->main_win, x_left, y_top,
1862 private_data->day_width, day_height);
1866 if (calendar->day_month[row][col] == MONTH_PREV)
1868 gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar)));
1870 else if (calendar->day_month[row][col] == MONTH_NEXT)
1872 gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar)));
1877 if (calendar->highlight_row == row && calendar->highlight_col == col)
1879 gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar)));
1880 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1881 private_data->day_width, day_height);
1884 if (calendar->selected_day == day)
1886 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->bg[GTK_STATE_SELECTED]));
1887 gdk_draw_rectangle (private_data->main_win, gc, TRUE, x_left, y_top,
1888 private_data->day_width, day_height);
1891 if (calendar->marked_date[day-1])
1892 gdk_gc_set_foreground (gc, MARKED_COLOR (GTK_WIDGET (calendar)));
1894 gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar)));
1896 if (calendar->selected_day == day)
1897 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_STATE_SELECTED]));
1899 gdk_gc_set_foreground (gc, & (GTK_WIDGET (calendar)->style->fg[GTK_WIDGET_STATE (calendar)]));
1903 sprintf (buffer, "%d", day);
1904 layout = gtk_widget_create_pango_layout (widget, buffer);
1905 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1907 x_loc -= logical_rect.width;
1909 y_loc = y_top + (day_height - logical_rect.height) / 2;
1910 gdk_draw_layout (private_data->main_win, gc,
1911 x_loc, y_loc, layout);
1912 if (calendar->marked_date[day-1]
1913 && calendar->day_month[row][col] == MONTH_CURRENT)
1914 gdk_draw_layout (private_data->main_win, gc,
1915 x_loc-1, y_loc, layout);
1917 if (GTK_WIDGET_HAS_FOCUS (calendar)
1918 && calendar->focus_row == row && calendar->focus_col == col)
1920 gdk_draw_rectangle (private_data->main_win, calendar->xor_gc,
1921 FALSE, x_left, y_top,
1922 private_data->day_width-1, day_height-1);
1925 g_object_unref (G_OBJECT (layout));
1930 gtk_calendar_paint_main (GtkWidget *widget)
1932 GtkCalendar *calendar;
1933 GtkCalendarPrivateData *private_data;
1936 g_return_if_fail (widget != NULL);
1937 g_return_if_fail (widget->window != NULL);
1938 g_return_if_fail (GTK_IS_CALENDAR (widget));
1940 calendar = GTK_CALENDAR (widget);
1941 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
1943 if (private_data->freeze_count)
1945 private_data->dirty_main = 1;
1948 private_data->dirty_main = 0;
1949 gdk_window_clear (private_data->main_win);
1951 /* gtk_calendar_compute_days (calendar); */ /* REMOVE later */
1953 for (col = 0; col < 7; col++)
1954 for (row = 0; row < 6; row++)
1955 gtk_calendar_paint_day (widget, row, col);
1959 gtk_calendar_compute_days (GtkCalendar *calendar)
1963 gint ndays_in_month;
1964 gint ndays_in_prev_month;
1970 g_return_if_fail (calendar != NULL);
1971 g_return_if_fail (GTK_IS_CALENDAR (calendar));
1973 year = calendar->year;
1974 month = calendar->month + 1;
1976 ndays_in_month = month_length[leap (year)][month];
1978 first_day = day_of_week (year, month, 1);
1980 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
1986 /* Compute days of previous month */
1988 ndays_in_prev_month = month_length[leap (year)][month-1];
1990 ndays_in_prev_month = month_length[leap (year)][12];
1991 day = ndays_in_prev_month - first_day + 1;
1996 for (col = 0; col < first_day; col++)
1998 calendar->day[row][col] = day;
1999 calendar->day_month[row][col] = MONTH_PREV;
2004 /* Compute days of current month */
2006 for (day = 1; day <= ndays_in_month; day++)
2008 calendar->day[row][col] = day;
2009 calendar->day_month[row][col] = MONTH_CURRENT;
2019 /* Compute days of next month */
2021 for (; row <= 5; row++)
2023 for (; col <= 6; col++)
2025 calendar->day[row][col] = day;
2026 calendar->day_month[row][col] = MONTH_NEXT;
2033 /* ----------------------------------------------------------------------
2034 NAME: gtk_calendar_display_options
2035 DESCRIPTION: Set display options (whether to display the
2036 heading and the month headings)
2038 flags is can be an XOR of:
2039 GTK_CALENDAR_SHOW_HEADING
2040 GTK_CALENDAR_SHOW_DAY_NAMES
2041 GTK_CALENDAR_NO_MONTH_CHANGE
2042 GTK_CALENDAR_SHOW_WEEK_NUMBERS
2043 GTK_CALENDAR_WEEK_START_MONDAY
2044 ---------------------------------------------------------------------- */
2047 gtk_calendar_display_options (GtkCalendar *calendar,
2048 GtkCalendarDisplayOptions flags)
2050 GtkCalendarPrivateData *private_data;
2055 g_return_if_fail (calendar != NULL);
2056 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2058 widget = GTK_WIDGET (calendar);
2059 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2061 if (GTK_WIDGET_REALIZED (widget))
2063 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE)
2066 if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE)
2067 && (private_data->header_win))
2069 calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE;
2070 gtk_calendar_realize_arrows (widget);
2074 for (i = 0; i < 4; i++)
2076 if (private_data->arrow_win[i])
2078 gdk_window_set_user_data (private_data->arrow_win[i],
2080 gdk_window_destroy (private_data->arrow_win[i]);
2081 private_data->arrow_win[i] = NULL;
2087 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING)
2091 if (flags & GTK_CALENDAR_SHOW_HEADING)
2093 calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING;
2094 gtk_calendar_realize_header (widget);
2098 for (i = 0; i < 4; i++)
2100 if (private_data->arrow_win[i])
2102 gdk_window_set_user_data (private_data->arrow_win[i],
2104 gdk_window_destroy (private_data->arrow_win[i]);
2105 private_data->arrow_win[i] = NULL;
2108 gdk_window_set_user_data (private_data->header_win, NULL);
2109 gdk_window_destroy (private_data->header_win);
2110 private_data->header_win = NULL;
2115 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES)
2119 if (flags & GTK_CALENDAR_SHOW_DAY_NAMES)
2121 calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES;
2122 gtk_calendar_realize_day_names (widget);
2126 gdk_window_set_user_data (private_data->day_name_win, NULL);
2127 gdk_window_destroy (private_data->day_name_win);
2128 private_data->day_name_win = NULL;
2132 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2136 if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
2138 calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS;
2139 gtk_calendar_realize_week_numbers (widget);
2143 gdk_window_set_user_data (private_data->week_win, NULL);
2144 gdk_window_destroy (private_data->week_win);
2145 private_data->week_win = NULL;
2149 if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY)
2151 if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY)
2152 calendar->display_flags &= ~GTK_CALENDAR_WEEK_START_MONDAY;
2154 calendar->display_flags |= GTK_CALENDAR_WEEK_START_MONDAY;
2156 gtk_calendar_compute_days (calendar);
2157 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2158 if (private_data->day_name_win)
2159 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2162 calendar->display_flags = flags;
2164 gtk_widget_queue_resize (GTK_WIDGET (calendar));
2168 calendar->display_flags = flags;
2173 gtk_calendar_select_month (GtkCalendar *calendar,
2177 g_return_val_if_fail (calendar != NULL, FALSE);
2178 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2179 g_return_val_if_fail (month <= 11, FALSE);
2181 calendar->month = month;
2182 calendar->year = year;
2184 gtk_calendar_compute_days (calendar);
2186 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2187 gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
2189 gtk_signal_emit (GTK_OBJECT (calendar),
2190 gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
2195 gtk_calendar_select_day (GtkCalendar *calendar,
2198 g_return_if_fail (calendar != NULL);
2199 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2200 g_return_if_fail (day <= 31);
2202 /* gtk_calendar_compute_days (calendar); */
2204 /* Deselect the old day */
2205 if (calendar->selected_day > 0)
2209 selected_day = calendar->selected_day;
2210 calendar->selected_day = 0;
2211 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2212 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day);
2215 calendar->selected_day = day;
2217 /* Deselect the new day */
2220 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2221 gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day);
2224 gtk_signal_emit (GTK_OBJECT (calendar),
2225 gtk_calendar_signals[DAY_SELECTED_SIGNAL]);
2229 gtk_calendar_clear_marks (GtkCalendar *calendar)
2233 g_return_if_fail (calendar != NULL);
2234 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2236 for (day = 0; day < 31; day++)
2238 calendar->marked_date[day] = FALSE;
2241 calendar->num_marked_dates = 0;
2243 if (GTK_WIDGET_DRAWABLE (calendar))
2245 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2250 gtk_calendar_mark_day (GtkCalendar *calendar,
2253 g_return_val_if_fail (calendar != NULL, FALSE);
2254 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2256 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == FALSE)
2258 calendar->marked_date[day - 1] = TRUE;
2259 calendar->num_marked_dates++;
2261 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2263 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2270 gtk_calendar_unmark_day (GtkCalendar *calendar,
2273 g_return_val_if_fail (calendar != NULL, FALSE);
2274 g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE);
2276 if (day >= 1 && day <= 31 && calendar->marked_date[day-1] == TRUE)
2278 calendar->marked_date[day - 1] = FALSE;
2279 calendar->num_marked_dates--;
2282 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar)))
2284 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2291 gtk_calendar_get_date (GtkCalendar *calendar,
2296 g_return_if_fail (calendar != NULL);
2297 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2300 *year = calendar->year;
2303 *month = calendar->month;
2306 *day = calendar->selected_day;
2310 gtk_calendar_button_press (GtkWidget *widget,
2311 GdkEventButton *event)
2313 GtkCalendar *calendar;
2314 GtkCalendarPrivateData *private_data;
2317 g_return_val_if_fail (widget != NULL, FALSE);
2318 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2319 g_return_val_if_fail (event != NULL, FALSE);
2321 calendar = GTK_CALENDAR (widget);
2322 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2324 x = (gint) (event->x);
2325 y = (gint) (event->y);
2327 if (event->window == private_data->main_win)
2328 gtk_calendar_main_button (widget, event);
2330 if (event->type != GDK_BUTTON_PRESS)
2331 return FALSE; /* Double-clicks? Triple-clicks? No thanks! */
2333 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2334 gtk_calendar_set_month_prev (calendar);
2336 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2337 gtk_calendar_set_month_next (calendar);
2339 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2340 gtk_calendar_set_year_prev (calendar);
2342 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2343 gtk_calendar_set_year_next (calendar);
2349 gtk_calendar_motion_notify (GtkWidget *widget,
2350 GdkEventMotion *event)
2352 GtkCalendar *calendar;
2353 GtkCalendarPrivateData *private_data;
2354 gint event_x, event_y;
2356 gint old_row, old_col;
2358 calendar = GTK_CALENDAR (widget);
2359 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2360 event_x = (gint) (event->x);
2361 event_y = (gint) (event->y);
2363 if (event->window == private_data->main_win)
2366 row = row_from_y (calendar, event_y);
2367 col = column_from_x (calendar, event_x);
2369 if (row != calendar->highlight_row || calendar->highlight_col != col)
2371 old_row = calendar->highlight_row;
2372 old_col = calendar->highlight_col;
2373 if (old_row > -1 && old_col > -1)
2375 calendar->highlight_row = -1;
2376 calendar->highlight_col = -1;
2377 gtk_calendar_paint_day (widget, old_row, old_col);
2380 calendar->highlight_row = row;
2381 calendar->highlight_col = col;
2383 if (row > -1 && col > -1)
2384 gtk_calendar_paint_day (widget, row, col);
2391 gtk_calendar_enter_notify (GtkWidget *widget,
2392 GdkEventCrossing *event)
2394 GtkCalendar *calendar;
2395 GtkCalendarPrivateData *private_data;
2397 g_return_val_if_fail (widget != NULL, FALSE);
2398 g_return_val_if_fail (event != NULL, FALSE);
2400 calendar = GTK_CALENDAR (widget);
2401 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2403 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2405 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT;
2406 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2409 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2411 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT;
2412 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2415 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2417 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT;
2418 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2421 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2423 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT;
2424 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2431 gtk_calendar_leave_notify (GtkWidget *widget,
2432 GdkEventCrossing *event)
2434 GtkCalendar *calendar;
2435 GtkCalendarPrivateData *private_data;
2439 g_return_val_if_fail (widget != NULL, FALSE);
2440 g_return_val_if_fail (event != NULL, FALSE);
2442 calendar = GTK_CALENDAR (widget);
2443 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2445 if (event->window == private_data->main_win)
2447 row = calendar->highlight_row;
2448 col = calendar->highlight_col;
2449 calendar->highlight_row = -1;
2450 calendar->highlight_col = -1;
2451 if (row > -1 && col > -1)
2452 gtk_calendar_paint_day (widget, row, col);
2455 if (event->window == private_data->arrow_win[ARROW_MONTH_LEFT])
2457 private_data->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL;
2458 gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT);
2461 if (event->window == private_data->arrow_win[ARROW_MONTH_RIGHT])
2463 private_data->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL;
2464 gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT);
2467 if (event->window == private_data->arrow_win[ARROW_YEAR_LEFT])
2469 private_data->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL;
2470 gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT);
2473 if (event->window == private_data->arrow_win[ARROW_YEAR_RIGHT])
2475 private_data->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL;
2476 gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT);
2483 gtk_calendar_paint_arrow (GtkWidget *widget,
2486 GtkCalendarPrivateData *private_data;
2489 GtkCalendar *calendar;
2493 g_return_if_fail (widget != NULL);
2495 calendar = GTK_CALENDAR (widget);
2496 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2498 if (private_data->freeze_count)
2500 private_data->dirty_header = 1;
2503 window = private_data->arrow_win[arrow];
2506 state = private_data->arrow_state[arrow];
2509 gdk_window_clear (window);
2510 gdk_window_set_background (window, &(widget)->style->bg[state]);
2511 gdk_window_get_size (window, &width, &height);
2512 gdk_window_clear_area (window,
2516 gdk_gc_set_foreground (gc, & (widget)->style->fg[state]);
2518 if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT)
2519 draw_arrow_left (window, gc, width/2 - 3, height/2 - 4, 8);
2521 draw_arrow_right (window, gc, width/2 - 2, height/2 - 4, 8);
2527 gtk_calendar_freeze (GtkCalendar *calendar)
2529 g_return_if_fail (calendar != NULL);
2530 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2532 GTK_CALENDAR_PRIVATE_DATA (calendar)->freeze_count++;
2536 gtk_calendar_thaw (GtkCalendar *calendar)
2538 GtkCalendarPrivateData *private_data;
2540 g_return_if_fail (calendar != NULL);
2541 g_return_if_fail (GTK_IS_CALENDAR (calendar));
2543 private_data = GTK_CALENDAR_PRIVATE_DATA (calendar);
2545 if (private_data->freeze_count)
2546 if (!(--private_data->freeze_count))
2548 if (private_data->dirty_header)
2549 if (GTK_WIDGET_DRAWABLE (calendar))
2550 gtk_calendar_paint_header (GTK_WIDGET (calendar));
2552 if (private_data->dirty_day_names)
2553 if (GTK_WIDGET_DRAWABLE (calendar))
2554 gtk_calendar_paint_day_names (GTK_WIDGET (calendar));
2556 if (private_data->dirty_week)
2557 if (GTK_WIDGET_DRAWABLE (calendar))
2558 gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar));
2560 if (private_data->dirty_main)
2561 if (GTK_WIDGET_DRAWABLE (calendar))
2562 gtk_calendar_paint_main (GTK_WIDGET (calendar));
2567 gtk_calendar_set_background (GtkWidget *widget)
2569 GtkCalendar *calendar;
2570 GtkCalendarPrivateData *private_data;
2573 g_return_if_fail (widget != NULL);
2574 g_return_if_fail (GTK_IS_CALENDAR (widget));
2576 calendar = GTK_CALENDAR (widget);
2577 private_data = GTK_CALENDAR_PRIVATE_DATA (widget);
2579 if (GTK_WIDGET_REALIZED (widget))
2581 for (i = 0; i < 4; i++)
2583 if (private_data->arrow_win[i])
2584 gdk_window_set_background (private_data->arrow_win[i],
2585 HEADER_BG_COLOR (widget));
2587 if (private_data->header_win)
2588 gdk_window_set_background (private_data->header_win,
2589 HEADER_BG_COLOR (widget));
2590 if (private_data->day_name_win)
2591 gdk_window_set_background (private_data->day_name_win,
2592 BACKGROUND_COLOR (widget));
2593 if (private_data->week_win)
2594 gdk_window_set_background (private_data->week_win,
2595 BACKGROUND_COLOR (widget));
2596 if (private_data->main_win)
2597 gdk_window_set_background (private_data->main_win,
2598 BACKGROUND_COLOR (widget));
2600 gdk_window_set_background (widget->window,
2601 BACKGROUND_COLOR (widget));
2606 gtk_calendar_style_set (GtkWidget *widget,
2607 GtkStyle *previous_style)
2609 g_return_if_fail (widget != NULL);
2610 g_return_if_fail (GTK_IS_CALENDAR (widget));
2612 if (previous_style && GTK_WIDGET_REALIZED (widget))
2613 gtk_calendar_set_background(widget);
2617 gtk_calendar_state_changed (GtkWidget *widget,
2618 GtkStateType previous_state)
2620 g_return_if_fail (widget != NULL);
2621 g_return_if_fail (GTK_IS_CALENDAR (widget));
2623 gtk_calendar_set_background (widget);
2627 gtk_calendar_focus_in (GtkWidget *widget,
2628 GdkEventFocus *event)
2630 GtkCalendar *calendar;
2632 g_return_val_if_fail (widget != NULL, FALSE);
2633 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2634 g_return_val_if_fail (event != NULL, FALSE);
2636 calendar = GTK_CALENDAR (widget);
2638 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2639 gtk_widget_draw_focus (widget);
2640 gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2646 gtk_calendar_destroy (GtkObject *object)
2648 GtkCalendarPrivateData *private_data;
2649 private_data = GTK_CALENDAR_PRIVATE_DATA (object);
2650 g_free (private_data);
2651 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2652 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2656 gtk_calendar_focus_out (GtkWidget *widget,
2657 GdkEventFocus *event)
2659 GtkCalendar *calendar;
2661 g_return_val_if_fail (widget != NULL, FALSE);
2662 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2663 g_return_val_if_fail (event != NULL, FALSE);
2665 calendar = GTK_CALENDAR (widget);
2667 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2668 gtk_widget_draw_focus (widget);
2669 gtk_calendar_paint_day (widget, calendar->focus_row, calendar->focus_col);
2675 gtk_calendar_key_press (GtkWidget *widget,
2678 GtkCalendar *calendar;
2684 g_return_val_if_fail (widget != NULL, FALSE);
2685 g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
2686 g_return_val_if_fail (event != NULL, FALSE);
2688 calendar = GTK_CALENDAR (widget);
2691 old_focus_row = calendar->focus_row;
2692 old_focus_col = calendar->focus_col;
2694 switch (event->keyval)
2698 if (event->state & GDK_CONTROL_MASK)
2700 gtk_calendar_set_month_prev (calendar);
2704 if (calendar->focus_col > 0)
2706 calendar->focus_col--;
2708 else if (calendar->focus_row > 0)
2710 calendar->focus_col = 6;
2711 calendar->focus_row--;
2713 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2714 gtk_calendar_paint_day (widget, calendar->focus_row,
2715 calendar->focus_col);
2720 if (event->state & GDK_CONTROL_MASK)
2722 gtk_calendar_set_month_next (calendar);
2726 if (calendar->focus_col < 6)
2728 calendar->focus_col++;
2730 else if (calendar->focus_row < 5)
2732 calendar->focus_col = 0;
2733 calendar->focus_row++;
2735 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2736 gtk_calendar_paint_day (widget, calendar->focus_row,
2737 calendar->focus_col);
2742 if (event->state & GDK_CONTROL_MASK)
2744 gtk_calendar_set_year_prev (calendar);
2748 if (calendar->focus_row > 0)
2750 calendar->focus_row--;
2752 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2753 gtk_calendar_paint_day (widget, calendar->focus_row,
2754 calendar->focus_col);
2759 if (event->state & GDK_CONTROL_MASK)
2761 gtk_calendar_set_year_next (calendar);
2765 if (calendar->focus_row < 5)
2767 calendar->focus_row++;
2769 gtk_calendar_paint_day (widget, old_focus_row, old_focus_col);
2770 gtk_calendar_paint_day (widget, calendar->focus_row,
2771 calendar->focus_col);
2775 row = calendar->focus_row;
2776 col = calendar->focus_col;
2777 day = calendar->day[row][col];
2779 if (row > -1 && col > -1)
2781 gtk_calendar_freeze (calendar);
2783 if (calendar->day_month[row][col] == MONTH_PREV)
2785 gtk_calendar_set_month_prev (calendar);
2787 else if (calendar->day_month[row][col] == MONTH_NEXT)
2789 gtk_calendar_set_month_next (calendar);
2792 gtk_calendar_select_day (calendar, day);
2794 for (row = 0; row < 6; row ++)
2795 for (col = 0; col < 7; col++)
2797 if (calendar->day_month[row][col] == MONTH_CURRENT
2798 && calendar->day[row][col] == day)
2800 calendar->focus_row = row;
2801 calendar->focus_col = col;
2804 gtk_calendar_thaw (calendar);