home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol1 / misc / clipboard < prev    next >
Text File  |  1990-01-26  |  12KB  |  364 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either expressed or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8.                       Using the Clipboard Device
  9.  
  10.                             by Andy Finkel
  11.  
  12.  
  13. The clipboard.device is an Exec device designed to be the standard
  14. method of data exchange between application programs on the Amiga computer.
  15. The clipboard.device lives in the DEVS: directory of Workbench, and keeps
  16. its clips in the DEVS:clipboards directory.
  17.  
  18. The most common use for the clipboard is passing information by cutting it 
  19. from one application and pasting it into another.  There are two methods an 
  20. application can use to pass data to the clipboard.  The first is to simply 
  21. WRITE the data to the clipboard.device.  In this case, the data is held in 
  22. memory until another application (or the same application) asks to READ the 
  23. data.  This is simple but uses a lot of memory if the data is large. Also
  24. it might waste memory if the data cut to the clipboard is not used.
  25.  
  26. For this reason, the clipboard.device also supports a a POST mechanism. This 
  27. is more complex than just writing the data to the clipboard.  To do a POST, 
  28. an application informs the clipboard.device that data is available.
  29. If that data is later requested from the clipboard by a second application, 
  30. the clipboard sends a message to the first application asking for the POSTed 
  31. information which is then sent.  That way, no memory is used unless it is 
  32. really needed.
  33.  
  34. Of the two methods, POSTing is better but is harder to implement.  To keep
  35. things simple, this article will cover only the WRITE method for using
  36. the clipboard.
  37.  
  38.  
  39.  
  40. Clipboard Data
  41.  
  42. All data on the clipboard should be in IFF format.  This allows the data
  43. to be self-identifying, thus avoiding the need for private formats to be 
  44. established between various applications.  Generally, only two types of 
  45. FORMs will be found on the clipboard: FTXT (text) and ILBM (graphics).
  46. However, other types are possible.
  47.  
  48. The clipboard.device keeps data in one of two places - memory or disk.  If 
  49. an application writes to the clipboard.device the data is copied into memory.  
  50. If there is not enough memory, the data will be copied to disk.  When the 
  51. clipboard.device is closed (ie no applications have it open) any data held
  52. by the clipboard.device is copied into a clip file in the clipboard directory.
  53. This allows applications to pass data even if both are not active at the same 
  54. time.  If this feature is not desired, the last application to have the 
  55. clipboard.device open may perform a reset before closing the clipboard.device.
  56. Some application writers dislike having the clipboard.device write to disk if 
  57. it contains data when closed.
  58.  
  59. The clipboard supports multiple data clips.  This is not to be confused with
  60. multiple chunks in a single clip, which allows for different representations of
  61. the same data.  Multiple clips store different data.  Applications performing
  62. cut and paste operations generally specify the primary clip.  The alternate
  63. clips are provided to aid applications in the maintainance of a set of clips
  64. (ala a scrapbook).  The multiple clips are implemented as different units in
  65. the clipboard device, and are thus accessed at open time.
  66.  
  67.  
  68.  
  69. Clipboard.device Commands
  70.  
  71. The commands and their implementation are as follows (the ones I'm going to 
  72. use will be listed first):
  73.  
  74.  
  75.     Read    Read data from the clipboard for a paste.  io_Offset and
  76.         io_ClipID must be set to zero for the first read of a paste
  77.         sequence.  An io_Actual that is less than the io_Length
  78.         indicates that all the data has been read.  After all the data
  79.         has been read, a subsequent read must be performed (one whose
  80.         io_Actual returns zero) to indicate to the clipboard device
  81.         that all the data has been read.  This allows random access of
  82.         the clip while reading (provided only valid reads are
  83.         performed).
  84.  
  85.     Write    Write data to the clipboard for a cut.  io_Offset and
  86.         io_ClipID must be set to zero for the first write of a cut
  87.         sequence.  An Update command must be given to tell the
  88.         the clipboard that all the data has been written.
  89.  
  90.     Update    Indicates that the data provided with a Write command is
  91.         complete, and available for a Read.  You cannot issue an
  92.         Update command if any Writes are pending.
  93.  
  94.     Clear    Clear the data from this unit.  Subsequent Reads will have
  95.         no data available.
  96.  
  97.     Reset    Reset the clipboard.device to power-on state without closing 
  98.         it.  This will also clear all the data.
  99.  
  100.     Stop    Service no commands except Invalid, Start, Flush.
  101.  
  102.     Start    Resume command servicing.
  103.  
  104.     Flush    Abort all pending commands.
  105.  
  106.     Post    Post the availability of clip data.  io_ClipID must be set to
  107.         zero, a subsequent write of this data does not have io_ClipID
  108.         set to zero as described above, but to the value in io_ClipID
  109.  
  110.     CurrentReadID    
  111.         Return the ClipID of the current clip to read.
  112.  
  113.     CurrentWriteID  
  114.         Return the ClipID of the latest clip written.
  115.  
  116.  
  117.  
  118. How To Use the Clipboard.device
  119.  
  120. To use the clipboard.device, you must set up an IORequest to talk to the 
  121. device.  The IORequest structure for the clipboard is called an IOClipReq.
  122. It is defined in the header file devices/clipboard.h and looks like this:
  123.  
  124. struct IOClipReq {
  125.     struct  Message io_Message;
  126.     struct  Device  *io_Device;        /* device node pointer  */
  127.     struct  Unit    *io_Unit;        /* unit (driver private)*/
  128.     UWORD   io_Command;            /* device command */
  129.     UBYTE   io_Flags;            /* including QUICK and SATISFY */
  130.     BYTE    io_Error;            /* error or warning num */
  131.     ULONG   io_Actual;            /* number of bytes transferred */
  132.     ULONG   io_Length;            /* number of bytes requested */
  133.     SPTR    io_Data;            /* either clip stream or post port */
  134.     ULONG   io_Offset;            /* offset in clip stream */
  135.     LONG    io_ClipID;            /* ordinal clip identifier */
  136. }
  137.  
  138. Notice that this is the same as a standard IO request structure with one
  139. extra field, io_ClipID.  To use the clipboard.device you first Open it by
  140. passing it the address of an IOClipReq and a clip unit number as follows:
  141.  
  142.     OpenDevice("clipboard.device", unit, &IOClipReq, 0);
  143.  
  144. The primary clip unit used by applications to share data is unit 0, use of 
  145. alternate clip units is by private convention.  After opening the clipboard,
  146. the IOClipReq must be initialized before doing a cut or paste operation.
  147.  
  148. When you do a READ or WRITE to the clipboard.device, you must initialize the 
  149. io_ClipID field to 0.  The clipboard.device will take care of it from then 
  150. on - the ID is used internally by the clipboard to keep track of clips.  You 
  151. must also initialize the io_Offset field to 0; this is used for random access 
  152. READs.  By using the offset, you can skip around inside the clip.  Only when 
  153. you trigger the end of clip by trying to read past the end does the 
  154. clipboard.device know you are finished with the clip.
  155.  
  156. The program listed below, CBIO, shows how to use the clipboard.device for
  157. simple text operations.  This code is based on an example by Bob Burns.
  158.  
  159.  
  160.  
  161. /*********************************************************************/
  162. /*                                                                   */
  163. /*  Program name:  cbio                                              */
  164. /*                                                                   */
  165. /*  Purpose:  To provide standard clipboard device interface routines*/
  166. /*            such as Open, Post, Read, Write, etc.             */
  167. /*                                                                   */
  168. /*********************************************************************/
  169. #include "exec/types.h"
  170. #include "exec/ports.h"
  171. #include "exec/io.h"
  172. #include "devices/clipboard.h"
  173.  
  174.  
  175. struct IOClipReq clipboardIO = 0;
  176. struct MsgPort clipboardMsgPort = 0;
  177. struct MsgPort satisfyMsgPort = 0;
  178.  
  179. int CBOpen(unit)
  180. int unit;
  181. {
  182.     int error;
  183.  
  184.     /* open the clipboard device */
  185.     if ((error = OpenDevice("clipboard.device", unit, &clipboardIO, 0)) != 0)
  186.     return(error);
  187.  
  188.     /* Set up the message port in the I/O request */
  189.     clipboardMsgPort.mp_Node.ln_Type = NT_MSGPORT;
  190.     clipboardMsgPort.mp_Flags = 0;
  191.     clipboardMsgPort.mp_SigBit = AllocSignal(-1);
  192.     clipboardMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
  193.     AddPort(&clipboardMsgPort);
  194.     clipboardIO.io_Message.mn_ReplyPort = &clipboardMsgPort;
  195.  
  196.     satisfyMsgPort.mp_Node.ln_Type = NT_MSGPORT;
  197.     satisfyMsgPort.mp_Flags = 0;
  198.     satisfyMsgPort.mp_SigBit = AllocSignal(-1);
  199.     satisfyMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
  200.     AddPort(&satisfyMsgPort);
  201.     return(0);
  202. }
  203.  
  204. CBClose()
  205. {
  206.     if(clipboardMsgPort.mp_SigBit >0)FreeSignal(clipboardMsgPort.mp_SigBit);
  207.     if(satisfyMsgPort.mp_SigBit >0)FreeSignal(satisfyMsgPort.mp_SigBit);
  208.     RemPort(&satisfyMsgPort);
  209.     RemPort(&clipboardMsgPort);
  210.     CloseDevice(&clipboardIO);
  211. }
  212.  
  213. CBSatisfyPost(string,length)
  214. char *string;
  215. int length;
  216. {
  217.     clipboardIO.io_Offset = 0;
  218.     writeLong("FORM");
  219.     length += 12;
  220.     writeLong(&length);
  221.     writeLong("FTXT");
  222.     writeLong("CHRS");
  223.     length -= 12;
  224.     writeLong(&length);
  225.  
  226.     clipboardIO.io_Command = CMD_WRITE;
  227.     clipboardIO.io_Data = string;
  228.     clipboardIO.io_Length = length;
  229.     DoIO(&clipboardIO);
  230.  
  231.     clipboardIO.io_Command = CMD_UPDATE;
  232.     return(DoIO(&clipboardIO));
  233. }
  234.  
  235. writeLong(ldata)
  236. LONG *ldata;
  237. {
  238.  
  239. int status;
  240.     clipboardIO.io_Command = CMD_WRITE;
  241.     clipboardIO.io_Data = ldata;
  242.     clipboardIO.io_Length = 4;
  243.     status=(DoIO(&clipboardIO));
  244. }
  245.  
  246. CBCutS(string,length)
  247. char *string;
  248. int length;
  249. {
  250.     clipboardIO.io_ClipID = 0;
  251.     return(CBSatisfyPost(string,length));
  252. }
  253.  
  254. int
  255. CBPasteS(string)
  256. char *string;
  257. {
  258.     int length=0,status=0;
  259.  
  260.     clipboardIO.io_Command = CMD_READ; /* get the FORM */
  261.     clipboardIO.io_Data = string;
  262.     clipboardIO.io_Length = 4;
  263.     clipboardIO.io_Offset = 0;
  264.     clipboardIO.io_ClipID = 0;
  265.     status -= DoIO(&clipboardIO);
  266.     string[4]='\0';
  267.  
  268.     if(!strcmp(string,"FORM")) { /* iff form */
  269.         clipboardIO.io_Command = CMD_READ; /* get the total length */
  270.         clipboardIO.io_Data = &length;
  271.         clipboardIO.io_Length = 4;
  272.     status -=DoIO(&clipboardIO);
  273.  
  274.         clipboardIO.io_Command = CMD_READ; /* read the chunk and body */
  275.         clipboardIO.io_Data = string;
  276.         clipboardIO.io_Length = 8;
  277.     status -=DoIO(&clipboardIO);
  278.     string[8]='\0';
  279.  
  280.         if(!strcmp(string,"FTXTCHRS")) {
  281.     clipboardIO.io_Command = CMD_READ; /* get the length of the data */
  282.     clipboardIO.io_Data = &length;
  283.     clipboardIO.io_Length = 4;
  284.     status -=DoIO(&clipboardIO);
  285.  
  286.     clipboardIO.io_Command = CMD_READ;
  287.     clipboardIO.io_Data = string;
  288.     clipboardIO.io_Length = length;
  289.     status -=DoIO(&clipboardIO);
  290.     }
  291.     }
  292.     /* force end of file to terminate read */
  293.     clipboardIO.io_Command = CMD_READ;
  294.     clipboardIO.io_Length = 1;
  295.     clipboardIO.io_Data = 0;
  296.     status -= DoIO(&clipboardIO);
  297.  
  298.     if(!status)return(length);
  299.     else return(-1);
  300. }
  301.  
  302.  
  303. int
  304. CBCurrentReadID()
  305. {
  306.     clipboardIO.io_Command = CBD_CURRENTREADID;
  307.     DoIO(&clipboardIO);
  308.     return(clipboardIO.io_ClipID);
  309. }
  310.  
  311. int
  312. CBCurrentWriteID()
  313. {
  314.     clipboardIO.io_Command = CBD_CURRENTWRITEID;
  315.     DoIO(&clipboardIO);
  316.     return(clipboardIO.io_ClipID);
  317. }
  318.  
  319.  
  320. BOOL
  321. CBCheckSatisfy(idVar)
  322. int *idVar;
  323. {
  324.     struct SatisfyMsg *sm;
  325.  
  326.     if (*idVar == 0)
  327.     return(TRUE);
  328.     if (*idVar < CBCurrentWriteID()) {
  329.     *idVar = 0;
  330.     return(TRUE);
  331.     }
  332.     if (sm = (struct SatisfyMsg *) GetMsg(&satisfyMsgPort)) {
  333.     if (*idVar == sm->sm_ClipID)
  334.         return(TRUE);
  335.     }
  336.     return(FALSE);
  337. }
  338.  
  339. CBCut(stream, length)
  340. char *stream;
  341. int length;
  342. {
  343.     clipboardIO.io_Command = CMD_WRITE;
  344.     clipboardIO.io_Data = stream;
  345.     clipboardIO.io_Length = length;
  346.     clipboardIO.io_Offset = 0;
  347.     clipboardIO.io_ClipID = 0;
  348.     DoIO(&clipboardIO);
  349.     clipboardIO.io_Command = CMD_UPDATE;
  350.     DoIO(&clipboardIO);
  351. }
  352.  
  353. int
  354. CBPost()
  355. {
  356.     clipboardIO.io_Command = CBD_POST;
  357.     clipboardIO.io_Data = &satisfyMsgPort;
  358.     clipboardIO.io_ClipID = 0;
  359.     DoIO(&clipboardIO);
  360.     return(clipboardIO.io_ClipID);
  361. }
  362.  
  363.  
  364.