  The Drag and Drop HOWTO
  Csar Augusto Rorato Crusius, cc..ccrruussiiuuss@@iieeeeee..oorrgg
  v1.0, 2 March 1996

  This document describes how to enable your X and Xt programs to use
  drag and drop using the DND protocol. A CC Xt interface to DND is pro-
  vided with OffiX, a collection of general utilities already using DND
  protocol (file manager and text editor included).

  11..  IInnttrroodduuccttiioonn

  11..11..  WWhhaatt iiss aa ddrraagg aanndd ddrroopp pprroottooccooll ??

  I'm supposing you understand what ``drag and drop'' means. It's an
  intuitive way to exchange data between programs. A drag and drop
  protocol is the mean used by the programs to comunicate with each
  other in order to perform this data exchange. If the programs want to
  exchange information, they must be able to comunicate with each other
  in a common language. This language is the ``protocol''. Therefore, if
  you create your own protocol, chances are other programs will not
  understand you. So you must ``talk'' to other programs in a common
  language. In this way, when you receive a drop, you will receive a ``I
  dropped on you'' message, and you will understand the message no
  matter who send it to you. This is the purpose of a drag and drop
  protocol: to provide a common language for this kind of actions.


  11..22..  WWhhaatt iiss DDNNDD,, aanndd wwhhyy sshhoouulldd II uussee iitt ??

  DND is a drag and drop protocol developed by Csar Crusius. A CC
  interface to Xt-based programs is avaliable together with OffiX, a
  collection of useful utilities using the DND protocol.

  If you have a program that could benefit from having drag and drop
  capabilities, DND might be a good choice for the following reasons:


  +o  It is public, unlike other ``standard'' protocols such as those
     used by Open Look and Motif. These two are incompatible, and
     aren't, as far as I know, published. Since Open Look and Motif
     applications are Xt based, you can choose to use DND or the
     specific protocol. This could be a compile-time option, for
     example.

  +o  You can use this protocol with _a_n_y X program. Motif, Open Look and
     Athena applications can exchange data using the DND protocol. Non-
     Xt programs can incorporate DND protocol too (see section ``The DND
     internals'').

  +o  A CC Xt interface is provided, so you can add drag and drop
     capabilities to an existing Xt program with a minimum effort.

  Of course, there are also reasons to _n_o_t use DND:


  +o  You _m_u_s_t exchange data between your application and another that
     uses another protocol.

  +o  You don't need drag and drop, and in this case I wonder why are you
     still reading this.

  I encourage you to use DND at least as a compile-time option for your
  program.  There is already a good reason to do that: the ``files''
  program furnished with OffiX. Won't it be good to be able to exchange
  data with a file manager?  Certainly will! And, as you will note, it's
  very easy to bring this new capability to your program.
  11..33..  GGeettttiinngg aanndd iinnssttaalllliinngg DDNNDD

  In the actual stage you can only get the Xt interface for DND. If you
  want to use DND in non-Xt applications, you must write some code. It
  is not a difficult task to do so (see section ``The DND internals'').

  The best way to install the DND Xt interface library is the following:


  +o  Get the OffiX package. It can be found at
     http://gutenberg.lcmi.ufsc.br/OffiX

  +o  Unpack the file somewhere. Edit the file IImmaakkee..ooppttiioonnss to suit your
     needs. If you don't want any OffiX utility installed, don't compile
     the OffiX modules (remove all from OOFFFFIIXX__MMOODDUULLEESS option).

  +o  Type the command xxmmkkmmff ;; mmaakkee MMaakkeeffiilleess ;; mmaakkee

  +o  As root, type mmaakkee iinnssttaallll

  +o  As root, type mmaakkee iinnssttaallll..mmaann

  Now you should have the static DND C and C++ libraries (libDnd and
  libDnd++ respectively) and the necessary header files installed on
  your system. If you are not root and want to compile your program with
  DND, just copy the files lliibbDDnndd..aa and the DND header files from the
  OffiX directory and compile and link them with your program (pass the
  options -L. -lDnd to the linker). If your program is in C++ use the
  lliibbDDnndd++++..aa instead.


  11..44..  DDNNDD aanndd wwiinnddooww mmaannaaggeerrss

  There seems to be a strange behaviour when DND programs run under
  OpenWindows, at least under the version I have in my work. With FVWM
  there are no problems reported yet. If you run DND programs under
  another window manager, please send me a note telling about the
  results.


  22..  UUssiinngg DDNNDD iinn yyoouurr XXtt pprrooggrraammss

  22..11..  IInnttrroodduuccttiioonn

  When a drag or a drop action occur within your program certain
  functions will be called. These functions are called _e_v_e_n_t _h_a_n_d_l_e_r_s,
  because they are only called when certain _e_v_e_n_t 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..22..  IInniittiiaalliizziinngg DDNNDD

  For each module of your program that uses DND you must include the
  header file OOffffiiXX//DDrraaggAAnnddDDrroopp..hh. The next thing to do is to initialize
  DND.  This is done with the function


       void DndInitialize(Widget toplevel);




  where ttoopplleevveell is the top level widget of your application. You must
  call the function after the creation of the widget (e.g. after XXttAApp--
  ppIInniittiiaalliizzee). 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 wwiiddggeett is the widget in consideration, hhaannddlleerr is the function
  to be called when the drop or drag actions take place, and dd is some-
  thing 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2..33..  TThhee DDNNDD ddaattaa ttyyppeess

  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 DDnnddSSeettDDaattaa function) you must
  furnish the correct structure for DND. The structure for the various
  types is the following:


     DDnnddRRaawwDDaattaa
        Any kind of data. If the data you want to send does not fall
        into any category, use this one. _D_o _n_o_t _u_s_e _D_n_d_U_n_k_n_o_w_n. See the
        DDnnddUUnnkknnoowwnn description to see why.

     DDnnddFFiillee
        A null-terminated string containing the name (with the complete
        path) of a file.

     DDnnddFFiilleess
        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.

     DDnnddTTeexxtt
        A null-terminated text block containing valid text characters.

     DDnnddDDiirr
        A null-terminated string containing the name (with the complete
        path) of a directory.

     DDnnddLLiinnkk
        A null-terminated string containing the name (with the complete
        path) of a link that points to nowhere (a stale link).

     DDnnddEExxee
        A null-terminated string containing the name (with the complete
        path) of an executable file (a program).

     DDnnddUUnnkknnoowwnn
        You must not set this type to any kind of data. Use DDnnddRRaawwDDaattaa
        instead. You can only _r_e_c_e_i_v_e 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 DDnnddRRaawwDDaattaa.


  22..44..  RReettrreeiivviinngg ddaattaa:: tthhee ddrroopp eevveenntt hhaannddlleerr

  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 eevveenntt is the event that the drop handler received. If the event
  was not a DND drop event, then the function returns DDnnddNNoottDDnndd. 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 DDaattaa is the data recipient and SSiizzee 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2..55..  SSeennddiinngg ddaattaa:: tthhee ddrraagg eevveenntt hhaannddlleerr

  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 SSiizzee field must be the total size of the data, including the NULL
  character of strings. The DDaattaa must be formatted according to the data
  TTyyppee. 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 DDnnddHHaannddlleeDDrraaggggiinngg. 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, DDnnddHHaannddlleeDDrraaggggiinngg will take control
  and will return only after the corresponding drop. Now, two things
  worth reading:

  +o  You don't need to allocate space for the Data, DND will do that for
     you.  In fact, when you call DDnnddSSeettDDaattaa, the old data stored on the
     DND global buffer will be destroyed.

  +o  The drag event handler can be called many times before a drag
     actually take place. The DDnnddSSeettDDaattaa function will return
     automatically if the data is already set. But the handler will
     perform the data initialization anyway, be careful. The function
     DDnnddHHaannddlleeDDrraaggggiinngg 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.


  33..  TThhee DDNNDD iinntteerrnnaallss

  I will not describe the DND internals in detail. Instead, I will give
  the information necessary for the non-Xt programmers to handle DND
  drops. I will do that because I don't have time to document the whole
  thing, sorry.  If you want to handle drags you may take a look at the
  DND code.  DND defines two atoms that you must define too. This can be
  done with the following code:


       ______________________________________________________________________
       Atom DndProtocol,DndSelection;
       DndProtocol=XInternAtom(display,"DndProtocol",False);
       DndSelection=XInternAtom(display,"DndSelection",False);
       ______________________________________________________________________




  When a drop occurs, DND will send a client message event to the top
  level window of the application that receives the drop. The event will
  have the following data:
       Event.xclient.type              = ClientMessage;
       Event.xclient.message_type      = DndProtocol;
       Event.xclient.format            = 32;
       Event.xclient.data.l[0]         = DataType;
       Event.xclient.data.l[1]         = (long)event->xbutton.state;
       Event.xclient.data.l[2]         = (long)widget;
       Event.xclient.data.l[3]         = 0;
       Event.xclient.data.l[4]         = 0;




  So your program main event loop will need to intercept this message
  and take the appropriate action. Normally, this action consists in
  getting the drop data and processing it. This can be done by getting
  the DDnnddSSeelleeccttiioonn property contents of the root window.


















































