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.c | Calls DnD_init() and
create_user_interface() |
-
Table E-1
| busy_site.icon | Contains the data to display the icon on the desktop indicating a busy drop site |
| drop_site.icon | Contains the data to display the icon on the desktop indicating a normal drop site |
| Makefile | Contains 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
| Frame | Pointer to opaque structure defining the frame |
| Panel | Pointer to opaque structure defining the panel |
| Textsw | Pointer to opaque structure defining the text subwindow |
| Panel_item | Pointer 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);
|
-
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);
}
|
|