xdiary 5/5 (X based calendar and diary)

Jason Baietto jason at gcx1.ssd.csd.harris.com
Thu Dec 13 10:29:37 AEST 1990


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 5)."
# Contents:  Calendar.c
# Wrapped by jason at hcx2 on Thu Dec  6 12:49:23 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Calendar.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Calendar.c'\"
else
echo shar: Extracting \"'Calendar.c'\" \(58171 characters\)
sed "s/^X//" >'Calendar.c' <<'END_OF_FILE'
X/*
X * Author: Jason Baietto, jason at ssd.csd.harris.com
X * xdiary Copyright 1990 Harris Corporation
X *
X * Permission to use, copy, modify, and distribute, this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of the copyright holder be used in
X * advertising or publicity pertaining to distribution of the software with
X * specific, written prior permission, and that no fee is charged for further
X * distribution of this software, or any modifications thereof.  The copyright
X * holder makes no representations about the suitability of this software for
X * any purpose.  It is provided "as is" without express or implied warranty.
X *
X * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND IN NO
X * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ITS USE,
X * LOSS OF DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT,
X * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
X * THE USE OR PERFORMANCE OF THIS SOFTWARE.
X */
X
X/*==========================================================================*/
X/*                              Header Files:                               */
X/*==========================================================================*/
X#include <stdio.h>
X#include <X11/Xos.h>
X#include <X11/StringDefs.h>
X#include <X11/IntrinsicP.h>
X#include <X11/Xmu/Converters.h>
X#include "CalendarP.h"
X
X#ifdef DEBUG
X#define BEGIN(str) (/*VARARGS0*/fprintf(stderr, "%s()\n", (str)))
X#define END(str) ;
X#else
X#define BEGIN(str) ;
X#define END(str) ;
X#endif
X
X
X/*==========================================================================*/
X/*                            Forward References:                           */
X/*==========================================================================*/
Xstatic void initialize_line_GCs();
Xstatic void initialize_font_GCs_and_info();
Xstatic void compute_minimum_cell_size();
Xstatic void compute_cell_geometry();
Xstatic void free_line_GCs();
Xstatic void free_font_GCs_and_info();
Xstatic void compute_grid();
Xstatic void draw_grid();
Xstatic void draw_weekdays();
Xstatic void draw_title();
Xstatic void draw_digits();
Xstatic void compute_title_string();
Xstatic void toggle_highlight();
Xstatic void rotate_weekdays();
Xstatic void calendar_update();
Xstatic void compute_month_data();
X
X
X
X
X/*==========================================================================*/
X/*                            Static Global Data:                           */
X/*==========================================================================*/
Xstatic int days_in_month[] = 
X   /* jan feb mar apr may jun jul aug sep oct nov dec */
X   {  31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31  };
X
X
X
X
X/*==========================================================================*/
X/*                              Resource List:                              */
X/*==========================================================================*/
X#define offset(field) XtOffset(CalendarWidget, field)
Xstatic XtResource calendar_resources[] = {
X   {
X      XtNcallback,
X      XtCCallback,
X      XtRCallback,
X      sizeof(XtPointer),
X      offset(calendar.callback),
X      XtRCallback,
X      NULL
X   },
X   {
X      XtNlineWidth,
X      XtCLineWidth,
X      XtRInt,
X      sizeof(int),
X      offset(calendar.line_width),
X      XtRImmediate,
X      (XtPointer)DEFAULT_LINE_WIDTH
X   },
X   {
X      XtNforeground,
X      XtCForeground,
X      XtRPixel,
X      sizeof(Pixel),
X      offset(calendar.foreground),
X      XtRString,
X      XtDefaultForeground
X   },
X   {
X      XtNbackground,
X      XtCBackground,
X      XtRPixel,
X      sizeof(Pixel),
X      offset(calendar.background),
X      XtRString,
X      XtDefaultBackground
X   },
X   {
X      XtNdigitFont,
X      XtCCalendarFont,
X      XtRFont,
X      sizeof(Font),
X      offset(calendar.digit_font),
X      XtRString,
X      CALENDAR_DEFAULT_FONT
X   },
X   {
X      XtNweekdayFont,
X      XtCCalendarFont,
X      XtRFont,
X      sizeof(Font),
X      offset(calendar.weekday_font),
X      XtRString,
X      CALENDAR_DEFAULT_FONT
X   },
X   {
X      XtNtitleFont,
X      XtCCalendarFont,
X      XtRFont,
X      sizeof(Font),
X      offset(calendar.title_font),
X      XtRString,
X      CALENDAR_DEFAULT_FONT
X   },
X   {
X      XtNinfoFont,
X      XtCCalendarFont,
X      XtRFont,
X      sizeof(Font),
X      offset(calendar.info_font),
X      XtRString,
X      CALENDAR_DEFAULT_FONT
X   },
X   {
X      XtNdigitGravity,
X      XtCDigitGravity,
X      XtRGravity,
X      sizeof(XtGravity),
X      offset(calendar.digit_gravity),
X      XtRImmediate,
X      (XtPointer)Center
X   },
X   {  XtNdigitNames,
X      XtCDigitNames,
X      XtRStringTable,
X      sizeof(StringTable),
X      offset(calendar.digit_names),
X      XtRString,
X      XtNDefaultDigitNames
X   },
X   {  XtNweekdayNames,
X      XtCWeekdayNames,
X      XtRStringTable,
X      sizeof(StringTable),
X      offset(calendar.weekday_names),
X      XtRString,
X      XtNDefaultWeekdayNames
X   },
X   {  XtNmonthNames,
X      XtCMonthNames,
X      XtRStringTable,
X      sizeof(StringTable),
X      offset(calendar.month_names),
X      XtRString,
X      XtNDefaultMonthNames
X   },
X   {  XtNhighlight,
X      XtCHighlight,
X      XtRBoolean,
X      sizeof(Boolean),
X      offset(calendar.highlight),
X      XtRImmediate,
X      (XtPointer)True
X   },
X   {  XtNshowYear,
X      XtCShowYear,
X      XtRBoolean,
X      sizeof(Boolean),
X      offset(calendar.show_year),
X      XtRImmediate,
X      (XtPointer)True
X   },
X   {  XtNstartingWeekday,
X      XtCStartingWeekday,
X      XtRDayName,
X      sizeof(XtDayName),
X      offset(calendar.starting_weekday),
X      XtRImmediate,
X      (XtPointer)Sunday
X   }
X};
X
X
X
X/*==========================================================================*/
X/*                           Action Declarations:                           */
X/*==========================================================================*/
Xstatic void select_cell_action();
Xstatic void default_button_up_action();
X
X
X
X/*==========================================================================*/
X/*                              Actions Table:                              */
X/*==========================================================================*/
Xstatic XtActionsRec calendar_actions[] = {
X   { "select",  select_cell_action       },
X   { "notify",  default_button_up_action }
X};
X
Xstatic char calendar_default_translations[] = XtRcalendarDefaultTranslations;
X
X
X/*==========================================================================*/
X/*                           Method Declarations:                           */
X/*==========================================================================*/
Xstatic void             calendar_initialize_method();
Xstatic void             calendar_class_initialize_method();
Xstatic void             calendar_expose_method();
Xstatic void             calendar_destroy_method();
Xstatic void             calendar_resize_method();
Xstatic Boolean          calendar_set_values_method();
Xstatic XtGeometryResult calendar_query_geometry_method();
X
X
X
X/*==========================================================================*/
X/*                       Class Record Initialization:                       */
X/*==========================================================================*/
XCalendarClassRec calendarClassRec = {
X   {
X      /* CORE CLASS PART:      */
X      /* superclass            */ (WidgetClass) &coreClassRec,
X      /* class_name            */ "Calendar",
X      /* widget_size           */ sizeof(CalendarRec),
X      /* class_initialize      */ calendar_class_initialize_method,
X      /* class_part_initialize */ NULL,
X      /* class_inited          */ FALSE,
X      /* initialize            */ calendar_initialize_method,
X      /* initialize_hook       */ NULL,
X      /* realize               */ XtInheritRealize,
X      /* actions               */ calendar_actions,
X      /* num_actions           */ XtNumber(calendar_actions),
X      /* resources             */ calendar_resources,
X      /* num_resources         */ XtNumber(calendar_resources),
X      /* xrm_class             */ NULLQUARK,
X      /* compress_motion       */ TRUE,
X      /* compress_exposure     */ TRUE,
X      /* compress_enterleave   */ TRUE,
X      /* visible_interest      */ FALSE,
X      /* destroy               */ calendar_destroy_method,
X      /* resize                */ calendar_resize_method,
X      /* expose                */ calendar_expose_method,
X      /* set_values            */ calendar_set_values_method,
X      /* set_values_hook       */ NULL,
X      /* set_values_almost     */ XtInheritSetValuesAlmost,
X      /* get_values_hook       */ NULL,
X      /* accept_focus          */ NULL,
X      /* version               */ XtVersion,
X      /* callback_private      */ NULL,
X      /* tm_table              */ calendar_default_translations,
X      /* query_geometry        */ calendar_query_geometry_method,
X      /* display_accelerator   */ XtInheritDisplayAccelerator,
X      /* extension             */ NULL
X   },
X   {
X      /* CALENDAR CLASS PART:  */
X      /* dummy field           */ 0
X   }
X};
X
X/* Define the calendar widget class in terms of the above record. */
XWidgetClass calendarWidgetClass = (WidgetClass) &calendarClassRec;
X
X
Xstatic XtConvertArgRec screenConvertArg[] = {
X   {  
X      XtBaseOffset,
X      (XtPointer)XtOffset(Widget, core.screen),
X      sizeof(Screen *)
X   }
X};
X
X
X
X/*==========================================================================*/
X/*                           Method Definitions:                            */
X/*==========================================================================*/
Xstatic void calendar_class_initialize_method()
X{
X   /* Register the string to gravity resource converter. */
X   XtAddConverter(
X      XtRString,                   /* source type */
X      XtRGravity,                  /* target type */
X      GravityConverter,            /* converter routine */
X      NULL,                        /* args for converter */
X      0                            /* num args for converter */
X   );
X
X   /* Register the string to gravity resource converter. */
X   XtAddConverter(
X      XtRString,                   /* source type */
X      XtRDayName,                  /* target type */
X      DayNameConverter,            /* converter routine */
X      NULL,                        /* args for converter */
X      0                            /* num args for converter */
X   );
X
X   /* Register the string to string table resource converter. */
X   XtAddConverter(
X      XtRString,                   /* source type */
X      XtRStringTable,              /* target type */
X      StringTableConverter,        /* converter routine */
X      NULL,                        /* args for converter */
X      0                            /* num args for converter */
X   );
X
X   /* Register the string to bitmap resource converter. */
X   XtAddConverter(
X      XtRString,                   /* source type */
X      XtRBitmap,                   /* target type */
X      XmuCvtStringToBitmap,        /* converter routine */
X      screenConvertArg,            /* args for converter */
X      XtNumber(screenConvertArg)   /* num args for converter */
X   );
X}
X
X
Xstatic void calendar_initialize_method(request, new)
XCalendarWidget request;
XCalendarWidget new;
X{
X   XrmValue from;
X   XrmValue to;
X   int i;
X   float initial_cell_width  = (float) request->core.width / (float) COLS;
X   float initial_cell_height = (float) request->core.height / (float) ROWS;
X
X   BEGIN("calendar_initialize_method");
X
X   /* Now entering the foggy zone. */
X   new->calendar.state = foggy;
X
X   /* First check resources: */
X
X   /* Did we get 7 weekday names? */
X   if (StringTableNumber(request->calendar.weekday_names) != 7) {
X      /*VARARGS*/
X      fprintf(stderr, "CalendarWidget: You must specify 7 weekday names.\n");
X
X      /* Explicitly invoke converter on default value */
X      from.addr = XtNDefaultWeekdayNames;
X      from.size = sizeof(StringTable);
X      XtConvert(new, XtRString, &from, XtRStringTable, &to);
X      request->calendar.weekday_names = *(StringTable *)to.addr;
X   }
X   
X   /* Make a widget specific copy so we can twiddle with it if necessary. */
X   new->calendar.weekday_names 
X      = StringTableCopy(request->calendar.weekday_names);
X
X   /* Do we need to rotate the weekdays? */
X   if (new->calendar.starting_weekday != SUNDAY) {
X      rotate_weekdays(new);
X   }
X
X   /* Did we get 12 month names? */
X   if (StringTableNumber(request->calendar.month_names) != 12) {
X      /*VARARGS*/
X      fprintf(stderr, "CalendarWidget: You must specify 12 month names.\n");
X
X      /* Explicitly invoke converter on default value */
X      from.addr = XtNDefaultMonthNames;
X      from.size = sizeof(StringTable);
X      XtConvert(new, XtRString, &from, XtRStringTable, &to);
X      new->calendar.month_names = *(StringTable *)to.addr;
X      
X   }
X
X   /* Did we get 31 digit names? */
X   if (StringTableNumber(request->calendar.digit_names) != 31) {
X      /*VARARGS*/
X      fprintf(stderr, "CalendarWidget: You must specify 31 digit names.\n");
X
X      /* Explicitly invoke converter on default value */
X      from.addr = XtNDefaultDigitNames;
X      from.size = sizeof(StringTable);
X      XtConvert(new, XtRString, &from, XtRStringTable, &to);
X      new->calendar.digit_names = *(StringTable *)to.addr;
X   }
X
X   range_check(
X      XtNlineWidth,
X      new->calendar.line_width,
X      MIN_LINE_WIDTH,
X      MAX_LINE_WIDTH
X   );
X
X   range_check(
X      XtNdigitGravity,
X      new->calendar.digit_gravity,
X      NorthWest,
X      SouthEast
X   );
X
X   /* Next compute initial state: */
X
X   /* Compute the lengths of the month, weekday and digit names once and keep */
X   /* around so we won't have to recompute them every time they're drawn. */
X   for (i=0; i < DAYS_IN_WEEK; i++) {
X      new->calendar.weekday_name_lengths[i] = strlen(new->calendar.weekday_names[i]);
X   }
X   for (i=0; i < MONTHS_IN_YEAR; i++) {
X      new->calendar.month_name_lengths[i] = strlen(new->calendar.month_names[i]);
X   }
X   for (i=0; i < MAX_DAYS_IN_MONTH; i++) {
X      new->calendar.digit_name_lengths[i] = strlen(new->calendar.digit_names[i]);
X   }
X
X   initialize_line_GCs(new);
X   initialize_font_GCs_and_info(new);
X   compute_minimum_cell_size(new);
X
X   new->calendar.real_cell_width
X      = MAX(new->calendar.min_cell_width + 1, initial_cell_width);
X   new->calendar.real_cell_height
X      = MAX(new->calendar.min_cell_height + 1, initial_cell_height);
X
X   new->calendar.old_window_width = -1;
X   new->calendar.old_window_height = -1;
X
X   if (new->core.width == 0) {
X      new->core.width = WINDOW_WIDTH(new->calendar.real_cell_width);
X   }
X   if (new->core.height == 0) {
X      new->core.height = WINDOW_HEIGHT(new->calendar.real_cell_height);
X   }
X
X   compute_grid          (new);
X   compute_cell_geometry (new);
X
X   /* Calendar defaults to current date. */
X   new->calendar.date = GetTodaysDate();
X
X   /* Allocate a fixed amount of space for the title string. */
X   new->calendar.title_string = (char *)XtMalloc(MAX_TITLE_LEN*sizeof(char));
X
X   /* Force a re-calculation of the month data for the current year. */
X   new->calendar.current_year = 0;
X   compute_month_data(new);
X
X   new->calendar.highlight_days_in_february 
X      = new->calendar.days_in_february;
X
X   /* Calendar highlights current day by default, if highligh is true. */
X   new->calendar.highlight_date = new->calendar.date;
X
X   compute_title_string(new);
X
X   END("calendar_initialize_method");
X}
X
X
X
X/*ARGSUSED*/
Xstatic void calendar_expose_method(widget, event)
XCalendarWidget widget;
XXExposeEvent *event;
X{
X   BEGIN("calendar_expose_method");
X
X   /* Okay, it's safe to draw now. */
X   widget->calendar.state = solid;
X
X   draw_weekdays    (widget);
X   draw_title       (widget);
X   draw_digits      (widget);
X
X   if (SYNC(widget)) {
X      toggle_highlight (widget, ON);
X   }
X
X   draw_grid        (widget);
X   
X   END("calendar_expose_method");
X}
X
X
X
Xstatic Boolean calendar_set_values_method(current, request, new)
XCalendarWidget current;
XCalendarWidget request;
XCalendarWidget new;
X{
X   Boolean redraw = False;
X   Boolean resize = False;
X   Boolean new_weekday_names = False;
X   Boolean new_starting_weekday = False;
X   Display * display;
X   XGCValues values;
X   XtGCMask mask;
X   int i; 
X   int new_width;
X   int new_height;
X
X   BEGIN("calendar_set_values_method");
X
X   display = XtDisplay(current);
X   
X   /* Line Width: */
X   if  (request->calendar.line_width != current->calendar.line_width) {
X      new->calendar.line_width = bound(
X         request->calendar.line_width,
X         MIN_LINE_WIDTH,
X         MAX_LINE_WIDTH
X      );
X   }
X   if (new->calendar.line_width != current->calendar.line_width) {
X      mask = GCLineWidth;
X      values.line_width = new->calendar.line_width;
X      XChangeGC(
X         display,
X         new->calendar.draw_gc,
X         mask,
X         &values
X      );
X      redraw = True;
X   }
X
X   /* Digit Gravity: */
X   if (request->calendar.digit_gravity != current->calendar.digit_gravity) {
X      new->calendar.digit_gravity = (XtGravity) bound(
X         (int) request->calendar.digit_gravity,
X         (int) NorthWest,
X         (int) SouthEast
X      );
X   }
X   if (new->calendar.digit_gravity != current->calendar.digit_gravity) {
X      redraw = True;
X   }
X   
X   /* Weekday Names: */
X   if (request->calendar.weekday_names != current->calendar.weekday_names) {
X      if (StringTableNumber(request->calendar.weekday_names) != DAYS_IN_WEEK) {
X         /*VARARGS*/
X         fprintf(stderr, "CalendarWidget: must specify 7 weekday names\n");
X      } else {
X         /* Copy the string table so we can rotate it if necessary. */
X         new->calendar.weekday_names = 
X            StringTableCopy(request->calendar.weekday_names);
X         for (i=0; i < DAYS_IN_WEEK; i++) {
X            new->calendar.weekday_name_lengths[i] 
X               = strlen(request->calendar.weekday_names[i]);
X         }
X         new_weekday_names = True;
X         redraw = True;
X         resize = True;
X      }
X   }
X
X   /* Month Names: */
X   if (request->calendar.month_names != current->calendar.month_names) {
X      if (StringTableNumber(request->calendar.month_names) != MONTHS_IN_YEAR) {
X         /*VARARGS*/
X         fprintf(stderr, "CalendarWidget: must specify 12 month names\n");
X      } else {
X         new->calendar.month_names = request->calendar.month_names;
X         for (i=0; i < MONTHS_IN_YEAR; i++) {
X            new->calendar.month_name_lengths[i] 
X               = strlen(request->calendar.month_names[i]);
X         }
X         compute_title_string(new);
X         redraw = True;
X         resize = True;
X      }
X   }
X
X   /* Digit Names: */
X   if (request->calendar.digit_names != current->calendar.digit_names) {
X      if (StringTableNumber(request->calendar.digit_names) != MAX_DAYS_IN_MONTH) {
X         /*VARARGS*/
X         fprintf(stderr, "CalendarWidget: must specify 31 digit names\n");
X      } else {
X         new->calendar.digit_names = request->calendar.digit_names;
X         for (i=0; i < MAX_DAYS_IN_MONTH; i++) {
X            new->calendar.digit_name_lengths[i] 
X               = strlen(request->calendar.digit_names[i]);
X         }
X         redraw = True;
X         resize = True;
X      }
X   }
X
X   /* Starting Weekday. */
X   new_starting_weekday = (request->calendar.starting_weekday 
X                           != current->calendar.starting_weekday);
X   if (new_starting_weekday 
X       && (request->calendar.starting_weekday < SUNDAY
X       || request->calendar.starting_weekday > SATURDAY)) {
X      /* Bogus value specified. */
X      /*VARARGS*/
X      fprintf(stderr, "CalendarWidget: invalid starting weekday, use [0..6]\n");
X      new_starting_weekday = FALSE;
X   }
X   if (new_starting_weekday && new_weekday_names) {
X      new->calendar.starting_weekday = request->calendar.starting_weekday;
X      rotate_weekdays(new);
X   } else if (new_weekday_names) {
X      rotate_weekdays(new);
X   } else if (new_starting_weekday) {
X      /* Rotate weekdays, taking into account current rotation. */
X      new->calendar.starting_weekday =
X         ( (7 - current->calendar.starting_weekday) 
X           + request->calendar.starting_weekday ) %7;
X      rotate_weekdays(new);
X      new->calendar.starting_weekday = request->calendar.starting_weekday;
X      redraw = True;
X   }
X
X   /* Highlight. */
X   if (request->calendar.highlight != current->calendar.highlight) {
X      new->calendar.highlight = request->calendar.highlight;
X   }
X
X   if (resize) {
X      compute_minimum_cell_size(new);
X      new_width =  WINDOW_WIDTH(new->calendar.min_cell_width);
X      new_height = WINDOW_HEIGHT(new->calendar.min_cell_height);
X      XtMakeResizeRequest(new, new_width, new_height, NULL, NULL);
X   }
X
X   END("calendar_set_values_method");
X
X   /* Return true if value change requires expose event to redraw. */
X   return (redraw);
X}
X
X
X
X
Xstatic void calendar_resize_method(widget)
XCalendarWidget widget;
X{
X   int window_width = widget->core.width;
X   int window_height = widget->core.height;
X   float avail_cell_width  = (float) window_width  / (float) COLS;
X   float avail_cell_height = (float) window_height / (float) ROWS;
X
X   BEGIN("calendar_resize_method");
X
X   /* Now entering the foggy zone. */
X   widget->calendar.state = foggy;
X
X   widget->calendar.real_cell_width = low_bound(
X      avail_cell_width, 
X      widget->calendar.min_cell_width
X   );
X
X   widget->calendar.real_cell_height = low_bound(
X      avail_cell_height, 
X      widget->calendar.min_cell_height
X   );
X
X   compute_grid          (widget);
X   compute_cell_geometry (widget);
X
X   /* Don't need to redraw the calendar, an expose event follows. */
X   END("calendar_resize_method");
X}
X
X
X
X
Xstatic XtGeometryResult calendar_query_geometry_method(widget, proposed, preferred)
XCalendarWidget widget;
XXtWidgetGeometry *proposed;
XXtWidgetGeometry *preferred;
X{
X   /* 
X    * There are three scenarios:
X    *
X    *   1. The geometry proposed by our parent is the same as our preferred
X    *      geometry.  Return XtGeometryYes to say, "Yes, I'm happy with your
X    *      proposed geometry so please resize me to it."
X    *
X    *   2. My preferred geometry is the same as our current geometry.  Return
X    *      XtGeometryNo to say, "I'm at my preferred geometry so please don't
X    *      resize me."
X    *
X    *   3. The geometry proposed by our parent is not our preferred geometry,
X    *      nor am I at my preferred geometry.  Return XtGeometryAlmost to say
X    *      "I'm sending you my preferred geometry.  Can't you try again to get
X    *      me the size I want?"
X    *
X    * Note that my parent is free to totally ignore this information, just like
X    * most parents ignore what their kids tell them.
X    */
X
X   BEGIN("calendar_query_geometry_method");
X
X   preferred->request_mode = CWWidth | CWHeight;
X   preferred->width        = WINDOW_WIDTH(widget->calendar.min_cell_width)   + 7;
X   preferred->height       = WINDOW_HEIGHT(widget->calendar.min_cell_height) + 8;
X
X   if ( ((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
X         && ((proposed->width == preferred->width) 
X         && (proposed->height == preferred->height)) ) {
X      /* Yes, I like your proposal. */
X      return XtGeometryYes;
X   } else {
X      if ( (preferred->width  == widget->core.width) &&
X           (preferred->height == widget->core.height) ) {
X         /* Don't resize me!  I'm already at my preferred geometry. */
X         return XtGeometryNo;
X      } else {
X         /* Please try again. */
X         return XtGeometryAlmost;
X      }
X   }
X
X   END("calendar_query_geometry_method");
X}
X
X
X
Xstatic void calendar_destroy_method(w)
XWidget w;
X{
X   free_line_GCs(w);
X   free_font_GCs_and_info(w);
X}
X
X
X
X/*==========================================================================*/
X/*                           Action Definitions:                            */
X/*==========================================================================*/
Xstatic void select_cell_action(widget, event)
XCalendarWidget widget;
XXButtonEvent *event;
X{
X   int window_width   = widget->core.width;
X   int window_height  = widget->core.height;
X   float cell_width   = widget->calendar.real_cell_width;
X   float cell_height  = widget->calendar.real_cell_height;
X   int current_x_cell = widget->calendar.current_x_cell;
X   int current_y_cell = widget->calendar.current_y_cell;
X   int x              = event->x;
X   int y              = event->y;
X   int new_y_cell     = y / cell_height;
X   int new_x_cell     = x / cell_width;
X   int cellnum;
X
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X
X   /* Ignore events that occur outside the window.  These are motion */
X   /* events that started inside the window but were dragged outside. */
X   if ( (x<1) || (x>window_width-1) || (y<1) || (y>window_height-1) ) {
X      return;
X   }
X
X   /* Ignore repeat events for the same cell. */
X   if (new_x_cell == current_x_cell && new_y_cell == current_y_cell) {
X      return;
X   }
X
X   /* Ignore events in the month/year box. */
X   if (new_y_cell<2) {
X      return;
X   }
X
X   /* Ignore events outide the cells that we care about for current month. */
X   cellnum = CELLXYtoCELLNUM(new_x_cell, new_y_cell);
X   if (cellnum < widget->calendar.month_start_cellnum ||
X       cellnum > widget->calendar.month_end_cellnum) {
X      return;
X   }
X
X   widget->calendar.cell_selected = True;
X
X   /* Reset the old selected cell. */
X   if (SYNC(widget)) {
X      toggle_highlight(widget, OFF);
X   }
X
X   /* Highlight the newly selected cell. */
X   widget->calendar.highlight_date.year = widget->calendar.date.year;
X   widget->calendar.highlight_date.month = widget->calendar.date.month;
X   widget->calendar.highlight_date.day = CELLNUMtoDAYNUM(cellnum);
X   toggle_highlight(widget, ON);
X
X   return;
X}
X
X
X
X/*ARGSUSED*/
Xstatic void default_button_up_action(widget, event)
XCalendarWidget widget;
XXButtonEvent *event;
X{
X   if (!widget->calendar.cell_selected) {
X      return;
X   }
X   widget->calendar.cell_selected = False;
X
X   /* The button-down or button-motion event inverted the cell, so all     */
X   /* we have to do is call any callbacks that the application registered. */
X   XtCallCallbacks(widget, XtNcallback, &widget->calendar.highlight_date);
X}
X
X
X
X/*==========================================================================*/
X/*                         Method Support Routines:                         */
X/*==========================================================================*/
Xstatic void initialize_line_GCs(widget)
XCalendarWidget widget;
X{
X   XGCValues values;
X   XtGCMask mask;
X
X   mask = GCForeground | GCBackground | GCLineWidth;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.line_width  = widget->calendar.line_width;
X   widget->calendar.draw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground;
X   values.foreground  = widget->calendar.background;
X   values.background  = widget->calendar.foreground;
X   widget->calendar.undraw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground | GCFunction;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.function    = GXinvert;
X   widget->calendar.invert_gc = XtGetGC(widget, mask, &values);
X}
X
X
X
X
Xstatic void initialize_font_GCs_and_info(widget)
XCalendarWidget widget;
X{
X   XGCValues values;
X   XtGCMask mask;
X
X/* Digit font */
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.font        = widget->calendar.digit_font;
X   widget->calendar.digit_draw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.background;
X   values.background  = widget->calendar.foreground;
X   values.font        = widget->calendar.digit_font;
X   widget->calendar.digit_undraw_gc = XtGetGC(widget, mask, &values);
X
X   widget->calendar.digit_fsp = XQueryFont(
X      XtDisplay(widget),
X      XGContextFromGC(widget->calendar.digit_draw_gc)
X   );
X
X/* Weekday font */
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.font        = widget->calendar.weekday_font;
X   widget->calendar.weekday_draw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.background;
X   values.background  = widget->calendar.foreground;
X   values.font        = widget->calendar.weekday_font;
X   widget->calendar.weekday_undraw_gc = XtGetGC(widget, mask, &values);
X
X   widget->calendar.weekday_fsp = XQueryFont(
X      XtDisplay(widget),
X      XGContextFromGC(widget->calendar.weekday_draw_gc)
X   );
X
X/* Title font */
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.font        = widget->calendar.title_font;
X   widget->calendar.title_draw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.background;
X   values.background  = widget->calendar.foreground;
X   values.font        = widget->calendar.title_font;
X   widget->calendar.title_undraw_gc = XtGetGC(widget, mask, &values);
X
X   widget->calendar.title_fsp = XQueryFont(
X      XtDisplay(widget),
X      XGContextFromGC(widget->calendar.title_draw_gc)
X   );
X
X/* Info font */
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.foreground;
X   values.background  = widget->calendar.background;
X   values.font        = widget->calendar.info_font;
X   widget->calendar.info_draw_gc = XtGetGC(widget, mask, &values);
X
X   mask = GCForeground | GCBackground | GCFont;
X   values.foreground  = widget->calendar.background;
X   values.background  = widget->calendar.foreground;
X   values.font        = widget->calendar.info_font;
X   widget->calendar.info_undraw_gc = XtGetGC(widget, mask, &values);
X
X   widget->calendar.info_fsp = XQueryFont(
X      XtDisplay(widget),
X      XGContextFromGC(widget->calendar.info_draw_gc)
X   );
X
X}
X
X
X
X/* Compute the minimum allowable height and width of a cell based on */
X/* the specified fonts.  This is done during initialization and when */
X/* XtSetValues changes a font or string table.                       */
Xstatic void compute_minimum_cell_size(new)
XCalendarWidget new;
X{
X   int max_day_digit_width   = 0;
X   int max_day_digit_height  = 0;
X   int max_day_name_width    = 0;
X   int max_day_name_height   = 0;
X   int max_month_name_width  = 0;
X   int max_year_width        = 0;
X   int max_title_width;
X   int max_title_height;
X   XFontStruct  * font;
X   char digit_string[4];
X   char * string;
X   int length;
X   int i;
X   int temp;
X
X   /* WIDTH: */
X
X   /* Compute the max width needed for all digits in the digit font. */
X   font = new->calendar.digit_fsp;
X   for (i=0; i < MAX_DAYS_IN_MONTH; i++) {
X      temp = 
X         XTextWidth(
X            font, 
X            new->calendar.digit_names[i],
X            new->calendar.digit_name_lengths[i]
X         );
X      max_day_digit_width = MAX(max_day_digit_width, temp);
X   }
X   /* Add in a space to avoid cramming. */
X   max_day_digit_width += XTextWidth(font, " ", 1);
X
X   /* Compute the max width needed for all weekday names in the names font. */
X   font = new->calendar.weekday_fsp;
X   for (i=0; i < DAYS_IN_WEEK; i++) {
X      string = new->calendar.weekday_names[i];
X      length = new->calendar.weekday_name_lengths[i];
X      temp   = XTextWidth(font, string, length);
X      max_day_name_width = MAX(max_day_name_width, temp);
X   }
X   max_day_name_width += XTextWidth(font, " ", 1);
X
X   /* Compute the max width needed for all month names in title font.  */
X   font = new->calendar.title_fsp;
X   for (i=0; i < MONTHS_IN_YEAR; i++) {
X      string = new->calendar.month_names[i];
X      length = new->calendar.month_name_lengths[i];
X      temp   = XTextWidth(font, string, length);
X      max_month_name_width = MAX(max_month_name_width, temp);
X   }
X
X   /* Compute the max width needed to hold any 5 digit year in title font. */
X   digit_string[1] = NULL;
X   for (i=0; i < 10; i++) {
X      digit_string[0] = (char) ('0' + i);
X      temp = XTextWidth(font, digit_string, 1);
X      max_year_width = MAX(max_year_width, temp);
X   }
X   max_year_width *= 5;
X
X   max_title_width
X      = max_month_name_width 
X      + max_year_width
X      + XTextWidth(font, " ", 1) ;
X
X   /* Divide this by the number of rows.  Add one for spacing. */
X   max_title_width /= (ROWS + 1);
X
X   /* Set the minimum cell width to the max width required above. */
X   new->calendar.min_cell_width =
X      (float) MAX3(max_day_digit_width,
X                   max_day_name_width,
X                   max_title_width);
X
X   /* HEIGHT: */
X   
X   font = new->calendar.digit_fsp;
X   max_day_digit_height = font->ascent + font->descent;
X  
X   font = new->calendar.weekday_fsp;
X   max_day_name_height = font->ascent + font->descent;
X
X   font = new->calendar.title_fsp;
X   max_title_height = font->ascent + font->descent;
X
X   /* Set the minimum cell height to the max height required above plus */
X   /* whatever we need to for the line width and borders. */
X   new->calendar.min_cell_height =
X      (float) MAX3(max_day_digit_height, max_day_name_height, max_title_height)
X      + 2 * INVERT_BORDER 
X      + 2 * new->calendar.line_width
X      + 2;
X}
X
X
X
Xstatic void free_line_GCs(widget)
XCalendarWidget widget;
X{
X   Display *display; 
X
X   display = XtDisplay(widget);
X
X   XFreeGC(display, widget->calendar.draw_gc);
X   XFreeGC(display, widget->calendar.undraw_gc);
X   XFreeGC(display, widget->calendar.invert_gc);
X}
X
X
X
X
Xstatic void free_font_GCs_and_info(widget)
XCalendarWidget widget;
X{
X   Display *display; 
X
X   display = XtDisplay(widget);
X
X   XFreeGC(display, widget->calendar.digit_draw_gc);
X   XFreeGC(display, widget->calendar.digit_undraw_gc);
X   XFreeFont(display, widget->calendar.digit_fsp);
X
X   XFreeGC(display, widget->calendar.weekday_draw_gc);
X   XFreeGC(display, widget->calendar.weekday_undraw_gc);
X   XFreeFont(display, widget->calendar.weekday_fsp);
X
X   XFreeGC(display, widget->calendar.title_draw_gc);
X   XFreeGC(display, widget->calendar.title_undraw_gc);
X   XFreeFont(display, widget->calendar.title_fsp);
X
X   XFreeGC(display, widget->calendar.info_draw_gc);
X   XFreeGC(display, widget->calendar.info_undraw_gc);
X   XFreeFont(display, widget->calendar.info_fsp);
X}
X
X
Xstatic void rotate_weekdays(widget)
XCalendarWidget widget;
X{
X   int weekday;
X   int i;
X   char * save_names[DAYS_IN_WEEK];
X   int save_lengths[DAYS_IN_WEEK];
X
X   weekday = widget->calendar.starting_weekday;
X   if (!weekday) {
X      return;
X   }
X
X   /* Save a copy of the table. */
X   for (i=0; i < DAYS_IN_WEEK; i++) {
X      save_names[i] = widget->calendar.weekday_names[i];
X      save_lengths[i] = widget->calendar.weekday_name_lengths[i];
X   }
X
X   /* Rotate the original. */
X   for (i=0; i < DAYS_IN_WEEK; i++) {
X      widget->calendar.weekday_names[i] = save_names[weekday];
X      widget->calendar.weekday_name_lengths[i] = save_lengths[weekday];
X      weekday++;
X      if (weekday == DAYS_IN_WEEK) {
X         weekday = 0;
X      }
X   }
X}
X
X
X
X/*
X   For simplicity and convenience, the window is divided into a grid of 7 by 8
X   rectangles.  However, vertical lines are not drawn in the top 2 rows of boxes
X   because that's where the month/year text and day-of-week names will go.
X*/
Xstatic void compute_grid(widget)
XCalendarWidget widget;
X{
X   int window_width      = widget->core.width;
X   int window_height     = widget->core.height;
X   float cell_width      = widget->calendar.real_cell_width;
X   float cell_height     = widget->calendar.real_cell_height;
X   float min_cell_width  = widget->calendar.min_cell_width;
X   float min_cell_height = widget->calendar.min_cell_height;
X   int bottom_showing    = (window_height >= ROWS * min_cell_height);
X   int right_showing     = (window_width >= COLS * min_cell_width);
X   int line_width        = widget->calendar.line_width;
X   int fudge             = line_width % 2;
X   int seg;
X   int i;
X
X   /* Compute horizontal segments. */
X   seg = 0;
X   for (i=2; i < HORIZ_SEGMENTS+2; i++, seg++) {
X      /* Starting point. */
X      widget->calendar.segments[seg].x1 = (short) (0);
X      widget->calendar.segments[seg].y1 = (short) (cell_height * i);
X
X      /* Ending point. */
X      widget->calendar.segments[seg].x2 = (short) (window_width);
X      widget->calendar.segments[seg].y2 = (short) (cell_height * i);
X   }
X
X   /* Compute vertical segments. */
X   for (i=1; i < VERTI_SEGMENTS+1; i++, seg++) {
X      /* Starting point. */
X      widget->calendar.segments[seg].x1 = (short) (cell_width * i);
X      widget->calendar.segments[seg].y1 = (short) (cell_height * 2);
X
X      /* Ending point. */
X      widget->calendar.segments[seg].x2 = (short) (cell_width * i);
X      widget->calendar.segments[seg].y2 = (short) (window_height);
X   }
X
X   /* Draw a border around the whole grid.  I could do this with an  */
X   /* XRectangle, but since I'm calling XDrawSegments, it's one less */
X   /* function call to do it this way (could still be slower though) */
X
X   /* draw solid top */
X   widget->calendar.segments[seg].x1 = (short) (0);
X   widget->calendar.segments[seg].y1 = (short) (0);
X   widget->calendar.segments[seg].x2 = (short) (window_width);
X   widget->calendar.segments[seg].y2 = (short) (0);
X
X   /* draw solid left */
X   seg++;
X   widget->calendar.segments[seg].x1 = (short) (0);
X   widget->calendar.segments[seg].y1 = (short) (0);
X   widget->calendar.segments[seg].x2 = (short) (0);
X   widget->calendar.segments[seg].y2 = (short) (window_height);
X
X   /* draw solid bottom */
X   if (bottom_showing) {
X      seg++;
X      widget->calendar.segments[seg].x1 = (short) (0);
X      widget->calendar.segments[seg].y1 = (short) (window_height - fudge);
X      widget->calendar.segments[seg].x2 = (short) (window_width);
X      widget->calendar.segments[seg].y2 = (short) (window_height - fudge);
X   }
X
X   /* draw solid right */
X   if (right_showing) {
X      seg++;
X      widget->calendar.segments[seg].x1 = (short) (window_width - fudge);
X      widget->calendar.segments[seg].y1 = (short) (0);
X      widget->calendar.segments[seg].x2 = (short) (window_width - fudge);
X      widget->calendar.segments[seg].y2 = (short) (window_height);
X   }
X
X   widget->calendar.number_segments = seg+1;
X}
X
X
X
X   
Xstatic void draw_grid(widget)
XCalendarWidget widget;
X{
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X
X   /* Draw the grid. */
X   XDrawSegments(
X      XtDisplay(widget),
X      XtWindow(widget),
X      widget->calendar.draw_gc,
X      widget->calendar.segments,
X      widget->calendar.number_segments
X   );
X}
X
X
X
X
Xstatic void compute_cell_geometry(widget)
XCalendarWidget widget;
X{
X   int window_width      = widget->core.width;
X   int window_height     = widget->core.height;
X   int old_window_width  = widget->calendar.old_window_width;
X   int old_window_height = widget->calendar.old_window_height;
X   float cell_width      = widget->calendar.real_cell_width;
X   float cell_height     = widget->calendar.real_cell_height;
X   int line_width        = widget->calendar.line_width;
X   int line_factor       = line_width / 2;
X   int fudge             = line_width % 2;
X   int temp_x;
X   int temp_y;
X   int x,y;
X
X   /* If the window size has changed, re-compute the cell_geometry array.  */
X   /* This takes a little while (lots of float arithmetic) but that's okay */
X   /* because it only happens on resize, and we should punish the user.    */
X
X   if (old_window_width != window_width || old_window_height != window_height) {
X
X      /* Compute geometries for cells not along top, right or bottom edge. */
X      for (x=0; x < COLS-1; x++) {
X         for (y=1; y < ROWS-1; y++) {
X            GEOMETRY(widget, x, y).x = temp_x
X               = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER);
X            GEOMETRY(widget, x, y).y = temp_y
X               = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER);
X            GEOMETRY(widget, x, y).width
X               = (unsigned short) ((x+1) * cell_width - line_factor - INVERT_BORDER - temp_x);
X            GEOMETRY(widget, x, y).height
X               = (unsigned short) ((y+1) * cell_height - line_factor - INVERT_BORDER - temp_y);
X         }
X      }
X
X      /* Compute geometries for cells along right edge. */
X      x = COLS-1;
X      for (y=0; y < ROWS-1; y++) {
X         GEOMETRY(widget, x, y).x = temp_x
X            = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER);
X         GEOMETRY(widget, x, y).y = temp_y
X            = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER);
X         GEOMETRY(widget, x, y).width
X            = (unsigned short) (COLS * cell_width - line_factor - INVERT_BORDER - temp_x - fudge);
X         GEOMETRY(widget, x, y).height
X            = (unsigned short) ((y+1) * cell_height - line_factor - INVERT_BORDER - temp_y);
X      }
X
X      /* Compute geometries for cells along bottom edge. */
X      /* For a valid calendar, at most the first two cells in the bottom */
X      /* row will be used. */
X      y = ROWS-1;
X      for (x=0; x < 3; x++) {
X         GEOMETRY(widget, x, y).x = temp_x
X            = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER);
X         GEOMETRY(widget, x, y).y = temp_y
X            = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER);
X         GEOMETRY(widget, x, y).width
X            = (unsigned short) ((x+1) * cell_width - line_factor - INVERT_BORDER - temp_x);
X         GEOMETRY(widget, x, y).height
X            = (unsigned short) (ROWS * cell_height - line_factor - INVERT_BORDER - temp_y - fudge);
X      }
X
X      /* Finally, compute the available rectangle for centering the title. */
X      widget->calendar.title_geometry.x = temp_x 
X         = (short) (line_factor + fudge + INVERT_BORDER);
X      widget->calendar.title_geometry.y = temp_y 
X         = (short) (line_factor + fudge + INVERT_BORDER);
X      widget->calendar.title_geometry.width
X         = (unsigned short) (COLS * cell_width - line_factor - INVERT_BORDER - temp_x - fudge);
X      widget->calendar.title_geometry.height
X         = (unsigned short) (cell_height - line_factor - INVERT_BORDER - temp_y);
X
X      /* Factor in the day names font size for a better appearance. */
X      widget->calendar.title_geometry.height
X         = (unsigned short) (widget->calendar.title_geometry.height
X                             + cell_height
X                             - widget->calendar.weekday_fsp->ascent 
X                             - widget->calendar.weekday_fsp->descent 
X                             - 1);
X
X      widget->calendar.old_window_height = window_height;
X      widget->calendar.old_window_width  = window_width;
X   }
X}
X
X
X
X
Xstatic void draw_weekdays(widget)
XCalendarWidget widget;
X{
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X
X   DrawStringsInRects(
X      XtDisplay(widget), 
X      XtWindow(widget),
X      widget->calendar.weekday_draw_gc,
X      widget->calendar.weekday_fsp, 
X      widget->calendar.weekday_names, 
X      widget->calendar.weekday_name_lengths,
X      &GEOMETRY(widget, 0, 1),
X      DAYS_IN_WEEK,
X      South,
X      1,0
X   );
X}
X
X
X
Xstatic void draw_digits(widget)
XCalendarWidget widget;
X{
X   int x,y;
X   int start = widget->calendar.month_start_cellnum;
X   int end   = widget->calendar.month_end_cellnum;
X
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X
X   CELLNUMtoCELLXY(start,x,y);
X
X   DrawStringsInRects(
X      XtDisplay(widget), 
X      XtWindow(widget),
X      widget->calendar.digit_draw_gc,
X      widget->calendar.digit_fsp, 
X      widget->calendar.digit_names,
X      widget->calendar.digit_name_lengths,
X      &GEOMETRY(widget, x, y),
X      end - start + 1,
X      widget->calendar.digit_gravity,
X      1,0
X   );
X}
X
X
X
Xstatic void draw_title(widget)
XCalendarWidget widget;
X{
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X
X   DrawStringInRect(
X      XtDisplay(widget), 
X      XtWindow(widget),
X      widget->calendar.title_draw_gc,
X      widget->calendar.title_fsp, 
X      widget->calendar.title_string,
X      widget->calendar.title_string_length,
X      &widget->calendar.title_geometry,
X      Center,
X      1,0
X   );
X}
X
X
X
X
X
X/* Routine to fill in the widget->calendar.month_starting_weekdays[] and  */
X/* the widget->calendar.days_in_february field, given a certain date.     */
X/* The data is only computed when the widget's current_year has changed.  */
X
Xstatic void compute_month_data(widget)
XCalendarWidget widget;
X{
X   int month = widget->calendar.date.month - 1;
X   int year  = widget->calendar.date.year;
X   int leap_days;
X   int total_days;
X   int weekday;
X   int i;
X
X   if (widget->calendar.current_year != year) {
X      /* Compute data for the whole year while we're at it. */
X      leap_days = 1;            /* Year 0 was a leap year. */
X      leap_days += year/4;      /* Add all years divisible by 4. */
X      leap_days -= year/100;    /* Subtract all century years. */
X      leap_days += year/400;    /* Add back century years divisible by 400. */
X
X      if (A_LEAP_YEAR(year)) {
X         leap_days--;
X         widget->calendar.days_in_february = 29;
X      } else {
X         widget->calendar.days_in_february = 28;
X      }
X
X      /* Compute days elapsed to beginning of the year. */
X      total_days = (year*365) + leap_days;
X
X      /* Compute the starting weekday for january in this year. */
X      weekday = DAYStoWEEKDAY(total_days);
X      weekday = ROTATE(widget, weekday);
X      widget->calendar.month_starting_weekdays[JANUARY] = weekday;
X
X      /* Compute the starting weekday for february in this year. */
X      total_days += days_in_month[JANUARY];
X      weekday = DAYStoWEEKDAY(total_days);
X      weekday = ROTATE(widget, weekday);
X      widget->calendar.month_starting_weekdays[FEBRUARY] = weekday;
X
X      /* Compute the starting weekday for the rest of the months. */
X      total_days += widget->calendar.days_in_february;
X      for (i=MARCH; i <= DECEMBER; i++) {
X         weekday = DAYStoWEEKDAY(total_days);
X         weekday = ROTATE(widget, weekday);
X         widget->calendar.month_starting_weekdays[i] = weekday;
X         total_days += days_in_month[i];
X      }
X      widget->calendar.current_year = year;
X
X      /* Compute the new year string. */
X      if (widget->calendar.show_year) {
X         sprintf(widget->calendar.year_string, "%d" ,widget->calendar.date.year);
X         widget->calendar.year_string_length = strlen(widget->calendar.year_string);
X      } else {
X         strcpy(widget->calendar.year_string, "");
X         widget->calendar.year_string_length = 0;
X      }
X   }
X
X   widget->calendar.month_start_cellnum 
X      = widget->calendar.month_starting_weekdays[month];
X
X   widget->calendar.month_end_cellnum
X      = widget->calendar.month_start_cellnum 
X      + DAYS_IN_MONTH(widget) - 1;
X}
X
X
X
X
X
X
Xstatic void compute_title_string(widget)
XCalendarWidget widget;
X{
X   int month = widget->calendar.date.month - 1;
X
X   /* Compute the title string length. */
X   widget->calendar.title_string_length = widget->calendar.month_name_lengths[month];
X
X   /* Fill in the title string. */
X   strcpy(widget->calendar.title_string, widget->calendar.month_names[month]);
X
X   if (widget->calendar.show_year) {
X      strcat(widget->calendar.title_string, " ");
X      widget->calendar.title_string_length += 1;
X
X      strcat(widget->calendar.title_string, widget->calendar.year_string);
X      widget->calendar.title_string_length += widget->calendar.year_string_length;
X   }
X}
X
X
X
X
X
X
Xstatic void clear_calendar(widget)
XCalendarWidget widget;
X{
X   int month_start_cellnum = widget->calendar.month_start_cellnum;
X   int month_end_cellnum   = widget->calendar.month_end_cellnum;
X   Display * display;
X   Window window;
X   int x,y;
X
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X   BEGIN("clear_calendar");
X
X   display = XtDisplay(widget);
X   window  = XtWindow(widget);
X
X   CELLNUMtoCELLXY(month_start_cellnum, x, y);
X   
X   /* Erase the digits. */
X   XFillRectangles(
X      display,
X      window,
X      widget->calendar.undraw_gc,
X      &GEOMETRY(widget,x,y),
X      month_end_cellnum - month_start_cellnum + 1
X   );
X
X   /* Erase the title box.  */
X   XFillRectangles(
X      display,
X      window,
X      widget->calendar.undraw_gc,
X      &widget->calendar.title_geometry,
X      1
X   );
X
X   END("clear_calendar");
X}
X
X
X
X
Xstatic void calendar_update(widget)
XCalendarWidget widget;
X{
X
X   BEGIN("calendar_update");
X
X   clear_calendar       (widget);
X   compute_month_data   (widget);
X   compute_title_string (widget);
X   draw_title           (widget);
X   draw_digits          (widget);
X
X   if (SYNC(widget)) {
X      toggle_highlight(widget, ON);
X   } else {
X      widget->calendar.current_x_cell = 0;
X      widget->calendar.current_y_cell = 0;
X   }
X
X   END("calendar_update");
X}
X
X
X
Xstatic void toggle_highlight(widget, state)
XCalendarWidget widget;
Xint state;
X{
X   int current_x_cell;
X   int current_y_cell;
X   int day;
X   Display * display;
X   Window window;
X   GC draw_gc;
X   GC undraw_gc;
X
X   if (widget->calendar.state == foggy) {
X      return;
X   }
X   BEGIN("toggle_highlight");
X
X   WIDGETtoCELLXY(
X      widget,
X      current_x_cell,
X      current_y_cell
X   );
X
X   day = widget->calendar.highlight_date.day - 1;
X
X   if (current_y_cell && widget->calendar.highlight) {
X
X      display = XtDisplay(widget);
X      window  = XtWindow(widget);
X
X      if (state == ON) {
X         draw_gc = widget->calendar.draw_gc;
X         undraw_gc = widget->calendar.digit_undraw_gc;
X      } else {
X         draw_gc = widget->calendar.undraw_gc;
X         undraw_gc = widget->calendar.digit_draw_gc;
X      }
X
X      XFillRectangles(
X         display,
X         window,
X         draw_gc,
X         &GEOMETRY(widget, current_x_cell, current_y_cell),
X         1
X      );
X
X      DrawStringInRect(
X         display, 
X         window,
X         undraw_gc,
X         widget->calendar.digit_fsp, 
X         widget->calendar.digit_names[day], 
X         widget->calendar.digit_name_lengths[day],
X         &GEOMETRY(widget, current_x_cell, current_y_cell),
X         widget->calendar.digit_gravity,
X         1,0
X      );
X
X      /* Eventually this will need to draw the day info as well. */
X   }
X
X   if (state == OFF) {
X      widget->calendar.current_x_cell = 0;
X      widget->calendar.current_y_cell = 0;
X   } else {
X      widget->calendar.current_x_cell = current_x_cell;
X      widget->calendar.current_y_cell = current_y_cell;
X   }
X
X   END("toggle_highlight");
X}
X 
X 
X
X
X
X/*==========================================================================*/
X/*                             Public Functions:                            */
X/*==========================================================================*/
Xvoid CalendarIncMonth(widget)
XCalendarWidget widget;
X{
X   if (widget->calendar.date.month == DECEMBER+1) {
X      widget->calendar.date.month = JANUARY+1;
X      widget->calendar.date.year++;
X   } else {
X      widget->calendar.date.month++;
X   }
X   calendar_update(widget);
X}
X
X
X
Xvoid CalendarDecMonth(widget)
XCalendarWidget widget;
X{
X   if (widget->calendar.date.month == JANUARY+1) {
X      widget->calendar.date.month = DECEMBER+1;
X      widget->calendar.date.year--;
X   } else {
X      widget->calendar.date.month--;
X   }
X   calendar_update(widget);
X}
X
X
Xvoid CalendarIncYear(widget)
XCalendarWidget widget;
X{
X   widget->calendar.date.year++;
X   calendar_update(widget);
X}
X
X
X
Xvoid CalendarDecYear(widget)
XCalendarWidget widget;
X{
X   widget->calendar.date.year--;
X   calendar_update(widget);
X}
X
X
X
X
Xvoid CalendarIncDay(widget, show)
XCalendarWidget widget;
XBoolean show;
X{
X   if (!widget->calendar.highlight_date.day) {
X      return;
X   }
X   BEGIN("CalendarIncDay");
X
X   if (SYNC(widget)) {
X      toggle_highlight(widget, OFF);
X   }
X
X   if (widget->calendar.highlight_date.day == DAYS_IN_HIGHLIGHT_MONTH(widget)) {
X      /* We've rolled over a month. */ 
X      widget->calendar.highlight_date.day = 1;
X
X      if (widget->calendar.highlight_date.month == DECEMBER+1) {
X         widget->calendar.highlight_date.month = JANUARY+1;
X         widget->calendar.highlight_date.year++;
X
X         /* We've rolled over a year, get new days in feb. */
X         widget->calendar.highlight_days_in_february 
X            = 28 + A_LEAP_YEAR(widget->calendar.highlight_date.year);
X
X      } else {
X         widget->calendar.highlight_date.month++;
X      }
X
X      if (show) {
X         CalendarShowMonth(widget, widget->calendar.highlight_date);
X      }
X
X   } else {
X      widget->calendar.highlight_date.day++;
X   }
X
X   if (SYNC(widget)) {
X      toggle_highlight(widget, ON);
X   }
X
X   END("CalendarIncDay");
X}
X
X
X
X
X
Xvoid CalendarDecDay(widget, show)
XCalendarWidget widget;
XBoolean show;
X{
X   if (!widget->calendar.highlight_date.day) {
X      return;
X   }
X   BEGIN("CalendarDecDay");
X
X   if (SYNC(widget)) {
X      toggle_highlight(widget, OFF);
X   }
X
X   if (widget->calendar.highlight_date.day == 1) {
X      /* We've rolled over a month. */
X
X      if (widget->calendar.highlight_date.month == JANUARY+1) {
X         widget->calendar.highlight_date.month = DECEMBER+1;
X         widget->calendar.highlight_date.year--;
X         widget->calendar.highlight_date.day = 31;
X
X         /* We've rolled over a year, get new days in feb. */
X         widget->calendar.highlight_days_in_february 
X            = 28 + A_LEAP_YEAR(widget->calendar.highlight_date.year);
X
X      } else {
X         widget->calendar.highlight_date.month--;
X         widget->calendar.highlight_date.day = DAYS_IN_HIGHLIGHT_MONTH(widget);
X      }
X
X      if (show) {
X         CalendarShowMonth(widget, widget->calendar.highlight_date);
X      }
X
X   } else {
X      widget->calendar.highlight_date.day--;
X   }
X
X   if (SYNC(widget)) {
X      toggle_highlight(widget, ON);
X   }
X
X   END("CalendarDecDay");
X}
X
X
X
X
X
Xvoid CalendarSetDate(widget, date)
XCalendarWidget widget;
XDate date;
X{
X   if (!is_valid_date(&date)) {
X      return;
X   }
X   BEGIN("CalendarSetDate");
X
X   if (SYNC(widget)) {
X      /* Reset any already highlighted date. */
X      toggle_highlight(widget, OFF);
X   }
X
X   if (widget->calendar.date.month == date.month &&
X       widget->calendar.date.year  == date.year) {
X      /* The date specified is on the calendar currently being shown. */
X
X      /* Highlight the specified date. */
X      widget->calendar.highlight_date = date;
X      toggle_highlight(widget, ON);
X   } else {
X      /* The date specified is not on the current calendar. */
X
X      if (date.year != widget->calendar.highlight_date.year) {
X         widget->calendar.highlight_days_in_february
X            = 28 + A_LEAP_YEAR(date.year);
X      }
X      widget->calendar.highlight_date = date;
X   }
X
X   END("CalendarSetDate");
X}
X
X
X
X
Xvoid CalendarShowMonth(widget, date)
XCalendarWidget widget;
XDate date;
X{
X   date.day = 1;
X   if (!is_valid_date(&date)) {
X      return;
X   }
X   BEGIN("CalendarShowMonth");
X
X   if (widget->calendar.date.month == date.month
X       && widget->calendar.date.year == date.year) {
X      /* The corresponding calendar is currently being displayed. */
X   } else {
X      /* The corresponding calendar is not currently being displayed. */
X      widget->calendar.date.month = date.month;
X      widget->calendar.date.year  = date.year;
X      calendar_update(widget);
X   }
X
X   END("CalendarShowMonth");
X}
X
X
X
Xvoid CalendarGetDate(widget, date_ptr)
XCalendarWidget widget;
XDate * date_ptr;
X{
X   *date_ptr = widget->calendar.highlight_date;
X}
X
X
X
XDate DateConverter(widget, string)
XCalendarWidget widget;
Xchar * string;
X{
X   /* Call the real converter.  This just allows us to hide details. */
X   return (convert_string_to_date(widget->calendar.month_names, string));
X}
X
X
X
X
X/* Returns a Date structure corresponding to the current date. */
X/* Most applications are going to need it so I'll just provide it. */
XDate GetTodaysDate()
X{
X   Date date;
X   time_t current_time = time(NULL);
X   struct tm * current_tm = localtime(&current_time);
X   date.month = current_tm->tm_mon + 1;
X   date.day   = current_tm->tm_mday;
X   date.year  = current_tm->tm_year + 1900;
X   return date;
X}
X
X
X
X
X/* Return a string like "Thursday October 15, 1990" */
Xchar * CalendarPrettyDate(widget)
XCalendarWidget widget;
X{
X   static char buffer[MAX_PRETTY_DATE_STRING_LENGTH];
X   Date highlight_date;
X   Date showing_date;
X   int weekday;
X   int month;
X
X   highlight_date = widget->calendar.highlight_date;
X   showing_date = widget->calendar.date;
X   
X   if (showing_date.year == highlight_date.year) {
X      month = highlight_date.month - 1;
X      weekday = widget->calendar.month_starting_weekdays[month];
X      weekday = (weekday + highlight_date.day - 1) % 7;
X   } else {
X      /* No info available, so resort to brute force. */
X      weekday = compute_weekday(highlight_date);
X      weekday = ROTATE(widget, weekday);
X   }
X
X   /*VARARGS*/
X   sprintf(
X      buffer,
X      "%s %s %d, %d",
X      widget->calendar.weekday_names[weekday],
X      widget->calendar.month_names[highlight_date.month-1],
X      highlight_date.day,
X      highlight_date.year
X   );
X
X   return buffer;
X}
X
X
X
Xstatic int compute_weekday(date)
XDate date;
X{
X   int leap_days;
X   int total_days;
X   int month;
X   int days_in_february;
X   
X   leap_days = 1;                 /* Year 0 was a leap year. */
X   leap_days += date.year/4;      /* Add all years divisible by 4. */
X   leap_days -= date.year/100;    /* Subtract all century years. */
X   leap_days += date.year/400;    /* Add back century years divisible by 400. */
X   
X   if (A_LEAP_YEAR(date.year)) {
X      leap_days--;
X      days_in_february = 29;
X   } else {
X      days_in_february = 28;
X   }
X
X   total_days = (date.year*365) + leap_days;
X
X   for (month=0; month < date.month - 1; month ++) {
X      if (month == FEBRUARY) {
X         total_days += days_in_february;
X      } else {
X         total_days += days_in_month[month];
X      }
X   }
X
X   total_days += date.day - 1;
X
X   return DAYStoWEEKDAY(total_days);
X}
END_OF_FILE
if test 58171 -ne `wc -c <'Calendar.c'`; then
    echo shar: \"'Calendar.c'\" unpacked with wrong size!
fi
# end of 'Calendar.c'
fi
echo shar: End of archive 5 \(of 5\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
|===================================|===================================|
|      Jason "Jasper" Baietto       |       otteiaB "repsaJ" nosaJ      |
| Harris Computer Systems Division  |  noisiviD smetsyS retupmoC sirraH |
|     Fort Lauderdale, Florida      |      adirolF ,eladreduaL troF     |
|   jason at hcx2.ssd.csd.harris.com   |   moc.sirrah.dsc.dss.2xch at nosaj   |
|===================================|===================================|



More information about the Alt.sources mailing list