X11 picture paste support (PNG format)

works with what GIMP puts in the X11 CLIPBOARD
This commit is contained in:
Thomas Bernard 2018-12-30 10:20:50 +01:00
parent a68343d2ad
commit 7331ad9bdf
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
7 changed files with 155 additions and 14 deletions

View File

@ -91,10 +91,6 @@
#include "fileformats.h"
#include "oldies.h"
#ifndef __no_pnglib__
static void Load_PNG_Sub(T_IO_Context * context, FILE * file);
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
@ -3769,7 +3765,7 @@ void Load_ICO(T_IO_Context * context)
#ifndef __no_pnglib__
if (png_sig_cmp(png_header, 0, 8) == 0)
{
Load_PNG_Sub(context, file);
Load_PNG_Sub(context, file, NULL, 0);
}
#else
if (0 == memcmp(png_header, "\x89PNG", 4))
@ -6239,8 +6235,39 @@ static int PNG_read_unknown_chunk(png_structp ptr, png_unknown_chunkp chunk)
}
struct PNG_memory_buffer {
const char * buffer;
unsigned long offset;
unsigned long size;
};
/// read from memory buffer
static void PNG_memory_read(png_structp png_ptr, png_bytep p, png_size_t count)
{
struct PNG_memory_buffer * buffer = (struct PNG_memory_buffer *)png_get_io_ptr(png_ptr);
GFX2_Log(GFX2_DEBUG, "PNG_memory_read(%p, %p, %u) (io_ptr=%p)\n", png_ptr, p, count, buffer);
if (buffer == NULL || p == NULL)
return;
if (buffer->offset + count <= buffer->size)
{
memcpy(p, buffer->buffer + buffer->offset, count);
buffer->offset += count;
}
else
{
unsigned long available_count = buffer->size - buffer->offset;
GFX2_Log(GFX2_DEBUG, "PNG_memory_read(): only %lu bytes available\n", available_count);
if (available_count > 0)
{
memcpy(p, buffer->buffer + buffer->offset, available_count);
buffer->offset += available_count;
}
}
}
/// Read PNG format file
static void Load_PNG_Sub(T_IO_Context * context, FILE * file)
void Load_PNG_Sub(T_IO_Context * context, FILE * file, const char * memory_buffer, unsigned long memory_buffer_size)
{
png_structp png_ptr;
png_infop info_ptr = NULL;
@ -6256,12 +6283,22 @@ static void Load_PNG_Sub(T_IO_Context * context, FILE * file)
png_byte color_type;
png_byte bit_depth;
byte bpp;
struct PNG_memory_buffer buffer;
// Setup a return point. If a pnglib loading error occurs
// in this if(), the else will be executed.
if (!setjmp(png_jmpbuf(png_ptr)))
{
// to read from memory, I need to use png_set_read_fn() instead of calling png_init_io()
if (file != NULL)
png_init_io(png_ptr, file);
else
{
buffer.buffer = memory_buffer;
buffer.offset = 8; // skip header
buffer.size = memory_buffer_size;
png_set_read_fn(png_ptr, &buffer, PNG_memory_read);
}
// Inform pnglib we already loaded the header.
png_set_sig_bytes(png_ptr, 8);
@ -6344,7 +6381,11 @@ static void Load_PNG_Sub(T_IO_Context * context, FILE * file)
ratio = PIXEL_TALL;
}
}
Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,ratio,bpp);
Pre_load(context,
png_get_image_width(png_ptr, info_ptr),
png_get_image_height(png_ptr, info_ptr),
file != NULL ? File_length_file(file) : memory_buffer_size,
FORMAT_PNG, ratio, bpp);
if (File_error==0)
{
@ -6569,7 +6610,7 @@ void Load_PNG(T_IO_Context * context)
{
// Do we recognize a png file signature ?
if ( !png_sig_cmp(png_header, 0, 8))
Load_PNG_Sub(context, file);
Load_PNG_Sub(context, file, NULL, 0);
else
File_error=1;
}

View File

@ -140,6 +140,7 @@ void Save_ICO(T_IO_Context *);
void Test_PNG(T_IO_Context *, FILE *);
void Load_PNG(T_IO_Context *);
void Save_PNG(T_IO_Context *);
void Load_PNG_Sub(T_IO_Context * context, FILE * file, const char * memory_buffer, unsigned long memory_buffer_size);
#endif
// -- INFO (Amiga ICONS) ----------------------------------------------------

View File

@ -1733,7 +1733,7 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
Display_bookmark(bookmark_dropdown[temp],temp);
}
#if defined(WIN32)
#if defined(WIN32) || defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
if (load)
Window_set_normal_button(62,180,115,14,"From Clipboard",0,1,SHORTCUT_PASTE); // 14
else

View File

@ -86,6 +86,7 @@ word * Drop_file_name_unicode = NULL;
#if defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
char * X11_clipboard = NULL;
unsigned long X11_clipboard_size = 0;
#endif
// --
@ -397,6 +398,7 @@ static void Handle_ClientMessage(const XClientMessageEvent * xclient)
}
else
{
/// @todo XFree the result of XGetAtomName
GFX2_Log(GFX2_INFO, "Unhandled ClientMessage message_type=\"%s\"\n", XGetAtomName(X11_display, xclient->message_type));
}
}
@ -478,6 +480,7 @@ static int Handle_SelectionNotify(const XSelectionEvent* xselection)
unsigned long count = 0, bytesAfter = 0;
unsigned char * value = NULL;
/// @todo XFree the result of XGetAtomName
GFX2_Log(GFX2_DEBUG, "xselection: selection=%s property=%s target=%s\n",
XGetAtomName(X11_display, xselection->selection),
xselection->property == None ? "None" : XGetAtomName(X11_display, xselection->property),
@ -489,9 +492,22 @@ static int Handle_SelectionNotify(const XSelectionEvent* xselection)
&count, &bytesAfter, &value);
if (r == Success && value != NULL)
{
X11_clipboard = strdup((char *)value);
/// @todo XFree the result of XGetAtomName
GFX2_Log(GFX2_DEBUG, "Clipboard value=%p %lu bytes format=%d type=%s\n",
value, count, format, XGetAtomName(X11_display, type));
X11_clipboard_size = count;
if (xselection->target == XInternAtom(X11_display, "UTF8_STRING", False))
X11_clipboard = strdup((char *)value); // Text Clipboard
else if (xselection->target == XInternAtom(X11_display, "image/png", False))
{ // Picture clipboard (PNG)
X11_clipboard = malloc(count);
if (X11_clipboard != NULL)
memcpy(X11_clipboard, value, count);
}
XFree(value);
}
else
GFX2_Log(GFX2_INFO, "XGetWindowProperty failed. r=%d value=%p\n", r, value);
user_feedback_required = 1;
}
else
@ -501,6 +517,7 @@ static int Handle_SelectionNotify(const XSelectionEvent* xselection)
}
else
{
/// @todo XFree the result of XGetAtomName
GFX2_Log(GFX2_INFO, "Unhandled SelectNotify selection=%s\n", XGetAtomName(X11_display, xselection->selection));
}
return user_feedback_required;
@ -1659,6 +1676,7 @@ int Get_input(int sleep_time)
}
else
{
/// @todo XFree the result of XGetAtomName
GFX2_Log(GFX2_INFO, "unrecognized WM event : %s\n", XGetAtomName(X11_display, (Atom)event.xclient.data.l[0]));
}
}

View File

@ -77,6 +77,14 @@ extern int Snap_axis_origin_Y;
extern char * Drop_file_name;
extern word * Drop_file_name_unicode;
#if defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
///
/// malloc'ed copy of the X11 clipboard
extern char * X11_clipboard;
extern unsigned long X11_clipboard_size;
#endif
#if defined __HAIKU__
#define SHORTCUT_COPY (KEY_c|MOD_ALT)
#elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__macosx__)

View File

@ -46,6 +46,9 @@
#include <SDL_image.h>
#include <SDL_endian.h>
#endif
#ifndef __no_pnglib__
#include <png.h>
#endif
#include "gfx2log.h"
#include "buttons.h"
@ -74,6 +77,13 @@
#include "fileformats.h"
#include "bitcount.h"
#if defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
#include "input.h"
#if defined(USE_X11)
extern Display * X11_display;
extern Window X11_window;
#endif
#endif
#if defined(USE_SDL) || defined(USE_SDL2)
// -- SDL_Image -------------------------------------------------------------
@ -1424,6 +1434,71 @@ static void Load_ClipBoard_Image(T_IO_Context * context)
}
}
CloseClipboard();
#elif defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
int i;
Atom selection;
Window selection_owner;
#if defined(SDL_VIDEO_DRIVER_X11)
Display * X11_display;
Window X11_window;
int old_wmevent_state;
if (!GFX2_Get_X11_Display_Window(&X11_display, &X11_window))
{
GFX2_Log(GFX2_ERROR, "Failed to get X11 display and window\n");
return;
}
if (X11_display == NULL)
{
#if defined(USE_SDL)
char video_driver_name[32];
GFX2_Log(GFX2_WARNING, "X11 display is NULL. X11 is needed for Copy/Paste. SDL video driver is currently %s\n", SDL_VideoDriverName(video_driver_name, sizeof(video_driver_name)));
#endif
return;
}
#endif
selection = XInternAtom(X11_display, "CLIPBOARD", False);
selection_owner = XGetSelectionOwner(X11_display, selection);
if (selection_owner == None)
return;
#if defined(USE_SDL) || defined(USE_SDL2)
old_wmevent_state = SDL_EventState(SDL_SYSWMEVENT, SDL_QUERY);
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
#endif
#ifndef __no_pnglib__
XConvertSelection(X11_display, selection, XInternAtom(X11_display, "image/png"/*"PIXMAP"*/, False),
XInternAtom(X11_display, "GFX2_CLIP", False), /* Property */
X11_window, CurrentTime);
// wait for the event to be received
for(i = 0; X11_clipboard == NULL && i < 10; i++)
{
Get_input(20);
}
#if defined(USE_SDL) || defined(USE_SDL2)
SDL_EventState(SDL_SYSWMEVENT, old_wmevent_state);
#endif
if (X11_clipboard != NULL)
{
if (png_sig_cmp((byte *)X11_clipboard, 0, 8) == 0)
{
File_error = 0;
Load_PNG_Sub(context, NULL, X11_clipboard, X11_clipboard_size);
}
else
{
GFX2_Log(GFX2_WARNING, "Clipboard content not in PNG format\n");
}
free(X11_clipboard);
X11_clipboard = NULL;
X11_clipboard_size = 0;
}
#else
GFX2_Log(GFX2_ERROR, "Need PNG support for X11 image copy/paste\n");
#endif
#else
GFX2_Log(GFX2_ERROR, "Load_ClipBoard_Image() not implemented on this platform yet\n");
File_error = 1;

View File

@ -72,9 +72,6 @@ extern Window X11_window;
#elif defined(__macosx__)
const char * get_paste_board(void);
#endif
#if defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
extern char * X11_clipboard;
#endif
// Virtual keyboard is ON by default on these platforms:
#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(GCWZERO)
@ -490,6 +487,7 @@ bye:
{
char * utf8_str = X11_clipboard;
X11_clipboard = NULL;
X11_clipboard_size = 0;
#else
{
// mac OS without X11