Jump to content

PMGuide - Direct Manipulation: Difference between revisions

From EDM2
Ak120 (talk | contribs)
mNo edit summary
Ak120 (talk | contribs)
Line 338: Line 338:
The DM_DROPHELP message is not supported for the Pickup and Drop protocol, because help could be requested for any subject at any point during the operation. If the application is to provide Drop help, it must do so from a menu choice and explicitly code the support to be provided.  
The DM_DROPHELP message is not supported for the Pickup and Drop protocol, because help could be requested for any subject at any point during the operation. If the application is to provide Drop help, it must do so from a menu choice and explicitly code the support to be provided.  
==About Rendering Mechanisms==
==About Rendering Mechanisms==
The following sections describe the standard rendering mechanisms used by various containers and applications for direct manipulation.  
The following sections describe the standard rendering mechanisms used by various containers and applications for direct manipulation.
 
===OS/2 File Rendering Mechanism===
===OS/2 File Rendering Mechanism===
This rendering mechanism can be used by various containers, including file folders and trash cans. These containers allow objects to be dragged and dropped on white space in the container to accomplish a Move or Copy operation. They also can allow objects in the same or another container to be dragged and dropped on objects within the container to accomplish an operation.  
This rendering mechanism can be used by various containers, including file folders and trash cans. These containers allow objects to be dragged and dropped on white space in the container to accomplish a Move or Copy operation. They also can allow objects in the same or another container to be dragged and dropped on objects within the container to accomplish an operation.
 
====Mechanism Name====
====Mechanism Name====
The string for this rendering mechanism is DRM_OS2FILE.  
The string for this rendering mechanism is DRM_OS2FILE.
 
====Messages====
====Messages====
The following messages are used by the DRM_OS2FILE:
The following messages are used by the DRM_OS2FILE:
 
;DM_RENDER:This message is sent by a target to a source to request a rendering for an object. When this message is received, the source determines if it understands the rendering mechanism and format selected by the target for the object. It also confirms that it allows the operation selected by the user for that object. The source must respond to this message before proceeding with the rendering operation.
;DM_RENDER
;DM_RENDERCOMPLETE:This message is posted by a source to a target to notify the target that the rendering operation has been completed by the source, either successfully or unsuccessfully. The source can elect to let the target retry a successful or an unsuccessful operation. In this case, it should return to its state at the time of the drop for that object and indicate, in the message, that a retry is allowed.
:This message is sent by a target to a source to request a rendering for an object. When this message is received, the source determines if it understands the rendering mechanism and format selected by the target for the object. It also confirms that it allows the operation selected by the user for that object. The source must respond to this message before proceeding with the rendering operation.
 
;DM_RENDERCOMPLETE
:This message is posted by a source to a target to notify the target that the rendering operation has been completed by the source, either successfully or unsuccessfully. The source can elect to let the target retry a successful or an unsuccessful operation. In this case, it should return to its state at the time of the drop for that object and indicate, in the message, that a retry is allowed.
 
:Support for this message by a source is optional. If this message is not supported, then:
:Support for this message by a source is optional. If this message is not supported, then:
::*The source must convey all necessary information to the target in order to allow it to handle the rendering operation.
::*The source must convey all necessary information to the target in order to allow it to handle the rendering operation.
::*It must always indicate that native rendering is allowed when replying to a DM_RENDER message.
;DM_ENDCONVERSATION:This message is sent by a target to a source to notify the source that the rendering operation is complete and that the conversation is terminated. When this message is received, the entire drop operation for the object is complete. The source can now release any resources it had allocated to the drop and rendering operations. When the reply is received, the target can release the resources it had allocated to the operation.


::*It must always indicate that native rendering is allowed when replying to a DM_RENDER message.
;DM_ENDCONVERSATION
:This message is sent by a target to a source to notify the source that the rendering operation is complete and that the conversation is terminated. When this message is received, the entire drop operation for the object is complete. The source can now release any resources it had allocated to the drop and rendering operations. When the reply is received, the target can release the resources it had allocated to the operation.
====Native Mechanism Actions====
====Native Mechanism Actions====
If the target understands the native rendering mechanism and format of the object, it may be possible to render the object without any involvement on the part of the source, provided the source has given the target sufficient information to do so. In order for the rendering to be performed by the target, the source must fill in, at a minimum, the hstrContainerName and hstrSourceName fields. The hstrContainerName field represents the subdirectory that the file indicated by hstrSourceName is in. For the target to do the rendering on its own, the true type of the object must be DTYP_OS2FILE. When these conditions are met, the target may proceed with the operation. When the operation is complete, the target must send a DM_ENDCONVERSATION message to the window indicated by hwndItem in the DRAGITEM data structure.
If the target understands the native rendering mechanism and format of the object, it may be possible to render the object without any involvement on the part of the source, provided the source has given the target sufficient information to do so. In order for the rendering to be performed by the target, the source must fill in, at a minimum, the hstrContainerName and hstrSourceName fields. The hstrContainerName field represents the subdirectory that the file indicated by hstrSourceName is in. For the target to do the rendering on its own, the true type of the object must be DTYP_OS2FILE. When these conditions are met, the target may proceed with the operation. When the operation is complete, the target must send a DM_ENDCONVERSATION message to the window indicated by hwndItem in the DRAGITEM data structure.
Line 439: Line 434:
Prior to establishing a DDE conversation, the target should determine the source-supported formats in which it wants to have the object rendered. It should register this format in the system atom table and use the resulting atom in the usFormat field of the DDESTRUCT used in the conversation.
Prior to establishing a DDE conversation, the target should determine the source-supported formats in which it wants to have the object rendered. It should register this format in the system atom table and use the resulting atom in the usFormat field of the DDESTRUCT used in the conversation.


The target should establish the DDE conversation by posting a WM_DDE_REQUEST message to the window indicated by the hwndItem field in the DRAGITEM data structure. The target acts as the client, and the source acts as the server in the conversation.  
The target should establish the DDE conversation by posting a WM_DDE_REQUEST message to the window indicated by the hwndItem field in the DRAGITEM data structure. The target acts as the client, and the source acts as the server in the conversation.
 
====Operation Specifics====
====Operation Specifics====
The following actions should be taken by the source, depending on the operation being performed:
The following actions should be taken by the source, depending on the operation being performed:

Revision as of 00:01, 29 May 2024

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

Presentation Manager Programming Guide and Reference
  1. How to Use this Book
  2. Device Functions
  3. Direct Manipulation Functions
  4. Dynamic Data Formatting Functions
  5. Hooks and Procedures
  6. Profile Functions
  7. Spooler Functions
  8. Window Functions
  9. Message Processing
  10. Data Types
  11. Errors
  12. Atom Tables
  13. Button Controls
  14. Clipboards
  15. Combination Box
  16. Container Controls
  17. Control Windows
  18. Cursors
  19. Dialog Windows
  20. Direct Manipulation
  21. Drawing in Windows
  22. Dynamic Data Exchange
  23. Entry-Field Controls
  24. File Dialog Controls
  25. Font Dialog Controls
  26. Frame Windows
  27. Hooks
  28. Initialization Files
  29. Keyboard Accelerators
  30. List-Box Controls
  31. Menus
  32. Messages and Message Queues
  33. Multiple-Line Entry Field Controls
  34. Mouse and Keyboard Input
  35. Mouse Pointers and Icons
  36. Notebook Controls
  37. Painting and Drawing
  38. Presentation Parameters
  39. Resource Files
  40. Scroll-Bar Controls
  41. Slider Controls
  42. Spin Button Controls
  43. Static Controls
  44. Title-Bar Controls
  45. Value Set Controls
  46. Windows
  47. Window Classes
  48. Window Procedures
  49. Window Timers
  50. Appendices
  51. Notices
  52. Glossary

Direct manipulation is the act of moving graphical representations such as OS/2 icons around the screen using a pointing device, such as a mouse. This chapter explains how to use direct manipulation in PM applications.

About Direct Manipulation

The direct manipulation protocol enables the user to select an object in a window, drag it to another location, and drop it on another object or in another window. Dragging is the act of moving an object as though it were attached to the pointer; it is performed by pressing and holding the drag button and moving the pointer. Dropping is the act of fixing the position of the dragged object by releasing the drag button on the pointer. This causes interaction (data exchange) between the window from which the selected object is dragged and the window containing the object on which the selected object is dropped.

The window containing the dragged object is the source. The window containing the object that was dropped on is the target. The source and target can be the same window, different windows within the same application, or windows belonging to different applications. The dragged object can be either the only visible object in the source window or one of many objects. The target object can be either the only visible object in the target window or one of many objects. A source or target window that contains multiple objects is a container window.

The data exchange that occurs between the source and target after a direct manipulation operation enables applications that support the protocol to integrate easily, while providing a simple user interface.

Application-Defined Drag Operations

At times it may be useful for an application to define its own drag operation to facilitate functions between two windows in the same application or between closely related applications. For example, an application implementing a keyboard remapping function may want to provide a method of redefining keys with direct manipulation. This application could define an operation whereby dragging one key to another exchanges the definitions of the two keys. The protocol provides the extendability to enable this kind of function.

Rendering Mechanism and Format

The rendering mechanism represents the way in which you want to exchange the data, for example, dynamic data exchange (DDE). The rendering format identifies the actual type or true type of the data, for example, text. To exchange data, both the source and target must know how to communicate with each other through the rendering mechanism and understand the particular format of the data.

The native rendering mechanism and format of the object is the mechanism that most naturally conveys the data, either where it is now, or where it can be put most easily. The format conveys all information about the data. For example, a spreadsheet cell has a location in a row and column of a spreadsheet. Rendering the spreadsheet cell in a simple text format would cause this information to be lost, so a more appropriate format should be chosen for its native rendering format.

A source application may be able to exchange data with a target through several mechanisms, such as:

  • Dynamic Data Exchange (DDE)
  • OS/2 File
  • Print

Additionally, the source application might be able to render the data in various formats, that is, into various types. For example, a spreadsheet application could render its contents in a spreadsheet format or into a simple text format. The ability of the source application to render the data in some format might, itself, depend on the exchange mechanism used. The rendering mechanisms and formats that a source application can support, for each object dropped, are provided to the target through the hstrRMF field in the DRAGITEM data structure.

The target application may also be able to exchange data with the source through several different combinations of mechanism and format. The target is responsible for obtaining the data from the source in the format that they both support and that provides the highest level of information about the data.

While making this determination, the target must consider the exchange capabilities offered by the mechanism. For example, an OS/2 File exchange mechanism can provide only a snapshot of the data at the time the direct manipulation operation occurred. An exchange using DDE, on the other hand, offers the target an opportunity to remain informed about changes to the data.

Non-Standard Rendering Mechanisms

Some standard rendering mechanisms are already defined, but the system lets the set of rendering mechanisms be expanded, allowing for:

  • Additional standard rendering mechanisms to be defined in the future
  • Application definition of private or nonstandard rendering mechanisms

An application can elect to support some, all, or none of the standard rendering mechanisms defined by the system. Applications that do not support any of the standard rendering mechanisms are not precluded from using direct manipulation. However, support of the standard rendering mechanisms and formats increases the chances of a successful data transfer between applications.

An application that supports a particular rendering mechanism, whether or not it is a rendering mechanism defined by the system, must follow a specific set of guidelines defined by that rendering mechanism, including conversation-initiation procedures and naming conventions.

Responsibilities of a Source Application

The source is responsible for starting a direct manipulation operation. Startup can be accomplished only with a pointing device, such as a mouse. The operation starts when the application detects that a drag button has been pressed and the pointing device has moved. Dragging continues until terminated, which is usually when the button is released.

Although the direct manipulation protocol lets the application use any button for dragging, it is recommended that the system-defined drag button be used for direct manipulation operations.

The source has the following responsibilities in preparing for the actual drag of the objects across the screen:

  • Allocate and initialize the DRAGINFO data structure that conveys the necessary information about each object to the target.
  • Initialize a set of DRAGIMAGE data structures that describe the image to be displayed during the drag operation.
  • Make the following information known to the system:
    • The type of each object being directly manipulated
    • The rendering mechanism and format for each object
    • The suggested name of the object at the target
    • The name of the container or folder containing the source object
    • The name of the object at the source
    • The true type of each object being directly manipulated
    • The native rendering mechanism and format for each object

Responsibilites of a Target Application

The target in a direct manipulation operation is responsible for determining whether a particular set of objects can be dropped on it, and for providing the user with visible cues regarding the operation. A target is informed of the operation through messages sent to it as the pointer, provided by the source, is dragged across the screen.

When a set of objects is dropped on the target, the target is responsible for establishing the appropriate conversations with the source to accomplish the data transfer. The type of conversation for each object is based on the rendering mechanism and format of the object being dropped.

The target application is responsible for:

  • Determining if data can be exchanged between source and target by verifying that both applications share knowledge of at least one rendering mechanism and format
  • Providing visible feedback, or target emphasis, on whether a drop is allowed
  • Defining the default state of a direct manipulation operation
  • Initiating conversations with the source for data transfer

Messages Sent to a Target Application

The following table describes the messages that are sent to each window whose boundaries are crossed as the user drags the object around the screen:

┌────────────────────┬────────────────────────────────────────┐
│Message Name        │Description                             │
├────────────────────┼────────────────────────────────────────┤
│DM_DRAGOVER         │Sent to the window under the pointer as │
│                    │the pointer is dragged across it. A     │
│                    │single DM_DRAGOVER message is sent each │
│                    │time the pointer moves and each time a  │
│                    │key is pressed or released, and it      │
│                    │contains a pointer to the DRAGINFO data │
│                    │structure. The target can access this   │
│                    │data structure with DrgAccessDraginfo.  │
├────────────────────┼────────────────────────────────────────┤
│DM_DRAGLEAVE        │Sent whenever the DM_DRAGOVER message   │
│                    │has been sent to a window, and the      │
│                    │pointer is moved outside the bounds of  │
│                    │that window. If the target or an object │
│                    │in the window had been emphasized as a  │
│                    │target, it should be de-emphasized.     │
├────────────────────┼────────────────────────────────────────┤
│DM_DROP             │Sent to the target to provide it with   │
│                    │the information necessary to establish a│
│                    │conversation for data exchange with the │
│                    │source. The target should immediately   │
│                    │remove any target emphasis. The data    │
│                    │transfers must not be done before       │
│                    │responding to the DM_DROP message.      │
├────────────────────┼────────────────────────────────────────┤
│DM_DROPHELP         │Posted to a target to indicate that the │
│                    │user requested help for the drag        │
│                    │operation while over that target.       │
└────────────────────┴────────────────────────────────────────┘

Response to Messages Sent to a Target Application

The following table shows the four possible responses available to the target when it receives a DM_DRAGOVER message. The target sends these values to the window handle specified in the DRAGINFO data structure.

┌────────────────────┬────────────────────────────────────────┐
│Message Name        │Description                             │
├────────────────────┼────────────────────────────────────────┤
│DOR_DROP            │Sent if the objects being dragged are   │
│                    │acceptable. A drop does not occur unless│
│                    │DOR_DROP is returned.                   │
├────────────────────┼────────────────────────────────────────┤
│DOR_NODROP          │Sent if the objects being dragged are   │
│                    │acceptable and the target supports the  │
│                    │current operation, but the objects      │
│                    │cannot be dropped on the current        │
│                    │location in the target window. For      │
│                    │example, a list box might return        │
│                    │DOR_NODROP if it contains objects that  │
│                    │can be dropped on, but the pointer is   │
│                    │over an object that cannot be dropped   │
│                    │on.                                     │
│                    │If the target response is DOR_NODROP,   │
│                    │the DM_DRAGOVER message continues to be │
│                    │sent to the target when:                │
│                    │o The pointer is moved                  │
│                    │o A keyboard key is pressed             │
│                    │o The pointer is moved out of           │
│                    │  and back into the window.             │
├────────────────────┼────────────────────────────────────────┤
│DOR_NODROPOP        │Sent if the objects being dragged are   │
│                    │acceptable, but the target does not     │
│                    │support the current operation. This     │
│                    │response implies that the drop may be   │
│                    │valid if the drag operation changes. For│
│                    │example, copying a file to a shredder   │
│                    │would not be valid, but moving a file to│
│                    │a shredder would be.                    │
│                    │Once the target has sent DOR_NODROPOP,  │
│                    │no further DM_DRAGOVER messages is sent │
│                    │to the target until:                    │
│                    │o A keyboard key is pressed             │
│                    │o The pointer is moved out of           │
│                    │  and back into the window.             │
├────────────────────┼────────────────────────────────────────┤
│DOR_NEVERDROP       │Sent when the objects being dragged are │
│                    │not acceptable, and the target will     │
│                    │never accept them.                      │
│                    │Once the target has sent DOR_NEVERDROP, │
│                    │no further DM_DRAGOVER messages are sent│
│                    │to that target until the pointer is     │
│                    │moved out of and back into the target   │
│                    │window.                                 │
└────────────────────┴────────────────────────────────────────┘

If a reply other than DOR_DROP is received from a target, the augmentation emphasis is automatically changed to indicate that no drop is allowed. This gives the user a visible cue that a drop cannot occur. The emphasis is reverted to drop allowed when a DOR_DROP reply is received from some target.

Two-Object Drag Operation

The following diagram represents the sequence of functions and message flows for a typical direct manipulation operation. The flow shows a two-object drag from App1 to App3, dragging over App2.

The direct manipulation operation is started by the source window procedure after the user selects the objects to be manipulated and the source receives a WM_BEGINDRAG message.

                                Two-Object Drag
┌─────────────────────────────────────────────────────────────────────────────┐
│               App1                   App2                    App3           │
└─────────────────────────────────────────────────────────────────────────────┘
                  .                      .                       .
  (user select)   .                      .                       .
 ────────────────�.                      .                       .
                  .                      .                       .
  WM_BEGINDRAG    .                      .                       .
 ────────────────�.                      .                       .
                  .                      .                       .
                  .                      .                       .
            DrgAllocDraginfo             .                       .
                  .                      .                       .
            DrgAddStrHandle              .                       .
                  .                      .                       .
            DrgAddStrHandle              .                       .
                  .                      .                       .
            DrgSetDragitem               .                       .
                  .                      .                       .
            DrgSetDragitem               .                       .
                  .                      .                       .
               DrgDrag                   .                       .
                  .                      .                       .
                  .     DM_DRAGOVER      .                       .
                  .─────────────────────�.                       .
                  .                      .                       .
                  .               DrgAccessDraginfo              .
                  .                      .                       .
                  .           DrgSetDragImage (optional)         .
                  .                      .                       .
                  .       (Verify that drop can be accepted)     .
                  .                      .                       .
                  .              (Target emphasis on)            .
                  .                      .                       .
                  .                 DrgFreeDraginfo              .
                  .                      .                       .
                  .                      .                       .
                  .      DOR_DROP        .                       .
                  .�─────────────────────.                       .
                  .                      .                       .
                  .    DM_DRAGLEAVE      .                       .
                  .─────────────────────�.                       .
                  .                      .                       .
                  .              (Target emphasis off)           .
                  .                      .                       .
                  .                      .                       .
                  .                      .                       .
                  .                      .                       .
                  .                 DM_DRAGOVER                  .
                  .─────────────────────────────────────────────�.
                  .                      .                       .
                  .                      .                DrgAccessDraginfo
                  .                      .                       .
                  .                      .            DrgSetDragImage (optional)
                  .                      .                       .
                  .                      .               (Target emphasis on)
                  .                      .                       .
                  .                      .                       .
                  .                      .                       .

                  .                  DOR_DROP                    .
                  .�─────────────────────────────────────────────.
   (WM_ENDDRAG)   .                      .                       .
 ────────────────�.                      .                       .
                  .                      .                       .
                  .                      .                       .
                  .                   DM_DROP                    .
                  .─────────────────────────────────────────────�.
                  .                      .                       .
                  .                      .                       .
                  .                      .            (Target emphasis off)
                  .                      .                       .
           (DrgDrag returns)             .             (Perform operation)
                  .                      .                       .
            DrgFreeDraginfo              .         DrgDeleteDraginfoStrHandles
                  .                      .                       .
                  .                      .               DrgFreeDraginfo
                  .                      .                       .
                  .                      .                       .

Conversation after the Drop

The following diagram represents the sequence of message flows for a typical direct manipulation data-transfer operation. The flow describes a single-object move from source to target. The user dropped on white space in the target container.

For this example, assume that the rendering mechanism selected is DRM_OS2FILE and that the source does not initially provide the target with the source item's file name. Also assume that the source and target items exist on different drives.

    ┌───────────────────────────────────────────────────────────────────┐
    │              Source                               Target          │
    └───────────────────────────────────────────────────────────────────┘
                     .                                     .
                     .                                     .
                     .                            DrgAllocDragtransfer
                     .                                     .
                     .                             DrgSendTransferMsg
                     .                                     .
                     .            DM_RENDER                .
                     .�────────────────────────────────────.
                     .                                     .
    Verify the rendering mechanism and format              .
                     .                                     .
               DrgAddStrHandle                             .
               (hstrSourceName)                            .
                     .                                     .
                     .          DM_RENDER(reply)           .
                     .────────────────────────────────────�.
                     .                                     .
                  DosCopy                                  .
                     .                                     .
            DrgFreeDragtransfer                            .
                     .                                     .
                     .         DM_RENDERCOMPLETE           .
                     .────────────────────────────────────�.
                     .                                     .
                     .         DM_ENDCONVERSATION          .
                     .�────────────────────────────────────.
                     .                                     .
                 DosDelete                        DrgFreeDragtransfer
                     .                                     .
              DrgFreeDraginfo                     DrgDeleteStrHandle
                     .                                     .
                     .                              DrgFreeDraginfo
                     .                                     .
                     .                                     .


Canceling a Drag Operation

The user can end a direct manipulation operation in one of the three following ways:

  • Pressing the Esc key to cancel the operation
  • Releasing the drag button when the pointer is over a target that cannot accept the drop
This action is equivalent to pressing the Esc key. When the pointer is over a target that can accept the drop, the target is informed of the drop, and the source is given the window handle of the target.
  • Pressing the F1 key to request help
A DM_DROPHELP message is posted to the target. This enables the target to provide the user with assistance regarding:
  • What would happen if the user dropped the object on that target
  • Why the target cannot accept a particular drop
The source sees this termination of the direct manipulation operation as a cancelation.

About Pickup and Drop

Pickup and Drop (also known as Lazy Drag) enables a drag operation to occur without requiring that the drag button be pressed for the duration of the operation (as in the standard direct manipulation operation). Pickup and Drop is non-modal in nature, allowing the user to interrupt the drag operation with other processes, and eliminating the requirement that both the source and target objects be visible prior to initiation of the drag operation (as in standard protocol). Pickup and Drop does not replace the standard, modal direct manipulation operation; it offers a more flexible alternative data transfer option.

Pickup and Drop is composed of one or more source object Pickup operations followed by a single Drop operation on a target object. Pickup and Drop is initiated by the first Pickup and is terminated by a Drop or Cancel Drag operation. When Pickup and Drop is initiated, the mouse pointer is augmented with the system Pickup pointer icon.

The drag images seen in a standard direct manipulation operation are not displayed. As additional items are selected, they are added to the system Pickup set, and pickup emphasis is displayed for each item. The Pickup set is currently limited to a single source window or folder. While the operation is in progress, all other operations are valid with the exception of a standard direct manipulation operation.

Pickup and Drop is initiated by DrgLazyDrag in response to a WM_PICKUP message generated when the user presses Alt+mouse button 2 on a source object. As the pointer moves over a potential target, DM_DRAGOVER and DM_DRAGLEAVE messages are sent when the user presses a key indicating the intention to drop the object. The target emphasis is not displayed until the user attempts to drop the object. Each time items are added to the Pickup set in response to a WM_PICKUP message, DrgReallocDraginfo must be called to reallocate the DRAGINFO data structure. The Pickup and Drop operation is then re-initiated by another DrgLazyDrag call. DrgLazyDrag returns upon initialization for the operation. The pointing device remains active during the operation and may be used as if no drag operation were in effect. If the pointer is over a valid target when a Drop is invoked, a DM_DROP message is sent to the target, and a DM_DROPNOTIFY message posted to the source window.

DrgCancelLazyDrag is called to cancel the operation, and similarly posts a DM_DROPNOTIFY message to the source window, but with a target window handle of zero in the mp2 parameter.

DrgLazyDrop can be used to programmatically invoke a drop operation; for example, from a menu choice.

DrgQueryDraginfoPtrFromHwnd and DrgQueryDraginfoPtrFromDragitem are called to query the DRAGINFO pointer at any time during the course of the operation.

DrgQueryDragStatus is called to determine whether a Pickup and Drop operation is currently in progress.

Data Structure Handling

Pickup and Drop (also known as Lazy Drag) enables a drag operation to occur without requiring that the drag button be pressed for the duration of the operation (as in the standard direct manipulation operation). Pickup and Drop is non-modal in nature, allowing the user to interrupt the drag operation with other processes, and eliminating the requirement that both the source and target objects be visible prior to initiation of the drag operation (as in standard protocol). Pickup and Drop does not replace the standard, modal direct manipulation operation; it offers a more flexible alternative data transfer option.

Pickup and Drop is composed of one or more source object Pickup operations followed by a single Drop operation on a target object. Pickup and Drop is initiated by the first Pickup and is terminated by a Drop or Cancel Drag operation. When Pickup and Drop is initiated, the mouse pointer is augmented with the system Pickup pointer icon.

The drag images seen in a standard direct manipulation operation are not displayed. As additional items are selected, they are added to the system Pickup set, and pickup emphasis is displayed for each item. The Pickup set is currently limited to a single source window or folder. While the operation is in progress, all other operations are valid with the exception of a standard direct manipulation operation.

Pickup and Drop is initiated by DrgLazyDrag in response to a WM_PICKUP message generated when the user presses Alt+mouse button 2 on a source object. As the pointer moves over a potential target, DM_DRAGOVER and DM_DRAGLEAVE messages are sent when the user presses a key indicating the intention to drop the object. The target emphasis is not displayed until the user attempts to drop the object. Each time items are added to the Pickup set in response to a WM_PICKUP message, DrgReallocDraginfo must be called to reallocate the DRAGINFO data structure. The Pickup and Drop operation is then re-initiated by another DrgLazyDrag call. DrgLazyDrag returns upon initialization for the operation. The pointing device remains active during the operation and may be used as if no drag operation were in effect. If the pointer is over a valid target when a Drop is invoked, a DM_DROP message is sent to the target, and a DM_DROPNOTIFY message posted to the source window.

DrgCancelLazyDrag is called to cancel the operation, and similarly posts a DM_DROPNOTIFY message to the source window, but with a target window handle of zero in the mp2 parameter.

DrgLazyDrop can be used to programmatically invoke a drop operation; for example, from a menu choice.

DrgQueryDraginfoPtrFromHwnd and DrgQueryDraginfoPtrFromDragitem are called to query the DRAGINFO pointer at any time during the course of the operation.

DrgQueryDragStatus is called to determine whether a Pickup and Drop operation is currently in progress.

Message Handling

In the standard direct manipulation protocol, DrgDrag does not return until the drag set is dropped on a target window. Pickup and Drop is slightly different, and requires a change in the handling of a Drop. Because the operation is non-modal, DrgLazyDrag returns as soon as it has completed drag initialiation and before a drop is performed. In the Pickup and Drop protocol, DM_DROPNOTIFY is posted to the source window as notification of a drop. The parameters of this message contain the pointer to the DRAGINFO data structure allocated by the source window and the handle of the target window. The source window should examine the mp2 parameter to determine if the target window and the source window are the same; if not, the source should free the DRAGINFO upon receipt of this message. Where the target and source are the same, the target window frees DRAGINFO after completing the post-drop conversation. The implementation of Pickup and Drop does not affect any of the existing post-drop conversation messages.

The DM_DROPHELP message is not supported for the Pickup and Drop protocol, because help could be requested for any subject at any point during the operation. If the application is to provide Drop help, it must do so from a menu choice and explicitly code the support to be provided.

About Rendering Mechanisms

The following sections describe the standard rendering mechanisms used by various containers and applications for direct manipulation.

OS/2 File Rendering Mechanism

This rendering mechanism can be used by various containers, including file folders and trash cans. These containers allow objects to be dragged and dropped on white space in the container to accomplish a Move or Copy operation. They also can allow objects in the same or another container to be dragged and dropped on objects within the container to accomplish an operation.

Mechanism Name

The string for this rendering mechanism is DRM_OS2FILE.

Messages

The following messages are used by the DRM_OS2FILE:

DM_RENDER
This message is sent by a target to a source to request a rendering for an object. When this message is received, the source determines if it understands the rendering mechanism and format selected by the target for the object. It also confirms that it allows the operation selected by the user for that object. The source must respond to this message before proceeding with the rendering operation.
DM_RENDERCOMPLETE
This message is posted by a source to a target to notify the target that the rendering operation has been completed by the source, either successfully or unsuccessfully. The source can elect to let the target retry a successful or an unsuccessful operation. In this case, it should return to its state at the time of the drop for that object and indicate, in the message, that a retry is allowed.
Support for this message by a source is optional. If this message is not supported, then:
  • The source must convey all necessary information to the target in order to allow it to handle the rendering operation.
  • It must always indicate that native rendering is allowed when replying to a DM_RENDER message.
DM_ENDCONVERSATION
This message is sent by a target to a source to notify the source that the rendering operation is complete and that the conversation is terminated. When this message is received, the entire drop operation for the object is complete. The source can now release any resources it had allocated to the drop and rendering operations. When the reply is received, the target can release the resources it had allocated to the operation.

Native Mechanism Actions

If the target understands the native rendering mechanism and format of the object, it may be possible to render the object without any involvement on the part of the source, provided the source has given the target sufficient information to do so. In order for the rendering to be performed by the target, the source must fill in, at a minimum, the hstrContainerName and hstrSourceName fields. The hstrContainerName field represents the subdirectory that the file indicated by hstrSourceName is in. For the target to do the rendering on its own, the true type of the object must be DTYP_OS2FILE. When these conditions are met, the target may proceed with the operation. When the operation is complete, the target must send a DM_ENDCONVERSATION message to the window indicated by hwndItem in the DRAGITEM data structure.

Preventing a Target from Rendering an Item

A source can prevent a target from doing the rendering operation on its own by not providing the source name for the object. This may be a necessary action for sources that implement some type of security, or that may not allow particular operations to be performed for an object move. When a source takes this course, it must fill in the hstrSourceName in the DRAGITEM data structure before replying to a DM_RENDER message. The target deletes the hstrSourceName string handle prior to freeing the DRAGINFO data structure, just as it would if the information had been passed to it at the time of the drop.

Requesting the Source to Render the Item

Whenever the conditions for a target to do the rendering operation without source participation are not met, the target must request the source to carry out the rendering by posting a DM_RENDER message to the source. Of course, the target can do this even if it is able to carry out the rendering mechanism on its own.

Allocating and Freeing a DRAGTRANSFER Data Structure

The data in a drag transfer message is carried in a DRAGTRANSFER data structure. DRAGTRANSFER data structures are allocated when the target calls DrgAllocDragtransfer.

When the conversation is completed, both the source and the target must call DrgFreeDragtransfer to free the shared memory. The target should do it immediately after sending a DM_ENDCONVERSATION message. The source should do it immediately after sending a DM_RENDERCOMPLETE message.

Operation Specifics

Regardless of the operation being performed, the target must fill in the hstrRenderToName field in the DRAGTRANSFER data structure before sending a DM_RENDER message. This is the fully qualified drive, path, and file name of the file that will contain the data when the rendering operation is complete. When the source has completed the operation, it must post a DM_RENDERCOMPLETE message to the target. The target then must complete the direct manipulation operation for that object by posting a DM_ENDCONVERSATION message to the source. Once the conversations for all of the objects involved in the drop are complete, the target can delete the string handles and free the DRAGINFO data structure.

Non-Native Mechanism Actions

The target may select the DRM_OS2FILE rendering mechanism when it is not the native rendering mechanism for an object, as long as the source supports it. In this case, the target must always request that the source carry out the rendering operation as described above. The source should render the data in the requested format to the file specified by the hstrRenderToName field. If the requested operation is a Move, the source should take whatever action is necessary to remove its knowledge of the object as long as no information regarding the object was lost in the transfer.

Naming Conventions

The naming conventions for this rendering mechanism are as follows:

hstrContainerName
  • Contains the fully qualified drive and path name for the source file, for example:
   C:\
   C:\MYSUBDIR\
   A:\SUBDIR1\SUBDIR2\
   \\NETWORK\SHARED\SUBDIRA\SUBDIRB\
hstrSourceName
  • Contains the name of the source file or subdirectory, for example:
   MYSOURCE.C
   MYSOURCE.H
   MYSOURCE IS A LONG FILE NAME
   SUBDIR3
If you specify a subdirectory, the action is applied to all files in the subdirectory.
hstrRenderToName
  • Contains the fully qualified file or subdirectory name that is to be used at the target, for example:
   C:\MYSUBDIR\MYSOURCE.C
   \\NETWORK\SHARED\SUBDIRA\SUBDIRB\MYSOURCE.H
   C:\SUBDIR1\SUBDIR2\SUBDIR3

Types

Any type that is allowed as a .TYPE extended attribute is allowed in the hstrType field of the DRAGITEM data structure. The type for a file can be obtained using DosQFileInfo; the type can be set by using DosSetFileInfo.

Print Rendering Mechanism

A common object that might be provided by a container is a printer. This object would allow objects to be dragged and dropped on it to accomplish a print operation.

Mechanism Name

The string for this rendering mechanism is DRM_PRINTOBJECT.

Messages

To support this rendering mechanism, a source must be able to receive and process a DM_PRINTOBJECT message. The target posts this message to the source. When the message is received, the source prints the current view of the object identified in the message to the printer. The second message parameter (of type PRINTDEST) gives all the parameters necessary to call DevPostDeviceModes and DevOpenDC.

Native Mechanism Actions

There are no native mechanism actions for this rendering mechanism, because the act of printing an object is considered a transform from the native rendering mechanism to the print mechanism.

Naming Conventions

None.

Dynamic Data Exchange (DDE) Rendering Mechanism

This rendering mechanism can be used by various containers and applications. The containers allow objects to be dragged and dropped on white space in the container to accomplish a Move or Copy operation. They can also allow objects in the same or another container to be dragged and dropped on objects within the container to accomplish some operation.

Mechanism Name

The string for this rendering mechanism is DRM_DDE.

Messages

To support this rendering mechanism, a source must be able to receive and process the following messages:

WM_DDE_REQUEST
This message is posted by the target to the window indicated by the hwndItem field in the DRAGITEM data structure to request information regarding the object. Note that WM_DDE_INITIATE is not required because the target already has the handle of the window it wants to converse with. This message is sent for all Move and Copy operations.
WM_DDE_ADVISE
This message is posted by the target to the window indicated by the hwndItem field in the DRAGITEM data structure order to maintain a hot link to the object.
WM_DDE_UNADVISE
This message is posted by the target to the window indicated by the hwndItem field in the DRAGITEM data structure to terminate a hot link to the object.
WM_DDE_TERMINATE
This message is posted by the target to the window indicated by the hwndItem field in the DRAGITEM data structure to terminate a conversation.

To support this rendering mechanism, a target must be able to receive and process the following messages:

WM_DDE_DATA
This message is posted to the target by the source to deliver the requested information regarding the object.
WM_DDE_ACK
This message is posted to the target by the source to acknowledge a WM_DDE_ADVISE or WM_DDE_UNADVISE message.
WM_DDE_TERMINATE
This message is posted to the target by the source to end a conversation.

Native Mechanism Actions

Prior to establishing a DDE conversation, the target should determine the source-supported formats in which it wants to have the object rendered. It should register this format in the system atom table and use the resulting atom in the usFormat field of the DDESTRUCT used in the conversation.

The target should establish the DDE conversation by posting a WM_DDE_REQUEST message to the window indicated by the hwndItem field in the DRAGITEM data structure. The target acts as the client, and the source acts as the server in the conversation.

Operation Specifics

The following actions should be taken by the source, depending on the operation being performed:

Copy
Send the data to the target.
Move
Remove knowledge of the object after receiving confirmation that the target has successfully completed its portion of the rendering operation.

Non-Native Mechanism Actions

The target and source proceed in the same way, regardless of whether DDE was the native rendering mechanism or an alternate rendering mechanism.

Naming Conventions

The naming conventions for the DRM_DDE rendering mechanism follow:

hstrSourceName
Contains the object name to be used in the DDE conversation.
hstrRMF
The format portion of the list of ordered pairs in the format <DRM_DDE,format> identifies the formats supported by the source for the object. The non-standard DDE formats that these formats map to must be registered in the system atom table by both the source and the target.

Types

Any type that is allowed as a .TYPE extended attribute is allowed in the hstrType field of the DRAGITEM data structure.

Application-Defined Rendering Mechanisms

An application can choose to define a new rendering mechanism. However, if an application intends to provide renderings from this extended rendering mechanism to existing rendering mechanisms, it should publish enough information so that other application developers can use the new mechanism. An application must address several distinct areas of definition. These areas are described below, in general, and also are addressed under the definition for the system mechanisms.

Mechanism Name

The string name of the rendering mechanism should be defined by the application. This string name is specified in the mechanism/format pair of the DRAGITEM data structure.

Native Mechanism Actions

When both a source and target application store the data in the same native mechanism, a transform is not required. Instead, the native Move and Copy actions for that mechanism can be performed by the target. An application must completely define the proper procedure for performing that action. In the case of files, the native Move action is defined as a DosMove or DosCopy/DosDelete. The native Copy action is DosCopy. An application need not support all of the basic actions; it can choose to define additional native mechanism actions, indicated by the DO_UNKNOWN action in the DRAGINFO data structure.

Naming Conventions

An application that is defining a new mechanism must completely specify the naming conventions for objects rendered in that mechanism. This information typically includes both the name of the data and preceding information describing the exact location of the data. Any special rules concerning uppercase and lowercase or character sets to be used in naming also must be specified. The semantics for using these mechanism names, as well as an algorithm for deriving location information, also must be defined.

An application that is defining a new rendering mechanism must completely define the set of messages that a target and source application must support, and must specify the appropriate action to be taken for each message. The message IDs (above WM_USER) for the messages must be published.

Performance Considerations

If an application provides or defines transforms from the newly defined mechanism to existing mechanisms, performance information about the transform between mechanisms should be provided. This aids the application developer in choosing the appropriate transform when it encounters an application that transforms from an unknown native mechanism to several different known mechanisms.

Using Direct Manipulation

This section shows the sequence of function and message flows for a typical direct manipulation operation. It also describes the activities that must be performed by the applications during direct manipulation.

Note: Most of the sample code in this section is part of a complete program illustrated in "Sample Code for Direct Manipulation".

Allocating Memory for the Drag Operation

To prepare for the drag operation, the source must invoke DrgAllocDraginfo to allocate memory for the DRAGINFO data structure. DrgAllocDraginfo initializes the DRAGINFO data structure as follows:

cbDraginfo
The size, in bytes, of the entire DRAGINFO data structure, including the DRAGITEM array
cbDragitem
The size, in bytes, of each DRAGITEM data structure
usOperation
DO_DEFAULT
xDrop and yDrop
The current mouse-pointer location, in desktop coordinates
cditem
The count of objects being dragged, as specified in DrgAllocDraginfo.

Initializing DRAGITEM Data Structure

After allocating memory for the DRAGINFO data structure, the source initializes a DRAGITEM data structure, as appropriate, for each of the objects to be dragged. This is accomplished either by using DrgSetDragitem or by obtaining a pointer to each DRAGITEM data structure with DrgQueryDragitemPtr, and initializing it directly.

The first step the source takes to initialize the DRAGITEM data structure is to create the appropriate drag string handles. String handles must be created for:

  • Object type
  • Supported rendering mechanisms and formats for the object
  • Suggested name of the object at the target
  • Name of the container holding the object (whether a container or folder)
  • Name of the object at the source when the source allows the target to carry out the operation for the object

Type

To directly manipulate an object, both the source and the target must support the object type, which describes the format of the object. For example, the input to a C compiler could have the type Plain Text (DRT_TEXT). The hstrType field in the DRAGITEM data structure conveys this information for each object being dragged. The type is represented by a string handle. The target should check to see if it supports the type before allowing the user to drop the object.

Several DTYP_* constants are defined as notational conveniences for common types of data. An application can extend these types by defining its own character strings and then creating string handles for them using DrgAddStrHandle.

True Type

The true type of an object is the type that most accurately describes the object. For example, the input to a C compiler could have the type Plain Text (DRT_TEXT), but would be more accurately described as C Code (DRT_C). C Code would be the true type of this object. Multiple types can be conveyed by using a comma to separate strings. The following figure shows the format to use to convey multiple types:

"type,type..."

The true type should appear first in the list of types, so the type string for the example object would be "C Code, Plain Text".

Rendering Mechanism and Format

The rendering mechanism and format are passed as a string handle in the DRAGITEM data structure. The string handle must be created using DrgAddStrHandle. The following figure shows the string handle format:

"elem {,elem,elem...}"

where elem is an ordered pair in the form:

"<mechanism,format>"

or a cross product in the form:

"(mechanism{,mechanism...}) X (format{,format...})"

Multiple cross products are permitted in a single rendering mechanism and format string handle, as are combinations of ordered pairs and cross products. When cross-product notation is used, the rendering mechanism is the left operand. When ordered-pair notation is used, the rendering mechanism is the left element in the ordered pair.

Several constants are defined for common rendering mechanisms and formats. For example, the rendering mechanism and format for a:

  • C source file might be "<DRM_OS2FILE,CF_OEMTEXT>"
  • Spreadsheet file might be "<DRM_OS2FILE,CF_SYLK>"

An application can extend these by defining its own "<mechanism,format>" strings and creating string handles for these using DrgAddStrHandle. For example, if an application understands and can generate an LU 6.2 data stream, it can define its own rendering format, "DRF_LU62", and use it in direct manipulation operations. If an application wishes to use its own rendering mechanisms or formats to communicate with other applications, it should publish the protocol for the mechanisms, the format of the data streams, or both.

Native Rendering Mechanism and Format

The native rendering mechanism and format of the object is the mechanism that most naturally conveys the data and its current format. For example, the native rendering mechanism and format for a:

  • C source file might be "<DRM_OS2FILE,CF_OEMTEXT>"
  • Spreadsheet file might be "<DRM_OS2FILE,CF_SYLK>"

In some direct-manipulation operations, it might be possible for the target to carry out the necessary action on the source object without the source's participation. However, this is possible only when the target supports both the true type and the native rendering mechanism and format of the object. Even when the target is not performing the necessary action on the source object, it is still important to know the native rendering mechanism and format. In determining the rendering mechanism and format to be used in the data exchange after the drop, the target might select the native format because, generally, performance is better when the native rendering mechanism and format are used.

The native rendering mechanism and format are conveyed to the target by making it the first ordered pair, or the first ordered pair to result from a cross product, in the list of rendering mechanisms and formats passed in the DRAGINFO data structure.

Suggested Name at Target

When dragging an object, for example, a file, from one container to another, it is important to know the name the object should have at the target. This may or may not be the same name it had at the source. This name enables the target to check if another object with the same name already exists at the target and to take the appropriate action. For example, a target container might not allow the user to drop the object if an object by that same name already exists at the target.

Container Name

Sometimes it is necessary for a target container to know the name of the source container. This name could carry some location information. For example, the default operation when dragging objects between containers is a Move. However, in the case of file folders on different drives, this default would be changed to a Copy operation. Thus, a file folder would fill this field with the drive and path information for a file, for example, A:\SUBDIR1\SUBDIR2\. A database container, on the other hand, might fill this field with the fully qualified OS/2 file name of the database.

Source Name

In some direct-manipulation operations, it is possible for the target to perform the necessary action on the source object without the source's participation. If the source allows this, the target name should be filled in with the name of the source object. For example, a file folder would put the name of the source file into this field, such as AUTOEXEC.BAT. A database manager, on the other hand, might fill this field with some location information so the target could find a particular record or field within the database.

Sample Code for Initializing DRAGITEM Data Structure

The following code fragment shows how to initialize the DRAGITEM array:

/***********************************************************************/
/*  Get our current directory for the container name.                  */
/***********************************************************************/
   dirlen                     = CCHMAXPATH-1;
   DosQueryCurrentDir(0, szDir, &dirlen);
   sprintf(szContainer, "\\%s\\", szDir);
   hstrContainer              = DrgAddStrHandle(szContainer);
   Dragitem.hwndItem          = hListWnd;
   Dragitem.hstrType          = hstrType;
   Dragitem.hstrRMF           = hstrRMF;
   Dragitem.hstrContainerName = hstrContainer;
   Dragitem.fsControl         = 0;
   Dragitem.fsSupportedOps    = DO_COPYABLE | DO_MOVEABLE;
   Dragitem.hstrSourceName    = DrgAddStrHandle (szBuffer);
   Dragitem.hstrTargetName    = Dragitem.hstrSourceName;
   Dragitem.ulItemID          = index;

/***********************************************************************/
/*  Set info, prepare for drag.                                        */
/***********************************************************************/
   DrgSetDragitem(pSourceDraginfo,
                  &Dragitem,
                  sizeof(DRAGITEM),
                  0);

Initializing DRAGIMAGE Data Structure

As part of the preparation for the actual drag, an application intializes a DRAGIMAGE data structure. The following sample code shows how to initialize the DRAGIMAGE data structure:

/***********************************************************************/
/*  Initialize the drag image.                                         */
/***********************************************************************/
   dimg.cb       = sizeof (DRAGIMAGE);
   dimg.hImage   = WinQuerySysPointer (HWND_DESKTOP, SPTR_FILE, FALSE);
   dimg.fl       = DRG_ICON | DRG_TRANSPARENT;
   dimg.cxOffset = 0;
   dimg.cyOffset = 0;

Starting the Drag Operation

Once initialization is complete, the source object calls DrgDrag to start the direct manipulation operation. The following sample code shows how to start the drag operation:

/***********************************************************************/
/*  Start drag operation.                                              */
/***********************************************************************/
  DrgDrag(hFrameWnd,
          pSourceDraginfo,
          &dimg,
          1L,
          VK_BUTTON2,
          NULL);

Responding to the DM_DRAGOVER Message

The DM_DRAGOVER message is sent to a target whenever the user drags the pointer into the window. To assess whether a drop can be accepted, the target must use DrgAccessDraginfo to get access to the DRAGINFO data structure. It then determines whether a drop can be accepted for each object. The object must meet the following minimum requirements to exchange data:

  • The source and target must share knowledge of at least one common type for the object. The target can make this determination by using DrgVerifyTypeSet or DrgVerifyType.
  • The source and target must share at least one common rendering mechanism and format for that type object. The target can make this determination by using DrgVerifyRMF.

DOR_DROP, DOR_NODROP, DOR_NODROPOP, and DOR_NEVERDROP are the four possible responses available to the target when it receives a DM_DRAGOVER message. The target sends these values to the window handle specified in the DRAGINFO data structure.

The following sample code shows how the target determines its response to the DM_DRAGOVER message:

/***********************************************************************/
/*  Someone's dragging an object over us.                              */
/***********************************************************************/
        case DM_DRAGOVER:
         dragInfo = (PDRAGINFO)mp1;

         /* Get access to the DRAGINFO data structure */
         DrgAccessDraginfo(dragInfo);

         /* Can we accept this drop? */
         switch (dragInfo->usOperation)
         {

          /* Return DOR_NODROPOP if current operation */
          /* is link or unknown                       */
           case DO_UNKNOWN:
              DrgFreeDraginfo(dragInfo);
              return (MRFROM2SHORT(DOR_NODROPOP,0));
              break;

           /* Our default operation is Move */
           case DO_DEFAULT:
              dragItem = DrgQueryDragitemPtr(dragInfo,0);
              ulBytes  = DrgQueryStrName(dragItem->hstrContainerName,
                                                   sizeof(szDir),
                                                   szDir);
              if (!ulBytes)
                return (MRFROM2SHORT(DOR_NODROPOP,0));
              else
                usOp = DO_MOVE;
              break;

           /* Do the requested specific operation */
           case DO_MOVE:
           case DO_COPY:
              usOp = dragInfo->usOperation;
              break;
         }

         usIndicator = DOR_DROP;
         cItems = DrgQueryDragitemCount(dragInfo);

          /* Now, we need to look at each item in turn */
          for (i = 0; i < cItems; i++)
          {
            dragItem = DrgQueryDragitemPtr(dragInfo, i);

            /* Make sure we can move for a Move request */
            /* or copy for a Copy                       */
            if (((dragItem->fsSupportedOps & DO_COPYABLE)   &&
                 (usOp == (USHORT)DO_COPY))                 ||
                ((dragItem->fsSupportedOps & DO_MOVEABLE)   &&
                 (usOp == (USHORT)DO_MOVE)))
            {
               /* Check the rendering format */
               if (DrgVerifyRMF(dragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
                  usIndicator = DOR_DROP;
               else
                  usIndicator = DOR_NEVERDROP;
            }
            else
               usIndicator = DOR_NODROPOP;
          }

          /* Release the draginfo data structure */
          DrgFreeDraginfo(dragInfo);

          return (MRFROM2SHORT(usIndicator, usOp));
          break;

Providing Target Emphasis

The target should provide target emphasis so the user knows exactly where the drop occurs or, if the drop is not allowed, the boundaries of the region where the drop is not allowed.

A container window should emphasize a target object by drawing a thin, black rectangle around it. The application should use DrgGetPS and DrgReleasePS to obtain the presentation space in which to draw target emphasis.

Providing Customized Images

The target can provide a customized pointer to be displayed while it is the target of the drop by calling DrgSetDragPointer after it starts processing the DM_DRAGOVER message but before it sends a response. It also can provide a customized image (icon, bit map, and so forth) to be displayed while it is the target by calling DrgSetDragImage. This capability may be used by a target to provide additional visible feedback to the user. The pointer is reverted to the default when it is moved to a new target.

Responding to the DM_DRAGLEAVE Message

DM_DRAGLEAVE is sent whenever the DM_DRAGOVER message is sent to a window, and the pointer is moved outside the bounds of that window. If the target or an object in the window had been emphasized as a target, it should be de-emphasized.

Container windows monitor the position of the pointer on DM_DRAGOVER messages and simulate the DM_DRAGLEAVE message when the pointer moves on or off a contained object.

A DM_DRAGLEAVE message is not sent if the user drops the objects being dragged within the window. Therefore, when DM_DROP is received, the application de-emphasizes any target that was emphasized as a valid target.

If the user drags the pointer outside the target window, resulting in a new target, a DM_DRAGLEAVE message is sent to the former target. The receiver of a DM_DRAGLEAVE message should use it to de-emphasize the target, thus providing the user with visible feedback that this is no longer the target.

Responding to the DM_DROP Message

When the user drops the objects, a DM_DROP message is sent to the target, providing it with the information necessary to process the objects that were dropped. The target application uses the information provided to exchange data with the source. The target is responsible for establishing the appropriate conversations, and the source must cooperate in establishing the necessary conversations to achieve the actual data exchange. After completing the direct manipulation operation, including the post-drop conversation with the source, the target uses DrgDeleteStrHandle or DrgDeleteDraginfoStrHandles to delete the string handles in the DRAGINFO data structure, and DrgFreeDraginfo to release the storage. The target should immediately remove any target emphasis. The data transfers must not be done before responding to the DM_DROP message.

The following sample code shows how a target processes an object that has been dropped on it. This code fragment is part of a complete program which is illustrated in "Sample Code for Direct Manipulation".

        /* Drop the object on us (receive the object) */
        case DM_DROP:

         /* Get access to the DRAGINFO data structure */
         DrgAccessDraginfo(dragInfo);

         /* Can we accept this drop? */
         switch (dragInfo->usOperation)
         {

           /* Return DOR_NODROPOP if current */
           /* operation is link or unknown.  */
           case DO_UNKNOWN:
              DrgFreeDraginfo(dragInfo);
              return (MRFROM2SHORT (DOR_NODROPOP, 0));
              break;

           /* Our default operation is Move */
           case DO_DEFAULT:
              dragItem = DrgQueryDragitemPtr(dragInfo, 0);
              ulBytes = DrgQueryStrName(dragItem->hstrContainerName,
                                                  sizeof(szDir),
                                                  szDir);
              if(!ulBytes)
                return (MRFROM2SHORT (DOR_NODROPOP, 0));
              usOp = (USHORT)DO_MOVE;
              break;

           /* Do the requested specific operation */
           case DO_MOVE:
           case DO_COPY:
              usOp = dragInfo->usOperation;
              break;
          }

          usIndicator = DOR_DROP;
          cItems = DrgQueryDragitemCount(dragInfo);

          /* Now, we need to look at each item in turn */
          for (i = 0; i < cItems; i++)
          {
            dragItem = DrgQueryDragitemPtr(dragInfo, i);

            /* Make sure we can move for a Move request */
            /* or copy for a Copy                       */
            if (((dragItem->fsSupportedOps & DO_COPYABLE)   &&
                 (usOp == (USHORT)DO_COPY))                 ||
                ((dragItem->fsSupportedOps & DO_MOVEABLE)   &&
                 (usOp == (USHORT)DO_MOVE)))

            {
               /* Check the rendering format */
               if (DrgVerifyRMF(dragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
                  usIndicator = DOR_DROP;
               else
                  usIndicator = DOR_NEVERDROP;
            }
            else
               usIndicator = DOR_NODROPOP;

/***********************************************************************/
/*  This is where we would actually move or copy the file,             */
/*  but we just display the name instead.                              */
/***********************************************************************/
            DrgQueryStrName(dragItem->hstrSourceName, 255, szBuffer);
            WinMessageBox(HWND_DESKTOP,
                          HWND_DESKTOP,
                          szBuffer,
                          "Dropped",
                          0,
                          MB_OK);
          }
          /* Release the draginfo data structure */
          DrgFreeDraginfo(dragInfo);

          return (MRFROM2SHORT(usIndicator, usOp));
          break;

Exchanging Data

Direct manipulation offers various ways for source and target applications to exchange data. To accomplish the exchange, a separate conversation must be established to transfer each data object from the source to the target. The target must inform the source about the rendering mechanism it is using and the format in which the data is to be exchanged. The target can establish the conversations to run in parallel, or it can initiate the conversations in a serial fashion.

The target determines which rendering mechanism and format to use in the following manner:

1.- Uses the native rendering mechanism and format whenever possible.

This rendering conveys all information about the data. A target can determine if it supports the native rendering mechanism and format by using the following functions:

  • DrgVerifyNativeRMF
  • DrgQueryNativeRMFLen
  • DrgQueryNativeRMF

Even if it can use the native rendering mechanism and format supported by the source, the target can elect to exchange the data in a rendering mechanism and format that conveys less information about the object.

2. Uses the next best rendering mechanism and format.

This is especially good for a Copy operation, because the user does not lose data about the object as occurs when the object is moved.

The target can determine the next best rendering mechanism and format to use through repeated calls to DrgVerifyRMF. The calls are made starting with the most desirable rendering mechanism and format pair and progressing to the least desirable pair. Once a pair that the source supports has been found, the target can exchange the data.

The following sample code shows how the target checks the rendering mechanism and format:

          /* Now, we need to look at each item in turn */
         for (i = 0; i < cItems; i++)
          {
            dragItem = DrgQueryDragitemPtr(dragInfo, i);

            /* Make sure we can move for a Move request */
            /* or copy for a Copy                       */
            if (((dragItem->fsSupportedOps & DO_COPYABLE)   &&
                 (usOp == (USHORT)DO_COPY))                 ||
                ((dragItem->fsSupportedOps & DO_MOVEABLE)   &&
                 (usOp == (USHORT)DO_MOVE)))
            {

               /* Check the rendering format */
               if (DrgVerifyRMF(dragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
                  usIndicator = DOR_DROP;
               else
                  usIndicator = DOR_NEVERDROP;
            }
            else
               usIndicator = DOR_NODROPOP;
          }

Performance Considerations

When context information about an object might be lost because of using a less-desirable rendering mechanism and format, the target can elect to pick a common mechanism and format that achieves the best performance. This is done the same way that the next best rendering mechanism and format is selected, proceeding from the best-performing rendering to the worst.

Regardless of the rendering mechanism used, the target might need to prepare the source for the rendering of the object. This is necessary when the source needs to create a window in order to handle the conversation. This preparation is done by sending a DM_RENDERPREPARE message to the hwndSource window in the DRAGINFO data structure. This message need be sent only when the DC_PREPARE flag is on in the fsControl field of the DRAGITEM data structure. When the source receives this message, it performs any necessary preparation for the rendering and fills in the hwndItem field in the DRAGITEM data structure, thereby allowing the target to establish conversation with that window.

Using Pickup and Drop

The following sample code shows a Pickup and Drop operation after the user has selected an object and pressed mouse button 2 while holding down the Pickup and Drop augmentation key (Alt):

#define INCL_WINSTDDRAG #include <os2.h>

PDRAGINFO pdinfo;           /* Pointer to a DRAGINFO data structure    */
HWND hwndSource;            /* Handle of the Source window             */
DRAGITEM ditem;             /* DRAGITEM data structure                 */
PDRAGIMAGE pdimg;           /* Pointer to DRAGIMAGE data structure     */
HBITMAP hbm;                /* Bit-map handle passed to DrgLazyDrag    */
APIRET rc;                  /* Allocation memory return code           */

case WM_PICKUP:

/***********************************************************************/
/*  Initialize the DRAGITEM data structure.                            */
/***********************************************************************/
ditem.hwndItem=hwndSource;        /* Handle of the source window       */
ditem.ulItemID=ID_ITEM;           /* App. defined id of item           */

ditem.hstrType          = DrgAddStrHandle("DRT_TEXT");  /* Text item   */
ditem.hstrRMF           = DrgAddStrHandle("<DRM_OS2FILE,DRF_TEXT>");
ditem.hstrContainerName = DrgAddStrHandle("C:\\");
ditem.hstrSourceName    = DrgAddStrHandle("C:\\CONFIG.SYS");
ditem.hstrTargetName    = DrgAddStrHandle("C:\\OS2\\CONFIG.SYS");

ditem.cxOffset         = 0;    /* Offset of the origin of the image    */
ditem.cyOffset         = 0;    /* from the pointer hotspot             */
ditem.fsControl        = 0;    /* Source item control flags            */
ditem.fsSupportedOps   = 0;

/***********************************************************************/
/*  Create the DRAGINFO data structures                                */
/***********************************************************************/
pdinfo=DrgAllocDraginfo(1);

/* Return FALSE if initialization fails */
if(!pdinfo) return FALSE;

/***********************************************************************/
/*  Initialize the DRAGIMAGE data structure.                           */
/***********************************************************************/
rc=DosAllocMem((PPVOID)&pdimg,    /* Allocate memory                   */
               sizeof(DRAGIMAGE),
               (ULONG)PAG_COMMIT |
                      PAG_READ   |
                      PAG_WRITE);

pdimg->cb=sizeof(DRAGIMAGE);      /* Size of the dragimage structure   */
pdimg->cptl=0;                    /* Image is not a polygon            */
pdimg->hImage=hbm;                /* Handle of image to display        */
pdimg->sizlStretch.cx=20L;        /* Size to stretch icon or bit map   */
pdimg->fl=DRG_BITMAP |            /* Flags passed to DrgLazyDrag       */
          DRG_STRETCH;

pdimg->cxOffset=0;                /* Offset of the origin of image     */
pdimg->cyOffset=0;                /* from the pointer hotspot          */

/***********************************************************************/
/*  Set the DRAGITEM data structure.                                   */
/***********************************************************************/
DrgSetDragitem(pdinfo,&ditem,(ULONG)sizeof(ditem),0);

/***********************************************************************/
/*  Begin the Lazy Drag operation.                                     */
/***********************************************************************/
if (DrgLazyDrag(hwndSource,       /* Source of the drag                */
                pdinfo,           /* Pointer to the DRAGINFO           */
                pdimg,            /* DRAGIMAGE array                   */
                1,                /* Size of the DRAGIMAGE             */
                NULL))            /* Reserved                          */
  {
    DosFreeMem(pdimg);            /* Free DRAGIMAGE if successful      */
  }

Graphical User Interface Support for Direct Manipulation

This section describes the support the direct manipulation provides for graphical user interfaces (GUIs). Except where noted, this support conforms to the guidelines in the SAA CUA Advanced Interface Design Reference.

Keyboard Augmentation

A direct manipulation operation begins in a default state, which means that, when the user drops objects on a target, the target is informed that it should perform its default operation. The target is responsible for defining its default operation. For a container window, the default should be a Move operation, if it is supported. The default for a device, such as a printer, should be a Copy operation.

As the user drags the object, the default operation can be overridden by pressing and holding one of the following augmentation keys:

Ctrl
Changes the operation to a Copy
Shift
Changes the operation to a Move
Ctrl+Shift
Changes the operation to a Link.

The last key pressed and held at the time of the drop determines the operation to be performed. The target can determine the defined augmentation key that was pressed at the time of the drop by inspecting the usOperation field of the DRAGINFO data structure.

A target can define additional augmentation keys for its own use. In this case, usOperation would indicate that the operation is unknown, and the target needs to use WinGetKeyState to determine the actual augmentation key that was used.

As the user presses augmentation keys, the pointer currently being displayed is modified to provide the user with a visible cue as to the type of operation being performed.

Sample Code for Direct Manipulation

This section illustrates a complete sample program for the drag portion of a drag-and-drop operation. Several parts of this program are explained in "Using Direct Manipulation".

Source Application Sample Code

The source application includes the following files:

  • Dragfrom.C
  • Dragfrom.H
  • Dragfrom.DEF
  • Dragfrom.LNK
  • Dragfrom.MAK

The following sample shows the source application code:

===============DRAGFROM.C===============

/***********************************************************************/
/*  DRAGFROM.C - Drag source program                                   */
/*                                                                     */
/*  This program displays a list of files in the current directory.    */
/*  Drag any file name to EPM, and drop, and the file will be          */
/*  displayed in the editor.                                           */
/***********************************************************************/
#define INCL_DOSFILEMGR
#define INCL_WIN
#define INCL_WINSTDDRAG
#define INCL_WINLISTBOXES
#define INCL_WINWINDOWMGR

#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dragfrom.h"

/***********************************************************************/
/*  Global variables.                                                  */
/***********************************************************************/
HAB      hab;
char     szFormats[]  = "<DRM_OS2FILE, DRF_UNKNOWN>";
char     szFileNames[50][CCHMAXPATH];
HWND     hFrameWnd;
HWND     hListWnd;
PFNWP    SysWndProc;
PFNWP    ListWndProc;
HPOINTER hptrFile;

/***********************************************************************/
/*  Function prototypes.                                               */
/***********************************************************************/
MRESULT EXPENTRY LocalWndProc(HWND, ULONG, MPARAM, MPARAM);
MRESULT EXPENTRY LocalListProc(HWND, ULONG, MPARAM, MPARAM);
BOOL DoDrag(void);
void LoadList(void);

/***********************************************************************/
/*   Main() - program entry point.                                     */
/***********************************************************************/
int main(void)
{
   FRAMECDATA   fcd;
   HMQ          hmq;
   QMSG         qmsg;

   if (!(hab = WinInitialize (0)))
     return FALSE;

   hmq = WinCreateMsgQueue (hab, 0);

   if (!hmq)
   {
      WinTerminate(hab);
      return FALSE;
   }

/***********************************************************************/
/*  Setup the frame control data for the frame window.                 */
/***********************************************************************/
   fcd.cb = sizeof(FRAMECDATA);
   fcd.flCreateFlags = FCF_TITLEBAR        |
                       FCF_SYSMENU         |
                       FCF_SIZEBORDER      |
                       FCF_SHELLPOSITION   |
                       FCF_MINMAX          |
                       FCF_TASKLIST;

   fcd.hmodResources = NULLHANDLE;

/***********************************************************************/
/*  Set our resource key (so PM can find menus, icons, etc).           */
/***********************************************************************/
   fcd.idResources = DRAGFROM;

/***********************************************************************/
/*  Create the frame - it will hold the list box.                      */
/***********************************************************************/
   hFrameWnd = WinCreateWindow(HWND_DESKTOP,
                               WC_FRAME,
                               "Drag Source",
                               0, 0, 0, 0, 0,
                               NULLHANDLE,
                               HWND_TOP,
                               DRAGFROM,
                               &fcd,
                               NULL);

/***********************************************************************/
/*  Verify that the frame was created; otherwise, stop.                */
/***********************************************************************/
   if (!hFrameWnd)
     return FALSE;

/***********************************************************************/
/*  Set an icon for the frame window.                                  */
/***********************************************************************/
   WinSendMsg(hFrameWnd,
              WM_SETICON,
              (MPARAM)WinQuerySysPointer(HWND_DESKTOP,
                                         SPTR_FOLDER,
                                         FALSE),
               NULL);

/***********************************************************************/
/*  Create a list window child - we willl list files in it.            */
/***********************************************************************/
   hListWnd = WinCreateWindow(hFrameWnd,
                              WC_LISTBOX,
                              NULL,
                              0, 0, 0, 0, 0,
                              hFrameWnd,
                              HWND_BOTTOM,
                              FID_CLIENT,
                              NULL,
                              NULL);

/***********************************************************************/
/*  We must intercept the frame window's messages.                     */
/*  We save the return value (the current WndProc),                    */
/*  so we can pass it all the other messages the frame gets.           */
/***********************************************************************/
   SysWndProc  = WinSubclassWindow(hFrameWnd, (PFNWP)LocalWndProc);
   ListWndProc = WinSubclassWindow (hListWnd, (PFNWP)LocalListProc);

   WinShowWindow(hFrameWnd, TRUE);
   WinPostMsg(hFrameWnd, WM_LOAD_LIST, 0, 0);

/***********************************************************************/
/*  Main message loop.                                                 */
/***********************************************************************/
   while (WinGetMsg (hab, &qmsg, 0L, 0, 0))
     WinDispatchMsg (hab, &qmsg);

   WinDestroyWindow (hFrameWnd);
   WinDestroyMsgQueue (hmq);
   WinTerminate (hab);
}

/***********************************************************************/
/*  LocalWndProc() - intercepts frame window messages.                 */
/***********************************************************************/
MRESULT EXPENTRY LocalWndProc (HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
{
   switch (msg)
   {
      /* Post a message to fill the list box */
      case WM_LOAD_LIST:
         LoadList();
         break;

      case WM_DESTROY:
         WinDestroyPointer (hptrFile);
          break;

      case WM_STARTDRAG:
         DoDrag();
         break;

      default:
         return (*SysWndProc)(hwnd, msg, mp1, mp2);
         break;
   }
   return FALSE;
}

/***********************************************************************/
/*  LocalListProc() - List box subclassing                             */
/*  (all we care about is starting a drag).                            */
/***********************************************************************/
MRESULT EXPENTRY LocalListProc(HWND hwnd,
                               ULONG msg,
                               MPARAM mp1,
                               MPARAM mp2)

{
   if (msg == WM_BUTTON2DOWN)
   {
      WinPostMsg(hFrameWnd, WM_STARTDRAG, mp1, 0);
      return (MRESULT)FALSE;
   }
   else
      return (*ListWndProc)(hwnd, msg, mp1, mp2);
}

/***********************************************************************/
/*  DoDrag() - the actual drag function.                               */
/***********************************************************************/
BOOL DoDrag ()
{
   char             szBuffer[CCHMAXPATH];
   char             szDir[256];
   SHORT            index, len;
   HWND             hTargetWnd;
   LHANDLE          hImage;

   DRAGITEM         Dragitem;
   HSTR             hstrType, hstrRMF, hstrContainer;
   CHAR             szItemName[64];
   CHAR             szContainer[CCHMAXPATH];
   PDRAGINFO        pSourceDraginfo;
   DRAGIMAGE        dimg;
   ULONG            dirlen;

/***********************************************************************/
/*  Get the file name from the listbox.                                */
/***********************************************************************/
   index = WinQueryLboxSelectedItem(hListWnd);
   len   = WinQueryLboxItemTextLength(hListWnd, index);
   WinQueryLboxItemText(hListWnd,
                        index,
                        szBuffer,
                        len);
   szBuffer[len] = '\0';

/***********************************************************************/
/*  Allocate the DRAGINFO data structure.                              */
/***********************************************************************/
   pSourceDraginfo = DrgAllocDraginfo(1);

/***********************************************************************/
/*  Define file type as unknown.                                       */
/***********************************************************************/
   hstrType  = DrgAddStrHandle (DRT_UNKNOWN);
   hstrRMF   = DrgAddStrHandle (szFormats);         /* OS2file unknown */

/***********************************************************************/
/*  Get our current directory for the container name.                  */
/***********************************************************************/
   dirlen                     = CCHMAXPATH-1;
   DosQueryCurrentDir(0, szDir, &dirlen);
   sprintf(szContainer, "\\%s\\", szDir);
   hstrContainer              = DrgAddStrHandle(szContainer);
   Dragitem.hwndItem          = hListWnd;
   Dragitem.hstrType          = hstrType;

   Dragitem.hstrRMF           = hstrRMF;
   Dragitem.hstrContainerName = hstrContainer;
   Dragitem.fsControl         = 0;
   Dragitem.fsSupportedOps    = DO_COPYABLE | DO_MOVEABLE;
   Dragitem.hstrSourceName    = DrgAddStrHandle (szBuffer);
   Dragitem.hstrTargetName    = Dragitem.hstrSourceName;
   Dragitem.ulItemID          = index;

/***********************************************************************/
/*  Set info, prepare for drag.                                        */
/***********************************************************************/
   DrgSetDragitem(pSourceDraginfo,
                  &Dragitem,
                  sizeof(DRAGITEM),
                  0);

/***********************************************************************/
/*  Initialize the drag image.                                         */
/***********************************************************************/
   dimg.cb       = sizeof (DRAGIMAGE);
   dimg.hImage   = WinQuerySysPointer (HWND_DESKTOP, SPTR_FILE, FALSE);
   dimg.fl       = DRG_ICON | DRG_TRANSPARENT;
   dimg.cxOffset = 0;
   dimg.cyOffset = 0;

   pSourceDraginfo->hwndSource = hFrameWnd;

/***********************************************************************/
/*  Start drag operation.                                              */
/***********************************************************************/
   DrgDrag(hFrameWnd,
           pSourceDraginfo,
           &dimg,
           1L,
           VK_BUTTON2,
           NULL);

   return TRUE;
}

/***********************************************************************/
/*  LoadList().                                                        */
/***********************************************************************/
void LoadList(void)
{
   char          szDir[CCHMAXPATH];
   FILEFINDBUF3  ffbFile;
   HDIR          hDir;
   int           rc, x;
   ULONG         dirlen;
   ULONG         count;

/***********************************************************************/
/*  We use a DosFindFirst/DosFindNext loop to fill the list box.       */
/***********************************************************************/
   hDir  = HDIR_CREATE;
   count = 1;
   rc = DosFindFirst("*.*",
                     &hDir,
                     0,
                     &ffbFile,
                     sizeof(FILEFINDBUF3),
                     &count,
                     FIL_STANDARD);

   x = 0;
   do
   {
      sprintf(szFileNames[x], "%s", ffbFile.achName);

      WinPostMsg(hListWnd,
                 LM_INSERTITEM,
                 MPFROMSHORT(LIT_END),
                 szFileNames[x]);
      count = 1;
      x++;

      rc = DosFindNext(hDir,
                       &ffbFile,
                       sizeof(FILEFINDBUF3),
                       &count);
   }
   while (count && (x < 50));

   DosFindClose(hDir);
}

===============
DRAGFROM.H
===============
#define DRAGFROM      100
#define WM_STARTDRAG  WM_USER+100
#define WM_LOAD_LIST  WM_USER+110

===============
DRAGFROM.DEF
===============
NAME            DRAGFROM WINDOWAPI

PROTMODE
HEAPSIZE        8192
STACKSIZE       32768
EXPORTS         LocalWndProc
                LocalListProc

===============
DRAGFROM.LNK
===============
dragfrom.obj
dragfrom.exe
dragfrom.map
dragfrom.def

===============
DRAGFROM.MAK
===============

CC      = icc /c /Ge /Gd- /Se /Re /ss /Gm+
LINK    = link386
HEADERS = dragfrom.h

#----------------------------------------------------------------------
#  A list of all of the object files.
#----------------------------------------------------------------------
ALL_OBJ1 = dragfrom.obj

all: dragfrom.exe

dragfrom.obj: dragfrom.c $(HEADERS)

dragfrom.exe: $(ALL_OBJ1) dragfrom.def dragfrom.lnk
              $(LINK) @dragfrom.lnk

Target Application Sample Code

The target application includes the following files:

  • Target.C
  • Target.RC
  • Target.H
  • Target.DEF
  • Target.LNK

The following sample shows the target application code:

================TARGET.C================
#define  INCL_WIN
#define  INCL_GPI

#include <os2.h>
#include "target.h"

#pragma  linkage (main,optlink)
INT      main(VOID);

/***********************************************************************/
/*  Main() - program entry point.                                      */
/*  This program accepts drops from EPM.                               */
/***********************************************************************/
MRESULT EXPENTRY LocalWndProc(HWND, ULONG, MPARAM, MPARAM);

HAB     hab;
HWND    hFrameWnd;
PFNWP   SysWndProc;

INT main (VOID)
{
   HMQ         hmq;
   HPOINTER    hPtr;
   FRAMECDATA  fcd;
   QMSG        qmsg;

   if (!(hab = WinInitialize(0)))
     return FALSE;

   if (!(hmq = WinCreateMsgQueue(hab, 0)))
     return FALSE;

/***********************************************************************/
/*  Set up the frame control data for the frame window.                */
/***********************************************************************/
   fcd.cb = sizeof(FRAMECDATA);
   fcd.flCreateFlags = FCF_TITLEBAR |
                       FCF_SYSMENU |
                       FCF_SIZEBORDER |
                       FCF_SHELLPOSITION |
                       FCF_MINMAX |
                       FCF_TASKLIST;
   fcd.hmodResources = NULLHANDLE;
   fcd.idResources = 0;

/***********************************************************************/
/*  Create the frame window.                                           */
/***********************************************************************/
   hFrameWnd = WinCreateWindow(HWND_DESKTOP,
                               WC_FRAME,
                               "Target",
                               0,
                               0, 0, 0, 0,
                               NULLHANDLE,
                               HWND_TOP,
                               0,
                               &fcd,
                               NULL);

/***********************************************************************/
/*  Verify that the frame was created; otherwise, stop.                */
/***********************************************************************/
   if (!hFrameWnd)
     return FALSE;
   hPtr = WinLoadPointer(HWND_DESKTOP,
                         NULLHANDLE,
                         TRASHCAN);

/***********************************************************************/
/*  Set an icon for the frame window.                                  */
/***********************************************************************/
   WinSendMsg(hFrameWnd,
              WM_SETICON,
              (MPARAM)hPtr,
              NULL);

/***********************************************************************/
/*  We must intercept the frame window's messages                      */
/*  (to capture any input from the container control).                 */
/*  We save the return value (the current WndProc),                    */
/*  so we can pass it all the other messages the frame gets.           */
/***********************************************************************/
   SysWndProc = WinSubclassWindow(hFrameWnd, (PFNWP)LocalWndProc);

   WinShowWindow(hFrameWnd, TRUE);

/***********************************************************************/
/*  Standard PM message loop - get it, dispatch it.                    */
/***********************************************************************/
   while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
       WinDispatchMsg(hab, &qmsg);

/***********************************************************************/
/*  Clean up on the way out.                                           */
/***********************************************************************/
   WinDestroyMsgQueue(hmq);
   WinTerminate(hab);

   return TRUE;
}

/***********************************************************************/
/*  LocalWndProc() - window procedure for the frame window.            */
/*  Called by PM whenever a message is sent to the frame.              */
/***********************************************************************/
MRESULT EXPENTRY LocalWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
{
   char        szDir[CCHMAXPATH];
   char        szBuffer[256];
   PDRAGINFO   dragInfo;
   PDRAGITEM   dragItem;
   USHORT      usOp;
   USHORT      usIndicator, cItems, i;
   ULONG       ulBytes;

   switch(msg)
   {

/***********************************************************************/
/*  Someone's dragging an object over us.                              */
/***********************************************************************/
     case DM_DRAGOVER:
     dragInfo = (PDRAGINFO)mp1;

     /* Get access to the DRAGINFO data structure */
     DrgAccessDraginfo(dragInfo);

     /* Can we accept this drop? */
     switch (dragInfo->usOperation)
     {

        /* Return DOR_NODROPOP if current operation */
        /* is link or unknown                       */
        case DO_UNKNOWN:
           DrgFreeDraginfo(dragInfo);
           return (MRFROM2SHORT (DOR_NODROPOP, 0));
           break;

        /* Our default operation is Move */
        case DO_DEFAULT:
           dragItem = DrgQueryDragitemPtr(dragInfo, 0);
            ulBytes = DrgQueryStrName(dragItem->hstrContainerName,
                                      sizeof(szDir),
                                      szDir);
           if (!ulBytes)
             return (MRFROM2SHORT (DOR_NODROPOP, 0));
           else
             usOp =  DO_MOVE;
           break;

        /* Do the requested specific operation */
        case DO_MOVE:
        case DO_COPY:
           usOp = dragInfo->usOperation;
           break;
     }

     usIndicator = DOR_DROP;
     cItems = DrgQueryDragitemCount(dragInfo);

     /* Now, we need to look at each item in turn */
     for (i = 0; i < cItems; i++)

     {
        dragItem = DrgQueryDragitemPtr(dragInfo, i);

        /* Make sure we can move for a Move request */
        /* or copy for a Copy                       */
        if (((dragItem->fsSupportedOps & DO_COPYABLE)   &&
             (usOp == (USHORT)DO_COPY))                 ||
            ((dragItem->fsSupportedOps & DO_MOVEABLE)   &&
             (usOp == (USHORT)DO_MOVE)))

        {
           /* Check the rendering format */
           if (DrgVerifyRMF(dragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
              usIndicator = DOR_DROP;
           else
              usIndicator = DOR_NEVERDROP;
        }
        else
           usIndicator = DOR_NODROPOP;
     }

     /* Release the draginfo data structure */
     DrgFreeDraginfo(dragInfo);

     return (MRFROM2SHORT(usIndicator, usOp));
     break;

     /* Dragged object just left */
     case DM_DRAGLEAVE:
        return (MRESULT)FALSE;
        break;

     /* Drop the object on us (receive the object) */
     case DM_DROP:

     /* Get access to the DRAGINFO data structure */
     DrgAccessDraginfo(dragInfo);

     /* Can we accept this drop? */
     switch (dragInfo->usOperation)

     {
        /* Return DOR_NODROPOP if current operation */
        /* is link or unknown                       */
        case DO_UNKNOWN:
           DrgFreeDraginfo(dragInfo);
           return (MRFROM2SHORT (DOR_NODROPOP, 0));
           break;

        /* Our default operation is Move */
        case DO_DEFAULT:
           dragItem = DrgQueryDragitemPtr(dragInfo, 0);
           ulBytes  = DrgQueryStrName(dragItem->hstrContainerName,
                                      sizeof(szDir),
                                      szDir);

           if (!ulBytes)
             return (MRFROM2SHORT (DOR_NODROPOP, 0));
           usOp = (USHORT)DO_MOVE;
           break;

        /* Do the requested specific operation */
        case DO_MOVE:
        case DO_COPY:
           usOp = dragInfo->usOperation;
           break;
     }

     usIndicator = DOR_DROP;
     cItems = DrgQueryDragitemCount(dragInfo);

     /* Now, we need to look at each item in turn */
     for (i = 0; i < cItems; i++)
     {
        dragItem = DrgQueryDragitemPtr(dragInfo, i);

        /* Make sure we can move for a Move request */
        /* or copy for a Copy                       */
        if (((dragItem->fsSupportedOps & DO_COPYABLE)   &&
             (usOp == (USHORT)DO_COPY))                 ||
            ((dragItem->fsSupportedOps & DO_MOVEABLE)   &&
             (usOp == (USHORT)DO_MOVE)))

        {
           /* Check the rendering format */
           if (DrgVerifyRMF(dragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
              usIndicator = DOR_DROP;
           else
              usIndicator = DOR_NEVERDROP;
        }
        else
           usIndicator = DOR_NODROPOP;

/***********************************************************************/
/*  This is where we would actually move or copy the file,             */
/*  but we just display the name instead.                              */
/***********************************************************************/
        DrgQueryStrName(dragItem->hstrSourceName, 255, szBuffer);
        WinMessageBox(HWND_DESKTOP,
                      HWND_DESKTOP,
                      szBuffer,
                      "Dropped",
                      0,
                      MB_OK);
     }

     /* Release the draginfo data structure */
     DrgFreeDraginfo(dragInfo);

     return (MRFROM2SHORT(usIndicator, usOp));
     break;

     /* Send the message to the usual WC_FRAME WndProc */
     default:
        return (*SysWndProc)(hwnd, msg, mp1, mp2);
        break;
   }
   return (*SysWndProc)(hwnd, msg, mp1, mp2);
}

================
TARGET.RC
================
#include <os2.h>
#include "target.h"

ICON TRASHCAN    trashcan.ico

================
TARGET.H
================
#define TRASHCAN 100

================
TARGET.DEF
================
NAME    TARGET   WINDOWAPI

DESCRIPTION 'PM Drag and Drop Sample'

CODE      MOVEABLE
DATA      MOVEABLE MULTIPLE

STACKSIZE 24576
HEAPSIZE  10240

PROTMODE

================
TARGET.LNK
================
target.obj
target.exe
target.map
target.def