/*- * Copyright (c) 1997-2002 The Protein Laboratory, University of Copenhagen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: Clipboard.c,v 1.42 2004/10/05 16:57:22 dk Exp $ */ #include "apricot.h" #include "Application.h" #include "Image.h" #include "Clipboard.h" #include #ifdef __cplusplus extern "C" { #endif #undef my #define inherited CComponent-> #define my ((( PClipboard) self)-> self) #define var (( PClipboard) self) #define cefInit 0 #define cefDone 1 #define cefStore 2 #define cefFetch 3 struct _ClipboardFormatReg; typedef SV* ClipboardExchangeFunc( Handle self, struct _ClipboardFormatReg * instance, int function, SV * data); typedef ClipboardExchangeFunc *PClipboardExchangeFunc; typedef struct _ClipboardFormatReg { char *id; long sysId; ClipboardExchangeFunc *server; void *data; Bool written; } ClipboardFormatReg, *PClipboardFormatReg; static SV * text_server ( Handle self, PClipboardFormatReg, int, SV *); static SV * utf8_server ( Handle self, PClipboardFormatReg, int, SV *); static SV * image_server ( Handle self, PClipboardFormatReg, int, SV *); static SV * binary_server( Handle self, PClipboardFormatReg, int, SV *); static int clipboards = 0; static int formatCount = 0; static Bool protect_formats = false; static PClipboardFormatReg formats = nil; void * Clipboard_register_format_proc( Handle self, char * format, void * serverProc); void Clipboard_init( Handle self, HV * profile) { inherited init( self, profile); if ( !apc_clipboard_create(self)) croak( "RTC0022: Cannot create clipboard"); if (clipboards == 0) { Clipboard_register_format_proc( self, "Text", (void*)text_server); Clipboard_register_format_proc( self, "Image", (void*)image_server); Clipboard_register_format_proc( self, "UTF8", (void*)utf8_server); protect_formats = 1; } clipboards++; CORE_INIT_TRANSIENT(Clipboard); } void Clipboard_done( Handle self) { clipboards--; if ( clipboards == 0) { protect_formats = 0; while( formatCount) my-> deregister_format( self, formats-> id); } apc_clipboard_destroy(self); inherited done( self); } Bool Clipboard_validate_owner( Handle self, Handle * owner, HV * profile) { if ( pget_H( owner) != application || application == nilHandle) return false; *owner = application; return true; } typedef Bool ActionProc ( Handle self, PClipboardFormatReg item, void * params); typedef ActionProc *PActionProc; static PClipboardFormatReg first_that( Handle self, void * actionProc, void * params) { int i; PClipboardFormatReg list = formats; if ( actionProc == nil) return nil; for ( i = 0; i < formatCount; i++) { if ((( PActionProc) actionProc)( self, list+i, params)) return list+i; } return nil; } static Bool find_format( Handle self, PClipboardFormatReg item, char *format) { return strcmp( item-> id, format) == 0; } static Bool reset_written( Handle self, PClipboardFormatReg item, char *format) { item-> written = false; return false; } void * Clipboard_register_format_proc( Handle self, char * format, void * serverProc) { PClipboardFormatReg list = first_that( self, (void*)find_format, format); if ( list) { my-> deregister_format( self, format); } if (!( list = allocn( ClipboardFormatReg, formatCount + 1))) return nil; if ( formats != nil) { memcpy( list, formats, sizeof( ClipboardFormatReg) * formatCount); free( formats); } formats = list; list += formatCount++; list-> id = duplicate_string( format); list-> server = ( ClipboardExchangeFunc *) serverProc; list-> sysId = ( long) list-> server( self, list, cefInit, nilSV); return list; } void Clipboard_deregister_format( Handle self, char * format) { PClipboardFormatReg fr, list; if ( protect_formats && ( ( strlen( format) == 0) || ( strcmp( format, "Text") == 0) || ( strcmp( format, "UTF8") == 0) || ( strcmp( format, "Image") == 0))) return; fr = first_that( self, (void*)find_format, format); if ( fr == nil) return; list = formats; fr-> server( self, fr, cefDone, nilSV); free( fr-> id); formatCount--; memcpy( fr, fr + 1, sizeof( ClipboardFormatReg) * ( formatCount - ( fr - list))); if ( formatCount > 0) { if (( fr = allocn( ClipboardFormatReg, formatCount))) memcpy( fr, list, sizeof( ClipboardFormatReg) * formatCount); } else fr = nil; free( formats); formats = fr; } Bool Clipboard_open( Handle self) { var-> openCount++; if ( var-> openCount > 1) return true; first_that( self, (void*) reset_written, nil); return apc_clipboard_open( self); } void Clipboard_close( Handle self) { if ( var-> openCount > 0) { PClipboardFormatReg text, utf8; var-> openCount--; if ( var-> openCount > 0) return; text = formats + cfText; utf8 = formats + cfUTF8; /* automatically downgrade UTF8 to TEXT */ if ( utf8-> written && !text-> written) { SV *utf8_sv, *text_sv; if (( utf8_sv = utf8-> server( self, utf8, cefFetch, nilSV))) { STRLEN l, charlen; U8 * src; src = ( U8 *) SvPV( utf8_sv, l); text_sv = newSVpvn("", 0); while ( l--) { register UV u = utf8_to_uvchr( src, &charlen); char c = ( u < 0x7f) ? u : '?'; src += charlen; sv_catpvn( text_sv, &c, 1); } text-> server( self, text, cefFetch, text_sv); sv_free( text_sv); } } apc_clipboard_close( self); } else var-> openCount = 0; } Bool Clipboard_format_exists( Handle self, char * format) { Bool ret; PClipboardFormatReg fr = first_that( self, (void*)find_format, format); if ( !fr) return false; my-> open( self); ret = apc_clipboard_has_format( self, fr-> sysId); my-> close( self); return ret; } SV * Clipboard_fetch( Handle self, char * format) { SV * ret; PClipboardFormatReg fr = first_that( self, (void*)find_format, format); my-> open( self); if ( !fr || !my-> format_exists( self, format)) ret = newSVsv( nilSV); else ret = fr-> server( self, fr, cefFetch, nilSV); my-> close( self); return ret; } void Clipboard_store( Handle self, char * format, SV * data) { PClipboardFormatReg fr = first_that( self, (void*)find_format, format); if ( !fr) return; my-> open( self); if ( var-> openCount == 1) { first_that( self, (void*) reset_written, nil); apc_clipboard_clear( self); } fr-> server( self, fr, cefStore, data); my-> close( self); } void Clipboard_clear( Handle self) { my-> open( self); first_that( self, (void*) reset_written, nil); apc_clipboard_clear( self); my-> close( self); } SV * Clipboard_get_handle( Handle self) { char buf[ 256]; snprintf( buf, 256, "0x%08lx", apc_clipboard_get_handle( self)); return newSVpv( buf, 0); } Bool Clipboard_register_format( Handle self, char * format) { void * proc; if (( strlen( format) == 0) || ( strcmp( format, "Text") == 0) || ( strcmp( format, "UTF8") == 0) || ( strcmp( format, "Image") == 0)) return false; proc = Clipboard_register_format_proc( self, format, (void*)binary_server); return proc != nil; } XS( Clipboard_get_formats_FROMPERL) { dXSARGS; Handle self; int i; PClipboardFormatReg list; if ( items != 1) croak ("Invalid usage of Clipboard.get_formats"); SP -= items; self = gimme_the_mate( ST( 0)); if ( self == nilHandle) croak( "Illegal object reference passed to Clipboard.get_formats"); my-> open( self); list = formats; for ( i = 0; i < formatCount; i++) { if ( !apc_clipboard_has_format( self, list[ i]. sysId)) continue; XPUSHs( sv_2mortal( newSVpv( list[ i]. id, 0))); } my-> close( self); PUTBACK; } XS( Clipboard_get_registered_formats_FROMPERL) { dXSARGS; Handle self; int i; PClipboardFormatReg list; if ( items < 1) croak ("Invalid usage of Clipboard.get_registered_formats"); SP -= items; self = gimme_the_mate( ST( 0)); if ( self == nilHandle) croak( "Illegal object reference passed to Clipboard.get_registered_formats"); list = formats; EXTEND( sp, formatCount); for ( i = 0; i < formatCount; i++) PUSHs( sv_2mortal( newSVpv( list[ i]. id, 0))); PUTBACK; } XS( Clipboard_get_standard_clipboards_FROMPERL) { dXSARGS; int i; PList l; (void)ax; SP -= items; l = apc_get_standard_clipboards(); if ( l && l-> count > 0) { EXTEND( sp, l-> count); for ( i = 0; i < l-> count; i++) { char *cc = (char *)list_at( l, i); PUSHs( sv_2mortal( newSVpv(cc, 0))); } } if (l) { list_delete_all( l, true); plist_destroy( l); } PUTBACK; } void Clipboard_get_formats ( Handle self) { warn("Invalid call of Clipboard::get_formats"); } void Clipboard_get_formats_REDEFINED ( Handle self) { warn("Invalid call of Clipboard::get_formats"); } void Clipboard_get_registered_formats ( Handle self) { warn("Invalid call of Clipboard::get_registered_formats"); } void Clipboard_get_registered_formats_REDEFINED ( Handle self) { warn("Invalid call of Clipboard::get_registered_formats"); } void Clipboard_get_standard_clipboards ( Handle self) { warn("Invalid call of Clipboard::get_standard_clipboards"); } void Clipboard_get_standard_clipboards_REDEFINED ( Handle self) { warn("Invalid call of Clipboard::get_standard_clipboards"); } static SV * text_server( Handle self, PClipboardFormatReg instance, int function, SV * data) { ClipboardDataRec c; switch( function) { case cefInit: return ( SV *) cfText; case cefFetch: if ( apc_clipboard_get_data( self, cfText, &c)) { data = newSVpv(( char*) c. data, c. length); free( c. data); return data; } break; case cefStore: if ( SvUTF8( data)) { /* jump to UTF8. close() will later downgrade data to ascii, if any */ instance = formats + cfUTF8; return instance-> server( self, instance, cefStore, data); } else { c. data = ( Byte*) SvPV( data, c. length); instance-> written = apc_clipboard_set_data( self, cfText, &c); } break; } return nilSV; } static SV * utf8_server( Handle self, PClipboardFormatReg instance, int function, SV * data) { ClipboardDataRec c; switch( function) { case cefInit: return ( SV *) cfUTF8; case cefFetch: if ( apc_clipboard_get_data( self, cfUTF8, &c)) { data = newSVpv(( char*) c. data, c. length); SvUTF8_on( data); free( c. data); return data; } break; case cefStore: c. data = ( Byte*) SvPV( data, c. length); instance-> written = apc_clipboard_set_data( self, cfUTF8, &c); break; } return nilSV; } static SV * image_server( Handle self, PClipboardFormatReg instance, int function, SV * data) { ClipboardDataRec c; switch( function) { case cefInit: return ( SV *) cfBitmap; case cefFetch: { HV * profile = newHV(); c. image = Object_create( "Prima::Image", profile); sv_free(( SV *) profile); if ( apc_clipboard_get_data( self, cfBitmap, &c)) { --SvREFCNT( SvRV( PImage(c. image)-> mate)); return newSVsv( PImage(c. image)-> mate); } Object_destroy( c. image); } break; case cefStore: c. image = gimme_the_mate( data); if ( !kind_of( c. image, CImage)) { warn("RTC0023: Not an image passed to clipboard"); return nilSV; } instance-> written = apc_clipboard_set_data( self, cfBitmap, &c); break; } return nilSV; } static SV * binary_server( Handle self, PClipboardFormatReg instance, int function, SV * data) { ClipboardDataRec c; switch( function) { case cefInit: return ( SV*) apc_clipboard_register_format( self, instance-> id); case cefDone: apc_clipboard_deregister_format( self, instance-> sysId); break; case cefFetch: if ( apc_clipboard_get_data( self, instance-> sysId, &c)) { SV * ret = newSVpv((char*) c. data, c. length); free( c. data); return ret; } break; case cefStore: c. data = (Byte*) SvPV( data, c. length); instance-> written = apc_clipboard_set_data( self, instance-> sysId, &c); break; } return nilSV; } #ifdef __cplusplus } #endif