gtkcalendar.c 71.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * GTK Calendar Widget
 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson and Mattias Grnlund
 * 
 * lib_date routines
 * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "gtkcalendar.h"
#include "gdk/gdkkeysyms.h"

/***************************************************************************/
/* The following date routines are taken from the lib_date package.  Keep
 * them seperate in case we want to update them if a newer lib_date comes
 * out with fixes.  */

38
39
40
typedef	 unsigned   int	    N_int;
typedef	 unsigned   long    N_long;
typedef	 signed	    long    Z_long;
41
42
typedef enum { false = FALSE , true = TRUE } boolean;

43
44
#define and	    &&	    /* logical (boolean) operators: lower case */
#define or	    ||
45
46
47

static N_int month_length[2][13] =
{
48
49
  { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
50
51
52
53
};

static N_int days_in_months[2][14] =
{
54
55
  { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
56
57
58
59
60
};

static Z_long  calc_days(N_int year, N_int mm, N_int dd);
static N_int   day_of_week(N_int year, N_int mm, N_int dd);
static Z_long  dates_difference(N_int year1, N_int mm1, N_int dd1,
61
				N_int year2, N_int mm2, N_int dd2);
62
63
64
65
66
static N_int   weeks_in_year(N_int year);

static boolean 
leap(N_int year)
{
67
  return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
68
69
70
71
72
}

static N_int 
day_of_week(N_int year, N_int mm, N_int dd)
{
73
74
75
76
  Z_long  days;
  
  days = calc_days(year, mm, dd);
  if (days > 0L)
77
    {
78
79
80
      days--;
      days %= 7L;
      days++;
81
    }
82
  return( (N_int) days );
83
84
85
86
}

static N_int weeks_in_year(N_int year)
{
87
  return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4)));
88
89
90
91
92
}

static boolean 
check_date(N_int year, N_int mm, N_int dd)
{
93
94
95
96
  if (year < 1) return(false);
  if ((mm < 1) or (mm > 12)) return(false);
  if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false);
  return(true);
97
98
99
100
101
}

static N_int 
week_number(N_int year, N_int mm, N_int dd)
{
102
103
104
105
106
  N_int first;
  
  first = day_of_week(year,1,1) - 1;
  return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
	  (first < 4) );
107
108
109
110
111
}

static Z_long 
year_to_days(N_int year)
{
112
  return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
113
114
115
116
117
118
}


static Z_long 
calc_days(N_int year, N_int mm, N_int dd)
{
119
120
121
122
123
124
  boolean lp;
  
  if (year < 1) return(0L);
  if ((mm < 1) or (mm > 12)) return(0L);
  if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L);
  return( year_to_days(--year) + days_in_months[lp][mm] + dd );
125
126
127
128
129
}

static boolean 
week_of_year(N_int *week, N_int *year, N_int mm, N_int dd)
{
130
131
132
133
134
135
136
137
138
139
140
141
142
  if (check_date(*year,mm,dd))
    {
      *week = week_number(*year,mm,dd);
      if (*week == 0) 
	*week = weeks_in_year(--(*year));
      else if (*week > weeks_in_year(*year))
	{
	  *week = 1;
	  (*year)++;
	}
      return(true);
    }
  return(false);
143
144
145
146
}

static Z_long 
dates_difference(N_int year1, N_int mm1, N_int dd1,
147
		 N_int year2, N_int mm2, N_int dd2)
148
{
149
  return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) );
150
151
152
153
}

/** END OF lib_date routines ************************************************/

154
155
156
157
#define CALENDAR_MARGIN		 0
#define CALENDAR_YSEP		 4
#define CALENDAR_XSEP		 4
#define INNER_BORDER		 4
158
159
160

#define DAY_XPAD		 2
#define DAY_YPAD		 2
161
#define DAY_XSEP		 0 /* not really good for small calendar */
162
163
164
#define DAY_YSEP		 0 /* not really good for small calendar */

/* Color usage */
165
166
167
168
169
#define HEADER_FG_COLOR(widget)		 (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
#define HEADER_BG_COLOR(widget)		 (& (widget)->style->bg[GTK_WIDGET_STATE (widget)])
#define DAY_NAME_COLOR(widget)		 (& (widget)->style->dark[GTK_WIDGET_STATE (widget)])
#define NORMAL_DAY_COLOR(widget)	 (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
#define SELECTION_FOCUS_COLOR(widget)	 (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
170
#define SELECTION_NO_FOCUS_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
171
172
173
174
175
176
#define PREV_MONTH_COLOR(widget)	 (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
#define NEXT_MONTH_COLOR(widget)	 (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
#define MARKED_COLOR(widget)		 (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
#define FOREGROUND_COLOR(widget)	 (& (widget)->style->fg[GTK_WIDGET_STATE (widget)])
#define BACKGROUND_COLOR(widget)	 (& (widget)->style->base[GTK_WIDGET_STATE (widget)])
#define HIGHLIGHT_BACK_COLOR(widget)	 (& (widget)->style->mid[GTK_WIDGET_STATE (widget)])
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

#define HEADER_FONT(widget) ((widget)->style->font)
#define LABEL_FONT(widget)   ((widget)->style->font)
#define DAY_FONT(widget)     ((widget)->style->font)

enum {
  ARROW_YEAR_LEFT,
  ARROW_YEAR_RIGHT,
  ARROW_MONTH_LEFT,
  ARROW_MONTH_RIGHT
};

enum {
  MONTH_PREV,
  MONTH_CURRENT,
  MONTH_NEXT
};

static GtkWidgetClass *parent_class = NULL;

enum {
  MONTH_CHANGED_SIGNAL,
  DAY_SELECTED_SIGNAL,
  DAY_SELECTED_DOUBLE_CLICK_SIGNAL,
  PREV_MONTH_SIGNAL,
  NEXT_MONTH_SIGNAL,
  PREV_YEAR_SIGNAL,
  NEXT_YEAR_SIGNAL,
  LAST_SIGNAL
};

static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 };

typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data);

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
static void gtk_calendar_class_init	(GtkCalendarClass *class);
static void gtk_calendar_init		(GtkCalendar *calendar);
static void gtk_calendar_realize	(GtkWidget *widget);
static void gtk_calendar_unrealize	(GtkWidget *widget);
static void gtk_calendar_draw_focus	(GtkWidget *widget);
static void gtk_calendar_size_request	(GtkWidget *widget,
					 GtkRequisition *requisition);
static void gtk_calendar_size_allocate	(GtkWidget *widget,
					 GtkAllocation *allocation);
static gint gtk_calendar_expose		(GtkWidget *widget,
					 GdkEventExpose *event);
static gint gtk_calendar_button_press	(GtkWidget *widget,
					 GdkEventButton *event);
static void gtk_calendar_main_button	(GtkWidget *widget,
					 GdkEventButton *event);
static gint gtk_calendar_motion_notify	(GtkWidget *widget,
					 GdkEventMotion *event);
static gint gtk_calendar_enter_notify	(GtkWidget *widget,
					 GdkEventCrossing *event);
static gint gtk_calendar_leave_notify	(GtkWidget *widget,
					 GdkEventCrossing *event);
static gint gtk_calendar_key_press	(GtkWidget	   *widget,
					 GdkEventKey	   *event);
static gint gtk_calendar_focus_in	(GtkWidget *widget,
					 GdkEventFocus *event);
static gint gtk_calendar_focus_out	(GtkWidget *widget,
					 GdkEventFocus *event);
static void gtk_calendar_state_changed	(GtkWidget *widget,
240
					 GtkStateType previous_state);
241
static void gtk_calendar_style_set	(GtkWidget *widget,
242
					 GtkStyle  *previous_style);
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
static void gtk_calendar_paint_header	    (GtkWidget *widget);
static void gtk_calendar_paint_day_names    (GtkWidget *widget);
static void gtk_calendar_paint_week_numbers (GtkWidget *widget);
static void gtk_calendar_paint_main	    (GtkWidget *widget);


static void gtk_calendar_paint		(GtkWidget    *widget,
					 GdkRectangle *area);
static void gtk_calendar_paint_arrow	(GtkWidget    *widget,
					 guint	       arrow);
static void gtk_calendar_paint_day_num	(GtkWidget    *widget,
					 gint	       day);
static void gtk_calendar_paint_day	(GtkWidget    *widget,
					 gint	       row,
					 gint	       col);
static void gtk_calendar_draw		(GtkWidget    *widget,
					 GdkRectangle *area);
static void gtk_calendar_compute_days	(GtkCalendar  *calendar);
static gint left_x_for_column		(GtkCalendar  *calendar,
					 gint	       column);
static gint top_y_for_row		(GtkCalendar  *calendar,
					 gint	       row);
265
266
267
268

static char    *default_abbreviated_dayname[7];
static char    *default_monthname[12];

269
270
GtkType
gtk_calendar_get_type (void)
271
{
272
273
  static GtkType calendar_type = 0;
  
274
275
276
277
278
279
280
281
282
283
284
285
  if (!calendar_type)
    {
      GtkTypeInfo calendar_info =
      {
	"GtkCalendar",
	sizeof (GtkCalendar),
	sizeof (GtkCalendarClass),
	(GtkClassInitFunc) gtk_calendar_class_init,
	(GtkObjectInitFunc) gtk_calendar_init,
	(GtkArgSetFunc) NULL,
	(GtkArgGetFunc) NULL,
      };
286
287
      
      calendar_type = gtk_type_unique (GTK_TYPE_WIDGET, &calendar_info);
288
    }
289
  
290
291
292
293
294
295
296
297
  return calendar_type;
}

static void
gtk_calendar_class_init (GtkCalendarClass *class)
{
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
298
  
299
300
  object_class = (GtkObjectClass*) class;
  widget_class = (GtkWidgetClass*) class;
301
302
303
  
  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
  
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  widget_class->realize = gtk_calendar_realize;
  widget_class->unrealize = gtk_calendar_unrealize;
  widget_class->expose_event = gtk_calendar_expose;
  widget_class->draw = gtk_calendar_draw;
  widget_class->draw_focus = gtk_calendar_draw_focus;
  widget_class->size_request = gtk_calendar_size_request;
  widget_class->size_allocate = gtk_calendar_size_allocate;
  widget_class->button_press_event = gtk_calendar_button_press;
  widget_class->motion_notify_event = gtk_calendar_motion_notify;
  widget_class->enter_notify_event = gtk_calendar_enter_notify;
  widget_class->leave_notify_event = gtk_calendar_leave_notify;
  widget_class->key_press_event = gtk_calendar_key_press;
  widget_class->focus_in_event = gtk_calendar_focus_in;
  widget_class->focus_out_event = gtk_calendar_focus_out;
  widget_class->style_set = gtk_calendar_style_set;
  widget_class->state_changed = gtk_calendar_state_changed;
320
  
321
322
323
  gtk_calendar_signals[MONTH_CHANGED_SIGNAL] =
    gtk_signal_new ("month_changed",
		    GTK_RUN_FIRST, object_class->type,
324
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, month_changed),
325
326
327
328
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[DAY_SELECTED_SIGNAL] =
    gtk_signal_new ("day_selected",
		    GTK_RUN_FIRST, object_class->type,
329
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected),
330
331
332
333
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] =
    gtk_signal_new ("day_selected_double_click",
		    GTK_RUN_FIRST, object_class->type,
334
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, day_selected_double_click),
335
336
337
338
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[PREV_MONTH_SIGNAL] =
    gtk_signal_new ("prev_month",
		    GTK_RUN_FIRST, object_class->type,
339
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_month),
340
341
342
343
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[NEXT_MONTH_SIGNAL] =
    gtk_signal_new ("next_month",
		    GTK_RUN_FIRST, object_class->type,
344
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, next_month),
345
346
347
348
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[PREV_YEAR_SIGNAL] =
    gtk_signal_new ("prev_year",
		    GTK_RUN_FIRST, object_class->type,
349
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, prev_year),
350
351
352
353
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  gtk_calendar_signals[NEXT_YEAR_SIGNAL] =
    gtk_signal_new ("next_year",
		    GTK_RUN_FIRST, object_class->type,
354
		    GTK_SIGNAL_OFFSET (GtkCalendarClass, next_year),
355
		    gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
356
  
357
  gtk_object_class_add_signals (object_class, gtk_calendar_signals, LAST_SIGNAL);
358
359
360
361
362
363
364
365
  
  class->month_changed = NULL;
  class->day_selected = NULL;
  class->day_selected_double_click = NULL;
  class->prev_month = NULL;
  class->next_month = NULL;
  class->prev_year = NULL;
  class->next_year = NULL;
366
367
368
369
370
371
372
373
374
375
376
}

static void
gtk_calendar_init (GtkCalendar *calendar)
{
  time_t secs;
  struct tm *tm;
  gint i;
  char buffer[255];
  time_t tmp_time;
  GtkWidget *widget;
377
  
378
379
  widget = GTK_WIDGET (calendar);
  GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
380
  
381
382
383
384
385
386
387
  if (!default_abbreviated_dayname[0])
    for (i=0; i<7; i++)
      {
	tmp_time= (i+3)*86400;
	strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time));
	default_abbreviated_dayname[i] = g_strdup (buffer);
      }
388
  
389
390
391
392
393
394
395
  if (!default_monthname[0])
    for (i=0; i<12; i++)
      {
	tmp_time=i*2764800;
	strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time));
	default_monthname[i] = g_strdup (buffer);
      }
396
  
397
398
399
400
401
  /* Set defaults */
  secs = time (NULL);
  tm = localtime (&secs);
  calendar->month = tm->tm_mon;
  calendar->year  = 1900 + tm->tm_year;
402
  
403
404
405
  for (i=0;i<31;i++)
    calendar->marked_date[i] = FALSE;
  calendar->selected_day = 1;
406
  
407
  calendar->arrow_width = 10;
408
  
409
410
  /* Create cursor */
  /* calendar->cross = gdk_cursor_new (GDK_PLUS); */
411
  
412
413
  calendar->highlight_row = -1;
  calendar->highlight_col = -1;
414
415
  
  
416
417
418
419
420
421
422
423
424
425
  calendar->max_day_char_width=0;
  calendar->max_week_char_width=0;
  calendar->dirty_header = 0;
  calendar->dirty_day_names = 0;
  calendar->dirty_week = 0;
  calendar->dirty_main = 0;
  calendar->frozen = 0;
}

GtkWidget*
426
gtk_calendar_new (void)
427
{
428
  return GTK_WIDGET (gtk_type_new (GTK_TYPE_CALENDAR));
429
430
431
432
433
}

/* column_from_x: returns the column 0-6 that the
 * x pixel of the xwindow is in */
static gint
434
435
column_from_x (GtkCalendar *calendar,
	       gint	    event_x)
436
437
438
{
  gint c, column;
  gint x_left, x_right;
439
  
440
  column = -1;
441
  
442
443
444
445
  for (c = 0; c < 7; c++)
    {
      x_left = left_x_for_column (calendar, c);
      x_right = x_left + calendar->day_width;
446
      
447
448
449
450
451
452
      if (event_x > x_left && event_x < x_right)
	{
	  column = c;
	  break;
	}
    }
453
  
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  return column;
}

static gint
row_height (GtkCalendar *calendar)
{
  return (calendar->main_h - CALENDAR_MARGIN
	  - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
	     ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6;
}


/* row_from_y: returns the row 0-5 that the
 * y pixel of the xwindow is in */
static gint
469
470
row_from_y (GtkCalendar *calendar,
	    gint	 event_y)
471
472
473
474
{
  gint r, row;
  gint height;
  gint y_top, y_bottom;
475
  
476
477
  height = row_height (calendar);
  row = -1;
478
  
479
480
481
482
  for (r = 0; r < 6; r++)
    {
      y_top = top_y_for_row (calendar, r);
      y_bottom = y_top + height;
483
      
484
485
486
487
488
489
      if (event_y > y_top && event_y < y_bottom)
	{
	  row = r;
	  break;
	}
    }
490
  
491
492
493
494
495
496
  return row;
}

/* left_x_for_column: returns the x coordinate
 * for the left of the column */
static gint
497
498
left_x_for_column (GtkCalendar *calendar,
		   gint		column)
499
500
501
{
  gint width;
  gint x_left;
502
  
503
504
505
506
507
  width = calendar->day_width;
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    x_left =  DAY_XSEP + (width + DAY_XSEP) * column;
  else
    x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column;
508
  
509
510
511
512
513
514
  return x_left;
}

/* top_y_for_row: returns the y coordinate
 * for the top of the row */
static gint
515
516
top_y_for_row (GtkCalendar *calendar,
	       gint	    row)
517
{
518
  
519
520
521
522
523
524
525
  return calendar->main_h - (CALENDAR_MARGIN + (6 - row) *
			     row_height (calendar));
}

/* This function should be done by the toolkit, but we don't like the
 * GTK arrows because they don't look good on this widget */
static void
526
527
528
529
530
draw_arrow_right (GdkWindow *window,
		  GdkGC	    *gc,
		  gint	     x,
		  gint	     y,
		  gint	     size)
531
532
{
  gint i;
533
  
534
535
536
537
538
539
540
541
542
543
544
545
546
  for (i = 0; i <= size / 2; i++)
    {
      gdk_draw_line (window, gc,
		     x + i,
		     y + i,
		     x + i,
		     y + size - i);
    }
}

/* This function should be done by the toolkit, but we don't like the
 * GTK arrows because they don't look good on this widget */
static void
547
548
549
550
551
draw_arrow_left (GdkWindow *window,
		 GdkGC	   *gc,
		 gint	    x,
		 gint	    y,
		 gint	    size)
552
553
{
  gint i;
554
  
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  for (i = 0; i <= size / 2; i++)
    {
      gdk_draw_line (window, gc,
		     x + size/2 - i,
		     y + i,
		     x + size/2 - i,
		     y + size - i);
    }
}

static void
gtk_calendar_set_month_prev (GtkCalendar *calendar)
{
  gint month_len;
569
  
570
571
  if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
    return;
572
  
573
574
575
576
577
578
579
  if (calendar->month == 0)
    {
      calendar->month = 11;
      calendar->year--;
    } 
  else 
    calendar->month--;
580
  
581
  month_len = month_length[leap (calendar->year)][calendar->month + 1];
582
  
583
584
  gtk_calendar_freeze (calendar);
  gtk_calendar_compute_days (calendar);
585
  
586
587
588
589
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[PREV_MONTH_SIGNAL]);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
590
  
591
592
593
594
595
596
597
598
599
600
601
602
  if (month_len < calendar->selected_day)
    {
      calendar->selected_day = 0;
      gtk_calendar_select_day (calendar, month_len);
    }
  else
    {
      if (calendar->selected_day < 0)
	calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1];
      else
	gtk_calendar_select_day (calendar, calendar->selected_day);
    }
603
  
604
605
606
607
608
609
610
611
612
613
  gtk_calendar_select_day (calendar, calendar->selected_day);
  gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
  gtk_calendar_thaw (calendar);
}


static void
gtk_calendar_set_month_next (GtkCalendar *calendar)
{
  gint month_len;
614
  
615
616
  g_return_if_fail (calendar != NULL);
  g_return_if_fail (GTK_IS_WIDGET (calendar));
617
  
618
619
  if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
    return;
620
621
  
  
622
623
624
625
626
627
628
  if (calendar->month == 11)
    {
      calendar->month = 0;
      calendar->year++;
    } 
  else 
    calendar->month++;
629
  
630
631
632
633
634
635
  gtk_calendar_freeze (calendar);
  gtk_calendar_compute_days (calendar);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[NEXT_MONTH_SIGNAL]);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
636
  
637
  month_len = month_length[leap (calendar->year)][calendar->month + 1];
638
  
639
640
641
642
643
644
645
  if (month_len < calendar->selected_day)
    {
      calendar->selected_day = 0;
      gtk_calendar_select_day (calendar, month_len);
    }
  else
    gtk_calendar_select_day (calendar, calendar->selected_day);
646
  
647
648
649
650
651
652
653
654
  gtk_calendar_paint (GTK_WIDGET(calendar), NULL);
  gtk_calendar_thaw (calendar);
}

static void
gtk_calendar_set_year_prev (GtkCalendar *calendar)
{
  gint month_len;
655
  
656
657
  g_return_if_fail (calendar != NULL);
  g_return_if_fail (GTK_IS_WIDGET (calendar));
658
  
659
660
661
662
663
664
665
  calendar->year--;
  gtk_calendar_freeze (calendar);
  gtk_calendar_compute_days (calendar);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[PREV_YEAR_SIGNAL]);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
666
  
667
  month_len = month_length[leap (calendar->year)][calendar->month + 1];
668
  
669
670
671
672
673
674
675
  if (month_len < calendar->selected_day)
    {
      calendar->selected_day = 0;
      gtk_calendar_select_day (calendar, month_len);
    }
  else
    gtk_calendar_select_day (calendar, calendar->selected_day);
676
  
677
678
679
680
681
682
683
684
685
  gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
  gtk_calendar_thaw (calendar);
}

static void
gtk_calendar_set_year_next (GtkCalendar *calendar)
{
  gint month_len;
  GtkWidget *widget;
686
  
687
688
  g_return_if_fail (calendar != NULL);
  g_return_if_fail (GTK_IS_WIDGET (calendar));
689
  
690
  widget = GTK_WIDGET (calendar);
691
  
692
  gtk_calendar_freeze (calendar);
693
  
694
695
696
697
698
699
  calendar->year++;
  gtk_calendar_compute_days (calendar);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[NEXT_YEAR_SIGNAL]);
  gtk_signal_emit (GTK_OBJECT (calendar),
		   gtk_calendar_signals[MONTH_CHANGED_SIGNAL]);
700
  
701
  month_len = month_length[leap (calendar->year)][calendar->month + 1];
702
  
703
704
705
706
707
708
709
  if (month_len < calendar->selected_day)
    {
      calendar->selected_day = 0;
      gtk_calendar_select_day (calendar, month_len);
    }
  else
    gtk_calendar_select_day (calendar, calendar->selected_day);
710
  
711
712
713
714
715
  gtk_calendar_paint (GTK_WIDGET (calendar), NULL);
  gtk_calendar_thaw (calendar);
}

static void
716
gtk_calendar_main_button (GtkWidget	 *widget,
717
718
719
720
721
722
			  GdkEventButton *event)
{
  GtkCalendar *calendar;
  gint x, y;
  gint row, col;
  gint day_month;
723
  
724
  calendar = GTK_CALENDAR (widget);
725
  
726
727
  x = (gint) (event->x);
  y = (gint) (event->y);
728
  
729
730
  row = row_from_y (calendar, y);
  col = column_from_x (calendar, x);
731
  
732
  day_month = calendar->day_month[row][col];
733
  
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  if (day_month == MONTH_CURRENT)
    {
      if (event->type == GDK_2BUTTON_PRESS)
	gtk_signal_emit (GTK_OBJECT (calendar),
			 gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]);
      else
	{
	  if (!GTK_WIDGET_HAS_FOCUS (widget))
	    gtk_widget_grab_focus (widget);
	  gtk_calendar_select_day (calendar, calendar->day[row][col]);
	}
    }
  else if (day_month == MONTH_PREV)
    gtk_calendar_set_month_prev (calendar);
  else if (day_month == MONTH_NEXT)
    gtk_calendar_set_month_next (calendar);
}

static void
gtk_calendar_realize_arrows (GtkWidget *widget)
{
  GtkCalendar *calendar;
  GdkWindowAttr attributes;
  gint attributes_mask;
  gint i;
759
  
760
761
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
762
  
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
  calendar = GTK_CALENDAR (widget);
  /* Arrow windows ------------------------------------- */
  if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
      && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING))
    {
      attributes.wclass = GDK_INPUT_OUTPUT;
      attributes.window_type = GDK_WINDOW_CHILD;
      attributes.visual = gtk_widget_get_visual (widget);
      attributes.colormap = gtk_widget_get_colormap (widget);
      attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
			       | GDK_BUTTON_PRESS_MASK	| GDK_BUTTON_RELEASE_MASK
			       | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
      attributes.y = 3;
      attributes.width = calendar->arrow_width;
      attributes.height = calendar->header_h - 7;
      for (i = 0; i < 4; i++)
	{
	  switch (i)
	    {
	    case ARROW_MONTH_LEFT:
	      attributes.x = 3;
	      break;
	    case ARROW_MONTH_RIGHT:
	      attributes.x = calendar->arrow_width + calendar->max_month_width;
	      break;
	    case ARROW_YEAR_LEFT:
	      attributes.x = (widget->allocation.width
			      - (3 + 2*calendar->arrow_width + calendar->max_year_width));
	      break;
	    case ARROW_YEAR_RIGHT:
	      attributes.x = widget->allocation.width - 3 - calendar->arrow_width;
	      break;
	    }
	  calendar->arrow_win[i] = gdk_window_new (calendar->header_win,
						   &attributes, attributes_mask);
	  calendar->arrow_state[i] = GTK_STATE_NORMAL;
	  gdk_window_set_background (calendar->arrow_win[i],
				     HEADER_BG_COLOR (GTK_WIDGET (calendar)));
	  gdk_window_show (calendar->arrow_win[i]);
	  gdk_window_set_user_data (calendar->arrow_win[i], widget);
	}
    }
  else
    for (i = 0; i < 4; i++)
      calendar->arrow_win[i] = NULL;
}

static void
gtk_calendar_realize_header (GtkWidget *widget)
{
  GtkCalendar *calendar;
  GdkWindowAttr attributes;
  gint attributes_mask;
817
  
818
819
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
820
  
821
  calendar = GTK_CALENDAR (widget);
822
  
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  /* Header window ------------------------------------- */
  if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
    {
      attributes.wclass = GDK_INPUT_OUTPUT;
      attributes.window_type = GDK_WINDOW_CHILD;
      attributes.visual = gtk_widget_get_visual (widget);
      attributes.colormap = gtk_widget_get_colormap (widget);
      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
      attributes.x = 0;
      attributes.y = 0;
      attributes.width = widget->allocation.width;
      attributes.height = calendar->header_h;
      calendar->header_win = gdk_window_new (widget->window,
					     &attributes, attributes_mask);
838
      
839
840
841
842
      gdk_window_set_background (calendar->header_win,
				 HEADER_BG_COLOR (GTK_WIDGET (calendar)));
      gdk_window_show (calendar->header_win);
      gdk_window_set_user_data (calendar->header_win, widget);
843
      
844
845
846
    }
  else
    calendar->header_win = NULL;
847
  
848
849
850
851
852
853
854
855
856
  gtk_calendar_realize_arrows (widget);
}

static void
gtk_calendar_realize_day_names (GtkWidget *widget)
{
  GtkCalendar *calendar;
  GdkWindowAttr attributes;
  gint attributes_mask;
857
  
858
859
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
860
  
861
  calendar = GTK_CALENDAR (widget);
862
863
  
  /* Day names	window --------------------------------- */
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
    {
      attributes.wclass = GDK_INPUT_OUTPUT;
      attributes.window_type = GDK_WINDOW_CHILD;
      attributes.visual = gtk_widget_get_visual (widget);
      attributes.colormap = gtk_widget_get_colormap (widget);
      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
      attributes.x = (widget->style->klass->xthickness + INNER_BORDER);
      attributes.y = calendar->header_h + (widget->style->klass->ythickness + INNER_BORDER);
      attributes.width = widget->allocation.width - (widget->style->klass->xthickness + INNER_BORDER) *2;
      attributes.height = calendar->day_name_h;
      calendar->day_name_win = gdk_window_new (widget->window,
					       &attributes, attributes_mask);
      gdk_window_set_background (calendar->day_name_win, BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
      gdk_window_show (calendar->day_name_win);
      gdk_window_set_user_data (calendar->day_name_win, widget);
    }
  else
    calendar->day_name_win = NULL;
}

static void
gtk_calendar_realize_week_numbers (GtkWidget *widget)
{
  GtkCalendar *calendar;
  GdkWindowAttr attributes;
  gint attributes_mask;
892
  
893
894
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
895
  
896
897
898
899
900
901
902
903
904
  calendar = GTK_CALENDAR (widget);
  /* Week number window -------------------------------- */
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    {
      attributes.wclass = GDK_INPUT_OUTPUT;
      attributes.window_type = GDK_WINDOW_CHILD;
      attributes.visual = gtk_widget_get_visual (widget);
      attributes.colormap = gtk_widget_get_colormap (widget);
      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
905
      
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
      attributes.x = + (widget->style->klass->xthickness + INNER_BORDER);
      attributes.y = (calendar->header_h + calendar->day_name_h 
		      + (widget->style->klass->ythickness + INNER_BORDER));
      attributes.width = calendar->week_width;
      attributes.height = calendar->main_h;
      calendar->week_win = gdk_window_new (widget->window,
					   &attributes, attributes_mask);
      gdk_window_set_background (calendar->week_win,  BACKGROUND_COLOR (GTK_WIDGET (calendar)));
      gdk_window_show (calendar->week_win);
      gdk_window_set_user_data (calendar->week_win, widget);
    } 
  else
    calendar->week_win = NULL;
}

static void
gtk_calendar_realize (GtkWidget *widget)
{
  GtkCalendar *calendar;
  GdkWindowAttr attributes;
  gint attributes_mask;
928
  
929
930
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
931
  
932
  calendar = GTK_CALENDAR (widget);
933
  
934
935
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
  gtk_calendar_compute_days (calendar);
936
  
937
938
939
940
941
942
943
944
945
946
  attributes.x = widget->allocation.x;
  attributes.y = widget->allocation.y;
  attributes.width = widget->allocation.width;
  attributes.height = widget->allocation.height;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.event_mask =  (gtk_widget_get_events (widget) 
			    | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK);
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
947
  
948
949
950
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  widget->window = gdk_window_new (widget->parent->window,
				   &attributes, attributes_mask);
951
  
952
  widget->style = gtk_style_attach (widget->style, widget->window);
953
  
954
955
  /* Header window ------------------------------------- */
  gtk_calendar_realize_header (widget);
956
  /* Day names	window --------------------------------- */
957
958
959
  gtk_calendar_realize_day_names (widget);
  /* Week number window -------------------------------- */
  gtk_calendar_realize_week_numbers (widget);
960
  /* Main Window --------------------------------------	 */
961
962
963
  attributes.event_mask =  (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK
			    | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
			    | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
964
  
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    attributes.x = calendar->week_width;
  else
    attributes.x = 0;
  attributes.x += (widget->style->klass->xthickness + INNER_BORDER);
  attributes.y = calendar->header_h + calendar->day_name_h + (widget->style->klass->ythickness + INNER_BORDER);
  attributes.width = widget->allocation.width - attributes.x - (widget->style->klass->xthickness + INNER_BORDER);
  attributes.height = calendar->main_h;
  calendar->main_win = gdk_window_new (widget->window,
				       &attributes, attributes_mask);
  gdk_window_set_background (calendar->main_win, BACKGROUND_COLOR ( GTK_WIDGET ( calendar)));
  gdk_window_show (calendar->main_win);
  gdk_window_set_user_data (calendar->main_win, widget);
  gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget));
  gdk_window_show (widget->window);
  gdk_window_set_user_data (widget->window, widget);
981
  
982
983
984
985
986
987
988
989
990
  /* Set widgets gc */
  calendar->gc = gdk_gc_new (widget->window);
}

static void
gtk_calendar_unrealize (GtkWidget *widget)
{
  GtkCalendar *calendar;
  gint i;
991
  
992
993
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
994
  
995
  calendar = GTK_CALENDAR (widget);
996
  
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  if (calendar->header_win)
    {
      for (i=0; i<4; i++)
	if (calendar->arrow_win[i])
	  {
	    gdk_window_set_user_data (calendar->arrow_win[i], NULL);
	    gdk_window_destroy (calendar->arrow_win[i]);
	    calendar->arrow_win[i] = NULL;
	  }
      gdk_window_set_user_data (calendar->header_win, NULL);
      gdk_window_destroy (calendar->header_win);
      calendar->header_win = NULL;
    }
1010
  
1011
1012
1013
1014
1015
1016
  if (calendar->week_win)
    {
      gdk_window_set_user_data (calendar->week_win, NULL);
      gdk_window_destroy (calendar->week_win);
      calendar->week_win = NULL;      
    }
1017
  
1018
1019
1020
1021
1022
1023
  if (calendar->main_win)
    {
      gdk_window_set_user_data (calendar->main_win, NULL);
      gdk_window_destroy (calendar->main_win);
      calendar->main_win = NULL;      
    }
1024
  
1025
1026
1027
1028
1029
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

static void
1030
gtk_calendar_size_request (GtkWidget	  *widget,
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
			   GtkRequisition *requisition)
{
  GtkCalendar *calendar;
  gint height;
  gint i;
  gchar buffer[255];
  gint calendar_margin = CALENDAR_MARGIN;
  gint header_width, main_width;
  gint lbearing;
  gint rbearing;
  gint ascent;
  gint descent;
  gint width;
1044
  
1045
  calendar = GTK_CALENDAR (widget);
1046
  
1047
  /*
1048
   * Calculate the requisition	width for the widget.
1049
   */
1050
  
1051
  /* Header width */
1052
  
1053
1054
1055
1056
1057
1058
1059
  if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
    {
      calendar->max_month_width = 0;
      for (i = 0; i < 12; i++)
	calendar->max_month_width = MAX (calendar->max_month_width,
					 gdk_string_measure (HEADER_FONT (widget),
							     default_monthname[i]) + 8);
1060
      
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
      calendar->max_year_width = 0;
      for (i=0; i<10; i++)
	{
	  sprintf (buffer, "%d%d%d%d", i,i,i,i);
	  calendar->max_year_width = MAX (calendar->max_year_width,
					  gdk_string_measure (HEADER_FONT (widget),
							      buffer) + 8);
	}
    } 
  else 
    {
      calendar->max_month_width = 0;
      calendar->max_year_width = 0;
    }
1075
  
1076
1077
1078
1079
1080
1081
  if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
    header_width = (calendar->max_month_width + calendar->max_year_width
		    + 3 * 3);
  else
    header_width = (calendar->max_month_width + calendar->max_year_width
		    + 4 * calendar->arrow_width + 3 * 3);
1082
  
1083
  /* Mainwindow labels width */
1084
  
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
  calendar->max_day_char_width = 0;
  for (i = 0; i < 9; i++)
    {
      sprintf (buffer, "%d%d", i, i);
      calendar->min_day_width = MAX (calendar->max_day_char_width,
				     gdk_string_measure (DAY_FONT (widget),
							 buffer));
    }
  /* We add one to max_day_char_width to be able to make the marked day "bold" */
  calendar->max_day_char_width = calendar->min_day_width / 2 +1;
1095
  
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
    for (i = 0; i < 7; i++)
      {
	gdk_text_extents (LABEL_FONT (widget),
			  default_abbreviated_dayname[i],
			  strlen(default_abbreviated_dayname[i]),
			  &lbearing,
			  &rbearing,
			  &width,
			  &ascent,
			  &descent);
	calendar->min_day_width = MAX (calendar->min_day_width, width);
	calendar->max_label_char_ascent = MAX (calendar->max_label_char_ascent, 
					       ascent);
	calendar->max_label_char_descent = MAX (calendar->max_label_char_descent
						, descent);
      }
1113
  
1114
1115
1116
1117
1118
1119
1120
1121
  calendar->max_week_char_width = 0;
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    for (i = 0; i < 9; i++)
      {
	sprintf (buffer, "%d%d", i, i);
	calendar->max_week_char_width = MAX (calendar->max_week_char_width,
					     gdk_string_measure (LABEL_FONT (widget), buffer) / 2);
      }
1122
  
1123
1124
1125
1126
  main_width = (7 * (calendar->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
		+ (calendar->max_week_char_width
		   ? calendar->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2
		   : 0));
1127
1128
  
  
1129
  requisition->width = MAX (header_width, main_width + (widget->style->klass->xthickness + INNER_BORDER) *2);
1130
  
1131
1132
1133
  /*
   * Calculate the requisition height for the widget.
   */
1134
  
1135
1136
1137
1138
1139
  if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
    calendar->header_h = (HEADER_FONT (widget)->ascent + HEADER_FONT (widget)->descent
			  + CALENDAR_YSEP * 2);
  else
    calendar->header_h = 0;
1140
1141
  
  
1142
1143
1144
1145
1146
1147
1148
1149
1150
  if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
    {
      calendar->day_name_h = (calendar->max_label_char_ascent
			      + calendar->max_label_char_descent
			      + 2 * DAY_YPAD + calendar_margin);
      calendar_margin = CALENDAR_YSEP;
    } 
  else
    calendar->day_name_h = 0;
1151
  
1152
  gdk_text_extents (DAY_FONT (widget),
1153
1154
1155
1156
1157
1158
1159
1160
		    "0123456789",
		    10,
		    &lbearing,
		    &rbearing,
		    &width,
		    &calendar->max_day_char_ascent,
		    &calendar->max_day_char_descent);
  
1161
1162
1163
1164
  calendar->main_h = (CALENDAR_MARGIN + calendar_margin
		      + 6 * (calendar->max_day_char_ascent
			     + calendar->max_day_char_descent + DAY_YPAD * 2)
		      + DAY_YSEP * 5);
1165
  
1166
1167
1168
  /* 
   * If we display weeknumbers we need some extra space 
   */
1169
  
1170
1171
1172
1173
1174
1175
1176
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    calendar->main_h = MAX (calendar->main_h,
			    (CALENDAR_MARGIN + calendar_margin
			     + 6 * (calendar->max_day_char_ascent 
				    + calendar->max_day_char_descent 
				    + DAY_YPAD * 2)
			     + DAY_YSEP * 5));
1177
  
1178
  height = calendar->header_h + calendar->day_name_h + calendar->main_h;
1179
  
1180
1181
1182
1183
  requisition->height = height + (widget->style->klass->ythickness + INNER_BORDER) * 2;
}

static void
1184
gtk_calendar_size_allocate (GtkWidget	  *widget,
1185
1186
1187
			    GtkAllocation *allocation)
{
  GtkCalendar *calendar;
1188
  
1189
1190
1191
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
  g_return_if_fail (allocation != NULL);
1192
  
1193
  widget->allocation = *allocation;
1194
  
1195
  calendar = GTK_CALENDAR (widget);
1196
  
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
    {
      calendar->day_width = (calendar->min_day_width
			     * ((allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2
				 - (CALENDAR_MARGIN * 2) -  (DAY_XSEP * 7) - CALENDAR_XSEP * 2))
			     / (7 * calendar->min_day_width + calendar->max_week_char_width * 2));
      calendar->week_width = ((allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2
			       - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 )
			      - calendar->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP);
    } 
  else 
    {
      calendar->day_width = (allocation->width
			     - (widget->style->klass->xthickness + INNER_BORDER) * 2
			     - (CALENDAR_MARGIN * 2)
			     - (DAY_XSEP * 7))/7;
      calendar->week_width = 0;
    }
1215
  
1216
1217
1218
1219
  if (GTK_WIDGET_REALIZED (widget))
    {
      gdk_window_move_resize (widget->window,
			      allocation->x, allocation->y,
1220
			      allocation->width, allocation->height);
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
      if (calendar->header_win)
	gdk_window_move_resize (calendar->header_win,
				0, 0,
				allocation->width, calendar->header_h);
      if (calendar->arrow_win[ARROW_MONTH_LEFT])
	gdk_window_move_resize (calendar->arrow_win[ARROW_MONTH_LEFT],
				3, 3,
				calendar->arrow_width,
				calendar->header_h - 7);
      if (calendar->arrow_win[ARROW_MONTH_RIGHT])
	gdk_window_move_resize (calendar->arrow_win[ARROW_MONTH_RIGHT],
				calendar->arrow_width + calendar->max_month_width, 3,
				calendar->arrow_width,
				calendar->header_h - 7);
      if (calendar->arrow_win[ARROW_YEAR_LEFT])
	gdk_window_move_resize (calendar->arrow_win[ARROW_YEAR_LEFT],
				allocation->width
				- (3 + 2*calendar->arrow_width + calendar->max_year_width),
				3,
				calendar->arrow_width,
				calendar->header_h - 7);
      if (calendar->arrow_win[ARROW_YEAR_RIGHT])
	gdk_window_move_resize (calendar->arrow_win[ARROW_YEAR_RIGHT],
				allocation->width - 3 - calendar->arrow_width, 3,
				calendar->arrow_width,
				calendar->header_h - 7);
      if (calendar->day_name_win)
	gdk_window_move_resize (calendar->day_name_win,
				(widget->style->klass->xthickness + INNER_BORDER),
				calendar->header_h + (widget->style->klass->ythickness + INNER_BORDER),
				allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2,
				calendar->day_name_h);
      if (calendar->week_win)
	gdk_window_move_resize (calendar->week_win,
				(widget->style->klass->xthickness + INNER_BORDER),
				calendar->header_h + calendar->day_name_h
				+ (widget->style->klass->ythickness + INNER_BORDER),
				calendar->week_width,
				calendar->main_h);
      gdk_window_move_resize (calendar->main_win,
			      (calendar->week_width ? calendar->week_width + CALENDAR_XSEP :0) 
			      + (widget->style->klass->xthickness + INNER_BORDER),
			      calendar->header_h + calendar->day_name_h
			      + (widget->style->klass->ythickness + INNER_BORDER),
			      allocation->width 
			      - (calendar->week_width ? calendar->week_width + CALENDAR_XSEP :0) 
			      - (widget->style->klass->xthickness + INNER_BORDER) * 2,
			      calendar->main_h);
    }
}

static void
gtk_calendar_draw_focus (GtkWidget *widget)
{
  gint width, height;
  gint x, y;
  GtkCalendar *calendar;
  
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_CALENDAR (widget));
  calendar = GTK_CALENDAR (widget);
  
  if (GTK_WIDGET_DRAWABLE (widget))
    {
      x = 0;
      y = 0;
      gdk_window_get_size (widget->window, &width, &height);
      gdk_window_clear (widget->window);
1289
      
1290
1291
1292
1293
1294
      if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)
	{
	  y += calendar->header_h;
	  height -= calendar->header_h;
	}
1295
      
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
      if (GTK_WIDGET_HAS_FOCUS (widget))
	{
	  x += 1;
	  y += 1;
	  width -= 2;
	  height -= 2;
	}
      else
	{
	  gdk_draw_rectangle (widget->window, 
			      widget->style->base_gc[GTK_WIDGET_STATE (widget)],
			      FALSE, x + 2, y + 2, width - 5, height - 5);
	}
      
      gtk_draw_shadow (widget->style, widget->window,
		       GTK_STATE_NORMAL, GTK_SHADOW_IN,
		       x, y, width, height);
      
      if (GTK_WIDGET_HAS_FOCUS (widget))
	{
	  gdk_window_get_size (widget->window, &width, &height);
	  gdk_draw_rectangle (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
			      FALSE, 0, 0, width - 1, height - 1);
	}
    }
}

static gint
1324
1325
gtk_calendar_expose (GtkWidget	    *widget,
		     GdkEventExpose *event)
1326
1327
{
  GtkCalendar *calendar;
1328
  
1329
1330
1331
  g_return_val_if_fail (widget != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);
1332
  
1333
  calendar = GTK_CALENDAR (widget);
1334
  
1335
1336
1337
1338
  if (GTK_WIDGET_DRAWABLE (widget))
    {
      if (event->window == calendar->main_win)
	gtk_calendar_paint_main (widget);
1339
      
1340
1341
      if (event->window == calendar->header_win)
	gtk_calendar_paint_header (widget);
1342
      
1343
1344
      if (event->window == calendar->day_name_win)
	gtk_calendar_paint_day_names (widget);
1345
      
1346
1347
1348
1349
1350
      if (event->window == calendar->week_win)
	gtk_calendar_paint_week_numbers (widget);
      if (event->window == widget->window)
	gtk_widget_draw_focus (widget);
    }
1351