/* * Copyright 2008-2012 Chris Young <chris@unsatisfactorysoftware.co.uk> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf 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; version 2 of the License. * * NetSurf 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, see <http://www.gnu.org/licenses/>. */ #include <proto/iffparse.h> #include <proto/intuition.h> #include <proto/exec.h> #include <proto/datatypes.h> #include <proto/diskfont.h> #include <diskfont/diskfonttag.h> #include <datatypes/textclass.h> #include <datatypes/pictureclass.h> #include "utils/nsoption.h" #include "utils/utf8.h" #include "desktop/browser.h" #include "desktop/plotters.h" #include "desktop/textinput.h" #include "desktop/gui_window.h" #include "desktop/gui_clipboard.h" #include "amiga/bitmap.h" #include "amiga/clipboard.h" #include "amiga/drag.h" #include "amiga/filetype.h" #include "amiga/gui.h" #include "amiga/iff_cset.h" #include "amiga/iff_dr2d.h" #include "amiga/menu.h" #include "amiga/misc.h" #include "amiga/utf8.h" #define ID_UTF8 MAKE_ID('U','T','F','8') struct IFFHandle *iffh = NULL; static struct IFFHandle *ami_clipboard_init_internal(int unit) { struct IFFHandle *iffhandle = NULL; if((iffhandle = AllocIFF())) { if((iffhandle->iff_Stream = (ULONG)OpenClipboard(unit))) { InitIFFasClip(iffhandle); } } return iffhandle; } void ami_clipboard_init(void) { iffh = ami_clipboard_init_internal(0); } static void ami_clipboard_free_internal(struct IFFHandle *iffhandle) { if(iffhandle == NULL) return; if(iffhandle->iff_Stream) CloseClipboard((struct ClipboardHandle *)iffhandle->iff_Stream); FreeIFF(iffhandle); } void ami_clipboard_free(void) { ami_clipboard_free_internal(iffh); } void gui_start_selection(struct gui_window *g) { if(!g) return; if(!g->shared->win) return; if(nsoption_bool(kiosk_mode) == true) return; OnMenu(g->shared->win, AMI_MENU_CLEAR); OnMenu(g->shared->win, AMI_MENU_COPY); if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_CUT) OnMenu(g->shared->win, AMI_MENU_CUT); } static char *ami_clipboard_cat_collection(struct CollectionItem *ci, LONG codeset, size_t *text_length) { struct CollectionItem *ci_new = NULL, *ci_next = NULL, *ci_curr = ci; size_t len = 0; char *text = NULL, *p; /* Scan the collected chunks to find out the total size. * If they are not in UTF-8, convert the chunks first and create a new CollectionItem list. */ do { switch(codeset) { case 106: len += ci_curr->ci_Size; break; case 0: if(ci_new) { ci_next->ci_Next = ami_misc_allocvec_clear(sizeof(struct CollectionItem), 0); ci_next = ci_next->ci_Next; } else { ci_new = ami_misc_allocvec_clear(sizeof(struct CollectionItem), 0); ci_next = ci_new; } utf8_from_local_encoding(ci_curr->ci_Data, ci_curr->ci_Size, (char **)&ci_next->ci_Data); ci_next->ci_Size = strlen(ci_next->ci_Data); len += ci_next->ci_Size; break; default: if(ci_new) { ci_next->ci_Next = ami_misc_allocvec_clear(sizeof(struct CollectionItem), 0); ci_next = ci_next->ci_Next; } else { ci_new = ami_misc_allocvec_clear(sizeof(struct CollectionItem), 0); ci_next = ci_new; } utf8_from_enc(ci_curr->ci_Data, (const char *)ObtainCharsetInfo(DFCS_NUMBER, codeset, DFCS_MIMENAME), ci_curr->ci_Size, (char **)&ci_next->ci_Data, NULL); ci_next->ci_Size = strlen(ci_next->ci_Data); len += ci_next->ci_Size; break; } } while ((ci_curr = ci_curr->ci_Next)); text = malloc(len); if(text == NULL) return NULL; /* p points to the end of the buffer. This is because the chunks are * in the list in reverse order. */ p = text + len; if(ci_new) { ci_curr = ci_new; } else { ci_curr = ci; } do { p -= ci_curr->ci_Size; memcpy(p, ci_curr->ci_Data, ci_curr->ci_Size); ci_next = ci_curr->ci_Next; if(ci_new) { free(ci_curr->ci_Data); FreeVec(ci_curr); } } while ((ci_curr = ci_next)); *text_length = len; return text; } static void gui_get_clipboard(char **buffer, size_t *length) { struct CollectionItem *ci = NULL; struct StoredProperty *sp = NULL; struct CSet *cset; if(OpenIFF(iffh,IFFF_READ)) return; if(CollectionChunk(iffh,ID_FTXT,ID_CHRS)) return; if(PropChunk(iffh,ID_FTXT,ID_CSET)) return; if(CollectionChunk(iffh,ID_FTXT,ID_UTF8)) return; if(StopOnExit(iffh, ID_FTXT, ID_FORM)) return; ParseIFF(iffh,IFFPARSE_SCAN); if((ci = FindCollection(iffh, ID_FTXT, ID_UTF8))) { *buffer = ami_clipboard_cat_collection(ci, 106, length); } else if((ci = FindCollection(iffh, ID_FTXT, ID_CHRS))) { LONG codeset = 0; if((sp = FindProp(iffh, ID_FTXT, ID_CSET))) { cset = (struct CSet *)sp->sp_Data; codeset = cset->CodeSet; } *buffer = ami_clipboard_cat_collection(ci, codeset, length); } CloseIFF(iffh); } static void gui_set_clipboard(const char *buffer, size_t length, nsclipboard_styles styles[], int n_styles) { char *text; struct CSet cset = {0, {0}}; if(buffer == NULL) return; if(!(OpenIFF(iffh, IFFF_WRITE))) { if(!(PushChunk(iffh, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN))) { if(nsoption_bool(clipboard_write_utf8)) { if(!(PushChunk(iffh, 0, ID_CSET, 32))) { cset.CodeSet = 106; // UTF-8 WriteChunkBytes(iffh, &cset, 32); PopChunk(iffh); } } } else { PopChunk(iffh); } if(!(PushChunk(iffh, 0, ID_CHRS, IFFSIZE_UNKNOWN))) { if(nsoption_bool(clipboard_write_utf8)) { WriteChunkBytes(iffh, buffer, length); } else { if(utf8_to_local_encoding(buffer, length, &text) == NSERROR_OK) { char *p; p = text; while(*p != '\0') { if(*p == 0xa0) *p = 0x20; p++; } WriteChunkBytes(iffh, text, strlen(text)); ami_utf8_free(text); } } PopChunk(iffh); } else { PopChunk(iffh); } if(!(PushChunk(iffh, 0, ID_UTF8, IFFSIZE_UNKNOWN))) { WriteChunkBytes(iffh, buffer, length); PopChunk(iffh); } else { PopChunk(iffh); } CloseIFF(iffh); } } void ami_drag_selection(struct gui_window *g) { int x; int y; char *utf8text; char *sel; struct IFFHandle *old_iffh = iffh; struct gui_window_2 *gwin = ami_window_at_pointer(AMINS_WINDOW); /* NB: 'gwin' is at the drop point, 'g' is where the selection was dragged from. * These may be different if the selection has been dragged between windows. */ if(!gwin) { DisplayBeep(scrn); return; } x = gwin->win->MouseX; y = gwin->win->MouseY; if(ami_text_box_at_point(gwin, (ULONG *)&x, (ULONG *)&y)) { iffh = ami_clipboard_init_internal(1); browser_window_key_press(g->bw, NS_KEY_COPY_SELECTION); browser_window_mouse_click(gwin->gw->bw, BROWSER_MOUSE_PRESS_1, x, y); browser_window_key_press(gwin->gw->bw, NS_KEY_PASTE); ami_clipboard_free_internal(iffh); iffh = old_iffh; } else { x = gwin->win->MouseX; y = gwin->win->MouseY; if(ami_gadget_hit(gwin->objects[GID_URL], x, y)) { if((sel = browser_window_get_selection(g->bw))) { utf8text = ami_utf8_easy(sel); RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_URL], gwin->win, NULL, STRINGA_TextVal, utf8text, TAG_DONE); free(sel); ami_utf8_free(utf8text); } } else if(ami_gadget_hit(gwin->objects[GID_SEARCHSTRING], x, y)) { if((sel = browser_window_get_selection(g->bw))) { utf8text = ami_utf8_easy(sel); RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_SEARCHSTRING], gwin->win, NULL, STRINGA_TextVal, utf8text, TAG_DONE); free(sel); ami_utf8_free(utf8text); } } else { DisplayBeep(scrn); } } } bool ami_easy_clipboard(const char *text) { gui_set_clipboard(text, strlen(text), NULL, 0); return true; } bool ami_easy_clipboard_bitmap(struct bitmap *bitmap) { Object *dto = NULL; if((dto = ami_datatype_object_from_bitmap(bitmap))) { DoDTMethod(dto,NULL,NULL,DTM_COPY,NULL); DisposeDTObject(dto); } return true; } #ifdef WITH_NS_SVG bool ami_easy_clipboard_svg(struct hlcache_handle *c) { const char *source_data; ULONG source_size; if(ami_mime_compare(c, "svg") == false) return false; if((source_data = content_get_source_data(c, &source_size)) == NULL) return false; if(!(OpenIFF(iffh,IFFF_WRITE))) { ami_svg_to_dr2d(iffh, source_data, source_size, nsurl_access(hlcache_handle_get_url(c))); CloseIFF(iffh); } return true; } #endif static struct gui_clipboard_table clipboard_table = { .get = gui_get_clipboard, .set = gui_set_clipboard, }; struct gui_clipboard_table *amiga_clipboard_table = &clipboard_table;