Fix typo in license headers
[oweals/cde.git] / cde / examples / dtdnd / demo.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: demo.c /main/5 1999/07/20 14:48:53 mgreess $ */
24 /*****************************************************************************
25  *****************************************************************************
26  **
27  **   File:         demo.c
28  **
29  **   Description:  The Drag & Drop Demo program demonstrates the
30  **                 CDE DnD functions in the Desktop Services library:
31  **               
32  **                     DtDndDragStart.3x
33  **                     DtDndDropRegister.3x
34  **                     DtDndCreateSourceIcon.3x
35  **               
36  **                 The demo consists of a row of three different sources
37  **                 for text, filename and appointment buffer drags.
38  **                 It also has a text field that can accept either
39  **                 text or filename drops.  Finally there is a data
40  **                 area that accepts filename or buffer drops.
41  **
42  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
43  **  (c) Copyright 1993, 1994 International Business Machines Corp.
44  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
45  **  (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
46  **      Novell, Inc.
47  **
48  ****************************************************************************
49  ************************************<+>*************************************/
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <time.h>
55
56 #include <X11/Intrinsic.h>
57
58 #include <Xm/Xm.h>
59 #include <Xm/DrawingA.h>
60 #include <Xm/Frame.h>
61 #include <Xm/List.h>
62 #include <Xm/MainW.h>
63 #include <Xm/MwmUtil.h>
64 #include <Xm/RowColumn.h>
65 #include <Xm/Separator.h>
66 #include <Xm/DragDrop.h>
67 #include <Xm/Screen.h>
68
69 #include <Dt/Dt.h>
70 #include <Dt/Dnd.h>
71
72 #include "icon.h"
73 #include "text.h"
74 #include "file.h"
75 #include "buff.h"
76
77  /*************************************************************************
78  *
79  *      Data Structures & Declarations For Drag & Drop Demo
80  *
81  *************************************************************************/
82
83 /*
84  * The Drag Threshold is the distance, measured in pixels, over which the
85  * pointer must travel while the BSelect button (first mouse button) is held
86  * down in order to start a drag. CDE defines this to be 10 pixels.
87  */
88
89 #define DRAG_THRESHOLD 10
90
91 /*
92  * Absolute value macro
93  */
94
95 #ifndef ABS
96 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
97 #endif
98
99 /*
100  * Global variables
101  */
102
103 Widget          demoTopLevel;
104 XtAppContext    demoAppContext;
105 Boolean         demoDoingDrag = False;
106
107 /*
108  * Private Drag & Drop Demo Function Declarations
109  */
110
111 void            demoTransferCallback(Widget, XtPointer, XtPointer);
112
113  /*************************************************************************
114  *
115  *      General-Purpose Drag & Drop Functions
116  *
117  *************************************************************************/
118
119 /*
120  * demoDragFinishCallback
121  *
122  * Resets drag state to indicate the drag is over.
123  */
124 void
125 demoDragFinishCallback(
126         Widget          widget,
127         XtPointer       clientData,
128         XtPointer       callData)
129 {
130         demoDoingDrag = False;
131 }
132
133 /*
134  * demoDragMotionHandler
135  *
136  * Determine if the pointer has moved beyond the drag threshold while button 1
137  * was being held down.
138  */
139 void
140 demoDragMotionHandler(
141         Widget          dragInitiator,
142         XtPointer       clientData,
143         XEvent         *event)
144 {
145         static int      initialX = -1;
146         static int      initialY = -1;
147         int             diffX, diffY;
148         long            dragProtocol = (long)clientData;
149
150         if (!demoDoingDrag) {
151
152                 /*
153                  * If the drag is just starting, set initial button down coords
154                  */
155
156                 if (initialX == -1 && initialY == -1) {
157                         initialX = event->xmotion.x;
158                         initialY = event->xmotion.y;
159                 }
160
161                 /*
162                  * Find out how far pointer has moved since button press
163                  */
164
165                 diffX = initialX - event->xmotion.x;
166                 diffY = initialY - event->xmotion.y;
167                 
168                 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
169                     (ABS(diffY) >= DRAG_THRESHOLD)) {
170                         demoDoingDrag = True;
171                         switch (dragProtocol) {
172                         case DtDND_TEXT_TRANSFER:
173                                 textDragStart(dragInitiator, event);
174                                 break;
175                         case DtDND_FILENAME_TRANSFER:
176                                 fileCheckForDrag(dragInitiator, event,
177                                         initialX, initialY);
178                                 break;
179                         case DtDND_BUFFER_TRANSFER:
180                                 apptDragStart(dragInitiator, event);
181                                 break;
182                         }
183                         initialX = -1;
184                         initialY = -1;
185                 }
186         }
187 }
188
189 /*
190  * demoLookForButton
191  */
192
193 /* ARGSUSED */
194 static Bool demoLookForButton(Display *d, XEvent *event, XPointer arg)
195 {
196 #define DAMPING 5
197 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
198
199     if( event->type == MotionNotify) 
200     {
201         XEvent * press = (XEvent *) arg;
202
203         if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > DAMPING ||
204             ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > DAMPING)
205           return(True);
206     }
207     else if (event->type == ButtonRelease) return(True);
208
209     return(False);
210 }
211
212 /*
213  * demoProcessPress
214  */
215
216 void demoProcessPress(Widget w, XEvent *event, String *parms, Cardinal *nparms)
217 {
218 #define SELECTION_ACTION        0
219 #define TRANSFER_ACTION         1
220
221    int i, action, cur_item;
222    int *selected_positions, nselected_positions;
223
224    /* 
225     * This action happens when Button1 is pressed and the Selection
226     * and Transfer are integrated on Button1.  It is passed two
227     * parameters: the action to call when the event is a selection,
228     * and the action to call when the event is a transfer.
229     */
230
231     if (*nparms != 2 || !XmIsList(w)) return;
232
233     action = SELECTION_ACTION;
234     cur_item = XmListYToPos(w, event->xbutton.y);
235     if (cur_item > 0)
236     {
237         XtVaGetValues(w,
238                 XmNselectedPositions, &selected_positions,
239                 XmNselectedPositionCount, &nselected_positions,
240                 NULL);
241
242         for (i=0; i<nselected_positions; i++)
243         {
244             if (cur_item == selected_positions[i])
245             {
246                 /*
247                  * The determination of whether this is a transfer drag
248                  * cannot be made until a Motion event comes in.  It is
249                  * not a drag as soon as a ButtonUp event happens.
250                  */
251                 XEvent new_event;
252                 
253                 XPeekIfEvent(
254                         XtDisplay(w),
255                         &new_event,
256                         &demoLookForButton,
257                         (XPointer) event);
258                 switch (new_event.type)
259                 {
260                     case MotionNotify:
261                        action = TRANSFER_ACTION;
262                        break;
263                     case ButtonRelease:
264                        action = SELECTION_ACTION;
265                        break;
266                 }
267                 break;
268             }
269         }
270     }
271
272     XtCallActionProc(w, parms[action], event, parms, *nparms);
273 }
274
275 /*
276  * demoDrawAnimateCallback
277  *
278  * Expands the icon melted into the draw area by Motif.
279  */
280 void
281 demoDrawAnimateCallback(
282         Widget          dragContext, /* WARNING: This is being destroyed. */
283         XtPointer       clientData,
284         XtPointer       callData)
285 {
286         DtDndDropAnimateCallbackStruct *animateInfo =
287                                 (DtDndDropAnimateCallbackStruct *) callData;
288         Widget          dropDraw = (Widget)clientData;
289         Display         *display = XtDisplayOfObject(dropDraw);
290         Screen          *screen = XtScreen(dropDraw);
291         Window          window = XtWindow(dropDraw);
292         int             expandWidth, expandHeight,
293                         sourceX, sourceY;
294         static GC       graphicsContext = NULL;
295         XGCValues       gcValues;
296         IconInfo        *iconPtr;
297         
298         /*
299          * Create graphics context if it doesn't yet exist
300          */
301
302         if (graphicsContext == NULL) {
303                 gcValues.foreground = BlackPixelOfScreen(screen);
304                 gcValues.background = WhitePixelOfScreen(screen);
305                 graphicsContext = XCreateGC(display, window,
306                                 GCForeground | GCBackground, &gcValues);
307         }
308
309         /*
310          * Get the dragged icon from the dropDraw area
311          */
312
313         XtVaGetValues(dropDraw, XmNuserData, &iconPtr, NULL);
314
315         if (iconPtr == NULL) {
316                 return;
317         }
318
319         /*
320          * Set clip mask and coordinates for this icon in the graphics context
321          */
322
323         gcValues.clip_mask = iconPtr->mask;
324         gcValues.clip_x_origin = iconPtr->icon.x;
325         gcValues.clip_y_origin = iconPtr->icon.y;
326         XChangeGC(display, graphicsContext,
327                         GCClipMask | GCClipXOrigin | GCClipYOrigin,
328                         &gcValues);
329
330         /*
331          * Reconstitute the icon after Motif melts it
332          */
333
334         for (expandWidth = expandHeight = 0;
335              expandWidth < (int)iconPtr->icon.width &&
336                 expandHeight < (int)iconPtr->icon.height;
337              expandWidth += 2, expandHeight += 2) {
338
339                 sourceX = ((int)iconPtr->icon.width - expandWidth)/2;
340                 sourceY = ((int)iconPtr->icon.height - expandHeight)/2;
341
342                 XCopyPlane(display, iconPtr->bitmap, window, graphicsContext,
343                         sourceX, sourceY, expandWidth, expandHeight,
344                         iconPtr->icon.x + sourceX, iconPtr->icon.y + sourceY,
345                         1L);
346
347                 XmeMicroSleep(25000L);
348                 XFlush(display);
349         }
350 }
351
352 /*
353  * demoDrawExposeCallback
354  *
355  * Draws all the icons associated with the drawing area.
356  */
357 void
358 demoDrawExposeCallback(
359         Widget          widget,
360         XtPointer       clientData,
361         XtPointer       callData)
362 {
363         IconInfo       *iconPtr;
364
365         XtVaGetValues(widget, XmNuserData, &iconPtr, NULL);
366
367         while (iconPtr != NULL) {
368                 IconDraw(widget, iconPtr);
369                 iconPtr = iconPtr->next;
370         }
371 }
372
373 /*
374  * demoDropSetup
375  *
376  * Registers draw area to accept drops of files or buffers such as appointments.
377  */
378 void
379 demoDropSetup(
380         Widget          dropDraw)
381 {
382         static XtCallbackRec transferCBRec[] = { {demoTransferCallback, NULL},
383                                                  {NULL, NULL} };
384         static XtCallbackRec animateCBRec[] = { {demoDrawAnimateCallback, NULL},
385                                                 {NULL, NULL} };
386
387         animateCBRec[0].closure = (XtPointer)dropDraw;
388
389         DtDndVaDropRegister(dropDraw,
390                 DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
391                 XmDROP_COPY | XmDROP_MOVE, transferCBRec, 
392                 DtNdropAnimateCallback,         animateCBRec,
393                 DtNtextIsBuffer,                True,
394                 DtNpreserveRegistration,        False,
395                 NULL);
396 }
397
398 /*
399  * demoTransferCallback
400  *
401  * Called when something is dropped on the drawing area drop site. If the
402  * transfer protocol is DtDND_FILENAME_TRANSFER or DtDND_BUFFER_TRANSFER
403  * the fileTransferCallback and apptTransferCallback are called respectively.
404  */
405 void
406 demoTransferCallback(
407         Widget          widget,
408         XtPointer       clientData,
409         XtPointer       callData)
410 {
411         DtDndTransferCallbackStruct *transferInfo =
412                                 (DtDndTransferCallbackStruct *) callData;
413
414         if (transferInfo == NULL) {
415                 return;
416         }
417
418         switch (transferInfo->dropData->protocol) {
419
420         case DtDND_FILENAME_TRANSFER:
421                 fileTransferCallback(widget, clientData, callData);
422                 break;
423         case DtDND_BUFFER_TRANSFER:
424                 apptTransferCallback(widget, clientData, callData);
425                 break;
426         }
427 }
428
429  /*************************************************************************
430  *
431  *      Demo Client Creation
432  *
433  *************************************************************************/
434
435 /*
436  * Fallback resources are used if app-defaults file is not found
437  */
438
439 String  fallbackResources[] = {
440         "title:                                 CDE Drag & Drop Demo",
441
442         "*outerRowColumn.orientation:           VERTICAL",
443         "*outerRowColumn.spacing:               15",
444         "*outerRowColumn.marginHeight:          15",
445         "*outerRowColumn.marginWidth:           15",
446
447         "*upperRowColumn.orientation:           HORIZONTAL",
448         "*upperRowColumn.packing:               PACK_COLUMN",
449         "*upperRowColumn.spacing:               15",
450         "*upperRowColumn.marginHeight:          0",
451         "*upperRowColumn.marginWidth:           0",
452
453         "*fileDraw.height:                      175",
454         "*fileDraw.resizePolicy:                RESIZE_NONE",
455
456         "*fruitList.listSizePolicy:             CONSTANT",
457         "*fruitList.scrollBarDisplayPolicy:     STATIC",
458         "*fruitList.selectionPolicy:            MULTIPLE_SELECT",
459
460         "*apptList.listSizePolicy:              CONSTANT",
461         "*apptList.scrollBarDisplayPolicy:      STATIC",
462         "*apptList.selectionPolicy:             MULTIPLE_SELECT",
463
464         "*textRowColumn.orientation:            HORIZONTAL",
465         "*textRowColumn.packing:                PACK_TIGHT",
466         "*textRowColumn*textLabel.labelString: Name:",
467         "*textRowColumn*textField.width:        550",
468         "*textRowColumn.marginWidth:            0",
469
470         "*dropDraw.height:                      100",
471         "*dropDraw.resizePolicy:                RESIZE_NONE",
472         NULL
473 };
474
475 /*
476  * demoCreateDropSite
477  *
478  * Creates the drawing area at the bottom of the demo which is used as a drop
479  * site for files and appointments.
480  */
481 Widget
482 demoCreateDropSite(
483         Widget          parent)
484 {
485         Widget          dropFrame,
486                         dropDraw;
487
488         dropFrame = XtVaCreateManagedWidget("dropFrame",
489                 xmFrameWidgetClass, parent,
490                 NULL);
491
492         dropDraw = XtVaCreateManagedWidget("dropDraw",
493                 xmDrawingAreaWidgetClass, dropFrame,
494                 NULL);
495
496         XtAddCallback(dropDraw,
497                 XmNexposeCallback, demoDrawExposeCallback,
498                 NULL);
499
500         return dropDraw;
501 }
502
503 /*
504  * main
505  *
506  * Create widgets for the demo program. Call protocol-specific functions
507  * to initialize the drag sources and drop sites.
508  */
509 void
510 main(
511         int             argc,
512         String         *argv)
513 {
514         Widget          outerRowColumn,
515                         upperRowColumn,
516                         textDragSource,
517                         fileDragSource,
518                         apptDragSource,
519                         separator,
520                         textDropSite,
521                         drawDropSite;
522
523         /*
524          * Create basic widgets and layout widgets
525          */
526
527         XtSetLanguageProc(NULL, NULL, NULL);
528
529         demoTopLevel = XtAppInitialize(&demoAppContext, "Dtdnddemo", 
530                 (XrmOptionDescList)NULL, 0, &argc, argv, 
531                 fallbackResources, (ArgList)NULL, 0);
532
533         DtAppInitialize(demoAppContext, XtDisplay(demoTopLevel), 
534                 demoTopLevel, argv[0], "Dtdnddemo"); 
535
536         outerRowColumn = XtVaCreateManagedWidget("outerRowColumn",
537                 xmRowColumnWidgetClass, demoTopLevel,
538                 NULL);
539
540         upperRowColumn = XtVaCreateManagedWidget("upperRowColumn",
541                 xmRowColumnWidgetClass, outerRowColumn,
542                 NULL);
543
544         /*
545          * Create the drag sources
546          */
547
548         textDragSource = textCreateDragSource(upperRowColumn);
549         fileDragSource = fileCreateDragSource(upperRowColumn);
550         apptDragSource = apptCreateDragSource(upperRowColumn);
551
552         /*
553          * Create a line separating the drag sources from the drop sites
554          */
555
556         separator = XtVaCreateManagedWidget("separator",
557                 xmSeparatorWidgetClass, outerRowColumn,
558                 NULL);
559         
560         /*
561          * Create the drop sites
562          */
563
564         textDropSite = textCreateDropSite(outerRowColumn);
565         drawDropSite = demoCreateDropSite(outerRowColumn);
566
567         /*
568          * Realize the widget tree
569          */
570
571         XtRealizeWidget(demoTopLevel);
572
573         /*
574          * Load the data typing database which is used to get icons
575          */
576
577         DtDtsLoadDataTypes();
578
579         /*
580          * Set up the drag sources
581          */
582
583         textDragSetup(textDragSource);
584         fileDragSetup(fileDragSource);
585         apptDragSetup(apptDragSource);
586
587         /*
588          * Set up the drop sites
589          */
590
591         textDropSetup(textDropSite);
592         demoDropSetup(drawDropSite);
593
594         /*
595          * Start the event processing loop
596          */
597
598         XtAppMainLoop(demoAppContext);
599 }