X11 picture paste support (PNG format)
works with what GIMP puts in the X11 CLIPBOARD
This commit is contained in:
parent
a68343d2ad
commit
7331ad9bdf
@ -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)))
|
||||
{
|
||||
png_init_io(png_ptr, file);
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -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) ----------------------------------------------------
|
||||
|
||||
@ -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
|
||||
|
||||
20
src/input.c
20
src/input.c
@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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__)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user