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.
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.
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:
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.
A null-terminated string containing the name (with the complete path) of a file.
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.
A null-terminated text block containing valid text characters.
A null-terminated string containing the name (with the complete path) of a directory.
A null-terminated string containing the name (with the complete path) of a link that points to nowhere (a stale link).
A null-terminated string containing the name (with the complete path) of an executable file (a program).
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
.
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.
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:
DndSetData
, the old data stored on the DND
global buffer will be destroyed.DndSetData
function will return automatically if
the data is already set. But the handler will perform the data
initialization anyway, be careful. The function DndHandleDragging
will return non-zero only if a drag really took place, otherwise it
will return zero. This can be useful if you want to keep track of
the current drag state.Next Chapter, Previous Chapter
Table of contents of this chapter, General table of contents
Top of the document, Beginning of this Chapter