home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Developer CD v1.2
/
amidev_cd_12.iso
/
reference
/
amiga_mail_vol1
/
misc
/
clipboard
< prev
next >
Wrap
Text File
|
1990-01-26
|
12KB
|
364 lines
(c) Copyright 1989 Commodore-Amiga, Inc. All rights reserved.
The information contained herein is subject to change without notice, and
is provided "as is" without warranty of any kind, either expressed or implied.
The entire risk as to the use of this information is assumed by the user.
Using the Clipboard Device
by Andy Finkel
The clipboard.device is an Exec device designed to be the standard
method of data exchange between application programs on the Amiga computer.
The clipboard.device lives in the DEVS: directory of Workbench, and keeps
its clips in the DEVS:clipboards directory.
The most common use for the clipboard is passing information by cutting it
from one application and pasting it into another. There are two methods an
application can use to pass data to the clipboard. The first is to simply
WRITE the data to the clipboard.device. In this case, the data is held in
memory until another application (or the same application) asks to READ the
data. This is simple but uses a lot of memory if the data is large. Also
it might waste memory if the data cut to the clipboard is not used.
For this reason, the clipboard.device also supports a a POST mechanism. This
is more complex than just writing the data to the clipboard. To do a POST,
an application informs the clipboard.device that data is available.
If that data is later requested from the clipboard by a second application,
the clipboard sends a message to the first application asking for the POSTed
information which is then sent. That way, no memory is used unless it is
really needed.
Of the two methods, POSTing is better but is harder to implement. To keep
things simple, this article will cover only the WRITE method for using
the clipboard.
Clipboard Data
All data on the clipboard should be in IFF format. This allows the data
to be self-identifying, thus avoiding the need for private formats to be
established between various applications. Generally, only two types of
FORMs will be found on the clipboard: FTXT (text) and ILBM (graphics).
However, other types are possible.
The clipboard.device keeps data in one of two places - memory or disk. If
an application writes to the clipboard.device the data is copied into memory.
If there is not enough memory, the data will be copied to disk. When the
clipboard.device is closed (ie no applications have it open) any data held
by the clipboard.device is copied into a clip file in the clipboard directory.
This allows applications to pass data even if both are not active at the same
time. If this feature is not desired, the last application to have the
clipboard.device open may perform a reset before closing the clipboard.device.
Some application writers dislike having the clipboard.device write to disk if
it contains data when closed.
The clipboard supports multiple data clips. This is not to be confused with
multiple chunks in a single clip, which allows for different representations of
the same data. Multiple clips store different data. Applications performing
cut and paste operations generally specify the primary clip. The alternate
clips are provided to aid applications in the maintainance of a set of clips
(ala a scrapbook). The multiple clips are implemented as different units in
the clipboard device, and are thus accessed at open time.
Clipboard.device Commands
The commands and their implementation are as follows (the ones I'm going to
use will be listed first):
Read Read data from the clipboard for a paste. io_Offset and
io_ClipID must be set to zero for the first read of a paste
sequence. An io_Actual that is less than the io_Length
indicates that all the data has been read. After all the data
has been read, a subsequent read must be performed (one whose
io_Actual returns zero) to indicate to the clipboard device
that all the data has been read. This allows random access of
the clip while reading (provided only valid reads are
performed).
Write Write data to the clipboard for a cut. io_Offset and
io_ClipID must be set to zero for the first write of a cut
sequence. An Update command must be given to tell the
the clipboard that all the data has been written.
Update Indicates that the data provided with a Write command is
complete, and available for a Read. You cannot issue an
Update command if any Writes are pending.
Clear Clear the data from this unit. Subsequent Reads will have
no data available.
Reset Reset the clipboard.device to power-on state without closing
it. This will also clear all the data.
Stop Service no commands except Invalid, Start, Flush.
Start Resume command servicing.
Flush Abort all pending commands.
Post Post the availability of clip data. io_ClipID must be set to
zero, a subsequent write of this data does not have io_ClipID
set to zero as described above, but to the value in io_ClipID
CurrentReadID
Return the ClipID of the current clip to read.
CurrentWriteID
Return the ClipID of the latest clip written.
How To Use the Clipboard.device
To use the clipboard.device, you must set up an IORequest to talk to the
device. The IORequest structure for the clipboard is called an IOClipReq.
It is defined in the header file devices/clipboard.h and looks like this:
struct IOClipReq {
struct Message io_Message;
struct Device *io_Device; /* device node pointer */
struct Unit *io_Unit; /* unit (driver private)*/
UWORD io_Command; /* device command */
UBYTE io_Flags; /* including QUICK and SATISFY */
BYTE io_Error; /* error or warning num */
ULONG io_Actual; /* number of bytes transferred */
ULONG io_Length; /* number of bytes requested */
SPTR io_Data; /* either clip stream or post port */
ULONG io_Offset; /* offset in clip stream */
LONG io_ClipID; /* ordinal clip identifier */
}
Notice that this is the same as a standard IO request structure with one
extra field, io_ClipID. To use the clipboard.device you first Open it by
passing it the address of an IOClipReq and a clip unit number as follows:
OpenDevice("clipboard.device", unit, &IOClipReq, 0);
The primary clip unit used by applications to share data is unit 0, use of
alternate clip units is by private convention. After opening the clipboard,
the IOClipReq must be initialized before doing a cut or paste operation.
When you do a READ or WRITE to the clipboard.device, you must initialize the
io_ClipID field to 0. The clipboard.device will take care of it from then
on - the ID is used internally by the clipboard to keep track of clips. You
must also initialize the io_Offset field to 0; this is used for random access
READs. By using the offset, you can skip around inside the clip. Only when
you trigger the end of clip by trying to read past the end does the
clipboard.device know you are finished with the clip.
The program listed below, CBIO, shows how to use the clipboard.device for
simple text operations. This code is based on an example by Bob Burns.
/*********************************************************************/
/* */
/* Program name: cbio */
/* */
/* Purpose: To provide standard clipboard device interface routines*/
/* such as Open, Post, Read, Write, etc. */
/* */
/*********************************************************************/
#include "exec/types.h"
#include "exec/ports.h"
#include "exec/io.h"
#include "devices/clipboard.h"
struct IOClipReq clipboardIO = 0;
struct MsgPort clipboardMsgPort = 0;
struct MsgPort satisfyMsgPort = 0;
int CBOpen(unit)
int unit;
{
int error;
/* open the clipboard device */
if ((error = OpenDevice("clipboard.device", unit, &clipboardIO, 0)) != 0)
return(error);
/* Set up the message port in the I/O request */
clipboardMsgPort.mp_Node.ln_Type = NT_MSGPORT;
clipboardMsgPort.mp_Flags = 0;
clipboardMsgPort.mp_SigBit = AllocSignal(-1);
clipboardMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
AddPort(&clipboardMsgPort);
clipboardIO.io_Message.mn_ReplyPort = &clipboardMsgPort;
satisfyMsgPort.mp_Node.ln_Type = NT_MSGPORT;
satisfyMsgPort.mp_Flags = 0;
satisfyMsgPort.mp_SigBit = AllocSignal(-1);
satisfyMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
AddPort(&satisfyMsgPort);
return(0);
}
CBClose()
{
if(clipboardMsgPort.mp_SigBit >0)FreeSignal(clipboardMsgPort.mp_SigBit);
if(satisfyMsgPort.mp_SigBit >0)FreeSignal(satisfyMsgPort.mp_SigBit);
RemPort(&satisfyMsgPort);
RemPort(&clipboardMsgPort);
CloseDevice(&clipboardIO);
}
CBSatisfyPost(string,length)
char *string;
int length;
{
clipboardIO.io_Offset = 0;
writeLong("FORM");
length += 12;
writeLong(&length);
writeLong("FTXT");
writeLong("CHRS");
length -= 12;
writeLong(&length);
clipboardIO.io_Command = CMD_WRITE;
clipboardIO.io_Data = string;
clipboardIO.io_Length = length;
DoIO(&clipboardIO);
clipboardIO.io_Command = CMD_UPDATE;
return(DoIO(&clipboardIO));
}
writeLong(ldata)
LONG *ldata;
{
int status;
clipboardIO.io_Command = CMD_WRITE;
clipboardIO.io_Data = ldata;
clipboardIO.io_Length = 4;
status=(DoIO(&clipboardIO));
}
CBCutS(string,length)
char *string;
int length;
{
clipboardIO.io_ClipID = 0;
return(CBSatisfyPost(string,length));
}
int
CBPasteS(string)
char *string;
{
int length=0,status=0;
clipboardIO.io_Command = CMD_READ; /* get the FORM */
clipboardIO.io_Data = string;
clipboardIO.io_Length = 4;
clipboardIO.io_Offset = 0;
clipboardIO.io_ClipID = 0;
status -= DoIO(&clipboardIO);
string[4]='\0';
if(!strcmp(string,"FORM")) { /* iff form */
clipboardIO.io_Command = CMD_READ; /* get the total length */
clipboardIO.io_Data = &length;
clipboardIO.io_Length = 4;
status -=DoIO(&clipboardIO);
clipboardIO.io_Command = CMD_READ; /* read the chunk and body */
clipboardIO.io_Data = string;
clipboardIO.io_Length = 8;
status -=DoIO(&clipboardIO);
string[8]='\0';
if(!strcmp(string,"FTXTCHRS")) {
clipboardIO.io_Command = CMD_READ; /* get the length of the data */
clipboardIO.io_Data = &length;
clipboardIO.io_Length = 4;
status -=DoIO(&clipboardIO);
clipboardIO.io_Command = CMD_READ;
clipboardIO.io_Data = string;
clipboardIO.io_Length = length;
status -=DoIO(&clipboardIO);
}
}
/* force end of file to terminate read */
clipboardIO.io_Command = CMD_READ;
clipboardIO.io_Length = 1;
clipboardIO.io_Data = 0;
status -= DoIO(&clipboardIO);
if(!status)return(length);
else return(-1);
}
int
CBCurrentReadID()
{
clipboardIO.io_Command = CBD_CURRENTREADID;
DoIO(&clipboardIO);
return(clipboardIO.io_ClipID);
}
int
CBCurrentWriteID()
{
clipboardIO.io_Command = CBD_CURRENTWRITEID;
DoIO(&clipboardIO);
return(clipboardIO.io_ClipID);
}
BOOL
CBCheckSatisfy(idVar)
int *idVar;
{
struct SatisfyMsg *sm;
if (*idVar == 0)
return(TRUE);
if (*idVar < CBCurrentWriteID()) {
*idVar = 0;
return(TRUE);
}
if (sm = (struct SatisfyMsg *) GetMsg(&satisfyMsgPort)) {
if (*idVar == sm->sm_ClipID)
return(TRUE);
}
return(FALSE);
}
CBCut(stream, length)
char *stream;
int length;
{
clipboardIO.io_Command = CMD_WRITE;
clipboardIO.io_Data = stream;
clipboardIO.io_Length = length;
clipboardIO.io_Offset = 0;
clipboardIO.io_ClipID = 0;
DoIO(&clipboardIO);
clipboardIO.io_Command = CMD_UPDATE;
DoIO(&clipboardIO);
}
int
CBPost()
{
clipboardIO.io_Command = CBD_POST;
clipboardIO.io_Data = &satisfyMsgPort;
clipboardIO.io_ClipID = 0;
DoIO(&clipboardIO);
return(clipboardIO.io_ClipID);
}