Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / dnd.c
1 /* $TOG: dnd.c /main/12 1998/04/09 11:43:47 mgreess $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <EUSCompat.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <memory.h>
16 #include <stdlib.h>
17 #include <rpc/rpc.h>
18 #include <X11/Xlib.h>
19
20 #include <Xm/Xm.h>
21 #include <Xm/Text.h>
22 #include <Xm/List.h>
23 #include <Xm/DragC.h>
24 #include <Xm/DragIcon.h>
25 #include <Xm/AtomMgr.h>
26 #include <Xm/ToggleBG.h>
27 #include <Dt/Dt.h>
28 #include <Dt/Dnd.h>
29 #include <csa.h>
30
31 #include "util.h"
32 #include "editor.h"
33 #include "todo.h"
34 #include "group_editor.h"
35 #include "calendar.h"
36 #include "props_pu.h"
37 #include "props.h"
38 #include "dnd.h"
39 #include "getdate.h"
40 #include "cm_tty.h"
41 #include "misc.h"
42 #include "help.h"
43
44 #ifdef FNS
45 #include "cmfns.h"
46 #endif
47
48 #include "drag_xbm"
49 #include "drag_mask_xbm"
50
51 static Bool lookForButton(Display *, XEvent *, XPointer);
52
53 #if !defined(linux)
54 extern char     *sys_errlist[];
55 #endif
56
57 extern int      drag_load_proc(char*, Calendar *);
58 static char     dnd_filename[20];
59
60 static Boolean 
61 validate_dropped_appt(char *filename, Calendar *c) {
62         Props                   *p = (Props *)c->properties;
63         Props_pu                *pu = (Props_pu *)c->properties_pu;
64         CmDataList              *list = CmDataListCreate();
65         Validate_op             op;
66         int                     i;
67         Dtcm_appointment        *a;
68
69         if (!filename || *filename == '\0')
70                 return(False);
71
72         op = parse_appt_from_file(c->DT_catd, filename, list, p, query_user, 
73                                   (void *)c, c->general->version);
74
75         for (i = 1; i <= list->count; i++)
76                 if (a = (Dtcm_appointment *)CmDataListGetData(list, i))
77                         free_appt_struct(&a);
78         CmDataListDestroy(list, B_FALSE);
79
80         if (op == VALID_APPT)
81                 return(True);
82         else
83                 return(False);
84
85 }
86
87 static void
88 handle_animate_cb(
89         Widget          dragContext,
90         XtPointer       client_data,
91         XtPointer       call_data)
92 {
93         DtDndDropAnimateCallbackStruct *animateInfo = (DtDndDropAnimateCallbackStruct *)call_data;
94         Calendar        *c;
95         char            *data;
96         int             size;
97         FILE            *fp;
98         int             i;
99 #if defined(FNS) && defined(FNS_DEMO)
100         char            buf[256];
101         char            addr_buf[256];
102 #endif
103
104         c = (Calendar *)client_data;
105
106         for (i = 0; i < animateInfo->dropData->numItems; i++) {
107                 switch(animateInfo->dropData->protocol) {
108                 case DtDND_FILENAME_TRANSFER:
109                         data = animateInfo->dropData->data.files[i];
110         
111 #if defined(FNS) && defined(FNS_DEMO)
112                         if (cmfns_use_fns(c->properties) &&
113                             cmfns_name_from_file(data, buf, sizeof(buf)) == 1) {
114                                 /* 
115                                  * Looks like an HFS file has been dropped on us.
116                                  * Get the calendar service associated with the
117                                  * FNS name and browse it
118                                  */
119                                 if (cmfns_lookup_calendar(buf,
120                                                 addr_buf, sizeof(addr_buf)) == 1) {
121                                         
122                                         switch_it(c, addr_buf, main_win);
123                                         return;
124                                 }
125                         }
126 #endif
127                         drag_load_proc(data, c);
128                         break;
129                 case DtDND_BUFFER_TRANSFER:
130         
131                         /*
132                          * Save data to a file so we can pass it to drag_load_proc().
133                          */
134
135 #ifdef NOT
136                         strcpy(filename, "/tmp/cmXXXXXX");
137                         mktemp(filename);
138 #endif
139
140                         if (!dnd_filename[0]){
141                                 return;
142                         }
143         
144 #ifdef NOT
145         
146                         if ((fp = fopen(dnd_filename, "w")) == 0) {
147                                 return;
148                         }
149         
150                         data = animateInfo->dropData->data.buffers[0].bp;
151                         size = animateInfo->dropData->data.buffers[0].size;
152                         fwrite(data, 1, size, fp);
153                         fclose(fp);
154 #endif
155         
156                         drag_load_proc(dnd_filename, c);
157         
158                         unlink(dnd_filename);
159                         dnd_filename[0] = NULL;
160                         break;
161                 default:
162                         return;
163                 }
164         }
165
166         return;
167 }
168
169 static void
170 handle_drop_cb(
171         Widget          w,
172         XtPointer       client_data,
173         XtPointer       call_data)
174 {
175         Display         *display = XtDisplay(w);
176         DtDndDropCallbackStruct *transfer_info = (DtDndDropCallbackStruct *)call_data;
177         Calendar        *c;
178         char            filename[20];
179         char            *data;
180         int             size;
181         FILE            *fp;
182         int             i;
183 #if defined(FNS) && defined(FNS_DEMO)
184         char            buf[256];
185         char            addr_buf[256];
186 #endif
187
188         c = (Calendar *)client_data;
189
190         transfer_info->status = DtDND_SUCCESS;
191
192         for (i = 0; i < transfer_info->dropData->numItems; i++) {
193                 switch(transfer_info->dropData->protocol) {
194                 case DtDND_FILENAME_TRANSFER:
195                         data = transfer_info->dropData->data.files[i];
196         
197 #if defined(FNS) && defined(FNS_DEMO)
198                         if (cmfns_use_fns(c->properties) &&
199                             cmfns_name_from_file(data, buf, sizeof(buf)) == 1) {
200                                 /* 
201                                  * Looks like an HFS file has been dropped on us.
202                                  * Get the calendar service associated with the
203                                  * FNS name and browse it
204                                  */
205                                 if (cmfns_lookup_calendar(buf,
206                                                 addr_buf, sizeof(addr_buf)) == 1) {
207                                         
208                                         switch_it(c, addr_buf, main_win);
209                                         return;
210                                 }
211                         }
212 #endif
213         
214                         if (validate_dropped_appt(data, c) == False) {
215                                 transfer_info->status = DtDND_FAILURE;
216                         }
217                         break;
218                 case DtDND_BUFFER_TRANSFER:
219         
220                         /*
221                          * Save data to a file so we can pass it to drag_load_proc().
222                          */
223                         strcpy(dnd_filename, "/tmp/cmXXXXXX");
224                         mktemp(dnd_filename);
225         
226                         if ((fp = fopen(dnd_filename, "w")) == 0) {
227                                 transfer_info->status = DtDND_FAILURE;
228                                 return;
229                         }
230         
231                         data = transfer_info->dropData->data.buffers[0].bp;
232                         size = transfer_info->dropData->data.buffers[0].size;
233                         fwrite(data, 1, size, fp);
234                         fclose(fp);
235         
236                         if (validate_dropped_appt(dnd_filename, c) == False) {
237                                 unlink(dnd_filename);
238                                 dnd_filename[0] = NULL; 
239                                 transfer_info->status = DtDND_FAILURE;
240                         }
241 #ifdef NOT
242                         unlink(filename);
243 #endif
244                         break;
245                 default:
246                         transfer_info->status = DtDND_FAILURE;
247                         return;
248                 }
249         }
250
251         return;
252 }
253
254 void
255 cm_register_drop_site(
256         Calendar        *c,
257         Widget          w)
258
259 {
260         XtCallbackRec   transfer_cb_rec[] = { {handle_drop_cb, NULL},
261                                               {NULL, NULL} };
262         static XtCallbackRec animateCBRec[] = { {handle_animate_cb, NULL},
263                                                 {NULL, NULL} };
264         Display         *display = XtDisplayOfObject(w);
265
266         /*
267          * The above string "CalendarAppointment" is hard coded to match the type
268          * used in dtdnddemo.  In the future we need to use the true
269          * type from the data typing database
270          */
271
272         transfer_cb_rec[0].closure = (XtPointer)c;
273         animateCBRec[0].closure = (XtPointer)c;
274
275         DtDndVaDropRegister(w, DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
276                         XmDROP_COPY,
277                         transfer_cb_rec, 
278                         DtNdropAnimateCallback, animateCBRec,
279                         DtNtextIsBuffer,        True,
280                         NULL);
281         return;
282 }
283
284 /*
285  * Insert the appointment into the calendar.
286  *
287  * Returns:
288  *              1       Success
289  *              0       User overuled.  Appointment not inserted.
290  *              -1      Failure
291  */
292 static int
293 schedule_appt(Calendar *c, Dtcm_appointment *a) {
294         char            date_buf[MAXNAMELEN], buf[BUFSIZ], buf2[BUFSIZ];
295         int             answer;
296         Editor          *e = (Editor *)c->editor;
297         ToDo            *t = (ToDo *)c->todo;
298         Props           *p = (Props *)c->properties;
299         CSA_entry_handle        entry;
300         OrderingType    ot = get_int_prop(p, CP_DATEORDERING);
301         SeparatorType   st = get_int_prop(p, CP_DATESEPARATOR);
302         Tick            tick;
303         int             rc;
304
305         if (strcmp(c->calname, c->view->current_calendar) != 0) {
306                 /*
307                  * Make sure user really meant to insert appointment
308                  * into somebody elses calendar.
309                  */
310                 char *ident = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
311                 char *title = XtNewString(catgets(c->DT_catd, 1, 212,
312                                 "Calendar : Schedule Appointment"));
313                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 210, "The appointment will be scheduled in the calendar\nyou are currently browsing.  Do you still want to schedule it?"));
314                 sprintf(buf2, "%s %s", catgets(c->DT_catd, 1, 211, "Schedule in"),
315                         c->view->current_calendar);
316                 answer = dialog_popup(c->frame,
317                         DIALOG_TITLE, title,
318                         DIALOG_TEXT, buf,
319                         BUTTON_IDENT, 1, ident,
320                         BUTTON_IDENT, 2, buf2,
321                         NULL);
322                 XtFree(title);
323                 XtFree(ident);
324                 if (answer == 1)
325                         return 0;
326         }
327
328         if (a->end_time) {
329         if (!editor_created(e))
330         {
331                 e_make_editor(c);
332                 XtUnmanageChild(e->base_form_mgr);
333                 e->editor_is_up = False;
334         }
335         if ((rc = editor_insert(a, &entry, c)) == True) {
336
337                 _csa_iso8601_to_tick(a->time->value->item.string_value, &tick);
338                 format_tick(tick, ot, st, date_buf);
339                 sprintf(buf, catgets(c->DT_catd, 1, 214,
340                                      "Appointment scheduled: %s"), date_buf);
341                 set_message(c->message_text, buf);
342                 return 1;
343         } else {
344                 set_message(c->message_text, "");
345                 if ( rc == 2)
346                         return 0;
347                         return -1;
348         }
349         } else {
350         if (!t->frame)
351         {
352                 t_make_todo(c);
353                 XtUnmanageChild(t->frame);
354                 t->todo_is_up = False;
355         }
356         if (todo_insert(a, &entry, c)) {
357                 /*
358                  * No messages displayed on calendar for todo.
359                  */
360                 return 1;
361         } else {
362                 /*
363                  * No messages displayed on calendar for todo.
364                  */
365                 return -1;
366         }
367         }
368 }
369
370 /*
371  * Call the routines in file_parse (in libDtCm) to read the appointments!
372  */
373 extern int 
374 drag_load_proc(char *filename, Calendar *c) {
375         int                     ret_val, i = 1;
376         char                    buf[MAXNAMELEN * 2];
377         CmDataList              *list = CmDataListCreate();
378         Props                   *p = (Props *)c->properties;
379         Props_pu                *pu = (Props_pu *)c->properties_pu;
380         Validate_op             op;
381         Dtcm_appointment        *a;
382         char                    *msg;
383
384         if (!filename || *filename == '\0')
385                 return -1;
386
387         op = parse_appt_from_file(c->DT_catd, filename, list, p, query_user, 
388                                   (void *)c, c->general->version);
389         if (list->count <= 0) {
390                 op = CANCEL_APPT;
391                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 842, 
392              "The information transferred did not\ncontain any appointments."));
393         }
394
395         switch(op) {
396         case COULD_NOT_OPEN_FILE:
397                 msg = XtNewString(catgets(c->DT_catd, 1, 843, 
398                                         "Drag and Drop operation failed."));
399                 sprintf(buf, "%s\n%s",
400                         msg,
401                         catgets(c->DT_catd, 1, 844, 
402                               "Unable to locate the transferred information."));
403                 XtFree(msg);
404                 break;
405         case INVALID_DATE:
406                 sprintf(buf, "%s",
407                         catgets(c->DT_catd, 1, 218, "Invalid DATE specified"));
408                 break;
409         case INVALID_START:
410                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 219,
411                                            "Invalid START time specified"));
412                 break;
413         case INVALID_STOP:
414                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 220,
415                                            "Invalid END time specified"));
416                 break;
417         case MISSING_DATE:
418                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 221,
419                                            "Empty or missing DATE field"));
420                 break;
421         case MISSING_START:
422                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 222,
423                                            "Empty or missing START field"));
424                 break;
425         case MISSING_WHAT:
426                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 223,
427                                            "Empty or missing WHAT field"));
428                 break;
429         case REPEAT_FOR_MISMATCH:
430                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 224,
431                                            "REPEAT and FOR field mismatch"));
432                 break;
433         case VALID_APPT:
434                 break;
435         case CANCEL_APPT:
436                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 225,
437                                            "Schedule appointment was cancelled."));
438                 break;
439         default:
440                 op = CANCEL_APPT;
441                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 225,
442                                            "Schedule appointment was cancelled."));
443                 break;
444         }
445
446         while (op == VALID_APPT && i <= list->count) {
447                 extern void scrub_attr_list(Dtcm_appointment *); 
448
449                 a = (Dtcm_appointment *)CmDataListGetData(list, i);
450
451                 scrub_attr_list(a);
452
453                 ret_val = schedule_appt(c, a);
454                 if (ret_val < 0) {
455                         op = CANCEL_APPT;
456                         sprintf(buf, "%s", catgets(c->DT_catd, 1, 226,
457                                 "Internal error scheduling appointment."));
458                 } else if (ret_val == 0) {
459                         op = CANCEL_APPT;
460                         sprintf(buf, "%s", catgets(c->DT_catd, 1, 225,
461                                 "Schedule appointment was cancelled."));
462                 }
463                 ++i;
464         }
465
466         for (i = 1; i <= list->count; i++)
467                 if (a = (Dtcm_appointment *)CmDataListGetData(list, i))
468                         free_appt_struct(&a);
469         CmDataListDestroy(list, B_FALSE);
470
471         if (op != VALID_APPT) {
472                 char *title = XtNewString(catgets(c->DT_catd, 1, 1073,
473                                           "Calendar : Error - Drag and Drop"));
474                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
475                 dialog_popup(c->frame,
476                         DIALOG_TITLE, title,
477                         DIALOG_TEXT, buf,
478                         BUTTON_IDENT, 1, ident,
479                         BUTTON_HELP, DND_ERROR_HELP,
480                         DIALOG_IMAGE, pu->xm_error_pixmap,
481                         NULL);
482                 XtFree(ident);
483                 XtFree(title);
484                 return -1;
485         }
486
487         return 0;
488 }
489
490 /* gets a pointer to the currently selected appointment in the editor.  
491    This will need to be changed if we ever allow more than one item 
492    to be selected in the editor at a time. */
493
494 CSA_entry_handle
495 get_appt_struct(DragContext *context) {
496         int             *item_list = NULL, item_cnt = 0, answer;
497         char            buf[MAXNAMELEN];
498         Widget          list;
499         Calendar        *c = context->calendar;
500         Props_pu        *pr;
501         CSA_entry_handle        entry;
502         Access_data     *ad;
503
504         pr = (Props_pu *)(c->properties_pu);
505
506         if (context->editor_type == SingleEditorList)
507                 list = ((Editor *) context->editor)->appt_list;
508         else if (context->editor_type == GroupEditorList)
509                 list = ((GEditor *) context->editor)->appt_list;
510         else if (context->editor_type == TodoEditorList)
511                 list = ((ToDo *) context->editor)->todo_list;
512
513         if (!XmListGetSelectedPos(list, &item_list, &item_cnt)) {
514                 char *title = XtNewString(catgets(c->DT_catd, 1, 230, 
515                                 "Calendar : Error - Drag Appointment"));
516                 char *text = XtNewString(catgets(c->DT_catd, 1, 231, "Select an appointment and DRAG again."));
517                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
518                 answer = dialog_popup(c->frame,
519                         DIALOG_TITLE, title,
520                         DIALOG_TEXT, text,
521                         BUTTON_IDENT, 1, ident,
522                         BUTTON_HELP, RESELECT_ERROR_HELP,
523                         DIALOG_IMAGE, pr->xm_error_pixmap,
524                         NULL);
525                 XtFree(ident);
526                 XtFree(text);
527                 XtFree(title);
528                 return(NULL);
529         }
530  
531
532         if (context->editor_type == SingleEditorList)
533                 entry = editor_nth_appt((Editor *)context->editor,
534                                         item_list[0] - 1);
535         else if (context->editor_type == GroupEditorList)
536                 entry = geditor_nth_appt((GEditor *)context->editor,
537                                          item_list[0] - 1, &ad);
538         else if (context->editor_type == TodoEditorList)
539                 entry = t_nth_appt((ToDo *)context->editor,
540                                          item_list[0] - 1);
541
542
543         if (!entry) {
544                 char *title = XtNewString(catgets(c->DT_catd, 1, 230, 
545                                         "Calendar : Error - Drag Appointment"));
546                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
547                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 845,
548                 "Drag and Drop operation Failed\nInternal consistency error."));
549                 answer = dialog_popup(c->frame,
550                         DIALOG_TITLE, title,
551                         DIALOG_TEXT, buf,
552                         BUTTON_IDENT, 1, ident,
553                         DIALOG_IMAGE, pr->xm_error_pixmap,
554                         NULL);
555                 XtFree(ident);
556                 XtFree(title);
557                 XtFree((XtPointer)item_list);
558                 return(NULL);
559         }
560
561         return entry;
562 }
563
564 /*
565  * ApptConvertCB
566  *
567  * Fills in data object with calendar appointment string based on which
568  * appointment in the list was under the pointer when the drag started.
569  */
570 static void
571 ApptConvertCB(
572         Widget          dragContext,
573         XtPointer       clientData,
574         XtPointer       callData)
575 {
576         DtDndConvertCallbackStruct *convertInfo 
577                                         = (DtDndConvertCallbackStruct*)callData;
578         DtDndBuffer     *data           = &(convertInfo->dragData->data.buffers[0]);
579         DragContext     *context        = (DragContext *)clientData;
580         Display         *display        = XtDisplay(dragContext);
581         Atom            CMAPPOINTMENT   
582                         = XmInternAtom(display, "CalendarAppointment", False);
583         Calendar        *c = context->calendar;
584
585         if (convertInfo->reason != DtCR_DND_CONVERT_DATA)
586                 return;
587
588         /* REMIND: Need to check convertInfo->reason, handle DELETE, etc */
589
590         data->bp   = XtNewString(context->data);
591         data->size = strlen(data->bp);
592         data->name = XtNewString(catgets(c->DT_catd, 1, 236, "CalendarAppointment"));
593 }
594
595 /*
596  * getIcon
597  *
598  * Returns a new IconInfo structure with bitmap, mask, width, height,
599  * icon type and name.
600  */
601 static void
602 GetIcon(Calendar *calendar)
603 {
604  
605         Display        *display = XtDisplay(calendar->frame);
606         Window          window = XtWindow(calendar->frame);
607         unsigned char  *bitmapData, *bitmapMask;
608         Editor          *e = (Editor *) calendar->editor;
609         GEditor         *ge = (GEditor *) calendar->geditor;
610  
611         if (e->drag_bitmap == NULL) {
612                 e->drag_bitmap = XCreateBitmapFromData(display,
613                         window, (char *) drag_xbm_bits,
614                         drag_xbm_width, drag_xbm_height);
615                 if (e->drag_bitmap == NULL) {
616
617                         printf(catgets(calendar->DT_catd, 1, 237, "XCreateBitmapFromData() failed for bitmap.\n"));
618                         return;
619                 }
620                 else
621                         ge->drag_bitmap = e->drag_bitmap;
622         }
623         if (e->drag_mask == NULL) {
624                 e->drag_mask = XCreateBitmapFromData(display,
625                         window, (char *) drag_mask_xbm_bits,
626                         drag_mask_xbm_width, drag_mask_xbm_height);
627                 if (e->drag_mask == NULL) {
628                         printf(catgets(calendar->DT_catd, 1, 238, "XCreateBitmapFromData() failed for mask.\n"));
629                         return;
630                 }
631                 else
632                         ge->drag_mask = e->drag_mask;
633         }
634 }
635  
636 /*
637  * DragFinishCB
638  *
639  * Resets drag state to indicate the drag is over. Free memory allocated
640  * with the drag.
641  */
642 static void
643 DragFinishCB(
644         Widget          widget,
645         XtPointer       clientData,
646         XtPointer       callData)
647 {
648         DragContext     *context = (DragContext *) clientData;
649
650         if (!context)
651                 return;
652
653         if ((context->editor_type == SingleEditorList) ||
654             (context->editor_type == SingleEditorIcon))
655                 ((Editor *) context->editor)->doing_drag = False;
656         else if ((context->editor_type == TodoEditorList) ||
657                  (context->editor_type == TodoEditorIcon))
658                 ((ToDo *) context->editor)->doing_drag = False;
659         else if ((context->editor_type == GroupEditorList) ||
660                  (context->editor_type == GroupEditorIcon)) 
661                 ((GEditor *) context->editor)->doing_drag = False;
662
663         if (context->data)
664                 free(context->data);
665
666         free(context);
667 }
668
669 Widget
670 CreateDragSourceIcon(
671         Widget          widget,
672         Pixmap          pixmap,
673         Pixmap          mask)
674 {
675         Widget          dragIcon;
676         Window          rootWindow;
677         int             pixmapX, pixmapY;
678         unsigned int    pixmapWidth, pixmapHeight, pixmapBorder, pixmapDepth;
679         Arg             args[20];
680         Cardinal        nn = 0;
681  
682         XGetGeometry (XtDisplayOfObject(widget), pixmap, &rootWindow,
683                 &pixmapX, &pixmapY, &pixmapWidth, &pixmapHeight,
684                 &pixmapBorder, &pixmapDepth);
685  
686         XtSetArg(args[nn], XmNwidth, pixmapWidth);  nn++;
687         XtSetArg(args[nn], XmNheight, pixmapHeight);  nn++;
688         XtSetArg(args[nn], XmNmaxWidth, pixmapWidth);  nn++;
689         XtSetArg(args[nn], XmNmaxHeight, pixmapHeight);  nn++;
690         XtSetArg(args[nn], XmNpixmap, pixmap);  nn++;
691         XtSetArg(args[nn], XmNmask, mask);  nn++;
692         XtSetArg(args[nn], XmNdepth, pixmapDepth);  nn++;
693         dragIcon = XmCreateDragIcon(widget, "sourceIcon", args, nn);
694
695         return(dragIcon);
696 }
697
698 void
699 TranslationDragStart(
700         Widget          widget,
701         XEvent          *event,
702         String          *parms,
703         Cardinal        *num_params)
704 {
705         static XtCallbackRec convertCBRec[] = { {ApptConvertCB, NULL},
706                                                 {NULL, NULL} };
707         static XtCallbackRec dragFinishCBRec[] =  { {DragFinishCB, NULL},
708                                                     {NULL, NULL} };
709  
710         Display        *display         = XtDisplay(widget);
711         DragContext     *context = calloc(sizeof(DragContext), 1);
712         Editor          *e = (Editor *) calendar->editor;
713         CSA_entry_handle        entry;
714         char            *apptstr;
715         Props           *p = (Props *)calendar->properties;
716  
717         context->calendar = calendar;
718
719         if (((Editor *)calendar->editor)->appt_list == widget) {
720                 context->editor_type = SingleEditorList;
721                 context->editor = (caddr_t) calendar->editor;
722         } else if (((GEditor *)calendar->geditor)->appt_list == widget) { 
723                 context->editor_type = GroupEditorList;
724                 context->editor = (caddr_t) calendar->geditor;
725         } else if (((ToDo *)calendar->todo)->todo_list == widget) { 
726                 context->editor_type = TodoEditorList;
727                 context->editor = (caddr_t) calendar->todo;
728         }
729         else
730         {
731           free(context);
732           return;
733         }
734
735         if (((entry = get_appt_struct(context)) == (CSA_entry_handle)NULL) ||
736             ((apptstr = parse_appt_to_string(calendar->cal_handle,
737                                              entry, p,
738                                              calendar->general->version))
739              == (char *)NULL))
740         {
741           switch (context->editor_type)
742           {
743           case SingleEditorList:
744             ((Editor *)context->editor)->doing_drag = False;
745             break;
746
747           case GroupEditorList:
748             ((GEditor *)context->editor)->doing_drag = False;
749             break;
750
751           case TodoEditorList:
752             ((ToDo *)context->editor)->doing_drag = False;
753             break;
754           }
755
756           free(context);
757           return;
758         }
759
760         context->data = apptstr;
761
762         GetIcon(calendar);
763
764         convertCBRec[0].closure = (XtPointer)context;
765         dragFinishCBRec[0].closure = (XtPointer)context;
766
767         if (e->drag_icon == NULL) {
768                 e->drag_icon = CreateDragSourceIcon(widget, 
769                                                     e->drag_bitmap, 
770                                                     e->drag_mask);
771         }
772
773         if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, 1,
774                              XmDROP_COPY, 
775                              convertCBRec, dragFinishCBRec,
776                              DtNsourceIcon, e->drag_icon,
777                              NULL) == NULL) {
778  
779                 printf(catgets(calendar->DT_catd, 1, 239, 
780                                         "DragStart returned NULL.\n"));
781         }
782 }
783  
784 void
785 ApptDragStart(
786         Widget          widget,
787         XEvent          *event,
788         Calendar        *calendar,
789         EditorType      editor_type)
790 {
791         static XtCallbackRec convertCBRec[] = { {ApptConvertCB, NULL},
792                                                 {NULL, NULL} };
793         static XtCallbackRec dragFinishCBRec[] =  { {DragFinishCB, NULL},
794                                                     {NULL, NULL} };
795  
796         Display        *display         = XtDisplay(widget);
797         DragContext     *context = calloc(sizeof(DragContext), 1);
798         Editor          *e = (Editor *) calendar->editor;
799         GEditor         *ge = (GEditor *) calendar->geditor;
800         ToDo            *t = (ToDo *) calendar->todo;
801         Dtcm_appointment        *appt;
802         char            *apptstr;
803         int             preDsswFlags, preRfpFlags;
804  
805         context->calendar = calendar;
806         context->editor_type = editor_type;
807  
808         if (editor_type == SingleEditorIcon)
809         {
810                 context->editor = (caddr_t) e;
811                 appt = allocate_appt_struct(appt_write, DATAVER_ARCHIVE, NULL);
812                 load_appt_defaults(appt, (Props *) calendar->properties);
813                 preDsswFlags = e->dsswFlags;
814                 preRfpFlags = e->rfpFlags;
815                 if (!dssw_form_flags_to_appt(&e->dssw, appt,
816                                              calendar->calname,
817                                              now(), &e->dsswFlags) ||
818                     !rfp_form_flags_to_appt(&e->rfp, appt,
819                                             calendar->calname,
820                                             &e->rfpFlags) ||
821                     (preDsswFlags != e->dsswFlags) ||
822                     (preRfpFlags != e->rfpFlags))
823                 {
824                   e->doing_drag = False;
825                   free_appt_struct(&appt);
826                   free(context);
827                   return;
828                 }
829         }
830         else if (editor_type == GroupEditorIcon)
831         {
832                 context->editor = (caddr_t) ge;
833                 appt = allocate_appt_struct(appt_write, DATAVER_ARCHIVE, NULL);
834                 load_appt_defaults(appt, (Props *) calendar->properties);
835                 preDsswFlags = ge->dsswFlags;
836                 preRfpFlags = ge->rfpFlags;
837                 if (!dssw_form_flags_to_appt(&ge->dssw, appt,
838                                              calendar->calname,
839                                              now(), &ge->dsswFlags) ||
840                     !rfp_form_flags_to_appt(&ge->rfp, appt,
841                                             calendar->calname,
842                                             &ge->rfpFlags) ||
843                     (preDsswFlags != ge->dsswFlags) ||
844                     (preRfpFlags != ge->rfpFlags))
845                 {
846                   ge->doing_drag = False;
847                   free_appt_struct(&appt);
848                   free(context);
849                   return;
850                 }
851         }
852         else if (editor_type == TodoEditorIcon)
853         {
854                 context->editor = (caddr_t) t;
855                 if (t->cal->general->version < DATAVER4)
856                   appt = allocate_appt_struct(appt_write, DATAVER_ARCHIVE, 
857                               CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I,
858                               CSA_ENTRY_ATTR_LAST_UPDATE_I,
859                               CSA_ENTRY_ATTR_ORGANIZER_I,
860                               CSA_ENTRY_ATTR_START_DATE_I,
861                               CSA_ENTRY_ATTR_TYPE_I,
862                               CSA_ENTRY_ATTR_CLASSIFICATION_I,
863                               CSA_ENTRY_ATTR_END_DATE_I,
864                               CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
865                               CSA_ENTRY_ATTR_SUMMARY_I,
866                               CSA_ENTRY_ATTR_STATUS_I,
867                               CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
868                               CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
869                               CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
870                               CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
871                               CSA_ENTRY_ATTR_AUDIO_REMINDER_I,
872                               CSA_ENTRY_ATTR_FLASHING_REMINDER_I,
873                               CSA_ENTRY_ATTR_MAIL_REMINDER_I,
874                               CSA_ENTRY_ATTR_POPUP_REMINDER_I,
875                               NULL);
876                 else
877                   appt = allocate_appt_struct(appt_write,
878                                               DATAVER_ARCHIVE, NULL); 
879
880                 dssw_form_to_todo(&t->dssw, appt, calendar->calname, now());
881                 preRfpFlags = t->rfpFlags;
882                 if (!rfp_form_flags_to_appt(&t->rfp, appt,
883                                             calendar->calname,
884                                             &t->rfpFlags) ||
885                     (preRfpFlags != t->rfpFlags))
886                 {
887                   t->doing_drag = False;
888                   free_appt_struct(&appt);
889                   free(context);
890                   return;
891                 }
892                 appt->type->value->item.sint32_value = CSA_TYPE_TODO;
893                 appt->show_time->value->item.sint32_value = True;
894                 t->completed_val = 
895                   XmToggleButtonGadgetGetState(t->completed_toggle);
896                 appt->state->value->item.sint32_value = 
897                   (t->completed_val) ? 
898                     CSA_STATUS_COMPLETED : CSA_X_DT_STATUS_ACTIVE;
899         }
900         else
901         {
902           free(context);
903           return;
904         }
905         apptstr = parse_attrs_to_string(appt, (Props *)calendar->properties, 
906                                         attrs_to_string(appt->attrs,
907                                                         appt->count));
908         free_appt_struct(&appt);
909
910         context->data = apptstr;
911
912         GetIcon(calendar);
913  
914         convertCBRec[0].closure = (XtPointer)context;
915         dragFinishCBRec[0].closure = (XtPointer)context;
916  
917         if (e->drag_icon == NULL) {
918                 e->drag_icon = CreateDragSourceIcon(widget, e->drag_bitmap,
919                                                     e->drag_mask);
920         }
921  
922         if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, 1,
923                 XmDROP_COPY, 
924                 convertCBRec, dragFinishCBRec,
925                 DtNsourceIcon,          e->drag_icon,
926                 NULL)
927             == NULL) {
928  
929                 printf(catgets(calendar->DT_catd, 1, 239,
930                                "DragStart returned NULL.\n"));
931         }
932 }
933
934 #define DAMPING 5
935 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
936
937 static Bool
938 lookForButton(
939         Display * display,
940         XEvent * event,
941         XPointer arg)
942 {
943     if (event->type == MotionNotify)
944     {
945         XEvent *press = (XEvent *)arg;
946
947         if ((ABS_DELTA(press->xbutton.x_root,
948                        event->xmotion.x_root) > DAMPING) ||
949             (ABS_DELTA(press->xbutton.y_root,
950                        event->xmotion.y_root) > DAMPING))
951             return(True);
952     }
953     else if (event->type == ButtonRelease)
954         return(True);
955
956     return(False);
957 }
958
959 /*
960  *
961 // DtcmProcessPress
962 //
963 // Translation implementing Motif 1.2.5 ProcessPress function
964 //
965  * Taken from dtmail/dtmail/RoamMenuWindow.C
966  */
967
968 #define SELECTION_ACTION        0
969 #define TRANSFER_ACTION         1
970
971 void
972 DtcmProcessPress(
973         Widget          w,
974         XEvent          *event,
975         String          *params,
976         Cardinal        *num_params)
977 {
978    int i, action, cur_item;
979    int *selected_positions, nselected_positions;
980
981    /*
982     *  This action happens when Button1 is pressed and the Selection
983     *  and Transfer are integrated on Button1.  It is passed two
984     *  parameters: the action to call when the event is a selection,
985     *  and the action to call when the event is a transfer.
986     */
987
988     if (*num_params != 2 || !XmIsList(w))
989       return;
990
991     action = SELECTION_ACTION;
992     cur_item = XmListYToPos(w, event->xbutton.y);
993
994     if (cur_item > 0)
995     {
996         XtVaGetValues(w,
997                 XmNselectedPositions, &selected_positions,
998                 XmNselectedPositionCount, &nselected_positions,
999                 NULL);
1000
1001         for (i=0; i<nselected_positions; i++)
1002         {
1003             if (cur_item == selected_positions[i])
1004             {
1005                 /*
1006                  * The determination of whether this is a transfer drag
1007                  * cannot be made until a Motion event comes in.  It is
1008                  * not a drag as soon as a ButtonUp event happens.
1009                  */
1010                 XEvent new_event;
1011
1012                 XPeekIfEvent(
1013                         XtDisplay(w),
1014                         &new_event,
1015                         lookForButton,
1016                         (XPointer)event);
1017                 switch (new_event.type)
1018                 {
1019                     case MotionNotify:
1020                        action = TRANSFER_ACTION;
1021                        break;
1022                     case ButtonRelease:
1023                        action = SELECTION_ACTION;
1024                        break;
1025                 }
1026                 break;
1027             }
1028         }
1029     }
1030
1031     XtCallActionProc(w, params[action], event, params, *num_params);
1032 }