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