Using the clipboard
===================

A useful feature of GEM, unfortunately not much used, is the clipboard. 
This is stored on disc which means that it can be slow if you don't have 
a hard disc, but also makes it crash proof and reset proof.

One reason why it isn't much used may be that there hasn't been any 
good instructions on how to use it. Many programs that do try to use 
it, such as First Word Plus, get it totally wrong.

Basically all the GEM functions do is remember where the clipboard is, 
your program has to actually read and write the files itself.

File formats
------------
You can store data in any format you like, or in several formats. 
Obviously it is a good idea to use standard formats such as .img for 
bitmaps, .gem for vector graphics, .txt, .asc or .rtf for text etc. If 
saving in one of these would lose lots of information that can be 
stored in your own format then save that as well. When reading the 
clipboard look for the best format, then the next best etc.

For example, if you are writing a spreadsheet you could write in your 
own format that stores the fonts used etc, and in Lotus 123 format for 
other spreadsheets, and as a text file for importing into other programs 
such as word processors. When you read from the clipboard you first 
look for your own format as that's most useful, if that doesn't exist 
then look for a lotus 123 file, and if that doesn't exist only then look 
for a text file.

Setting up the clipboard
------------------------
Before you read or write to the clipboard you need to make sure it is 
set up properly, and set it up if it isn't.

This shouldn't be difficult but in order to cope with other brain 
damaged programs which do silly things to the clipboard string they 
pass to the AES, you have some quite complicated string manipulation.

I've included below a routine to do this, which I'll explain in more 
detail.

The first thing I do is to check if MiNT is installed and if so try to 
set a semaphore. Semaphores protect resources from lots of programs 
accessing them at once, and if another program has set the clipboard 
semaphore then it will wait here until that program has finished. 
Unfortunately most programs don't bother with this semaphore so you 
can still get clashes.

The next thing I do is to use scrp_read which checks if the AES 
already knows what the clipboard path is. scrp_read() finds out what 
it is and then I check whether it's empty. The clipboard path should 
end in a slash. If it doesn't then there are two possibilites. a) A 
brain damaged program has forgotten the slash, or b) an even more 
brain damaged program has put in a filename instead of just the 
directory. I use Fsfirst() to see whether it's a directory or a 
program, and correct the path as appropriate.

If there wasn't a path already known to the AES then I have to create 
a clipboard folder on the boot drive. Depending whether drive c: 
exists or not I use a:\clipbrd or c:\clipbrd. It probably already 
exists, in which case Dcreate() will return an error, but I just 
ignore it.

Finally I tell the AES where I've set the path to with scrp_write(), 
and return a pointer to the scrap path so I can use it later.

        char *clip_setup( void )
        {
                static char scrap_path[200] ;
                char temp[200] ;
                struct FILEINFO dta ;
                int length ;
                int drive_map ;
        
                if( getcookie( 'MiNT', NULL ) )
                        Psemaphore( 2 /* SEM_LOCK */ , '_CLP', -1 ) ;
        
                Fsetdta( &dta ) ;
                
                if( scrp_read( scrap_path ) && isalpha( scrap_path[0] ) )
                {       
                        length = strlen( scrap_path ) ;
                        if( scrap_path[length-1] != '\\' )
                        {
                                Fsfirst( scrap_path, 0x17 ) ;
                                if( dta.attr & 0x10 )
                                        strcat( scrap_path, "\\" ) ;
                                else
                                {
                                        strcpy( temp, scrap_path ) ;
                                        stcgfp( scrap_path, temp ) ;
                                }
                        }
                }
                else
                {
                        drive_map = Drvmap() ;
                        if( drive_map & 0x04 )
                                strcpy( scrap_path, "c:\clipbrd" ) ;
                        else
                                strcpy( scrap_path, "a:\clipbrd" ) ;
                        Dcreate( scrap_path ) ;
                        strcat( scrap_path, "\\" ) ;
                }
        
                scrp_write( scrap_path ) ;
                return( scrap_path ) ;
        }

Writing to the clipboard
------------------------
When the user selects copy or cut, the first thing you have to do is 
to set up the clipboard path as described above. Then you have to 
delete all files in there.

The following routine should do the trick.

        void clip_clear( char *path )
        {
                short err ;
                char scrapfile[200] ;
                char delfile[200] ;
                struct FILEINFO dta ;
                
                Fsetdta( &dta ) ;
                
                strcpy( scrapfile, path ) ;
                strcat( scrapfile, "scrap.*" ) ;
                
                err = Fsfirst( scrapfile, 2 ) ;
                while( !err )
                {
                        strcpy( delfile, path ) ;
                        strcat( delfile, dta.name ) ;
                        Fdelete( delfile ) ;
                        err = Fsnext() ;
                }
        }

Then you just write each file format to files called scrap.xxx where 
xxx depends on the file format. There's not much I can say about this 
as it depends on the formats you use.

Finally you should, if you're using MiNT, release the semaphore.

        void clip_finish( void )
        {
                if( getcookie( 'MiNT', NULL ) )
                        Psemaphore( 3 /* SEM_LOCK */, '_CLP', -1 ) ;
        }

Reading the clipboard
---------------------
When the user selects paste, you have to set up the clipboard, then 
search for a file you can use and read from it. Finally of course you 
release the semaphore if you're using MiNT.

For example in the following code I'm looking for .txt or .asc files. 
(This bit isn't a cut-out-and-keep routine, it's just a fragment from a 
program I've written, although you will probably want something similar)

        clippath = clip_setup() ;
        
        strcpy( filename, clippath ) ;
        strcat( filename, "scrap.asc" ) ;
        
        if( fp = fopen( filename, "rb" ) )
                read_ascii_file(fp) ;
        else
        {       strcpy( filename, clippath ) ;
                strcat( filename, "scrap.txt" ) ;
                
                if( fp = fopen( filename, "rb" ) )
                        read_text_file(fp) ;
        }

        clip_finish() ;
        
Summary
-------
Using the clipboard isn't difficult, the hardest bit is coping with 
all the programs that set it up wrongly. It's nice when you get it 
working to cut and paste between your program and another, 
particularly on a multitasking system!

One final suggestion of how you might improve this. Using the GEM 
clipboard on floppies is slow, and even on a hard disc it isn't 
instant; using your own clipboard in memory is much faster but you 
then can't paste into other programs. How about, then, storing it in 
memory but writing to the GEM clipboard when you quit or, in a 
multitasking system, when another application is topped? Just an 
idea...


Mark Baker

mark.baker@mettav.exnet.com  (turbonet 100:1011/0.17 fidonet 2:254/108.17)
