home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
drgthr.zip
/
drgthrnd.doc
< prev
next >
Wrap
Text File
|
1993-07-27
|
12KB
|
240 lines
DRGTHRND.EXE (DRaG THread ReNDering) is a sample program that demonstrates
OS/2's Drag/Drop facilities (aka Direct Manipulation). It implements source
rendering after the drop. This sample does its rendering in secondary threads
so as not to hold up the User Interface. If you are looking for something a
little simpler that is single-threaded, try and find my DRGRENDR.EXE sample. It
also implements rendering and is exactly like this program except for the
additional threads.
DRGTHRND creates 2 frame windows with containers as their client windows. One
of the windows plays the role of a 'drag' window, the other plays the role of a
'drop' window. Their roles are not interchangeable, not because it was a problem
to program, rather because the roles of the dragger (called the source window)
and the droppee (called the target window) are 2 different ones and it is
easier to understand their roles if they cannot mix.
The reason that containers are used is not to make the program more complex. On
the contrary, containers make Drag/Drop easier to program because the app does
not have to draw representations of things that can be dragged and dropped. The
container provides simple facilities to place draggable icons into its window.
Listboxes were considered but containers are visually easier to understand.
NOTE THAT THE TOOLKIT HAS A DRAG/DROP SAMPLE CALLED 'DRAGDROP' THAT IS A VERY
GOOD DRAG/DROP SAMPLE PROGRAM.
To run this sample program, type DRGTHRND on the command line. The 2 windows
will appear on the bottom of your display. The left-hand container is the 'drag'
container, the right one is the 'drop' container. Drag one or more icons from
the 'drag' container to the 'drop' container. Then double-click on any of the
icons that are created in the 'drop' container. A listbox window will be
displayed that lists the contents of a 'database table'.
This is what happens on the drag/drop:
First, there are 2 files that are in the .zip file that represent a database of
sorts (a very simple representation). The files are named dbase_?.db. Have a
look at one of them. Here is part of dbase_1.db:
TABLEKEY=>table_1
This is row 1 for the table_1 table in dbase_1
This is row 2 for the table_1 table in dbase_1
This is row 3 for the table_1 table in dbase_1
This is row 4 for the table_1 table in dbase_1
This is row 5 for the table_1 table in dbase_1
TABLEKEY=>table_2
This is row 1 for the table_2 table in dbase_1
This is row 2 for the table_2 table in dbase_1
This is row 3 for the table_2 table in dbase_1
This is row 4 for the table_2 table in dbase_1
This is row 5 for the table_2 table in dbase_1
TABLEKEY=>end_of_database
DRGTHRND scans all dbase_?.db files at startup. Every time it finds a
TABLEKEY=> record, it creates an icon in the 'drag' container that represents
the table whose name follows the TABLEKEY=> literal. When it encounters an
'end_of_databse' record it assumes end-of-file. So the simulation here is of
multiple databases each with multiple tables. The text under each icon is
created by concatenating the database name with the table name. For instance,
the table_2 table in the dbase_1.db file would be represented by an icon with
'dbase_1:table_2' as its text.
When you drag an icon from the 'drag' container (hereafter referred to as the
'source' window) to the 'drop' container ('target' window) and drop it,
rendering takes place. This rendering causes the source window to copy the rows
from the specified table to a file whose name was provided by the target. When
the source indicates that the rendering is complete, the target inserts an icon
into its container that now represents that file. Double-clicking on an icon in
the 'drop' window will bring up a listbox that displays the contents of the
file.
This is meant to simulate a real-world scenario where the source represents its
contents by icons and its contents are really in a database that most targets
would not be able to read on their own (i.e. they don't know the format, don't
know SQL, etc.)
Here is the message flow once the user has begun to drag an icon from the
source window:
SOURCE TARGET
────── ──────
CN_INITDRAG .............................
......................................... CN_DRAGOVER
......................................... CN_DROP (send DM_RENDERPREPARE)
DM_RENDERPREPARE ........................
......................................... CN_DROP (send DM_RENDER to source)
DM_RENDER ...............................
(do the rendering) ......................
(send DM_RENDERCOMPLETE to target)....... DM_RENDERCOMPLETE
(send DM_ENDCONVERSATION to src)
DM_ENDCONVERSATION.......................
To show the thread interaction, this is a further breakdown:
MAIN THREAD
─────────── SOURCE RENDER TARGET RENDER
SOURCE TARGET THREAD THREAD
────── ────── ───────────── ─────────────
CN_INITDRAG ........
.................... CN_DRAGOVER
.................... CN_DROP .... (start thread) ............... CN_DROP
DM_RENDERPREPARE ................ (start thread) ....
DM_RENDER
DM_RENDERCOMPLETE
DM_ENDCONVERSATION
This is basically it. Of course it is more complicated than this in real life
as problems can happen in any of these steps that alter the flow of control.
Note that until DM_RENDER time, everything is done as a group of items, i.e.
all DRAGITEM's are lumped together with a DRAGINFO structure and the DRAGINFO
structure is passed with the messages. When the target gets the CN_DROP, at that
point all messages are on an individual DRAGITEM basis. If the user is only
dragging one icon, there is no difference. With multiple icons this really
comes into play.
Note also that the CN_ messages are WM_CONTROL messages sent by the container
to its owner when it gets the normal PM messages. The reason for this is so that
the container can provide its owner with more information than it would normally
get with the regular PM messages. The mapping goes like this:
PM message (container gets this) Message sent by container to owner
──────────────────────────────── ──────────────────────────────────
WM_BEGINDRAG ......................... CN_INITDRAG
DM_DRAGOVER .......................... CN_DRAGOVER
DM_DROP .............................. CN_DROP
The ValueSet control also provides this type of interface to its owner.
Obviously if your program just uses a normal client window you would use the
messages on the left-hand side.
THE MOST IMPORTANT THING that you need to know about Drag/Drop is that the
information passed between the source and target is in shared memory so it has
to be freed by both sides when they are done with it. Since you don't allocate
the shared memory (PMDRAG.DLL does), it is more difficult to think in terms of
freeing it. The memory that has to be freed is the DRAGINFO structure and all
the string handles in it and its attached DRAGITEM structures, and any
DRAGTRANSFER structures that were used (during rendering) and their string
handles.
You use DrgFreeDraginfo() to free the DRAGINFO structure and
DrgFreeDragtransfer() to free the DRAGTRANSFER structures. The DRAGINFO
structure is allocated by the source when it starts the drag (using the
DrgAllocDraginfo() API), and PM takes care of disbursing this memory to
processes that need it when they call DrgAccessDraginfo(). The DRAGTRANSFER
structures are allocated by the target (using the DrgAllocDragtransfer() API)
when drop processing starts. Whenever it communicates with the source, it uses
DrgSend/PostTransferMsg() API's that cause PM to give their process access to
the DRAGTRANSFER structure.
Here are the documented times for freeing these structures when rendering is
involved (as in this sample program):
SOURCE
──────
If DrgDrag() returns NULLHANDLE (which it will if the user hits F1 or Esc during
the drop so that there is no target window), it should make the following calls:
DrgDeleteDraginfoStrHandles();
DrgFreeDragInfo();
DrgDeleteDraginfoStrHandles() deletes all the string handles in all the
DRAGITEMs associated with the DRAGINFO structure. DrgFreeDraginfo() frees the
DRAGINFO structure.
If DrgDrag() doesn't return NULLHANDLE, that means a drop occurred and the
return value is the target's window handle. In this case, it is the target's
responsibility to delete the string handles but the source needs to free the
DRAGINFO structure and the DRAGTRANSFER structures. Here's what it should do:
When the source is done rendering, it posts the DM_RENDERCOMPLETE message to
the target. After it posts this message it needs to call DrgFreeDragtransfer()
for the DRAGITEM that it just rendered.
Under DM_ENDCONVERSATION, when the DM_ENDCONVERSATION for the *last* DRAGITEM
comes thru, the source needs to call DrgFreeDraginfo(). Keep in mind that
this means a global counter must be used (or store it in a window word like
this program does) so it can keep track of when the last one comes thru.
TARGET
──────
If rendering does not take place for some reason, the target needs to make the
following calls under the CN_DROP (or DM_DROP if not a container owner) message:
DrgDeleteDraginfoStrHandles();
DrgFreeDraginfo();
If rendering does take place:
After the target completes processing the DM_RENDERCOMPLETE message it will
send the source a DM_ENDCONVERSATION message. At this point it should call
DrgFreeDragtransfer() for the DRAGITEM that it just processed. It must also
call DrgDeleteStrHandle() for all HSTR's in the DRAGTRANSFER structure. These
would normally be DRAGTRANSFER.hstrSelectedRMF and
DRAGTRANSFER.hstrRenderToName.
If the last DRAGITEM is being processed (also must be implemented with a
counter), DrgDeleteDraginfoStrHandles() and DrgFreeDraginfo() must be called.
DRGTHRND frees these structures when the documentation recommends freeing them
(as illustrated above). Unfortunately the documentation isn't real clear on
this and you have to search to find it. REMEMBER THAT IF YOUR APPLICATION DOES
NOT FREE THESE STRUCTURES WHEN IT IS SUPPOSED TO THAT YOUR APP COULD SCREW UP
OTHER APPS IF IT ALLOWS DIRECT MANIPULATION TO OCCUR WITH OTHER APPS. This is
an important thing to note. If direct manipulation is not done properly it
could lead to a PM resource leak because shared memory might never be freed
that should be freed.
DRGTHRND.EXE is built from 5 source modules:
DRGTHRND.C - base code that creates all windows and contains the window procs
DBACCESS.C - functions that access the 'databases'
DRAG.C - contains the main-thread basic Drag/Drop related code.
SRCRENDR.C - contains the secondary-thread rendering code for the source window.
TRGRENDR.C - contains the secondary-thread rendering code for the target window.
Hope this sample program helps someone.
===============================================================================
GLOBAL HISTORY
7-19-93 - Completed coding.
===============================================================================
Rick Fishman
Code Blazers, Inc.
4113 Apricot
Irvine, CA 92720
CIS ID: 72251,750