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