Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtcm / dtcm / monthglance.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*******************************************************************************
24 **
25 **  monthglance.c
26 **
27 **  $XConsortium: monthglance.c /main/13 1996/11/21 19:43:07 drk $
28 **
29 **  RESTRICTED CONFIDENTIAL INFORMATION:
30 **
31 **  The information in this document is subject to special
32 **  restrictions in a confidential disclosure agreement between
33 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
35 **  Sun's specific written approval.  This document and all copies
36 **  and derivative works thereof must be returned or destroyed at
37 **  Sun's request.
38 **
39 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40 **
41 *******************************************************************************/
42
43 /*                                                                      *
44  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
45  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
46  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
47  * (c) Copyright 1993, 1994 Novell, Inc.                                *
48  */
49
50 #ifndef lint
51 static  char sccsid[] = "@(#)monthglance.c 1.82 95/07/27 Copyr 1994 Sun Microsystems, Inc.";
52 #endif
53
54 #include <EUSCompat.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <sys/stat.h>
59 #include <sys/param.h> /* MAXPATHLEN defined here */
60 #ifdef SVR4
61 #include <sys/utsname.h> /* SYS_NMLN */
62 #endif /* SVR4 */
63 #include <dirent.h>
64 #include <ctype.h>
65 #include <string.h>
66 #include <sys/time.h>
67 #include <time.h>
68 #include <rpc/rpc.h>
69 #include <sys/resource.h>
70 #include <sys/wait.h>
71 #include <netinet/in.h>
72 #include <X11/Xlib.h>
73 #include <X11/IntrinsicP.h>
74 #include <Xm/Xm.h>
75 #include <Xm/DrawingA.h>
76 #include <Xm/Label.h>
77 #include <Xm/PushB.h>
78 #include <Xm/RowColumn.h>
79 #include <Xm/ToggleBG.h>
80 #include <Dt/HourGlass.h>
81 #include "calendar.h"
82 #include "util.h"
83 #include "timeops.h"
84 #include "datefield.h"
85 #include "x_graphics.h"
86 #include "props.h"
87 #include "select.h"
88 #include "editor.h"
89 #include "group_editor.h"
90 #include "monthglance.h"
91 #include "weekglance.h"
92 #include "format.h"
93 #include "browser.h"
94 #include "blist.h"
95 #include "dayglance.h"
96 #include "yearglance.h"
97 #include "todo.h"
98 #include "find.h"
99 #include "goto.h"
100 #include "tempbr.h"
101
102 #define XOS_USE_XT_LOCKING
103 #define X_INCLUDE_TIME_H
104 #include <X11/Xos_r.h>
105
106 static void     paint_day_entries(Tick, int, int, int, int,
107                                   Paint_cache *, CSA_uint32, XRectangle *);
108 static Boolean  allocated(Calendar *);
109 static void     allocator(Calendar *);
110 static void     deallocator(Calendar *);
111 extern void     layout_children(Calendar *);
112 static void     display_header(Calendar *);
113 static void     quick_button_cb(Widget, XtPointer, XtPointer);
114 static Boolean  print_month ( Calendar *, int,
115                              void *, Tick, Props *, Boolean);
116 static int      count_month_pages(Calendar *, Tick, int);
117 static void     paint_daynames(Calendar *, XRectangle *);
118 static void     paint_month(Calendar *, Tick, XRectangle *);
119 static void     unmanage_children(Calendar *);
120 static void     manage_children(Calendar *);
121 static int      count_month_appts(CSA_entry_handle *, int, Calendar *);
122
123 static int
124 compute_pad_width(
125         Cal_Font        *pf)
126 {
127         int              nop,
128                          width;
129
130         CalTextExtents(pf, "1", 1, &nop, &nop, &width, &nop);
131
132         return width;
133 }
134
135 static void
136 paint_day_entries(
137         Tick    day,
138         int     x,
139         int     y,
140         int     w,
141         int     h,
142         Paint_cache *cache,
143         CSA_uint32 appt_total,
144         XRectangle *rect)
145 {
146         char *buf;
147         int i, loop, nlines = 0, maxchars;
148         Calendar *c=calendar;
149         Props *p = (Props*)c->properties;
150         DisplayType dt = get_int_prop(p, CP_DEFAULTDISP);
151         Lines *lines=NULL;
152         Tick start_tick;
153         new_XContext *xc    =   c->xcontext;
154         Cal_Font *pf =          c->fonts->viewfont;
155         XFontSetExtents fontextents;
156         int pfy;
157         int maxlines;
158         Tick lower      =       lowerbound(day);
159         Tick upper      =       next_ndays(day, 1);
160
161         CalFontExtents(pf, &fontextents);
162         pfy = fontextents.max_ink_extent.height;
163         maxlines = h / pfy;
164
165         /* loop thru the list of appointments twice, first displaying 
166            the no time appointments, and then the appointments with times 
167            associated. */
168
169         for (loop = 0; loop < 2; loop++) {
170                 for (i = 0; i < appt_total; i++) {
171                         start_tick = cache[i].start_time;
172                         if (start_tick >= lower && 
173                             start_tick < upper && 
174                             (loop == cache[i].show_time)) {                        
175                                 if (nlines < maxlines) {
176                                         Boolean pad;
177                                         static int pad_width = 0;
178
179                                         lines = 
180                                              text_to_lines(cache[i].summary, 1);
181                                         if (lines != NULL) {
182                                                 buf = ckalloc(
183                                                       cm_strlen(lines->s) + 18);
184                                                 pad = format_line(start_tick, 
185                                                             lines->s, buf, 
186                                                             start_tick, 
187                                                             cache[i].show_time, 
188                                                             dt);
189                                         }
190                                         else {
191                                                 buf = ckalloc(15);
192                                                 pad = format_line(start_tick, 
193                                                             (char*)NULL, buf, 
194                                                             start_tick, 
195                                                             cache[i].show_time,
196                                                             dt);
197                                         }
198                                         destroy_lines(lines); lines=NULL;
199
200                                         if (!pad_width) {
201                                                 pad_width = 
202                                                         compute_pad_width(pf);
203                                         }
204                                         if (pad) {
205                                                 maxchars = gr_nchars(
206                                                                 w - pad_width, 
207                                                                 buf, pf);
208                                                 if (cm_strlen(buf) > maxchars)
209                                                         buf[maxchars] = NULL;
210                                                 (void)gr_text(xc, x + pad_width,
211                                                               y, pf, buf, rect);
212                                         } else {
213                                                 maxchars = gr_nchars(w, buf, 
214                                                                      pf);
215                                                 if (cm_strlen(buf) > maxchars)
216                                                         buf[maxchars] = NULL;
217                                                 (void)gr_text(xc, x, y, pf, 
218                                                               buf, rect);
219                                         }
220                                         free(buf); buf=NULL;
221                                         y = y + pfy;
222                                         nlines++;
223                                 }
224                         }
225                         else
226                                 continue;
227                 }
228         }
229 }
230
231 extern void
232 month_button(Widget widget, XtPointer data, XtPointer cbs)
233 {
234         Calendar *c = calendar;
235
236         if (c->view->glance == monthGlance)
237                 return;
238
239         XtUnmapWidget(c->canvas);
240
241         switch (c->view->glance) {
242                 case dayGlance:
243                         c->view->glance = monthGlance;
244                         cleanup_after_dayview(c);
245                         break;
246                 case weekGlance:
247                         c->view->glance = monthGlance;
248                         cleanup_after_weekview(c);
249                         break;
250                 case yearGlance:
251                         cleanup_after_yearview(c);
252                         c->view->glance = monthGlance;
253                         break;
254                 default:
255                         break;
256         }
257         prepare_to_paint_monthview (c, NULL);
258
259         XtMapWidget(c->canvas);
260 }
261
262 /*
263  * Do the actual month grid, headers and appointments
264  */
265 static void
266 paint_month(Calendar *c, Tick key, XRectangle *rect)
267 {
268         Month           *m = (Month *)c->view->month_info;
269         int             x, y, i, j;
270         CSA_uint32      a_total;
271         int             firstdom, boxw, boxh, dayname_height, margin, default_height;
272         Tick            day;
273         struct tm       tm;
274         new_XContext    *xc;
275         Dimension       btn_ht=0, btn_w=0;
276         time_t          start, stop;
277         CSA_enum        *ops;
278         CSA_attribute   *range_attrs;
279         CSA_entry_handle *list = NULL;
280         XFontSetExtents fontextents;
281         _Xltimeparams   localtime_buf;
282  
283         tm              = *_XLocaltime(&key, localtime_buf);
284         tm.tm_mday      = 1;
285 #ifdef SVR4
286         tm.tm_isdst      = -1;
287         day             = mktime(&tm);
288 #else
289         day             = timelocal(&tm);
290 #endif /* SVR4 */
291         m->ndays        = ((tm.tm_mon==1) && leapyr(tm.tm_year+1900))? 29 :
292                                 monthdays[tm.tm_mon];
293         tm              = *_XLocaltime(&day, localtime_buf);
294         firstdom        = tm.tm_wday;
295         boxw            = calendar->view->boxw;
296         boxh            = calendar->view->boxh;
297         margin          = calendar->view->outside_margin;
298         dayname_height  = ((Month *) calendar->view->month_info)->dayname_height;
299         xc              = calendar->xcontext;
300  
301
302         if (c->paint_cache == NULL) {
303                 start = (time_t) lowerbound(day);
304                 stop = (time_t) last_dom(day);
305                 setup_range(&range_attrs, &ops, &j, start, stop, CSA_TYPE_EVENT,
306                         NULL, B_FALSE, c->general->version);
307                 csa_list_entries(c->cal_handle, j, range_attrs, ops, &a_total, &list, NULL);
308         
309                 free_range(&range_attrs, &ops, j);
310                 allocate_paint_cache(list, a_total, &c->paint_cache);
311                 c->paint_cache_size = a_total;
312                 csa_free(list);
313         }
314
315         CalFontExtents(c->fonts->viewfont, &fontextents);
316         default_height = fontextents.max_logical_extent.height;
317         x = firstdom; y = 0;
318  
319         for(i = 1; i <= m->ndays; i++) {
320                 int box_origin_x=0, box_origin_y=0;
321
322                 box_origin_x = (x * boxw) + margin;
323                 box_origin_y = (y * boxh) + dayname_height + c->view->topoffset;
324
325                 XtVaGetValues(m->hot_button[i-1], XmNheight, &btn_ht,
326                         XmNwidth, &btn_w, NULL);
327
328                 /*
329                  * Paint the list of calendar entries for this day
330                  */
331                 paint_day_entries(day,
332                         box_origin_x + 2,
333                         box_origin_y + default_height + btn_ht, 
334                         boxw - 4, boxh - btn_ht - 4,
335                         c->paint_cache, c->paint_cache_size, rect);
336
337                 day = nextday(day);
338                 x++;
339                 if (x > 6 & i != m->ndays) {
340                         x = 0;
341                         y++;
342                 }
343         }
344 }
345
346 /*
347  * Set the label header for the view to current month name
348  */
349 static void
350 display_header(Calendar *c)
351 {
352         Month           *m = (Month *) c->view->month_info;
353         char            buf[BUFSIZ];
354         XmString        str;
355         Position        x, y;
356         struct tm       *tm_ret;
357         Tick            tmptick = c->view->date;
358         _Xltimeparams   localtime_buf;
359
360 /* label */
361         tm_ret = _XLocaltime(&tmptick, localtime_buf);
362
363         /* NL_COMMENT
364            Attention Translator:
365
366            This string is used in the calendar month view.  In the C locale
367            it has the form:
368
369                 July, 1995
370
371            strftime conversion string: "%B, %Y" is used.
372
373            Use the appropriate strftime conversion for your locale.
374         */
375         sprintf( buf, "%s, %d", months[tm_ret->tm_mon+1],
376                 tm_ret->tm_year + 1900 );
377
378         str = XmStringCreateLocalized(buf);
379         XtVaSetValues(m->month_label, XmNlabelString, str, NULL);
380         XmStringFree(str);
381
382 /* positioning */
383         x = c->view->outside_margin; y = 15;
384         XtVaSetValues(m->month_label, XtNx, x, XtNy, y, NULL);
385
386 /* now manage it */
387         if (!XtIsManaged(m->month_label)) {
388                 XtManageChild(m->month_label);
389         }
390 }
391
392 static void
393 paint_daynames(Calendar *c, XRectangle    *rect)
394 {
395         int             i, middle;
396         int             boxw = c->view->boxw;
397         int             margin = c->view->outside_margin;
398         int             dayname_height = 
399                                 ((Month *)c->view->month_info)->dayname_height;
400         Cal_Font        *pf = c->fonts->viewfont;
401         new_XContext    *xc = c->xcontext;
402
403         for(i = 0; i < 7; i++) {
404                 gr_draw_box(xc, (boxw * i)+margin,
405                         c->view->topoffset,
406                         boxw, dayname_height, rect);
407                 middle = gr_center(boxw, days[i], pf);
408                 gr_text(xc, (boxw*i)+middle+margin, 
409                                 c->view->topoffset+dayname_height-3,
410                                 pf, days[i], rect);
411         }
412 }
413
414 extern void
415 paint_grid(Calendar *c, XRectangle *rect)
416 {
417         int i;
418         int boxh        = c->view->boxh;
419         int boxw        = c->view->boxw;
420         int nrows       = c->view->nwks;
421         int margin      = c->view->outside_margin;
422         int dayname_height = ((Month *)c->view->month_info)->dayname_height;
423         int rightmargin = margin + 7 * boxw;
424         int bottomargin = c->view->topoffset+ dayname_height+boxh*nrows;
425         new_XContext *xc    = c->xcontext;
426
427         /* horizontal */                   
428         for (i = 1; i <= nrows; i++) {
429                 gr_draw_line(xc, margin,
430                         (i*boxh)+c->view->topoffset+dayname_height,
431                          rightmargin, i*boxh+c->view->topoffset+dayname_height,
432                         gr_solid, rect);
433         }
434  
435         /* vertical */
436         for (i = 0; i < 8; i++) {
437                 gr_draw_line(xc, margin+(i*boxw),
438                         c->view->topoffset+dayname_height,
439                         margin+(i*boxw), bottomargin, gr_solid, rect);
440         }
441         /* embolden grid outline */
442         gr_draw_box(xc, margin-1,
443                 c->view->topoffset-1, 7*boxw+2,
444                         nrows*boxh+2+dayname_height, rect);
445 }
446
447 extern void
448 layout_month(
449         Calendar        *c,
450         Tick             date)
451 {
452         Month           *m = (Month *)c->view->month_info;
453         int              i, x, y,
454                          firstdom,
455                          boxw = calendar->view->boxw,
456                          boxh = calendar->view->boxh,
457                          margin = calendar->view->outside_margin,
458                          dayname_height = m->dayname_height;
459         struct  tm       tm;
460         Tick             day;
461         _Xltimeparams    localtime_buf;
462
463         tm = *_XLocaltime(&date, localtime_buf);
464         tm.tm_mday = 1;
465 #ifdef SVR4
466         tm.tm_isdst = -1;
467         day = mktime(&tm);
468 #else
469         day = timelocal(&tm);
470 #endif /* SVR4 */
471         m->ndays = ((tm.tm_mon==1) && 
472                     leapyr(tm.tm_year+1900))? 29 : monthdays[tm.tm_mon];
473         tm = *_XLocaltime(&day, localtime_buf);
474         firstdom = tm.tm_wday;
475
476         x = firstdom;
477         y = 0;
478         for(i = 1; i <= m->ndays; i++) {
479                 int     box_origin_x = 0,
480                         box_origin_y = 0;
481
482                 box_origin_x = (x * boxw) + margin;
483                 box_origin_y = (y * boxh) + dayname_height + c->view->topoffset;
484
485                 m->button_loc[i-1].x = box_origin_x + 3;
486                 m->button_loc[i-1].y = box_origin_y + 3;
487
488                 x++;
489                 if (x > 6 & i != m->ndays) {
490                         x = 0;
491                         y++;
492                 }
493                 XtMoveWidget(m->hot_button[i-1], 
494                                 m->button_loc[i-1].x, m->button_loc[i-1].y);
495         }
496
497         /* Unmanage any unneeded navigator buttons (ie. 29, 30, 31) */
498         for (i=m->ndays; i<31; i++)
499                 if (XtIsManaged(m->hot_button[i]))
500                         XtUnmanageChild(m->hot_button[i]);
501 }
502
503 extern void
504 repaint_damaged_month(
505         Calendar        *c,
506         XRectangle      *rect)
507 {
508         /* allocate Month memory & widgets if necessary */
509         if (!allocated(c)) {
510                 XFontSetExtents         boldfontextents;
511
512                 allocator(c);
513                 XmToggleButtonGadgetSetState(c->month_scope, True, False);
514                 CalFontExtents(c->fonts->boldfont, &boldfontextents);
515                 ((Month *) c->view->month_info)->dayname_height =  
516                                 boldfontextents.max_logical_extent.height + 6;
517                 layout_month(c, c->view->date); 
518                 display_header(c);
519                 manage_children(c);
520         }
521
522         paint_daynames(c, rect);
523         paint_grid(c, rect);
524         paint_month(c, c->view->date, rect);
525         calendar_select(c, daySelect, (caddr_t)NULL);
526 }
527
528 extern void
529 prepare_to_paint_monthview(Calendar *c, XRectangle *rect)
530 {
531         Dimension               w, h;
532         c = calendar;
533
534         XmToggleButtonGadgetSetState(c->month_scope, True, False);
535         XtVaGetValues(c->canvas, XmNwidth, &w, XmNheight, &h, NULL);
536         cache_dims(c, w, h);
537
538         /* allocate Month memory & widgets if necessary */
539         if (!allocated(c)) {
540                 XFontSetExtents         boldfontextents;
541
542                 allocator(c);
543                 CalFontExtents(c->fonts->boldfont, &boldfontextents);
544                 ((Month *) c->view->month_info)->dayname_height = 
545                                 boldfontextents.max_logical_extent.height + 6;
546         }
547  
548         /*
549          * need to unmanage buttons while drawing to avoid many exposures
550          * when they are moved
551          */
552         display_header(c);
553         layout_month(c, c->view->date); 
554         gr_clear_area(c->xcontext, 0, 0, c->view->winw, c->view->winh);
555         manage_children(c);
556 }
557
558 /* ADDED FOR PRINTING */
559 extern void
560 get_time_str (Dtcm_appointment *appt, char *buf)
561 {
562         Calendar        *c = calendar;
563         Props           *p = (Props*)c->properties;
564         DisplayType     dt = get_int_prop(p, CP_DEFAULTDISP);
565         struct tm       *tm;
566         int             hr, mn;
567         Tick            start_tick;
568         _Xltimeparams   localtime_buf;
569
570         _csa_iso8601_to_tick(appt->time->value->item.date_time_value, &start_tick);
571         buf[0] = NULL;
572
573         if (appt==NULL || !showtime_set(appt) || magic_time(start_tick))
574                 return;
575
576         tm = _XLocaltime(&start_tick, localtime_buf);
577         hr = tm->tm_hour;
578         mn = tm->tm_min;
579
580         if (dt == HOUR12) {
581                 adjust_hour(&hr);
582                 (void) sprintf(buf, "%2d:%02d ", hr, mn);
583         }
584         else
585                 (void) sprintf(buf, "%02d%02d ", hr, mn);
586 }
587
588 extern void
589 month_event(XEvent *event)
590 {
591         static int      lastcol, lastrow;
592         static XEvent   lastevent;
593         int             x, y, j, toffset;
594         int             boxw, boxh, row, col, margin, dayname_height;
595         Tick            date;
596         Calendar        *c = calendar;
597         Editor          *e = (Editor*)c->editor;
598         ToDo            *t = (ToDo*)c->todo;
599         GEditor         *ge = (GEditor*)c->geditor;
600
601         boxw    = c->view->boxw;
602         boxh    = c->view->boxh;
603         margin  = c->view->outside_margin;
604         dayname_height  = ((Month *) c->view->month_info)->dayname_height;
605         date    = c->view->date;
606         x       = event->xbutton.x;
607         y       = event->xbutton.y;
608         toffset = c->view->topoffset;
609
610         if (boxw == 0)
611                 col = 0;
612         else
613                 col     = (x-margin)/boxw;
614         if  (boxh == 0)
615                 row = 0;
616         else
617                 row     = (y-c->view->topoffset-dayname_height)/boxh;
618
619         /* boundary conditions */
620         if (x < margin || col > 6 || y < (dayname_height+toffset) || row > c->view->nwks-1) {
621                 calendar_deselect(c);
622                 lastcol=0; lastrow=0;
623                 return;
624         }
625
626         /* boundary check for click in invalid cell */
627         if (((col < fdom(date)) && (row==0)) ||
628             ((col > ldom(date)) && (row==c->view->nwks - 1))) {
629                 calendar_deselect(c);
630                 lastcol=0; lastrow=0;
631                 return;
632         }
633
634         switch(event->type) {
635         case MotionNotify:
636                if (col !=lastcol || row !=lastrow) {
637                         calendar_deselect(c);
638                         j = xytoclock(col+1, row+1, date);
639                         if (j > 0) {
640                                 c->view->olddate = c->view->date;
641                                 c->view->date = j;
642                                 calendar_select(c, daySelect, (caddr_t)NULL);
643                         }
644                         lastcol=col;
645                         lastrow=row;
646                 }
647                 break;
648       case ButtonPress:
649                 if (ds_is_double_click(&lastevent, event)) {
650                         _DtTurnOnHourGlass(c->frame);
651                         if (lastcol == col && lastrow == row)
652                                 show_editor(c, 0, 0, False);
653                         _DtTurnOffHourGlass(c->frame);
654                 }
655                 else {
656                         calendar_deselect(c);
657                         j = xytoclock(col+1, row+1, date);
658                         if (j > 0) {
659                            c->view->olddate = c->view->date;
660                            c->view->date = j;
661                            calendar_select(c, daySelect, (caddr_t)NULL);
662                         }
663
664                         if (editor_showing(e)) {
665                                 set_editor_defaults(e, 0, 0, False);
666                                 add_all_appt(e);
667                         }
668                 }
669                 if (todo_showing(t)) {
670                         set_todo_defaults(t);
671                         add_all_todo(t);
672                 }
673                 if (geditor_showing(ge)) {
674                         set_geditor_defaults(ge, 0, 0);
675                         add_all_gappt(ge);
676                 }
677                 lastcol=col;
678                 lastrow=row;
679                 break;
680         default:
681         break;
682         };              /* switch */
683         lastevent = *event;
684 }
685  
686 static int
687 count_month_pages(Calendar *c, Tick start_date, int lines_per_box)
688 {
689         int                     i, j;
690         int                     rows, pages;
691         struct  tm              tm;
692         int                     day, ndays, num_appts, max = 0;
693         CSA_uint32              a_total;
694         time_t                  start, stop;
695         CSA_entry_handle        *list;
696         CSA_attribute           *range_attrs;
697         CSA_enum                *ops;
698         _Xltimeparams           localtime_buf;
699
700         tm    = *_XLocaltime(&start_date, localtime_buf);
701         tm.tm_mday = 1;
702 #ifdef SVR4
703         tm.tm_isdst = -1;
704         day   = (int)mktime(&tm);
705 #else
706         day   = (int)timelocal(&tm);
707 #endif /* SVR4 */
708         ndays = ((tm.tm_mon==1) && leapyr(tm.tm_year+1900))? 29 :
709                         monthdays[tm.tm_mon];
710  
711         /* print days of the week at the top */
712         rows = numwks (start_date);
713  
714         /* need minimum 5 rows to paint miniature months */
715         if (rows == 4) rows++;
716  
717         /* print the times and text of appts */
718         for (i = 1; i <= ndays; i++)
719         {
720                 /* setup a time limit for appts searched */
721                 start = (time_t) lowerbound (day);
722                 stop = (time_t) next_ndays(day, 1) - 1;
723                 setup_range(&range_attrs, &ops, &j, start, stop,
724                             CSA_TYPE_EVENT, NULL, B_FALSE,
725                             c->general->version);
726                 csa_list_entries(c->cal_handle, j, range_attrs, ops,
727                                  &a_total, &list, NULL);
728                 free_range(&range_attrs, &ops, j);
729
730                 num_appts = count_month_appts(list, a_total, c);
731                 if (num_appts > max)
732                         max = num_appts;
733  
734                 day = nextday(day);
735                 csa_free(list);
736         }
737  
738  
739         pages = max / lines_per_box;
740         if ((max % lines_per_box) > 0)
741                 pages++;
742
743         return(pages);   
744 }
745
746  
747 static Boolean
748 print_month ( Calendar *c,
749     int num_page,
750     void *xp,
751     Tick first_date,
752     Props *p,
753     Boolean first)
754 {
755         int             rows, i, j, lines_per_box;
756         time_t          lo_hour, hi_hour;
757         char            buf[50];
758         int             ndays, num_appts;
759         Boolean         more, done = False, all_done = True;
760         Tick            day;
761         OrderingType    ot = get_int_prop(p, CP_DATEORDERING);
762         CSA_entry_handle *list;
763         CSA_attribute   *range_attrs;
764         CSA_enum        *ops;
765         CSA_uint32      a_total;
766         static Tick     tick = 0;
767         static int      total_pages;
768
769         if (first)
770                 tick = first_date;
771         if (num_page > 1)
772                 tick = prevmonth_exactday(tick);
773  
774         /* print days of the week at the top */
775         rows = numwks (tick);
776  
777         /* need minimum 5 rows to paint miniature months */
778         if (rows == 4) rows++;
779
780         x_init_printer(xp, LANDSCAPE);
781         x_init_month(xp, rows);
782         lines_per_box = x_get_month_lines_per_page(xp);
783
784         if (num_page == 1)
785           total_pages = (lines_per_box > 0) ?
786             count_month_pages(c, tick, lines_per_box) : 1;
787
788         day = first_dom(tick);
789         ndays = monthlength(tick);
790  
791         /* print month & year on top */
792         format_date(tick, ot, buf, 0, 0, 0);
793
794         x_print_header(xp, buf, num_page, total_pages);
795         x_month_daynames(xp, rows);
796  
797         /* print the times and text of appts */
798         for (i = 1; i <= ndays; i++)
799         {
800           /* setup a time limit for appts searched */
801           lo_hour = (time_t)lowerbound (day);
802           hi_hour = (time_t) next_ndays(day, 1) - 1;
803           setup_range(&range_attrs, &ops, &j, lo_hour, hi_hour,
804                       CSA_TYPE_EVENT, NULL, B_FALSE, c->general->version);
805           csa_list_entries(c->cal_handle, j, range_attrs,
806                            ops, &a_total, &list, NULL);
807           free_range(&range_attrs, &ops, j);
808           num_appts = count_month_appts(list, a_total, c);
809           if ((lines_per_box > 0) &&
810               (num_appts > (lines_per_box * num_page)))
811             more = True;
812           else
813             more = False;
814
815           x_month_timeslots(xp, day, more);
816
817           /* print out times and appts */
818           if (lines_per_box > 0)
819             done = x_print_month_appts(xp, list, a_total, num_page,
820                                        hi_hour, lines_per_box);
821           else done = True;
822
823           if (!done)
824             all_done = False;
825
826           day = nextday(day);
827           csa_free(list);
828         }
829
830         /* paint miniature previous & next month */
831         x_print_little_months(xp, tick);
832         x_finish_printer(xp);
833
834         tick = nextmonth(tick);
835          
836         return(all_done);
837 }
838
839 extern void
840 print_month_range(Calendar *c, Tick start_tick, Tick end_tick)
841 {
842         Props           *p = (Props *)c->properties;
843         register Tick   end, first_date = start_tick;
844         int             n;
845         Boolean         done = False, first = True;
846         int             num_page = 1;
847         void            *xp = (void *)NULL;
848
849         /* counting up the month pages is a little trickier than in the day
850            and week cases.  Months will have variable numbers of seconds in 
851            them, simple dividing the difference by the number of seconds
852            per month doesn't work.  We'll brute force this by grinding thru,
853            adding seconds until we pass the end tick time. */
854
855         end_tick = last_dom(end_tick);
856         end = last_dom(start_tick);
857         for (n = 1; end < end_tick; n++)
858           end = last_dom(nextmonth(end));
859
860         if ((xp = x_open_file(c)) == (void *)NULL)
861           return;
862
863         for (; n > 0; n--)
864         {
865           while (!done)
866           {
867             done = print_month(c, num_page, xp,
868                                first_date, p, first);
869             num_page++;
870             first = False;
871           }
872
873           done = False;
874           num_page = 1;
875         }
876
877         x_print_file(xp, c);
878 }
879
880 static int 
881 count_month_appts(CSA_entry_handle *list, int a_total, Calendar *c)
882 {
883         int                     count = 0, i, meoval;
884         Props                   *pr = (Props*)c->properties;
885         Dtcm_appointment        *appt;
886         CSA_return_code         stat;
887  
888         meoval = get_int_prop(pr, CP_PRINTPRIVACY);
889  
890         appt = allocate_appt_struct(appt_read, 
891                                         c->general->version,
892                                         CSA_ENTRY_ATTR_CLASSIFICATION_I, 
893                                         NULL);
894         for (i = 0; i < a_total; i++) {
895
896                 stat = query_appt_struct(c->cal_handle, list[i], appt);
897                 if (stat != CSA_SUCCESS) {
898                         free_appt_struct(&appt);
899                         return 0;
900                 }
901
902                 if ((privacy_set(appt) == CSA_CLASS_PUBLIC) && !(meoval & PRINT_PUBLIC))
903                         continue;
904                 else if ((privacy_set(appt) == CSA_CLASS_CONFIDENTIAL) && !(meoval & PRINT_SEMIPRIVATE))
905                         continue;
906                 else if ((privacy_set(appt) == CSA_CLASS_PRIVATE) && !(meoval & PRINT_PRIVATE))
907                         continue;
908
909
910                 count++;
911         }
912         free_appt_struct(&appt);
913         return(count);
914 }        
915
916 /*
917  * Handler for "hot" buttons to navigate to day view
918  * Client data is index of activated button [0..30]
919  */
920 static void
921 quick_button_cb(Widget widget, XtPointer client, XtPointer call)
922 {
923         Calendar *c = calendar;
924         int      dom = (int) client;
925
926         c->view->olddate = c->view->date;
927         c->view->date = next_ndays(first_dom(c->view->date), dom);
928
929         calendar_select(c, daySelect, NULL);
930  
931         cleanup_after_monthview(c);
932         
933         c->view->glance = dayGlance;
934         init_mo(c);
935         (void)init_dayview(c);
936
937         paint_day(c);
938 }
939
940 /*
941  * Handle positioning and managing of hotbuttons
942  *
943  * IMPORTANT: This function assumes that it is being called during the
944  *      Resize method of the canvas (XmDrawingArea), and for that reason
945  *      it is effectively widget code and can legally call XtMoveWidget.
946  *      Don't try this at home !    (and never from non-widget code)
947  *
948  * Also, this needs to be called *after* paint_month, as it relies on data
949  * calculated there and stores in the month data structure.
950  */
951 extern void
952 layout_children(Calendar *c)
953 {
954         Month   *m = (Month *)c->view->month_info;
955         Widget  *btns = m->hot_button;
956         int     i;
957
958         /* Position required navigator buttons  - note that if they're
959            mapped when this happens, many exposes will occur */
960         for (i=0; i < m->ndays; i++)
961                 XtMoveWidget(btns[i], m->button_loc[i].x, m->button_loc[i].y);
962
963         /* Unmanage any unneeded navigator buttons (ie. 29, 30, 31) */
964         for (i=m->ndays; i<31; i++)
965                 if (XtIsManaged(m->hot_button[i]))
966                         XtUnmanageChild(m->hot_button[i]);
967 }
968
969 static void
970 manage_children(Calendar *c)
971 {
972         int     i;
973         Month   *m = (Month *)c->view->month_info;
974  
975         /* manage the header widget */
976         XtManageChild(m->month_label);
977         XtManageChildren(m->hot_button, m->ndays);
978 }
979
980 static void
981 unmanage_children(Calendar *c)
982 {
983         int     i;
984         Month   *m = (Month *)c->view->month_info;
985  
986         /* unmanage the header widget */
987         XtUnmanageChild(m->month_label);
988         XtUnmanageChildren(m->hot_button, 31);
989 }
990
991 /*
992  * Clean up anything left around that won't be removed on
993  * switching to another view, such as the hot buttons for
994  * navigation to day view.
995  */
996 extern void
997 cleanup_after_monthview(Calendar *c)
998 {
999
1000         invalidate_cache(c);
1001
1002         XtUnmapWidget(c->canvas);
1003         unmanage_children(c);
1004
1005         XmToggleButtonGadgetSetState(c->month_scope, False, False);
1006
1007         /*
1008          * Deallocating everything causes all this view's memory to be
1009          * freed (at least all we have allocated in this application)
1010          * at the expense of rebuilding the view next time it is used.
1011          * Commenting it out improves usability and avoids any risk
1012          * of memory leakage from Xt and Motif.
1013          */
1014 /*
1015         deallocator(c);
1016 */
1017
1018         XtMapWidget(c->canvas);
1019 }
1020
1021 /*
1022  * check whether month view is allocated yet
1023  */
1024 static Boolean
1025 allocated(Calendar *c)
1026 {
1027   return (c->view->month_info != NULL);
1028 }
1029
1030 /*
1031  * allocate storage & subwidgets used by month view
1032  */ static void 
1033 allocator(Calendar *c)
1034 {
1035         int     n;
1036         char    buf[BUFSIZ];
1037         Month   *m;
1038         XmString str;
1039
1040         /* main storage for other month data */
1041         calendar->view->month_info = (caddr_t) ckalloc(sizeof(Month));
1042         m = (Month *)c->view->month_info;
1043
1044         m->button_loc = (XPoint *) ckalloc(31 * sizeof(XPoint));
1045
1046         /* label for month & navigation button to year */
1047         m->month_label = XmCreateLabel(c->canvas, "monthLabel", NULL, 0);
1048         
1049         /* navigation buttons to day view */
1050         m->hot_button = (Widget *) ckalloc(31 * sizeof(Widget));
1051         for (n=0; n<31; n++) {
1052                 sprintf(buf, "%d", n+1);
1053                 str = XmStringCreateLocalized(buf);
1054                 sprintf(buf, "month2day%d", n);
1055                 m->hot_button[n] =
1056                         XmCreatePushButton(c->canvas, buf, NULL, 0);
1057                 XtVaSetValues(m->hot_button[n], XmNlabelString, str, NULL);
1058                 XtAddCallback(m->hot_button[n],XmNactivateCallback, 
1059                         quick_button_cb, (XtPointer)n);
1060                 XmStringFree(str);
1061         }
1062 }
1063
1064 /*
1065  * (Not in service)
1066  * allocate storage & subwidgets used by month view
1067  */
1068 static void 
1069 deallocator(Calendar *c)
1070 {
1071         Month   *m = (Month *)c->view->month_info;
1072         int     n;
1073
1074         /* free cache of points for buttons positions */
1075         free(m->button_loc);
1076
1077         /* destroy widgets used for header */
1078         XtDestroyWidget(m->month_label);
1079
1080         /* hot buttons */
1081         for (n=0; n<31; n++)
1082                 XtDestroyWidget(m->hot_button[n]);
1083
1084         /* array that held navigation buttons */
1085         free(m->hot_button);
1086
1087         /* structure holding month information */
1088         free(m);
1089         c->view->month_info = NULL;
1090 }