1 /* $TOG: demo.c /main/5 1999/07/20 14:48:53 mgreess $ */
2 /*****************************************************************************
3 *****************************************************************************
7 ** Description: The Drag & Drop Demo program demonstrates the
8 ** CDE DnD functions in the Desktop Services library:
11 ** DtDndDropRegister.3x
12 ** DtDndCreateSourceIcon.3x
14 ** The demo consists of a row of three different sources
15 ** for text, filename and appointment buffer drags.
16 ** It also has a text field that can accept either
17 ** text or filename drops. Finally there is a data
18 ** area that accepts filename or buffer drops.
20 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
21 ** (c) Copyright 1993, 1994 International Business Machines Corp.
22 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
23 ** (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
26 ****************************************************************************
27 ************************************<+>*************************************/
34 #include <X11/Intrinsic.h>
37 #include <Xm/DrawingA.h>
41 #include <Xm/MwmUtil.h>
42 #include <Xm/RowColumn.h>
43 #include <Xm/Separator.h>
44 #include <Xm/DragDrop.h>
45 #include <Xm/Screen.h>
55 /*************************************************************************
57 * Data Structures & Declarations For Drag & Drop Demo
59 *************************************************************************/
62 * The Drag Threshold is the distance, measured in pixels, over which the
63 * pointer must travel while the BSelect button (first mouse button) is held
64 * down in order to start a drag. CDE defines this to be 10 pixels.
67 #define DRAG_THRESHOLD 10
70 * Absolute value macro
74 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
82 XtAppContext demoAppContext;
83 Boolean demoDoingDrag = False;
86 * Private Drag & Drop Demo Function Declarations
89 void demoTransferCallback(Widget, XtPointer, XtPointer);
91 /*************************************************************************
93 * General-Purpose Drag & Drop Functions
95 *************************************************************************/
98 * demoDragFinishCallback
100 * Resets drag state to indicate the drag is over.
103 demoDragFinishCallback(
105 XtPointer clientData,
108 demoDoingDrag = False;
112 * demoDragMotionHandler
114 * Determine if the pointer has moved beyond the drag threshold while button 1
115 * was being held down.
118 demoDragMotionHandler(
119 Widget dragInitiator,
120 XtPointer clientData,
123 static int initialX = -1;
124 static int initialY = -1;
126 long dragProtocol = (long)clientData;
128 if (!demoDoingDrag) {
131 * If the drag is just starting, set initial button down coords
134 if (initialX == -1 && initialY == -1) {
135 initialX = event->xmotion.x;
136 initialY = event->xmotion.y;
140 * Find out how far pointer has moved since button press
143 diffX = initialX - event->xmotion.x;
144 diffY = initialY - event->xmotion.y;
146 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
147 (ABS(diffY) >= DRAG_THRESHOLD)) {
148 demoDoingDrag = True;
149 switch (dragProtocol) {
150 case DtDND_TEXT_TRANSFER:
151 textDragStart(dragInitiator, event);
153 case DtDND_FILENAME_TRANSFER:
154 fileCheckForDrag(dragInitiator, event,
157 case DtDND_BUFFER_TRANSFER:
158 apptDragStart(dragInitiator, event);
172 static Bool demoLookForButton(Display *d, XEvent *event, XPointer arg)
175 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
177 if( event->type == MotionNotify)
179 XEvent * press = (XEvent *) arg;
181 if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > DAMPING ||
182 ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > DAMPING)
185 else if (event->type == ButtonRelease) return(True);
194 void demoProcessPress(Widget w, XEvent *event, String *parms, Cardinal *nparms)
196 #define SELECTION_ACTION 0
197 #define TRANSFER_ACTION 1
199 int i, action, cur_item;
200 int *selected_positions, nselected_positions;
203 * This action happens when Button1 is pressed and the Selection
204 * and Transfer are integrated on Button1. It is passed two
205 * parameters: the action to call when the event is a selection,
206 * and the action to call when the event is a transfer.
209 if (*nparms != 2 || !XmIsList(w)) return;
211 action = SELECTION_ACTION;
212 cur_item = XmListYToPos(w, event->xbutton.y);
216 XmNselectedPositions, &selected_positions,
217 XmNselectedPositionCount, &nselected_positions,
220 for (i=0; i<nselected_positions; i++)
222 if (cur_item == selected_positions[i])
225 * The determination of whether this is a transfer drag
226 * cannot be made until a Motion event comes in. It is
227 * not a drag as soon as a ButtonUp event happens.
236 switch (new_event.type)
239 action = TRANSFER_ACTION;
242 action = SELECTION_ACTION;
250 XtCallActionProc(w, parms[action], event, parms, *nparms);
254 * demoDrawAnimateCallback
256 * Expands the icon melted into the draw area by Motif.
259 demoDrawAnimateCallback(
260 Widget dragContext, /* WARNING: This is being destroyed. */
261 XtPointer clientData,
264 DtDndDropAnimateCallbackStruct *animateInfo =
265 (DtDndDropAnimateCallbackStruct *) callData;
266 Widget dropDraw = (Widget)clientData;
267 Display *display = XtDisplayOfObject(dropDraw);
268 Screen *screen = XtScreen(dropDraw);
269 Window window = XtWindow(dropDraw);
270 int expandWidth, expandHeight,
272 static GC graphicsContext = NULL;
277 * Create graphics context if it doesn't yet exist
280 if (graphicsContext == NULL) {
281 gcValues.foreground = BlackPixelOfScreen(screen);
282 gcValues.background = WhitePixelOfScreen(screen);
283 graphicsContext = XCreateGC(display, window,
284 GCForeground | GCBackground, &gcValues);
288 * Get the dragged icon from the dropDraw area
291 XtVaGetValues(dropDraw, XmNuserData, &iconPtr, NULL);
293 if (iconPtr == NULL) {
298 * Set clip mask and coordinates for this icon in the graphics context
301 gcValues.clip_mask = iconPtr->mask;
302 gcValues.clip_x_origin = iconPtr->icon.x;
303 gcValues.clip_y_origin = iconPtr->icon.y;
304 XChangeGC(display, graphicsContext,
305 GCClipMask | GCClipXOrigin | GCClipYOrigin,
309 * Reconstitute the icon after Motif melts it
312 for (expandWidth = expandHeight = 0;
313 expandWidth < (int)iconPtr->icon.width &&
314 expandHeight < (int)iconPtr->icon.height;
315 expandWidth += 2, expandHeight += 2) {
317 sourceX = ((int)iconPtr->icon.width - expandWidth)/2;
318 sourceY = ((int)iconPtr->icon.height - expandHeight)/2;
320 XCopyPlane(display, iconPtr->bitmap, window, graphicsContext,
321 sourceX, sourceY, expandWidth, expandHeight,
322 iconPtr->icon.x + sourceX, iconPtr->icon.y + sourceY,
325 XmeMicroSleep(25000L);
331 * demoDrawExposeCallback
333 * Draws all the icons associated with the drawing area.
336 demoDrawExposeCallback(
338 XtPointer clientData,
343 XtVaGetValues(widget, XmNuserData, &iconPtr, NULL);
345 while (iconPtr != NULL) {
346 IconDraw(widget, iconPtr);
347 iconPtr = iconPtr->next;
354 * Registers draw area to accept drops of files or buffers such as appointments.
360 static XtCallbackRec transferCBRec[] = { {demoTransferCallback, NULL},
362 static XtCallbackRec animateCBRec[] = { {demoDrawAnimateCallback, NULL},
365 animateCBRec[0].closure = (XtPointer)dropDraw;
367 DtDndVaDropRegister(dropDraw,
368 DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
369 XmDROP_COPY | XmDROP_MOVE, transferCBRec,
370 DtNdropAnimateCallback, animateCBRec,
371 DtNtextIsBuffer, True,
372 DtNpreserveRegistration, False,
377 * demoTransferCallback
379 * Called when something is dropped on the drawing area drop site. If the
380 * transfer protocol is DtDND_FILENAME_TRANSFER or DtDND_BUFFER_TRANSFER
381 * the fileTransferCallback and apptTransferCallback are called respectively.
384 demoTransferCallback(
386 XtPointer clientData,
389 DtDndTransferCallbackStruct *transferInfo =
390 (DtDndTransferCallbackStruct *) callData;
392 if (transferInfo == NULL) {
396 switch (transferInfo->dropData->protocol) {
398 case DtDND_FILENAME_TRANSFER:
399 fileTransferCallback(widget, clientData, callData);
401 case DtDND_BUFFER_TRANSFER:
402 apptTransferCallback(widget, clientData, callData);
407 /*************************************************************************
409 * Demo Client Creation
411 *************************************************************************/
414 * Fallback resources are used if app-defaults file is not found
417 String fallbackResources[] = {
418 "title: CDE Drag & Drop Demo",
420 "*outerRowColumn.orientation: VERTICAL",
421 "*outerRowColumn.spacing: 15",
422 "*outerRowColumn.marginHeight: 15",
423 "*outerRowColumn.marginWidth: 15",
425 "*upperRowColumn.orientation: HORIZONTAL",
426 "*upperRowColumn.packing: PACK_COLUMN",
427 "*upperRowColumn.spacing: 15",
428 "*upperRowColumn.marginHeight: 0",
429 "*upperRowColumn.marginWidth: 0",
431 "*fileDraw.height: 175",
432 "*fileDraw.resizePolicy: RESIZE_NONE",
434 "*fruitList.listSizePolicy: CONSTANT",
435 "*fruitList.scrollBarDisplayPolicy: STATIC",
436 "*fruitList.selectionPolicy: MULTIPLE_SELECT",
438 "*apptList.listSizePolicy: CONSTANT",
439 "*apptList.scrollBarDisplayPolicy: STATIC",
440 "*apptList.selectionPolicy: MULTIPLE_SELECT",
442 "*textRowColumn.orientation: HORIZONTAL",
443 "*textRowColumn.packing: PACK_TIGHT",
444 "*textRowColumn*textLabel.labelString: Name:",
445 "*textRowColumn*textField.width: 550",
446 "*textRowColumn.marginWidth: 0",
448 "*dropDraw.height: 100",
449 "*dropDraw.resizePolicy: RESIZE_NONE",
456 * Creates the drawing area at the bottom of the demo which is used as a drop
457 * site for files and appointments.
466 dropFrame = XtVaCreateManagedWidget("dropFrame",
467 xmFrameWidgetClass, parent,
470 dropDraw = XtVaCreateManagedWidget("dropDraw",
471 xmDrawingAreaWidgetClass, dropFrame,
474 XtAddCallback(dropDraw,
475 XmNexposeCallback, demoDrawExposeCallback,
484 * Create widgets for the demo program. Call protocol-specific functions
485 * to initialize the drag sources and drop sites.
492 Widget outerRowColumn,
502 * Create basic widgets and layout widgets
505 XtSetLanguageProc(NULL, NULL, NULL);
507 demoTopLevel = XtAppInitialize(&demoAppContext, "Dtdnddemo",
508 (XrmOptionDescList)NULL, 0, &argc, argv,
509 fallbackResources, (ArgList)NULL, 0);
511 DtAppInitialize(demoAppContext, XtDisplay(demoTopLevel),
512 demoTopLevel, argv[0], "Dtdnddemo");
514 outerRowColumn = XtVaCreateManagedWidget("outerRowColumn",
515 xmRowColumnWidgetClass, demoTopLevel,
518 upperRowColumn = XtVaCreateManagedWidget("upperRowColumn",
519 xmRowColumnWidgetClass, outerRowColumn,
523 * Create the drag sources
526 textDragSource = textCreateDragSource(upperRowColumn);
527 fileDragSource = fileCreateDragSource(upperRowColumn);
528 apptDragSource = apptCreateDragSource(upperRowColumn);
531 * Create a line separating the drag sources from the drop sites
534 separator = XtVaCreateManagedWidget("separator",
535 xmSeparatorWidgetClass, outerRowColumn,
539 * Create the drop sites
542 textDropSite = textCreateDropSite(outerRowColumn);
543 drawDropSite = demoCreateDropSite(outerRowColumn);
546 * Realize the widget tree
549 XtRealizeWidget(demoTopLevel);
552 * Load the data typing database which is used to get icons
555 DtDtsLoadDataTypes();
558 * Set up the drag sources
561 textDragSetup(textDragSource);
562 fileDragSetup(fileDragSource);
563 apptDragSetup(apptDragSource);
566 * Set up the drop sites
569 textDropSetup(textDropSite);
570 demoDropSetup(drawDropSite);
573 * Start the event processing loop
576 XtAppMainLoop(demoAppContext);