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