/* * clip_beos.cpp - Clipboard handling, BeOS implementation * * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "clip.h" #include "main.h" #include "cpu_emulation.h" #include "emul_op.h" #define DEBUG 0 #include "debug.h" // Global variables static bool we_put_this_data = false; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Be side static BTranslatorRoster *roster; static float input_cap = 0; static translator_info input_info; static float output_cap = 0; static translator_id output_trans = 0; /* * Clipboard manager thread (for calling clipboard functions; this is not safe * under R4 when running on the MacOS stack in kernel space) */ // Message constants const uint32 MSG_QUIT_CLIP_MANAGER = 'quit'; const uint32 MSG_PUT_TEXT = 'ptxt'; static thread_id cm_thread = -1; static sem_id cm_done_sem = -1; // Argument passing static void *cm_scrap; static int32 cm_length; static status_t clip_manager(void *arg) { for (;;) { // Receive message thread_id sender; uint32 code = receive_data(&sender, NULL, 0); D(bug("Clipboard manager received %08lx\n", code)); switch (code) { case MSG_QUIT_CLIP_MANAGER: return 0; case MSG_PUT_TEXT: if (be_clipboard->Lock()) { be_clipboard->Clear(); BMessage *clipper = be_clipboard->Data(); // Convert text from Mac charset to UTF-8 int32 dest_length = cm_length * 3; int32 state = 0; char *inbuf = new char[cm_length]; memcpy(inbuf, cm_scrap, cm_length); // Copy to user space char *outbuf = new char[dest_length]; if (convert_to_utf8(B_MAC_ROMAN_CONVERSION, inbuf, &cm_length, outbuf, &dest_length, &state) == B_OK) { for (int i=0; iAddData("text/plain", B_MIME_TYPE, outbuf, dest_length); be_clipboard->Commit(); } else { D(bug(" text conversion failed\n")); } delete[] outbuf; delete[] inbuf; be_clipboard->Unlock(); } break; } // Acknowledge release_sem(cm_done_sem); } } /* * Initialize clipboard */ void ClipInit(void) { // check if there is a translator that can handle the pict datatype roster = BTranslatorRoster::Default(); int32 num_translators, i,j; translator_id *translators; const char *translator_name, *trans_info; int32 translator_version; const translation_format *t_formats; long t_num; roster->GetAllTranslators(&translators, &num_translators); for (i=0;iGetTranslatorInfo(translators[i], &translator_name, &trans_info, &translator_version); D(bug("found translator %s: %s (%.2f)\n", translator_name, trans_info, translator_version/100.)); // does this translator support the pict datatype ? roster->GetInputFormats(translators[i], &t_formats,&t_num); //printf(" supports %d input formats \n",t_num); for (j=0;jinput_cap) { input_info.type = t_formats[j].type; input_info.group = t_formats[j].group; input_info.quality = t_formats[j].quality; input_info.capability = t_formats[j].capability; strcpy(input_info.MIME,t_formats[j].MIME); strcpy(input_info.name,t_formats[j].name); input_info.translator=translators[i]; input_cap = t_formats[j].capability; } D(bug("matching input translator found:type:%c%c%c%c group:%c%c%c%c quality:%f capability:%f MIME:%s name:%s\n", t_formats[j].type>>24,t_formats[j].type>>16,t_formats[j].type>>8,t_formats[j].type, t_formats[j].group>>24,t_formats[j].group>>16,t_formats[j].group>>8,t_formats[j].group, t_formats[j].quality, t_formats[j].capability,t_formats[j].MIME, t_formats[j].name)); } } roster->GetOutputFormats(translators[i], &t_formats,&t_num); //printf("and %d output formats \n",t_num); for (j=0;joutput_cap) { output_trans = translators[i]; output_cap = t_formats[j].capability; } D(bug("matching output translator found:type:%c%c%c%c group:%c%c%c%c quality:%f capability:%f MIME:%s name:%s\n", t_formats[j].type>>24,t_formats[j].type>>16,t_formats[j].type>>8,t_formats[j].type, t_formats[j].group>>24,t_formats[j].group>>16,t_formats[j].group>>8,t_formats[j].group, t_formats[j].quality, t_formats[j].capability,t_formats[j].MIME, t_formats[j].name)); } } } delete [] translators; // clean up our droppings // Start clipboard manager thread cm_done_sem = create_sem(0, "Clipboard Manager Done"); cm_thread = spawn_thread(clip_manager, "Clipboard Manager", B_NORMAL_PRIORITY, NULL); resume_thread(cm_thread); } /* * Deinitialize clipboard */ void ClipExit(void) { // Stop clipboard manager if (cm_thread > 0) { status_t l; send_data(cm_thread, MSG_QUIT_CLIP_MANAGER, NULL, 0); while (wait_for_thread(cm_thread, &l) == B_INTERRUPTED) ; } // Delete semaphores delete_sem(cm_done_sem); } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); if (we_put_this_data) { we_put_this_data = false; return; } if (length <= 0) return; switch (type) { case 'TEXT': D(bug(" clipping TEXT\n")); cm_scrap = scrap; cm_length = length; while (send_data(cm_thread, MSG_PUT_TEXT, NULL, 0) == B_INTERRUPTED) ; while (acquire_sem(cm_done_sem) == B_INTERRUPTED) ; break; case 'PICT': D(bug(" clipping PICT\n")); //!! this has to be converted to use the Clipboard Manager #if 0 if (be_clipboard->Lock()) { be_clipboard->Clear(); BMessage *clipper = be_clipboard->Data(); // Waaaah! This crashes! if (input_cap > 0) { // if there is an converter for PICT datatype convert data to bitmap. BMemoryIO *in_buffer = new BMemoryIO(scrap, length); BMallocIO *out_buffer = new BMallocIO(); status_t result=roster->Translate(in_buffer,&input_info,NULL,out_buffer,B_TRANSLATOR_BITMAP); clipper->AddData("image/x-be-bitmap", B_MIME_TYPE, out_buffer->Buffer(), out_buffer->BufferLength()); D(bug("conversion result:%08x buffer_size:%d\n",result,out_buffer->BufferLength())); delete in_buffer; delete out_buffer; } clipper->AddData("image/pict", B_MIME_TYPE, scrap, length); be_clipboard->Commit(); be_clipboard->Unlock(); } #endif break; } } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { M68kRegisters r; D(bug("GetScrap handle %p, type %08lx, offset %ld\n", handle, type, offset)); return; //!! GetScrap is currently broken (should use Clipboard Manager) //!! replace with clipboard notification in BeOS R4.1 switch (type) { case 'TEXT': D(bug(" clipping TEXT\n")); if (be_clipboard->Lock()) { BMessage *clipper = be_clipboard->Data(); char *clip; ssize_t length; // Check if we already copied this data if (clipper->HasData("application/x-SheepShaver-cookie", B_MIME_TYPE)) return; bigtime_t cookie = system_time(); clipper->AddData("application/x-SheepShaver-cookie", B_MIME_TYPE, &cookie, sizeof(bigtime_t)); // No, is there text in it? if (clipper->FindData("text/plain", B_MIME_TYPE, &clip, &length) == B_OK) { D(bug(" text/plain found\n")); // Convert text from UTF-8 to Mac charset int32 src_length = length; int32 dest_length = length; int32 state = 0; char *outbuf = new char[dest_length]; if (convert_from_utf8(B_MAC_ROMAN_CONVERSION, clip, &src_length, outbuf, &dest_length, &state) == B_OK) { for (int i=0; iCommit(); be_clipboard->Unlock(); } break; case 'PICT': D(bug(" clipping PICT\n")); if (be_clipboard->Lock()) { BMessage *clipper = be_clipboard->Data(); char *clip; ssize_t length; // Check if we already copied this data if (clipper->HasData("application/x-SheepShaver-cookie", B_MIME_TYPE)) return; bigtime_t cookie = system_time(); clipper->AddData("application/x-SheepShaver-cookie", B_MIME_TYPE, &cookie, sizeof(bigtime_t)); static uint16 proc2[] = { 0x598f, // subq.l #4,sp 0xa9fc, // ZeroScrap() 0x2f3c, 0, 0, // move.l #length,-(sp) 0x2f3c, 'PI', 'CT', // move.l #'PICT',-(sp) 0x2f3c, 0, 0, // move.l #buf,-(sp) 0xa9fe, // PutScrap() 0x588f, // addq.l #4,sp M68K_RTS }; // No, is there a pict ? if (clipper->FindData("image/pict", B_MIME_TYPE, &clip, &length) == B_OK ) { D(bug(" image/pict found\n")); // Add pict to Mac clipboard *(int32 *)(proc2 + 3) = length; *(char **)(proc2 + 9) = clip; we_put_this_data = true; Execute68k((uint32)proc2, &r); #if 0 // No, is there a bitmap ? } else if (clipper->FindData("image/x-be-bitmap", B_MIME_TYPE, &clip, &length) == B_OK || output_cap > 0) { D(bug(" image/x-be-bitmap found\nstarting conversion to PICT\n")); BMemoryIO *in_buffer = new BMemoryIO(clip, length); BMallocIO *out_buffer = new BMallocIO(); status_t result=roster->Translate(output_trans,in_buffer,NULL,out_buffer,'PICT'); D(bug("result of conversion:%08x buffer_size:%d\n",result,out_buffer->BufferLength())); // Add pict to Mac clipboard *(int32 *)(proc2 + 3) = out_buffer->BufferLength(); *(char **)(proc2 + 9) = (char *)out_buffer->Buffer(); we_put_this_data = true; Execute68k(proc2, &r); delete in_buffer; delete out_buffer; #endif } be_clipboard->Commit(); be_clipboard->Unlock(); } break; } }