Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtcm / dtcm / dtcm_editor.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 /* $TOG: dtcm_editor.c /main/14 1999/09/20 10:32:17 mgreess $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <Xm/XmAll.h>
36 #include <Dt/EnvControlP.h>
37 #include <Dt/Dnd.h>
38 #include <Dt/Icon.h>
39 #include <Dt/UserMsg.h>
40 #include <Tt/tttk.h>
41 #include <csa.h>
42 #include "calendar.h"
43 #include "props.h"
44 #include "props_pu.h"
45 #include "dssw.h"
46 #include "rfp.h"
47 #include "dnd.h"
48 #include "util.h"
49 #include "cm_tty.h"
50 #include <nl_types.h>
51 #include <locale.h>
52 #if !defined(NL_CAT_LOCALE)
53 #define NL_CAT_LOCALE       0
54 #endif
55
56 int debug = 0;
57 static Tt_message load_cb();
58
59 static const char *ptype = "Dt_AppointmentEditor";
60
61 typedef enum {no_tt, file_tt, buffer_tt} Dtcm_editor_start;
62
63 /* Absolute value macro */
64 #ifndef ABS
65 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
66 #endif
67  
68
69 #include "drag_xbm"
70 #include "drag_mask_xbm"
71
72 /*
73 **  Structure for stand-alone editor
74 */
75 typedef struct {
76         Widget          attach_button;
77         Calendar        *c;
78         DSSW            *dssw;
79         char            *file;
80         char            *vtype;
81         Dtcm_editor_start init;
82         Boolean         read_only;
83         Tt_pattern      *contract_pats;
84         Tt_message      contract;
85         Widget          form;
86         Props           *p;
87         Props_pu        *pu;
88         Widget          reset_button;
89         RFP             *rfp;
90         Widget          top_level;
91         Boolean         modified;
92         Dtcm_appointment *orig_appt;
93         Widget          drag_source;
94         int             initialX;
95         int             initialY;
96         Boolean         doing_drag;
97         Widget          drag_icon;
98         Pixmap          drag_bitmap;
99         Pixmap          drag_mask;
100         int             dsswFlags;
101         int             rfpFlags;
102 } DTCM_editor;
103
104 static void de_apply_proc(Widget , XtPointer , XtPointer );
105
106 /*
107 **  Hate like hell to make this global, but I can find no way to get at it
108 **  when I need it in other methods ...
109 **
110 **  Also, help uses a global reference to calendar which hoses us ...
111 */
112 XtAppContext    app;
113 Calendar        *calendar;
114
115 static void
116 de_mark_change(Widget w, XtPointer data, XtPointer cbs) {
117  
118         DTCM_editor        *de = (DTCM_editor *)data;
119
120         de->modified = True;
121
122         if ((w == de->dssw->start_text) ||
123             (w == de->dssw->start_am) ||
124             (w == de->dssw->start_pm) ||
125             (w == de->dssw->stop_text) ||
126             (w == de->dssw->stop_am) ||
127             (w == de->dssw->stop_pm))
128           de->dsswFlags = 0;
129
130         if (w == de->rfp->repeat_menu)
131           de->rfpFlags = 0;
132 }
133
134 static void
135 merge_old_values(Dtcm_appointment *original, Dtcm_appointment *new) {
136
137         /* This routine takes in the original appointment structure 
138            from the edited appointment, and merges back in any attributes 
139            that aren't controlled by our editor, so that when the 
140            appointment is written back out to the buffering agent, those 
141            attributes are not lost. */
142
143         int     source_count, dest_count, new_attrs;
144         int     dest_attr_num = new->count;
145         Boolean found;
146
147         if (original == NULL)
148                 return;
149         
150         /* We need to see how much larger the attribute array needs to 
151            get.  For each of the guys in the source attribute array, 
152            we need to look and see if it's already a member of the 
153            destination array.  Those that don't exist, we count, and 
154            later move. */
155
156         for (source_count = 0, new_attrs = 0; source_count < original->count; source_count++) {
157                 found = False;
158                 for (dest_count = 0; dest_count < dest_attr_num; dest_count++) {
159                         if (original->attrs[source_count].name && new->attrs[dest_count].name) {
160                                 if (strcmp(original->attrs[source_count].name, new->attrs[dest_count].name) == 0) {
161                                         found = True;
162                                         break;
163                                 }
164                         }
165                 }
166
167                 if (found == False)
168                         new_attrs++;
169         }
170
171         if (new_attrs == 0)
172                 return;
173
174         /* realloc the attrs array to be large enough to accommodate the new
175            attibutes */
176
177         new->attrs = (CSA_attribute *) realloc(new->attrs, (dest_attr_num + new_attrs) * sizeof(CSA_attribute));
178
179         /* Copy in the new attribute values */
180         for (source_count = 0; source_count < original->count; source_count++) {
181                 found = False;
182                 for (dest_count = 0; dest_count < new->count; dest_count++) {
183                         if (original->attrs[source_count].name && new->attrs[dest_count].name) {
184                                 if (strcmp(original->attrs[source_count].name, new->attrs[dest_count].name) == 0) {
185                                         found = True;
186                                         break;
187                                 }
188                         }
189                 }
190
191                 if (found == False)
192                 {
193                         new->attrs[new->count] = original->attrs[source_count];
194                         new->count++;
195                 }
196         }
197
198         /* reset the appointment links, as the old ones have been 
199            thrashed by reallocing the attribute array. */
200
201         set_appt_links(new);
202 }
203
204 Widget
205 CreateDragSourceIcon(
206         Widget          widget,
207         Pixmap          pixmap,
208         Pixmap          mask)
209 {
210         Widget          dragIcon;
211         Window          rootWindow;
212         int             pixmapX, pixmapY;
213         unsigned int    pixmapWidth, pixmapHeight, pixmapBorder, pixmapDepth;
214         Arg             args[20];
215         Cardinal        nn = 0;
216  
217         XGetGeometry (XtDisplayOfObject(widget), pixmap, &rootWindow,
218                 &pixmapX, &pixmapY, &pixmapWidth, &pixmapHeight,
219                 &pixmapBorder, &pixmapDepth);
220  
221         XtSetArg(args[nn], XmNwidth, pixmapWidth);  nn++;
222         XtSetArg(args[nn], XmNheight, pixmapHeight);  nn++;
223         XtSetArg(args[nn], XmNmaxWidth, pixmapWidth);  nn++;
224         XtSetArg(args[nn], XmNmaxHeight, pixmapHeight);  nn++;
225         XtSetArg(args[nn], XmNpixmap, pixmap);  nn++;
226         XtSetArg(args[nn], XmNmask, mask);  nn++;
227         XtSetArg(args[nn], XmNdepth, pixmapDepth);  nn++;
228         dragIcon = XmCreateDragIcon(widget, "sourceIcon", args, nn);
229
230         return(dragIcon);
231 }
232
233 /*
234  * getIcon
235  *
236  * Returns a new IconInfo structure with bitmap, mask, width, height,
237  * icon type and name.
238  */
239 static void
240 GetIcon(DTCM_editor *de)
241 {
242  
243         Display        *display = XtDisplay(calendar->frame);
244         Window          window = XtWindow(calendar->frame);
245         unsigned char  *bitmapData, *bitmapMask;
246  
247         if (de->drag_bitmap == 0) {
248                 de->drag_bitmap = XCreateBitmapFromData(display,
249                         window, (char *) drag_xbm_bits,
250                         drag_xbm_width, drag_xbm_height);
251                 if (de->drag_bitmap == 0) {
252
253                         printf("%s", catgets(calendar->DT_catd, 1, 237, "XCreateBitmapFromData() failed for bitmap.\n"));
254                         return;
255                 }
256         }
257         if (de->drag_mask == 0) {
258                 de->drag_mask = XCreateBitmapFromData(display,
259                         window, (char *) drag_mask_xbm_bits,
260                         drag_mask_xbm_width, drag_mask_xbm_height);
261                 if (de->drag_mask == 0) {
262                         printf("%s", catgets(calendar->DT_catd, 1, 238, "XCreateBitmapFromData() failed for mask.\n"));
263                         return;
264                 }
265         }
266 }
267  
268  
269 /*
270  * DragFinishCB
271  *
272  * Resets drag state to indicate the drag is over. Free memory allocated
273  * with the drag.
274  */
275 static void
276 DragFinishCB(
277         Widget          widget,
278         XtPointer       clientData,
279         XtPointer       callData)
280 {
281         DragContext     *context = (DragContext *) clientData;
282
283         if (!context)
284                 return;
285
286         if (context->editor_type == StandAloneEditor)
287             ((DTCM_editor *) context->editor)->doing_drag = False;
288
289         if (context->data)
290             free(context->data);
291
292         free(context);
293 }
294
295 /*
296  * ApptConvertCB
297  *
298  * Fills in data object with calendar appointment string based on which
299  * appointment in the list was under the pointer when the drag started.
300  */
301 static void
302 ApptConvertCB(
303         Widget          dragContext,
304         XtPointer       clientData,
305         XtPointer       callData)
306 {
307         DtDndConvertCallbackStruct *convertInfo 
308                                         = (DtDndConvertCallbackStruct*)callData;
309         DtDndBuffer     *data           = &(convertInfo->dragData->data.buffers[0]);
310         DragContext     *context        = (DragContext *)clientData;
311         Display         *display        = XtDisplay(dragContext);
312         Atom            CMAPPOINTMENT   
313                         = XmInternAtom(display, "CalendarAppointment", False);
314         Calendar        *c = context->calendar;
315
316         if (convertInfo->reason != DtCR_DND_CONVERT_DATA)
317                 return;
318
319         /* REMIND: Need to check convertInfo->reason, handle DELETE, etc */
320
321         data->bp   = XtNewString(context->data);
322         data->size = strlen(data->bp);
323         data->name = XtNewString(catgets(c->DT_catd, 1, 236, "CalendarAppointment"));
324 }
325
326 void
327 StandaloneApptDragStart(
328         Widget          widget,
329         XEvent          *event,
330         DTCM_editor     *de,
331         EditorType      editor_type)
332 {
333         static XtCallbackRec convertCBRec[] = { {ApptConvertCB, NULL},
334                                                 {NULL, NULL} };
335         static XtCallbackRec dragFinishCBRec[] =  { {DragFinishCB, NULL},
336                                                     {NULL, NULL} };
337  
338         Display        *display         = XtDisplay(widget);
339         int             itemCount, selectedPos;
340         DragContext     *context = calloc(sizeof(DragContext), 1);
341         Calendar        *c = de->c;
342         Dtcm_appointment        *appt;
343         int             old_attr_count;
344         char            *apptstr;
345         int             preDsswFlags, preRfpFlags;
346         char            *attrstring = NULL;
347
348         /* Convert appointment into string.  If not successful, don't start drag. */
349         appt = allocate_appt_struct(appt_write, DATAVER_ARCHIVE, NULL);
350         load_appt_defaults(appt, de->p);
351         preDsswFlags = de->dsswFlags;
352         preRfpFlags = de->rfpFlags;
353         if (!dssw_form_flags_to_appt(de->dssw, appt, de->c->calname,
354                                      now(), &de->dsswFlags) ||
355             !rfp_form_flags_to_appt(de->rfp, appt, de->c->calname,
356                                     &de->rfpFlags) ||
357             (preDsswFlags != de->dsswFlags) ||
358             (preRfpFlags != de->rfpFlags))
359         {
360             de->doing_drag = False;
361             free_appt_struct(&appt);
362             free(context);
363             return;
364         }
365
366         /* save the old count of attributes so that when this appointment 
367            gets freed, we can prevent the added attribute references from 
368            being freed. */
369
370         old_attr_count = appt->count;
371         merge_old_values(de->orig_appt, appt);
372         attrstring = attrs_to_string(appt->attrs, appt->count);
373         apptstr = parse_attrs_to_string(appt, de->p, attrstring);
374         free(attrstring);
375         appt->count = old_attr_count;
376         free_appt_struct(&appt);
377
378         context->data = apptstr;
379         context->calendar = c;
380         context->editor_type = editor_type;
381         context->editor = (caddr_t) de;
382  
383         GetIcon(de);
384  
385         convertCBRec[0].closure = (XtPointer)context;
386         dragFinishCBRec[0].closure = (XtPointer)context;
387  
388         if (de->drag_icon == NULL) {
389                 de->drag_icon = CreateDragSourceIcon(widget, de->drag_bitmap, de->drag_mask);
390         }
391  
392         if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, 1,
393                 XmDROP_COPY, 
394                 convertCBRec, dragFinishCBRec,
395                 DtNsourceIcon,          de->drag_icon,
396                 NULL)
397             == NULL) {
398  
399                 printf("%s", catgets(c->DT_catd, 1, 239, "DragStart returned NULL.\n"));
400         }
401 }
402
403 /*
404  * dragMotionHandler
405  *
406  * Determine if the pointer has moved beyond the drag threshold while button 1
407  * was being held down.
408  */
409 static void
410 EditApptDragMotionHandler(
411         Widget          dragInitiator,
412         XtPointer       clientData,
413         XEvent         *event)
414 {
415         int             diffX, diffY;
416         DTCM_editor     *de = (DTCM_editor *) clientData;
417         Calendar        *c = de->c;
418         Dimension       source_height, source_width;
419         Position        source_x, source_y;
420  
421         if (!de->doing_drag) {
422
423                 /* check to see if the iniital value was within the
424                    bounds for the drag source icon. */
425  
426                 XtVaGetValues(de->drag_source,
427                                 XmNx, &source_x,
428                                 XmNy, &source_y,
429                                 XmNheight, &source_height,
430                                 XmNwidth, &source_width,
431                                 NULL);
432  
433                 if ((event->xmotion.x < source_x) ||
434                     (event->xmotion.y < source_y) ||
435                     (event->xmotion.x > (int) (source_x + source_width)) ||
436                     (event->xmotion.y > (int) (source_y + source_height)))
437                         return;
438  
439
440                 /*
441                  * If the drag is just starting, set initial button down coords
442                  */
443                 if (de->initialX == -1 && de->initialY == -1) {
444                         de->initialX = event->xmotion.x;
445                         de->initialY = event->xmotion.y;
446                 }
447                 /*
448                  * Find out how far pointer has moved since button press
449                  */
450                 diffX = de->initialX - event->xmotion.x;
451                 diffY = de->initialY - event->xmotion.y;
452  
453                 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
454                     (ABS(diffY) >= DRAG_THRESHOLD)) {
455                         de->doing_drag = True;
456                         StandaloneApptDragStart(dragInitiator, event, de, StandAloneEditor);
457                         de->initialX = -1;
458                         de->initialY = -1;
459                 }
460         }
461 }
462
463 /*
464 **  Static callbacks
465 */
466 static void
467 de_quit_handler(Widget w, XtPointer cdata, XtPointer data) {
468         DTCM_editor *de = (DTCM_editor *)cdata;
469         int answer;
470
471         if (de->modified == True) {
472                 char *title = XtNewString(catgets(de->c->DT_catd, 1, 1008, "Calendar Appointment : Help"));
473                 char *text = XtNewString(catgets(de->c->DT_catd, 1, 451, "You have made unsaved changes.\nYou may save your changes, discard your changes, \nor return to your previous place in the dialog."));
474                 char *ident1 = XtNewString(catgets(de->c->DT_catd, 1, 452, "Save"));
475                 char *ident2 = XtNewString(catgets(de->c->DT_catd, 1, 700, "Discard"));
476                 char *ident3 = XtNewString(catgets(de->c->DT_catd, 1, 923, "Cancel"));
477                 answer = dialog_popup(de->top_level,
478                         DIALOG_TITLE, title,
479                         DIALOG_TEXT, text,
480                         BUTTON_IDENT, 1, ident1,
481                         BUTTON_IDENT, 2, ident2,
482                         BUTTON_IDENT, 3, ident3,
483                         DIALOG_IMAGE, de->pu->xm_warning_pixmap,
484                         NULL);
485                 XtFree(ident3);
486                 XtFree(ident2);
487                 XtFree(ident1);
488                 XtFree(text);
489                 XtFree(title);
490
491                 if (answer == 1) {
492                         de_apply_proc(NULL, (XtPointer)de, NULL);
493                         XtPopdown(de->top_level);
494                 }
495                 else  if (answer == 2) {
496                         if (de->contract)
497                                 tttk_message_fail(de->contract, TT_DESKTOP_ECANCELED, NULL, True);
498                         XtPopdown(de->top_level);
499                 }
500                 else  if (answer == 3) {
501                         return;
502                 }
503
504         }
505         else {
506                 if (de->contract)
507                         tttk_message_fail(de->contract, TT_DESKTOP_ECANCELED, NULL, True);
508                 XtPopdown(de->top_level);
509         }
510
511         free(de->c);
512         free(de->dssw);
513         if (de->file)
514                 free(de->file);
515         free(de->p);
516         free(de->pu);
517         free(de->rfp);
518         free(de);
519         exit(0);
520 }
521
522 static void
523 load_from_file(DTCM_editor *de) {
524         int                     i;
525         CmDataList              *list = NULL;
526         Dtcm_appointment        *appt;
527
528         list = CmDataListCreate();
529         parse_appt_from_file(de->c->DT_catd, de->file, list, de->p, 
530                              query_user, de->c, DATAVER_ARCHIVE);
531         if (appt = (Dtcm_appointment *)CmDataListGetData(list, 1)) {
532                 dssw_attrs_to_form(de->dssw, appt);
533                 rfp_attrs_to_form(de->rfp, appt);
534         }
535         for (i = 1; i <= list->count; i++)
536                 if (appt = (Dtcm_appointment *)
537                     CmDataListGetData(list, i)) {
538                         if (de->orig_appt)
539                                 free_appt_struct(&de->orig_appt);
540
541                         de->orig_appt = appt;
542                 }
543         CmDataListDestroy(list, B_FALSE);
544         de->dsswFlags = de->rfpFlags = 0;
545 }
546
547 static void
548 de_set_defaults(DTCM_editor *de) {
549
550         if (de->file && (access(de->file, R_OK) == 0)) {
551                 load_from_file(de);
552         } else {
553                 set_dssw_defaults(de->dssw, now(), True);
554                 set_rfp_defaults(de->rfp);
555                 de->dsswFlags = de->rfpFlags = 0;
556         }
557
558         de->modified = False;
559 }
560
561 static void
562 de_apply_proc(Widget w, XtPointer client_data, XtPointer data) {
563         char                    *str;
564         FILE                    *fp;
565         DTCM_editor             *de = (DTCM_editor *)client_data;
566         Dtcm_appointment        *appt;
567         int                     old_attr_count;
568         Display                 *dpy = XtDisplayOfObject(w);
569         char                    *attrstring = NULL;
570
571         appt = allocate_appt_struct(appt_write, 
572                                         DATAVER_ARCHIVE,
573                                         NULL);
574         load_appt_defaults(appt, de->p);
575         de->dsswFlags = 0;
576         dssw_form_to_appt(de->dssw, appt, de->c->calname, now());
577         de->rfpFlags = 0;
578         rfp_form_to_appt(de->rfp, appt, de->c->calname);
579
580         /* save the old count of attributes so that when this appointment 
581            gets freed, we can prevent the added attribute references from 
582            being freed. */
583
584         old_attr_count = appt->count;
585         merge_old_values(de->orig_appt, appt);
586         attrstring = attrs_to_string(appt->attrs, appt->count);
587         str = parse_attrs_to_string(appt, de->p, attrstring);
588         free(attrstring);
589         appt->count = old_attr_count;
590         de->modified = False;
591
592         if (!str) {
593                 free_appt_struct(&appt);
594                 return;
595         }
596
597         /* we need to distinguish between whether the data is being 
598            saved as part of application termination, or as part of 
599            pressing the "Apply" button.  If it's is app termination, 
600            we need to call ttmedia_load_reply, and if it is an 
601            intermediate save, we are supposed to call ttmedia_Deposit.  
602            Hmmph.  We also need to be pretty clear about saving it back 
603            in the same fashion is was supplied.  If it came as part of 
604            a buffer, it needs to go back that way. */
605
606
607         /* The first case is from application exit */
608
609         if (w == NULL) {
610
611                 /* if it was a file transfer, we should write out the 
612                    file, and set the buffer to null.  If it came from 
613                    a buffer, we don't bother to write out the file. */
614
615                 if (de->read_only) {
616                         ttmedia_load_reply(de->contract, NULL, 0, True);
617                 }
618                 else {
619                         if (de->init == file_tt) {
620                                 fp = fopen(de->file, "w");
621
622                                 if (!fp) {
623                                         XBell(dpy, 50);
624                                         free(str);
625                                         free_appt_struct(&appt);
626                                         return;
627                                 }
628
629                                 fprintf(fp, "%s", str);
630                                 fclose(fp);
631                                 ttmedia_load_reply(de->contract, NULL, 0, True);
632                         }
633                         else {
634                                 ttmedia_load_reply(de->contract, (unsigned char *) str, strlen(str), True);
635                         }
636                 }
637         }
638         else {
639
640                 /* This case is from the "Apply" button.  In this case, 
641                    if the app was started normally (no tt), then we 
642                    just write out the file.  If it was from tt, we then 
643                    use ttmedia_Deposit to send the data back. */
644
645                 if ((de->init == no_tt) || (de->init == file_tt)) {
646                         fp = fopen(de->file, "w");
647
648                         if (!fp) {
649                                 XBell(dpy, 50);
650                                 free(str);
651                                 free_appt_struct(&appt);
652                                 return;
653                         }
654
655                         fprintf(fp, "%s", str);
656                         fclose(fp);
657
658                         if (de->init == file_tt)
659                                 ttmedia_Deposit(de->contract,
660                                                 NULL,
661                                                 de->vtype,
662                                                 NULL,
663                                                 0,
664                                                 de->file,
665                                                 app,
666                                                 30000);
667                 }
668                 else {
669                         ttmedia_Deposit(de->contract,
670                                         NULL,
671                                         de->vtype,
672                                         (const unsigned char *)str,
673                                         strlen(str),
674                                         NULL,
675                                         app,
676                                         30000);
677                 }
678
679         }
680
681         free(str);
682         free_appt_struct(&appt);
683 }
684
685 static void
686 de_reset_proc(Widget w, XtPointer client_data, XtPointer data) {
687         DTCM_editor     *de = (DTCM_editor *)client_data;
688
689         de_set_defaults(de);
690         de->dsswFlags = de->rfpFlags = 0;
691 }
692
693 static void
694 display_command_usage(void)
695 {
696         fprintf(stderr, "\ndtcm_editor Usage:  dtcm [filename]\n\n");
697         exit(0);
698 }
699
700 static void
701 OKCB (Widget dialog, XtPointer client_data, XtPointer call_data)
702 {
703     XtUnmanageChild((Widget) client_data);
704 }
705
706 void
707 DieFromToolTalkError(DTCM_editor *de, char *errfmt, Tt_status status)
708 {
709     Arg          args[10];
710     Widget       dialog, dialogShell;
711     char        *errmsg, *statmsg, *title;
712     XmString     xms_errmsg, xms_ok, xms_title;
713     int          n;
714
715     if (! tt_is_err(status)) return;
716
717     statmsg = tt_status_message(status);
718     errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
719     sprintf(errmsg, errfmt, statmsg);
720
721     xms_ok = XmStringCreateLocalized(catgets(de->c->DT_catd, 2, 3, "OK"));
722     xms_errmsg = XmStringCreateLocalized(errmsg);
723     xms_title = XmStringCreateLocalized(catgets(de->c->DT_catd, 2, 4,
724                         "Calendar : Appointment Editor - Warning"));
725
726     n = 0;
727     XtSetArg(args[n], XmNautoUnmanage, False); n++;
728     XtSetArg(args[n], XmNokLabelString, xms_ok); n++;
729     XtSetArg(args[n], XmNdialogTitle, xms_title); n++;
730     XtSetArg(args[n], XmNmessageString, xms_errmsg); n++;
731     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
732     XtSetArg(args[n], XmNdialogType, XmDIALOG_WARNING); n++;
733
734     dialog = XmCreateMessageDialog(de->top_level, "IconEditorError", args, n);
735     XtAddCallback(dialog, XmNokCallback, OKCB, (XtPointer) dialog);
736     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
737     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
738
739     /*
740      * Disable the frame menu from dialog since we don't want the user
741      * to be able to close dialogs with the frame menu
742      */
743     dialogShell = XtParent(dialog);
744     n = 0;
745     XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MENU); n++;
746     XtSetValues(dialogShell, args, n);
747     XtManageChild(dialog);
748     XtRealizeWidget(dialogShell);
749
750     _DtSimpleError("Dtcm", DtWarning, NULL, errmsg);
751
752     XtFree(errmsg);
753     XmStringFree(xms_ok);
754     XmStringFree(xms_errmsg);
755     XmStringFree(xms_title);
756 }
757
758
759
760 /* 
761  * Initialize tooltalk.  Can be called multiple times: the first call
762  * initializes tooltalk, subsequent calls are no-ops.
763  *
764  * Returns
765  *              -1      Error.  Tooltalk not initialized
766  *              0       Tooltalk already initialized
767  *              1       Tooltalk succussfully intialized
768  */
769
770 Tt_status
771 cmtt_init(
772         char            *toolname,
773         DTCM_editor     *de,
774         XtAppContext    context,
775         Widget           shell)
776
777 {
778         static int      initialized = 0;
779         int             ttfd;
780         Tt_status       status;
781         char            *ttenv;
782         char            *session;
783
784         if (de->c->tt_procid) {
785                 return 0;
786         }
787
788         ttenv = (char *)getenv("TT_SESSION");
789         if (!ttenv || strlen(ttenv) == 0) {
790                 session = tt_X_session(XDisplayString(XtDisplay(shell)));
791                 tt_default_session_set(session);
792                 tt_free(session);
793         }
794
795         de->c->tt_procid = ttdt_open(&ttfd, toolname, "SunSoft", "%I", 1);
796         status = tt_ptr_error(de->c->tt_procid);
797         if (tt_is_err(status)) {
798                 de->c->tt_procid = NULL;
799                 return status;
800         }
801
802         /*
803          * Declare our ptype, and register the callback to handle
804          * Edit/Display/Compose requests
805          */
806         status = ttmedia_ptype_declare(ptype, 0, load_cb, (void *)de, 1);
807
808         if (tt_is_err(status)) {
809                 fprintf(stderr, "cmtt_init could not declare ptype: %s\n",
810                         tt_status_message(status));
811                 return status;
812         }
813
814         status = ttmedia_ptype_declare(ptype, 1000, load_cb, (void *)de, 0);
815
816         if (tt_is_err(status)) {
817                 fprintf(stderr, "cmtt_init could not declare ptype: %s\n",
818                         tt_status_message(status));
819         }
820
821         ttdt_session_join(0, NULL, shell, de->c, 1);
822
823         XtAppAddInput(context, ttfd, (XtPointer)XtInputReadMask,
824                         tttk_Xt_input_handler, de->c->tt_procid);
825
826         tttk_Xt_input_handler( 0, 0, 0 );
827
828         return TT_OK;
829 }
830
831 Tt_message
832 reply_cb(Tt_message m, 
833         void *c_data, 
834         Tttk_op op, 
835         unsigned char *contents, 
836         int len, 
837         char *file)
838 {
839         char *client_procID = tt_message_handler(m);
840         if ( debug && (client_procID != NULL) ) {
841                 fprintf(stderr, "DEBUG: reply_cb():client_procID = %s\n", client_procID);
842                 fprintf(stderr, "DEBUG: reply_cb():message_op = %s\n", tt_message_op(m));
843         }
844         return(m);
845 }
846
847 static Tt_message
848 contract_cb(
849         Tt_message      msg,
850         void            *clientdata,
851         Tt_message      contract)
852 {
853
854         /* For now do nothing 
855
856         switch (op) {
857         case TTDT_QUIT:
858         case TTDT_GET_STATUS:
859         case TTDT_PAUSE:
860         case TTDT_RESUME:
861                 break;
862         }
863 */
864         return msg;
865 }
866
867 /*
868  * Handle Edit, Display and Compose requests
869  */
870 static Tt_message
871 load_cb(
872         Tt_message      msg,
873         void            *clientdata,
874         Tttk_op         op,
875         Tt_status       diagnosis,
876         unsigned char   *contents,
877         int             len,
878         char            *file,
879         char            *docname
880 )
881
882 {
883         Tt_status status;
884         char    *p;
885         DTCM_editor     *de;
886         FILE            *fp;
887         char            filename[20];
888         CmDataList              *list = NULL;
889         Dtcm_appointment        *appt;
890         int             i;
891
892         de = (DTCM_editor *)clientdata;
893
894         de->vtype = strdup(tt_message_arg_type(msg, 0));
895
896         if (diagnosis != TT_OK) {
897                 if (tt_message_status(msg) == TT_WRN_START_MESSAGE) {
898                         /*
899                          * Error in start message!  we may want to exit
900                          * here, but for now let toolkit handle error
901                          */
902                          return msg;
903                 }
904
905                 /* Let toolkit handle the error */
906                 return msg;
907         }
908
909         de->contract_pats = ttdt_message_accept(msg, contract_cb, clientdata,
910                                                 de->c->frame, 1, 1);
911
912         tt_ptype_undeclare(ptype);
913
914         if ((status = tt_ptr_error(de->contract_pats)) != TT_OK) {
915                 fprintf(stderr, "dtcm: load_cb could not accept message: %s\n",
916                         tt_status_message(status));
917         } else {
918         /*
919                 tttk_patterns_destroy(de->contract_pats);
920         */
921         }
922
923         de->read_only = False;
924
925         switch (op) {
926
927         case TTME_COMPOSE:
928                         XtSetSensitive(de->attach_button, True);
929                         break;
930         case TTME_DISPLAY:
931         case TTME_EDIT:
932                         /* for Display only messages, the "Attach" 
933                            button makes no sense */
934
935                         if (op == TTME_EDIT)
936                                 XtSetSensitive(de->attach_button, True);
937                         else {
938                                 XtSetSensitive(de->attach_button, False);
939                                 de->read_only = True;
940                         }
941                         list = CmDataListCreate();
942                         if (file == NULL)
943                         {
944                                 /*
945                                  * Save data to a file so we can pass it to parse_appt_from_file
946                                  */
947                                 
948                                 strcpy(filename, "/tmp/cmXXXXXX");
949                                 mktemp(filename);
950                                 if ((fp = fopen(filename, "w")) == 0) {
951                                         tttk_message_fail( msg, TT_DESKTOP_ENODATA, 0, 1 );
952                                         return 0;
953                                 }
954
955                                 fwrite(contents, 1, len, fp);
956                                 fclose(fp);
957                                 parse_appt_from_file(de->c->DT_catd, filename, 
958                                                 list, de->p, query_user, 
959                                                 de->c, DATAVER_ARCHIVE);
960                                 unlink(filename);
961                                 de->init = buffer_tt;
962                         }
963                         else
964                         {
965                                 de->file = strdup(file);
966                                 parse_appt_from_file(de->c->DT_catd, de->file, 
967                                                 list, de->p, query_user, 
968                                                 de->c, DATAVER_ARCHIVE);
969                                 de->init = file_tt;
970                         }
971
972                         if (appt = (Dtcm_appointment *)CmDataListGetData(list, 1)) {
973                                 dssw_attrs_to_form(de->dssw, appt);
974                                 rfp_attrs_to_form(de->rfp, appt);
975                         }
976                         for (i = 1; i <= list->count; i++)
977                                 if (appt = (Dtcm_appointment *)
978                                 CmDataListGetData(list, i)) {
979                                         if (de->orig_appt)
980                                                 free_appt_struct(&de->orig_appt);
981
982                                         de->orig_appt = appt;
983                                 }
984                         CmDataListDestroy(list, B_FALSE);
985
986                         break;
987         }
988
989         de->contract = msg;
990         de->modified = False;
991         de->dsswFlags = de->rfpFlags = 0;
992
993         tt_free((caddr_t)contents);
994         tt_free(file);
995         tt_free(docname);
996
997         return 0;
998 }
999
1000 static void
1001 handle_drop_cb(
1002         Widget          w,
1003         XtPointer       client_data,
1004         XtPointer       call_data)
1005 {
1006         Display         *display = XtDisplay(w);
1007         DtDndDropCallbackStruct *transfer_info = (DtDndDropCallbackStruct *)call_data;
1008         DTCM_editor     *de;
1009         char            filename[20];
1010         char            *data;
1011         int             size;
1012         FILE            *fp;
1013         int             i;
1014
1015         de = (DTCM_editor *)client_data;
1016
1017         transfer_info->status = DtDND_SUCCESS;
1018
1019         for (i = 0; i < transfer_info->dropData->numItems; i++) {
1020                 switch(transfer_info->dropData->protocol) {
1021                 case DtDND_FILENAME_TRANSFER:
1022                         /* REMIND -- handle multiple filenames */
1023                         data = transfer_info->dropData->data.files[0];
1024         
1025                         de->file = strdup(data);
1026                         load_from_file(de);
1027                         break;
1028                 case DtDND_BUFFER_TRANSFER:
1029         
1030                         /*
1031                          * Save data to a file so we can pass it to drag_load_proc().
1032                          */
1033                         strcpy(filename, "/tmp/cmXXXXXX");
1034                         mktemp(filename);
1035         
1036                         if ((fp = fopen(filename, "w")) == 0) {
1037                                 transfer_info->status = DtDND_FAILURE;
1038                                 return;
1039                         }
1040         
1041                         data = transfer_info->dropData->data.buffers[0].bp;
1042                         size = transfer_info->dropData->data.buffers[0].size;
1043                         fwrite(data, 1, size, fp);
1044                         fclose(fp);
1045         
1046                         de->file = strdup(filename);
1047                         load_from_file(de);
1048         
1049                         unlink(filename);
1050                         break;
1051                 default:
1052                         transfer_info->status = DtDND_FAILURE;
1053                         return;
1054                 }
1055         }
1056
1057         return;
1058 }
1059
1060 void
1061 de_register_drop_site(
1062         DTCM_editor     *de,
1063         Widget          w,
1064         Boolean         registerchildren)
1065
1066 {
1067         XtCallbackRec   transfer_cb_rec[] = { {handle_drop_cb, NULL},
1068                                               {NULL, NULL} };
1069         Display         *display = XtDisplayOfObject(w);
1070
1071         transfer_cb_rec[0].closure = (XtPointer)de;
1072
1073         DtDndVaDropRegister(w, DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
1074                         XmDROP_COPY | XmDROP_MOVE,
1075                         transfer_cb_rec, 
1076                         DtNregisterChildren, registerchildren,  
1077                         NULL);
1078         return;
1079 }
1080
1081 /*
1082 **  Main line
1083 */
1084 int 
1085 main(int argc, char **argv) {
1086         int             dssw_loffset, rfp_loffset, start, stop;
1087         Dimension       dssw_x, rfp_x;
1088         DTCM_editor     *de;
1089         XmString        xmstr;
1090         Boolean         btn1_transfer;
1091         Dimension       width, longest_dssw_label, longest_rfp_label;
1092         WidgetList      children;
1093         Widget          widgets[20];
1094         int             i = 0;
1095         int             j = 0;
1096         int             n;
1097         char            *title;
1098         XmString        label_str;
1099         Tt_status       status;
1100
1101         de = (DTCM_editor *)ckalloc(sizeof(DTCM_editor));
1102         de->file = NULL;
1103
1104         if (argc > 1) {
1105                 if (strcasecmp(argv[1], "-h") == 0)
1106                         display_command_usage();
1107                 else if (argv[1][0] != '-')
1108                         de->file = cm_strdup(argv[1]);
1109         }
1110         
1111         XtSetLanguageProc(NULL, NULL, NULL);
1112         _DtEnvControl(DT_ENV_SET); /* set up environment variables */
1113
1114         de->top_level = XtVaAppInitialize(&app,
1115                 "Dtcm", NULL, 0, &argc, argv, NULL,
1116                 XmNallowShellResize, True,
1117                 XmNdeleteResponse, XmDO_NOTHING,
1118                 NULL);
1119         setup_quit_handler(de->top_level, de_quit_handler, (caddr_t)de);
1120
1121         /*
1122         **  First, create a calendar and fill only the stuff we're going to
1123         **  use.
1124         */
1125         calendar = (Calendar *)ckalloc(sizeof(Calendar));
1126         de->c = calendar;
1127         de->p = (Props *)ckalloc(sizeof(Props));
1128         de->c->properties = (caddr_t)de->p;
1129         de->c->general = (General*) ckalloc(sizeof(General));
1130         de->c->general->version = DATAVER_ARCHIVE;
1131         de->c->frame = de->top_level;
1132         de->pu = (Props_pu *)ckalloc(sizeof(Props_pu));
1133         de->c->properties_pu = (caddr_t)de->pu;
1134         de->init = no_tt;
1135         read_props(de->p);
1136         cal_convert_cmrc(de->p);
1137         if ((start = get_int_prop(de->p, CP_DAYBEGIN)) < 0)
1138                 start = 0;
1139         else if (start > 22)
1140                 start = 22;
1141         if ((stop = get_int_prop(de->p, CP_DAYEND)) <= start)
1142                 stop = start + 1;
1143         else if (stop > 23)
1144                 stop = 23;
1145         set_int_prop(de->p, CP_DAYBEGIN, start);
1146         set_int_prop(de->p, CP_DAYEND, stop);
1147         de->c->calname = cm_strdup(get_char_prop(de->p, CP_DEFAULTCAL));
1148         de->c->DT_catd = catopen(DTCM_CAT, NL_CAT_LOCALE);
1149
1150         /* Open the message catalog for internationalization */
1151         calendar->DT_catd = catopen(DTCM_CAT, NL_CAT_LOCALE);
1152
1153         title = XtNewString(catgets(calendar->DT_catd, 1, 1074, 
1154                                                 "Calendar Appointment"));
1155         XtVaSetValues(de->top_level, 
1156                 XmNtitle, title,
1157                 NULL);
1158         XtFree(title);
1159
1160         /*
1161         **  Okay, now create the form manager and the widgets
1162         */
1163         de->form = XtVaCreateWidget("form",
1164                 xmFormWidgetClass, de->top_level,
1165                 XmNautoUnmanage, True,
1166                 XmNfractionBase, 5,
1167                 NULL);
1168
1169         label_str = XmStringCreateLocalized(catgets(de->c->DT_catd, 1, 846, "Save"));
1170         de->attach_button = XtVaCreateWidget("attach_button",
1171                 xmPushButtonGadgetClass, de->form,
1172                 XmNlabelString, label_str,
1173                 XmNleftAttachment, XmATTACH_POSITION,
1174                 XmNleftPosition, 1,
1175                 XmNrightAttachment, XmATTACH_POSITION,
1176                 XmNrightPosition, 2,
1177                 XmNbottomAttachment, XmATTACH_FORM,
1178                 XmNbottomOffset, 10,
1179                 NULL);
1180         XmStringFree(label_str);
1181         XtAddCallback(de->attach_button, XmNactivateCallback, de_apply_proc, (XtPointer)de);
1182         if (!de->file)
1183                 XtSetSensitive(de->attach_button, False);
1184
1185         label_str = XmStringCreateLocalized(catgets(de->c->DT_catd, 1, 691, "Reset"));
1186         de->reset_button = XtVaCreateWidget("reset_button",
1187                 xmPushButtonGadgetClass, de->form,
1188                 XmNlabelString, label_str,
1189                 XmNleftAttachment, XmATTACH_POSITION,
1190                 XmNleftPosition, 3,
1191                 XmNrightAttachment, XmATTACH_POSITION,
1192                 XmNrightPosition, 4,
1193                 XmNbottomAttachment, XmATTACH_FORM,
1194                 XmNbottomOffset, 10,
1195                 NULL);
1196         XmStringFree(label_str);
1197         XtAddCallback(de->reset_button, XmNactivateCallback, de_reset_proc, de);
1198
1199         create_all_pixmaps(de->pu, de->form);
1200
1201         de->rfpFlags = 0;
1202         de->rfp = (RFP *)ckalloc(sizeof(RFP));
1203         build_rfp(de->rfp, de->c, de->form);
1204         XtVaSetValues(de->rfp->rfp_form_mgr,
1205                 XmNbottomAttachment, XmATTACH_WIDGET,
1206                 XmNbottomWidget, de->attach_button,
1207                 XmNbottomOffset, 25,
1208                 XmNleftAttachment, XmATTACH_FORM,
1209                 XmNleftOffset, 5,
1210                 NULL);
1211         XtVaGetValues(de->rfp->rfp_form_mgr,
1212                 XmNchildren,            &children,
1213                 XmNnumChildren,         &n,
1214                 NULL);
1215         /* We don't want to manage the privacy widgets */
1216         for (i = 0; i < n; i++) {
1217                 if ((children[i] == de->rfp->privacy_label) ||
1218                     (children[i] == de->rfp->privacy_menu))
1219                     continue;
1220                 widgets[j++] = children[i];
1221         }
1222         XtManageChildren(widgets, n - 2);       
1223
1224         /*
1225          * Add a drag source icon inside the dssw, lower right
1226          */
1227         xmstr = XmStringCreateLocalized(
1228                         catgets(de->c->DT_catd, 1, 627, "Drag Appt"));
1229         de->drag_source = XtVaCreateWidget("drag_source",
1230                 dtIconGadgetClass, de->form,
1231                 XmNpixmapPosition, XmPIXMAP_TOP,
1232                 XmNstringPosition, XmSTRING_BOTTOM,
1233                 XmNalignment, XmALIGNMENT_CENTER,
1234                 XmNstring, xmstr,
1235                 XmNbottomAttachment, XmATTACH_WIDGET,
1236                 XmNbottomWidget, de->attach_button,
1237                 XmNbottomOffset, 25,
1238                 XmNleftAttachment, XmATTACH_WIDGET,
1239                 XmNleftWidget, de->rfp->rfp_form_mgr,
1240                 XmNrightAttachment, XmATTACH_FORM,
1241                 XmNtraversalOn, False,
1242                 NULL);
1243         XmStringFree(xmstr);
1244
1245         XtAddEventHandler(XtParent(de->drag_source), Button1MotionMask, False,
1246                 (XtEventHandler)EditApptDragMotionHandler, (XtPointer) de);
1247
1248         XtVaGetValues((Widget)XmGetXmDisplay(XtDisplay(de->form)),
1249                 "enableBtn1Transfer",   &btn1_transfer,
1250                 NULL);
1251
1252         /* btn1_transfer is a tri-state variable - see 1195846 */
1253         if ((Boolean)btn1_transfer != True)
1254                 XtAddEventHandler(XtParent(de->drag_source),
1255                                 Button2MotionMask, False,
1256                                 (XtEventHandler)EditApptDragMotionHandler,
1257                                 (XtPointer) de);
1258
1259
1260         if (de->pu->drag_icon_xbm)
1261                 XtVaSetValues(de->drag_source,
1262                                 XmNpixmap, de->pu->drag_icon_xbm,
1263                                 NULL);
1264
1265         de->dsswFlags = 0;
1266         de->dssw = (DSSW *)ckalloc(sizeof(DSSW));
1267         build_dssw(de->dssw, de->c, de->form, True, True);
1268         XtVaSetValues(de->dssw->dssw_form_mgr,
1269                 XmNtopAttachment, XmATTACH_FORM,
1270                 XmNtopOffset, 10,
1271                 XmNbottomAttachment, XmATTACH_WIDGET,
1272                 XmNbottomWidget, de->rfp->rfp_form_mgr,
1273                 XmNbottomOffset, 15,
1274                 XmNleftAttachment, XmATTACH_FORM,
1275                 XmNleftOffset, 10,
1276                 NULL);
1277         ManageChildren(de->dssw->dssw_form_mgr);
1278
1279         /* set up callback to detect whether the appointment 
1280            definition has been modified */
1281
1282         XtAddCallback(de->dssw->start_text, XmNvalueChangedCallback, de_mark_change, de);
1283         XtAddCallback(de->dssw->start_am, XmNvalueChangedCallback, de_mark_change, de);
1284         XtAddCallback(de->dssw->start_pm, XmNvalueChangedCallback, de_mark_change, de);
1285         XtAddCallback(de->dssw->stop_text, XmNvalueChangedCallback, de_mark_change, de);
1286         XtAddCallback(de->dssw->stop_am, XmNvalueChangedCallback, de_mark_change, de);
1287         XtAddCallback(de->dssw->stop_pm, XmNvalueChangedCallback, de_mark_change, de);
1288         XtAddCallback(de->dssw->what_text, XmNvalueChangedCallback, de_mark_change, de);
1289         XtAddCallback(de->rfp->repeat_menu, XmNselectionCallback, de_mark_change, de);
1290         XtAddCallback(de->rfp->for_menu, XmNselectionCallback, de_mark_change, de);
1291
1292         ManageChildren(de->form);
1293         XtManageChild(de->form);
1294         XtRealizeWidget(de->top_level);
1295
1296         /*
1297         **  Do some monkeying to compensate for Motif's pitiful form managers
1298         XtVaGetValues(de->dssw->start_menu, XmNx, &dssw_x,
1299                 XmNleftOffset, &dssw_loffset,
1300                 NULL);
1301         XtVaGetValues(de->rfp->repeat_menu, XmNx, &rfp_x,
1302                 XmNleftOffset, &rfp_loffset,
1303                 NULL);
1304
1305         if (dssw_x > rfp_x)
1306                 XtVaSetValues(de->rfp->rfp_form_mgr,
1307                         XmNleftOffset, rfp_loffset + (dssw_x - rfp_x),
1308                         NULL);
1309         else if (rfp_x > dssw_x)
1310                 XtVaSetValues(de->dssw->dssw_form_mgr,
1311                         XmNleftOffset, dssw_loffset + (rfp_x - dssw_x),
1312                         NULL);
1313         */
1314
1315 /*      Don't need these any more.      
1316         XtVaGetValues(de->dssw->date_label, XmNwidth, &longest_dssw_label, NULL);
1317
1318         XtVaGetValues(de->dssw->start_label, XmNwidth, &width, NULL);
1319         if (width > longest_dssw_label)
1320                 longest_dssw_label = width;
1321
1322         XtVaGetValues(de->dssw->stop_label, XmNwidth, &width, NULL);
1323         if (width > longest_dssw_label)
1324                 longest_dssw_label = width;
1325
1326         XtVaGetValues(de->dssw->what_label, XmNwidth, &width, NULL);
1327         if (width > longest_dssw_label)
1328                 longest_dssw_label = width;
1329
1330         XtVaGetValues(de->rfp->frequency_label, XmNwidth, &longest_rfp_label, NULL);
1331         XtVaGetValues(de->rfp->for_label, XmNwidth, &width, NULL);
1332         if (width > longest_rfp_label)
1333                 longest_rfp_label = width;
1334
1335         XtVaSetValues(de->dssw->dssw_form_mgr, 
1336                         XmNleftOffset, longest_rfp_label - longest_dssw_label, 
1337                         NULL);
1338 */
1339
1340         de_set_defaults(de);
1341
1342         de_register_drop_site(de, de->form, True);
1343         de_register_drop_site(de, de->dssw->dssw_form_mgr, False);
1344         de_register_drop_site(de, de->rfp->rfp_form_mgr, False); 
1345
1346         XmProcessTraversal(de->dssw->what_text, XmTRAVERSE_CURRENT);
1347         XtVaSetValues(de->form, XmNinitialFocus, de->dssw->what_text, NULL);
1348
1349
1350         status = cmtt_init("AppointmentEditor", de, app, calendar->frame);
1351         if (TT_OK != status) {
1352             char *errfmt;
1353             errfmt = catgets(calendar->DT_catd, 2, 2,
1354                         "Could not connect to ToolTalk:\n%s\n");
1355             DieFromToolTalkError( de, errfmt, status );
1356         }
1357
1358         XtAppMainLoop(app);
1359
1360         return 0;
1361 }