From f20c07d757388482ff2f4ca4eb7ceaf52712814a Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Thu, 18 Jul 2019 17:46:10 +0200 Subject: X11: support copy/paste of image via clipboard within a single app X11 requires to process differently paste if both copy and paste are within the same app or are in 2 separate apps. This was implemented for paste of text. It's now also implemented for paste of image. --- src/Fl_x.cxx | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 36418ffe8..6c1da73a4 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -751,18 +751,56 @@ const char * fl_selection_type[2]; int fl_selection_buffer_length[2]; char fl_i_own_selection[2] = {0,0}; +static void read_int(uchar *c, int& i) { + i = *c; + i |= (*(++c))<<8; + i |= (*(++c))<<16; + i |= (*(++c))<<24; +} + +// turn BMP image FLTK produced by create_bmp() back to Fl_RGB_Image +static Fl_RGB_Image *own_bmp_to_RGB(char *bmp) { + int w, h; + read_int((uchar*)bmp + 18, w); + read_int((uchar*)bmp + 22, h); + int R=(3*w+3)/4 * 4; // the number of bytes per row, rounded up to multiple of 4 + bmp += 54; + uchar *data = new uchar[w*h*3]; + uchar *p = data; + for (int i = h-1; i >= 0; i--) { + char *s = bmp + i * R; + for (int j = 0; j < w; j++) { + *p++=s[2]; + *p++=s[1]; + *p++=s[0]; + s+=3; + } + } + Fl_RGB_Image *img = new Fl_RGB_Image(data, w, h, 3); + img->alloc_array = 1; + return img; +} + // Call this when a "paste" operation happens: void Fl_X11_System_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) { if (fl_i_own_selection[clipboard]) { // We already have it, do it quickly without window server. - // Notice that the text is clobbered if set_selection is - // called in response to FL_PASTE! - // However, for now, we only paste text in this function - if (fl_selection_type[clipboard] != Fl::clipboard_plain_text) return; //TODO: allow copy/paste of image within same app - Fl::e_text = fl_selection_buffer[clipboard]; - Fl::e_length = fl_selection_length[clipboard]; - if (!Fl::e_text) Fl::e_text = (char *)""; - receiver.handle(FL_PASTE); + if (type == Fl::clipboard_plain_text && fl_selection_type[clipboard] == type) { + // Notice that the text is clobbered if set_selection is + // called in response to FL_PASTE! + // However, for now, we only paste text in this function + Fl::e_text = fl_selection_buffer[clipboard]; + Fl::e_length = fl_selection_length[clipboard]; + if (!Fl::e_text) Fl::e_text = (char *)""; + } else if (clipboard == 1 && type == Fl::clipboard_image && fl_selection_type[1] == type) { + Fl::e_clipboard_data = own_bmp_to_RGB(fl_selection_buffer[1]); + Fl::e_clipboard_type = Fl::clipboard_image; + } else return; + int retval = receiver.handle(FL_PASTE); + if (retval == 0 && type == Fl::clipboard_image) { + delete (Fl_RGB_Image*)Fl::e_clipboard_data; + Fl::e_clipboard_data = NULL; + } return; } // otherwise get the window server to return it: @@ -775,11 +813,15 @@ void Fl_X11_System_Driver::paste(Fl_Widget &receiver, int clipboard, const char int Fl_X11_System_Driver::clipboard_contains(const char *type) { + if (fl_i_own_selection[1]) { + return fl_selection_type[1] == type; + } XEvent event; Atom actual; int format; unsigned long count, remaining, i = 0; unsigned char* portion = NULL; Fl_Window *win = Fl::first_window(); if (!win || !fl_xid(win)) return 0; + win->wait_for_expose(); XConvertSelection(fl_display, CLIPBOARD, TARGETS, CLIPBOARD, fl_xid(win), CurrentTime); XFlush(fl_display); do { -- cgit v1.2.3