2. Using DND in your Xt programs

Contents of this section

2.1 Introduction

When a drag or a drop action occur within your program certain functions will be called. These functions are called event handlers, because they are only called when certain event occurs. The format of an Xt event handler function is

void EventHandler(Widget,XtPointer,Event*,Boolean*);
Thanks to DND, that is all you have to know about events and event handlers. I will assume only that you know what a widget is (since you are programming with the Xt interface this is very fair). Your program may have a lot of event handlers, since you may want to handle drop events in different ways for different areas of your application. The same thing applies to drag actions.

2.2 Initializing DND

For each module of your program that uses DND you must include the header file OffiX/DragAndDrop.h. The next thing to do is to initialize DND. This is done with the function

void DndInitialize(Widget toplevel);
where toplevel is the top level widget of your application. You must call the function after the creation of the widget (e.g. after XtAppInitialize). The next thing to do is to register the widgets you want to be able to receive drops and/or to send drag events (note that a widget can be able to receive drops but nothing can be dragged from it - e.g. a waste basket). You can do this with the functions
void DndRegisterDropWidget(Widget widget,XtEventHandler handler,XtPointer d);
void DndRegisterDragWidget(Widget widget,XtEventHandler handler,XtPointer d);
where widget is the widget in consideration, handler is the function to be called when the drop or drag actions take place, and d is something you should not care about, just replace with NULL.

If you want to handle drops on non-registered widgets, use the function

void DndRegisterOtherDrop(XtEventHandler handler);
for drops on icons,
void DndRegisterIconDrop(XtEventHandler handler);
and, if something can be dragged from your program, you may want to handle drops on the root window (e.g. the ``files'' program open a new file window each time a directory is dropped on the root window),
void DndRegisterRootDrop(XtEventHandler handler);

Now your DND protocol is initialized. Now you must define the handlers and link your program with the option -lDnd and everything should work. The next sections are devoted to the handler functions definition. Before going on, just a note about the icon drops:

Icon drops will not work with the vast majority of window managers. This happens because the managers do not pass the client message events that are sent to the icons to the client windows. If the window manager does that, then icon drops will work.

2.3 The DND data types

The current data type supported by DND are the following:

DndRawData      Any kind of data.
DndFile         A file name.
DndFiles        List of file names.
DndText         Text block.
DndDir          Directory name.
DndLink         Name of a stale link.
DndExe          Name of a program.
DndUnknown      Undefined data.

When you initialize the data (with the DndSetData function) you must furnish the correct structure for DND. The structure for the various types is the following:

DndRawData

Any kind of data. If the data you want to send does not fall into any category, use this one. Do not use DndUnknown. See the DndUnknown description to see why.

DndFile

A null-terminated string containing the name (with the complete path) of a file.

DndFiles

A sequence of null-terminated strings, each one containing a complete file name. The end of the list is determined by a zero-lenght file name.

DndText

A null-terminated text block containing valid text characters.

DndDir

A null-terminated string containing the name (with the complete path) of a directory.

DndLink

A null-terminated string containing the name (with the complete path) of a link that points to nowhere (a stale link).

DndExe

A null-terminated string containing the name (with the complete path) of an executable file (a program).

DndUnknown

You must not set this type to any kind of data. Use DndRawData instead. You can only receive unknown data. This can happen when a program compiled with a newer version of DND send a data that your version of DND does not understand. Your program must handle this kind of data as if it were a DndRawData.

2.4 Retreiving data: the drop event handler

Ok, so you received a drop, and the event handler for this drop was called. The first think you need to know, as a programmer, is that your drop event handler can be called even if a drop did not occur (it's a rare thing, but can happen). The next thing you need to know is the data type of the drop event. Both needs can be satisfied by the function

int DndDataType(XEvent *event)
where event is the event that the drop handler received. If the event was not a DND drop event, then the function returns DndNotDnd. If it was, then the function will return the data type.

Ok, it's a drop event, and you want to process the specific data type. To retreive the drop data, use the function

void DndGetData(unsigned char **Data,unsigned long *Size)
where Data is the data recipient and Size a unsigned long that will contain the data lenght (including NULL characters at the end of strings).

Here is an example of how to use these two functions in a drop event handler:


void MyDropEventHandler(Widget w,XtPointer pnt,XEvent *event,Boolean* b)
{
        int DataType;
        unsigned long DataSize;
        char *Data;
        
        if(DndDataType(event)==DndNotDnd) return;
        DndGetData(& Data,& DataSize);
        
        ... data processing ...
        
}

Now, just a note about memory management: the actual version of DND does not reserve any space for the data. Therefore, if your data processing takes too long and the user make another drag and drop action the data will be corrupted. So, if you want to keep the data for a long time, the best thing to do is to alloc space for it and copy the returned contents.

2.5 Sending data: the drag event handler

Hey - the user said - I want to send data from you to another program right now! So here you are, on the drag event handler. So you, as the programmer, wants to set the data and let DND take care of the rest. For the first task you can use the function

void DndSetData(int Type,unsigned char *Data,unsigned long Size);
The Size field must be the total size of the data, including the NULL character of strings. The Data must be formatted according to the data Type. For a description of the data structures refer to section The DND data types .

Now all you need to do is to call DND and let it handle the drag action by calling the function DndHandleDragging. Here is an example of a drag handler:


void MyDragEventHandler(Widget w,XtPointer pnt,XEvent *event,Boolean* b)
{
        int DataType;
        unsigned long DataSize;
        char *Data;
        
        ... data initialization ...
        
        DndSetData(DataType,Data,DataSize);
        DndHandleDragging(w,event);
}

Once a drag action takes place, DndHandleDragging will take control and will return only after the corresponding drop. Now, two things worth reading:


Next Chapter, Previous Chapter

Table of contents of this chapter, General table of contents

Top of the document, Beginning of this Chapter