Desktop Integration Guide
검색에만이 책은
PDF로 이 문서 다운로드

Drag and Drop Programming Example for XView Toolkit

E

This example program illustrates an implementation of drag and drop using the XView toolkit. Its source file, icon resources, and Makefile can be found online at $OPENWINHOME/share/src/dig_samples/dnd_xview1. When the program is executed, it opens a text window with a drag and drop target. Users may drag any text file from the file manager and drop it on the window's drop site. The text will be displayed in the text pane, and the filename path will appear in the window header. The file can also be imported by entering the filename in the window header.
The document can be exported by dragging the drag and drop target to another window. A portion of the text can be moved by selecting the desired text and dropping it at a specific insert point. Section 3.4, "Drag and Drop Programming Example: OLIT Toolkit" shows a drag and drop example implemented with the OLIT toolkit.
Table E-1
xview_dnd.cCalls DnD_init() and
create_user_interface()
Table E-1
busy_site.iconContains the data to display the icon on the desktop indicating a busy drop site
drop_site.iconContains the data to display the icon on the desktop indicating a normal drop site
MakefileContains the commands to compile and link the example executable
Table E-2 Overview of the Functions
main()Calls DnD_init() and
create_user_interface()
create_user_interface()Creates the frame and text window
DnD_init()Creates drop site & drag object
drop_proc()Event callback procedure; the event
procedure for the drop
get_primary_selection()Called from drop_proc(); gets the data from the source
load_file_proc()Event callback procedure; callback that displays the file name on the panel
The following sections describe the contents of xview_dnd.c in more detail.

E.1 Opening Declarations

The program begins with the compiler include directives and the global object definitions. Note that the header file dragdrop.h is only distributed with OpenWindows Version 3.0.1 or later.
Four global data types are defined:
Table E-3
FramePointer to opaque structure defining the frame
PanelPointer to opaque structure defining the panel
TextswPointer to opaque structure defining the text subwindow
Panel_itemPointer to opaque structure defining a panel item (the load_file prompt)
A structure with two members (atom and *name) is declared to store three server atoms. It is initialized with zeros at this time. Actual server atom values will be loaded during the initialization (in the DnD_init() function called later). Note that the structure does not have a formal name declared. A formal structure name is not required when a structure is declared if the storage is allocated at the same time.
Here are the contents of the top of xview_dnd.c, before the definition of the main function:

  #include <xview/xview.h>  
  #include <xview/panel.h>  
  #include <xview/textsw.h>  
  #include <xview/dragdrop.h>  
  #include <xview/xv_xrect.h>  
  
  /* Global Object definitions  
   *  
   */  
  
  Frame        frame;  
  Panel        panel;  
  Textsw       textsw;  
  Panel_item   load_file;  
  
  #define FILE_NAME_ATOM        0  
  #define _SUN_AVAILABLE_TYPES_ATOM        1  
  #define XA_STRING_ATOM        2  
  #define TOTAL_ATOMS                3  


  struct  
  {  
       Atomatom;  
       char*name;  
  } atom_list[TOTAL_ATOMS] =  
  {  
       {0,"FILE_NAME"},  
       {0,"_SUN_AVAILABLE_TYPES"},  
       {0,"XA_STRING"},  
  };  
  
  Drag_dropdrag_object; /* The drag object */  

E.2 Function: Main()

The program's main function is straightforward. Two functions without return values, create_user_interface() and DnD_init(), are declared. The xv_init() procedure establishes connections with the X server, initializes the Notifier, reads the ~/.Xdefaults database and reads any passed arguments.
The program then calls the two functions: create_user_interface() creates the frame, the panel, and the text sub window; and DnD_init() creates the drop site and the drag object.
Finally, xv_main_loop() is executed, telling the Notifier to start dispatching events.

  main(int argc, char **argv)  
  {  
       Xv_Server   server;  
          void        DnD_init(), create_user_interface();  
       server = xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);  
          create_user_interface();  
  
          DnD_init(server);  


       xv_main_loop(frame);  
  }  

E.3 Function: create_user_interface()

The create_user_interface() function, called from main(), uses the xv_create() procedure call to create the frame, the panel, the panel text (the file name prompt), and the text subwindow where the file is displayed. Notice that the xv_create() procedure with the load_file handle that creates the Filename: prompt also registers the load_file_proc() function with the Notifier.

  /*  
   *  create_user_interface: Create the user interface components.  
   */  
  
  void  
  create_user_interface()  
  {  
          Panel_setting    load_file_proc();  
       frame = xv_create(NULL,       FRAME,  
                           XV_LABEL, "Drag-n-Drop Demo",  
                              XV_WIDTH,  600,  
                              XV_HEIGHT, 300,  
                              FRAME_SHOW_FOOTER, TRUE,  
                              NULL);  
  
          panel = xv_create(frame,      PANEL,  
                              XV_X,     0,  
                              XV_Y,     0,  
                              XV_WIDTH, WIN_EXTEND_TO_EDGE,  
                              XV_HEIGHT,50,  
                              NULL);  
  
          load_file = xv_create(panel,  PANEL_TEXT,  
                                  PANEL_VALUE_DISPLAY_LENGTH, 45,  
                                  PANEL_VALUE_STORED_LENGTH, 80,  
                                  PANEL_LABEL_STRING, "Filename:",  
                                  PANEL_LAYOUT,PANEL_HORIZONTAL,  
                                  PANEL_READ_ONLY, FALSE,  
                                  PANEL_NOTIFY_PROC, load_file_proc,  


                                  NULL);  
  
           textsw = xv_create(frame,        TEXTSW,  
                                WIN_BELOW,  panel,  
                                XV_WIDTH,   WIN_EXTEND_TO_EDGE,  
                                XV_HEIGHT,  WIN_EXTEND_TO_EDGE,  
                                NULL);  
  }  

E.4 Function: DnD_init()

The DnD_init() function creates the drag and drop target as well as the drag and drop target busy glyph. The for loop gets the three server atoms and loads them into the structure (which was declared in the global object definitions at the beginning of the program). Note that the last xv_create() procedure registers the drop_proc() function with the Notifier.

  /*  
   *  DnD_init: Create a drop site, and a drag object.  
   */  
  void  
  DnD_init(Xv_Server server)  
  {  
       Xv_drop_sitedrop_site;  
       Xv_opaquedrop_glyph;  
       Xv_opaquebusy_glyph;  
  
          static unsigned short   drop_icon[] = {  
  #include "drop_site.icon"  
          };  
          static unsigned short   busy_icon[] = {  
  #include "busy_site.icon"  
          };  
  
       inti;  
  
       for(i = 0; i < TOTAL_ATOMS; i++)  
       {  
       atom_list[i].atom = xv_get(server,  
                SERVER_ATOM,  
                atom_list[i].name);  


       }  
  
       atom_list[XA_STRING_ATOM].atom = XA_STRING;  
  
       drag_object = xv_create(panel, DRAGDROP, NULL);  
  
          drop_glyph = xv_create(XV_NULL, SERVER_IMAGE,  
                  SERVER_IMAGE_BITS, drop_icon,  
                  SERVER_IMAGE_DEPTH, 1,  
                  XV_WIDTH, 32,  
                  XV_HEIGHT, 32,  
                  NULL);  
  
          busy_glyph = xv_create(XV_NULL, SERVER_IMAGE,  
                  SERVER_IMAGE_BITS, busy_icon,  
                  SERVER_IMAGE_DEPTH, 1,  
                  XV_WIDTH, 32,  
                  XV_HEIGHT, 32,  
                  NULL);  
  
       xv_create(panel,                        PANEL_DROP_TARGET,  
           PANEL_DROP_DND,drag_object,  
           PANEL_DROP_GLYPH,drop_glyph,  
           PANEL_DROP_BUSY_GLYPH,busy_glyph,  
           PANEL_NOTIFY_PROC,drop_proc,  
           PANEL_DROP_FULL,TRUE,  
           NULL);  
  }  

E.5 Function: drop_proc()

The drop_proc() routine is the event callback procedure that initiates the drag and drop operation. If the operation is a drag, the case statement handles it either as a move or a copy. If the operation is a drag from the drag and drop target, the third case statement (LOC_DRAG) is used. This code determines whether the filename or the data string is passed.
This first xv_create() associates the selection targets with a corresponding selection atom. The second xv_create() will determine if a filename is being passed, and the third, if the text string is to be passed. In addition, the message
"Start dragging" is printed in the lower left of the frame. Notice that the argument lists of xv_create() and xv_set() are variable length and must be terminated with NULL statements.
The create_user_interface() function, described earlier, registers drop_proc() with the Notifier.

  /* drop_proc: Setup the drag operation and handle the drop.  
   *  
   */  
  void  
  drop_proc(Xv_opaque item, unsigned int value, Event *event)  
  {  
       long    length;  
       int     format;  
       char    *sel_string;  
       char    *string;  
       Selection_requestorsel_req;  
       char    *buff;  
       int     txt_len;  
       Atom    list[4];  
          void             get_primary_selection(Selection_requestor  
  sel_req);  
  
       sel_req = xv_get(item, PANEL_DROP_SEL_REQ);  
  
       printf("sel_req = %X\n", sel_req);  
       switch(event_action(event))  
       {  
       caseACTION_DRAG_MOVE:/* they are moving the object */  
       printf("drag move\n");  
       get_primary_selection(sel_req);  
       break;  
  
       caseACTION_DRAG_COPY:/* they are copying the object */  
       printf("drag copy\n");  
       get_primary_selection(sel_req);  
       break;  
  
       caseLOC_DRAG:  
       list[0] = atom_list[_SUN_AVAILABLE_TYPES_ATOM].atom;  
       list[1] = atom_list[FILE_NAME_ATOM].atom;  
       list[2] = atom_list[XA_STRING_ATOM].atom;  
       list[3] = NULL;  


       xv_create(drag_object, SELECTION_ITEM,  
           SEL_DATA, list,  
           SEL_FORMAT,32,  
           SEL_LENGTH,4,  
           SEL_TYPE,    atom_list[_SUN_AVAILABLE_TYPES_ATOM].atom,  
           SEL_OWN,TRUE,  
           NULL);  
  
       string = (char *)xv_get(load_file, PANEL_VALUE);  
  
       xv_create(drag_object, SELECTION_ITEM,  
           SEL_DATA, string,  
           SEL_FORMAT,8,  
           SEL_LENGTH,strlen(string),  
           SEL_TYPE,atom_list[FILE_NAME_ATOM].atom,  
           SEL_OWN,TRUE,  
           NULL);  
  
       txt_len = xv_get(textsw, TEXTSW_LENGTH) + 1;  
       string = (char *)calloc(txt_len,1);  
       xv_get(textsw,  
           TEXTSW_CONTENTS, 0, string, txt_len);  
  
       xv_create(drag_object, SELECTION_ITEM,  
           SEL_DATA, string,  
           SEL_FORMAT,8,  
           SEL_LENGTH,strlen(string),  
           SEL_TYPE,atom_list[XA_STRING_ATOM].atom,  
           SEL_OWN,TRUE,  
           NULL);  
  
       xv_set(frame,  
           FRAME_LEFT_FOOTER,"Start draging",  
           NULL);  
       printf("Start draging\n");  
       break;  
       default:  
       printf("unknown event %d\n", event_action(event));  
       }  
  
  }  

E.6 Function: get_primary_selection()

The get_primary_selection() function is called from either the move or copy switch statements of the drop_proc() callback function. This function will get data from the source in the format mutually agreed upon. The first xv_get() function determines from the passed atom the selection datatype. If the selection is a filename, the text string is retrieved from the file and placed in the text subwindow. If the selection is a text string, the last xv_get() function retrieves the string and places it in the text subwindow.

  void  
  get_primary_selection(Selection_requestor sel_req)  
  {  
       long            length;  
       int             format;  
       char*sel_string;  
       char*string;  
       Atom*list;  
       int i;  
  
       list = NULL;  
       xv_set(sel_req, SEL_TYPE,  
  atom_list[_SUN_AVAILABLE_TYPES_ATOM].atom, 0);  
       list = (Atom *) xv_get(sel_req, SEL_DATA, &length, &format);  
       if (length == SEL_ERROR)  
       {  
       printf("*** Unable to get target list.\n");  
       }  
       else  
       {  
       printf("length = %d format = %d\n", length, format);  
       while(*list)  
       {  
           printf("list = %X\n", list);  
           for(i = 0; i < TOTAL_ATOMS; i++)  
           {  
                if(*list == atom_list[i].atom)  
                {  
                printf("supports %d %s\n", i,  
                     atom_list[i].name);  
                break;  
                }  
           }  
           list++;  


       }  
       }  
       xv_set(sel_req, SEL_TYPE, atom_list[FILE_NAME_ATOM].atom,  
  0);  
       string = (char *) xv_get(sel_req, SEL_DATA, &length,  
  &format);  
       if (length != SEL_ERROR)  
       {  
       printf("length = %d format = %d\n", length, format);  
       /* Create a NULL-terminated version of 'string' */  
       sel_string = (char *) calloc(1, length + 1);  
       strncpy(sel_string, string, length);  
  
       xv_set(load_file, PANEL_VALUE, string, NULL);  
       xv_set(textsw,  
           TEXTSW_FILE,string,  
           NULL);  
       return;  
       }  
       else  
       {  
       printf("*** Unable to get FILE_NAME_ATOM selection.\n");  
       }  
  
       xv_set(sel_req, SEL_TYPE, atom_list[XA_STRING_ATOM].atom,  
  0);  
       string = (char *) xv_get(sel_req, SEL_DATA, &length,  
  &format);  
       if (length != SEL_ERROR)  
       {  
       printf("length = %d format = %d\n", length, format);  
       /* Create a NULL-terminated version of 'string' */  
       sel_string = (char *) calloc(1, length + 1);  
       strncpy(sel_string, string, length);  
  
       textsw_reset(textsw, 0, 0);  
       textsw_insert(textsw, string, length);  
       }  
       else  
       {  
       printf("*** Unable to get XA_STRING_ATOM selection.\n");  
       }  
  }  

E.7 Function: load_file_proc()

The function load_file_proc() is the event callback procedure that loads the selected file into the text subwindow when the user enters a valid file name followed by a Return.

  /*  
   * Notify callback function for `filename'. This routine loads the  
   * named file into the textpane.  
   */  
  
  Panel_setting  
  load_file_proc(Panel_item item, Event *event)  
  {  
       char *value = (char *) xv_get(item, PANEL_VALUE);  
  
       fprintf(stderr, "DnD_demo: load_file: value: %s\n", value);  
  
       xv_set(textsw,  
       TEXTSW_FILE,value,  
       NULL);  
  
       return panel_text_notify(item, event);  
  }