X11 copying code and support PRIMARY & CLIPBOARD clipboards.
This commit is contained in:
parent
57522db6e2
commit
9f41e5b67a
@ -466,6 +466,7 @@ extern "C" {
|
|||||||
#define GLFW_PLATFORM_ERROR 0x00070008
|
#define GLFW_PLATFORM_ERROR 0x00070008
|
||||||
#define GLFW_WINDOW_NOT_ACTIVE 0x00070009
|
#define GLFW_WINDOW_NOT_ACTIVE 0x00070009
|
||||||
#define GLFW_CLIPBOARD_FORMAT_UNAVAILABLE 0x00070010
|
#define GLFW_CLIPBOARD_FORMAT_UNAVAILABLE 0x00070010
|
||||||
|
#define GLFW_CLIPBOARD_CANNOT_OWN 0x00070011
|
||||||
|
|
||||||
/* Gamma ramps */
|
/* Gamma ramps */
|
||||||
#define GLFW_GAMMA_RAMP_SIZE 256
|
#define GLFW_GAMMA_RAMP_SIZE 256
|
||||||
|
@ -71,5 +71,8 @@ GLFWAPI size_t glfwGetClipboardData(void *data, size_t size, int format)
|
|||||||
if (format == GLFW_CLIPBOARD_FORMAT_NONE)
|
if (format == GLFW_CLIPBOARD_FORMAT_NONE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!data || !size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return _glfwPlatformGetClipboardData(data, size, format);
|
return _glfwPlatformGetClipboardData(data, size, format);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
|
// TODO: Incremental support? Overkill perhaps.
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -45,28 +47,101 @@
|
|||||||
static Atom *getInternalFormat(int fmt)
|
static Atom *getInternalFormat(int fmt)
|
||||||
{
|
{
|
||||||
// Get the necessary atoms
|
// Get the necessary atoms
|
||||||
|
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
{
|
{
|
||||||
case GLFW_CLIPBOARD_FORMAT_STRING:
|
case GLFW_CLIPBOARD_FORMAT_STRING:
|
||||||
return _glfwLibrary.X11.selection.stringatoms;
|
return _glfwLibrary.X11.selection.atoms.string;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//========================================================================
|
||||||
|
// X11 selection request event
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
Atom _glfwSelectionRequest(XSelectionRequestEvent *request)
|
||||||
|
{
|
||||||
|
Atom *atoms = _glfwLibrary.X11.selection.atoms.string;
|
||||||
|
if (request->target == XA_STRING)
|
||||||
|
{
|
||||||
|
// TODO: ISO Latin-1 specific characters don't get converted
|
||||||
|
// (yet). For cleanliness, would we need something like iconv?
|
||||||
|
XChangeProperty(_glfwLibrary.X11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->target,
|
||||||
|
request->target,
|
||||||
|
8,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char *)_glfwLibrary.X11.selection.clipboard.string,
|
||||||
|
8);
|
||||||
|
}
|
||||||
|
else if (request->target == atoms[_GLFW_STRING_ATOM_COMPOUND] ||
|
||||||
|
request->target == atoms[_GLFW_STRING_ATOM_UTF8])
|
||||||
|
{
|
||||||
|
XChangeProperty(_glfwLibrary.X11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->target,
|
||||||
|
request->target,
|
||||||
|
8,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char *)_glfwLibrary.X11.selection.clipboard.string,
|
||||||
|
_glfwLibrary.X11.selection.clipboard.stringlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Should we set an error? Probably not.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return request->target;
|
||||||
|
}
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Set the clipboard contents
|
// Set the clipboard contents
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardData(void *data, size_t size, int format)
|
void _glfwPlatformSetClipboardData(void *data, size_t size, int format)
|
||||||
{
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case GLFW_CLIPBOARD_FORMAT_STRING:
|
||||||
|
{
|
||||||
|
// Allocate memory to keep track of the clipboard
|
||||||
|
char *cb = malloc(size+1);
|
||||||
|
|
||||||
|
// Copy the clipboard data
|
||||||
|
memcpy(cb, data, size);
|
||||||
|
|
||||||
|
// Set the string length
|
||||||
|
_glfwLibrary.X11.selection.clipboard.stringlen = size;
|
||||||
|
|
||||||
|
// Check if existing clipboard memory needs to be freed
|
||||||
|
if (_glfwLibrary.X11.selection.clipboard.string)
|
||||||
|
free(_glfwLibrary.X11.selection.clipboard.string);
|
||||||
|
|
||||||
|
// Now set the clipboard (awaiting the event SelectionRequest)
|
||||||
|
_glfwLibrary.X11.selection.clipboard.string = cb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
_glfwSetError(GLFW_CLIPBOARD_FORMAT_UNAVAILABLE,
|
||||||
|
"X11/GLX: Unavailable clipboard format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the selection owner to our active window
|
||||||
|
XSetSelectionOwner(_glfwLibrary.X11.display, XA_PRIMARY,
|
||||||
|
_glfwLibrary.activeWindow->X11.handle, CurrentTime);
|
||||||
|
XSetSelectionOwner(_glfwLibrary.X11.display,
|
||||||
|
_glfwLibrary.X11.selection.atoms.clipboard
|
||||||
|
[_GLFW_CLIPBOARD_ATOM_CLIPBOARD],
|
||||||
|
_glfwLibrary.activeWindow->X11.handle, CurrentTime);
|
||||||
|
XFlush(_glfwLibrary.X11.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Return the current clipboard contents
|
// Return the current clipboard contents
|
||||||
// TODO: Incremental support? Overkill perhaps.
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format)
|
size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format)
|
||||||
@ -74,46 +149,60 @@ size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format)
|
|||||||
size_t len, rembytes, dummy;
|
size_t len, rembytes, dummy;
|
||||||
unsigned char *d;
|
unsigned char *d;
|
||||||
int fmt;
|
int fmt;
|
||||||
Window window;
|
Atom type;
|
||||||
Atom *xfmt, type;
|
|
||||||
|
|
||||||
// Try different formats that relate to the GLFW format with preference
|
// Try different clipboards and formats that relate to the GLFW
|
||||||
// for better formats first
|
// format with preference for more appropriate formats first
|
||||||
for (xfmt = getInternalFormat(format); *xfmt; xfmt++)
|
Atom *xcbrd = _glfwLibrary.X11.selection.atoms.clipboard;
|
||||||
|
Atom *xcbrdend = _glfwLibrary.X11.selection.atoms.clipboard +
|
||||||
|
_GLFW_CLIPBOARD_ATOM_COUNT;
|
||||||
|
Atom *xfmt = getInternalFormat(format);
|
||||||
|
Atom *xfmtend = xfmt + _GLFW_STRING_ATOM_COUNT;
|
||||||
|
|
||||||
|
// Get the currently active window
|
||||||
|
Window window = _glfwLibrary.activeWindow->X11.handle;
|
||||||
|
|
||||||
|
for (; xcbrd != xcbrdend; xcbrd++)
|
||||||
|
{
|
||||||
|
for (; xfmt != xfmtend; xfmt++)
|
||||||
{
|
{
|
||||||
// Specify the format we would like.
|
// Specify the format we would like.
|
||||||
_glfwLibrary.X11.selection.request = *xfmt;
|
_glfwLibrary.X11.selection.request = *xfmt;
|
||||||
|
|
||||||
// Convert the selection into a format we would like.
|
// Convert the selection into a format we would like.
|
||||||
window = _glfwLibrary.activeWindow->X11.handle;
|
XConvertSelection(_glfwLibrary.X11.display, *xcbrd,
|
||||||
XConvertSelection(_glfwLibrary.X11.display, XA_PRIMARY,
|
*xfmt, None, window, CurrentTime);
|
||||||
*xfmt, None, window,
|
|
||||||
CurrentTime);
|
|
||||||
XFlush(_glfwLibrary.X11.display);
|
XFlush(_glfwLibrary.X11.display);
|
||||||
|
|
||||||
// Process pending events until we get a SelectionNotify.
|
// Process pending events until we get a SelectionNotify.
|
||||||
while (!_glfwLibrary.X11.selection.converted)
|
while (!_glfwLibrary.X11.selection.converted)
|
||||||
_glfwPlatformWaitEvents();
|
_glfwPlatformWaitEvents();
|
||||||
|
|
||||||
// If there is no owner to the selection/wrong request, bail out.
|
// Successful?
|
||||||
if (_glfwLibrary.X11.selection.converted == 2)
|
if (_glfwLibrary.X11.selection.converted == 1)
|
||||||
{
|
break;
|
||||||
_glfwLibrary.X11.selection.converted = 0;
|
|
||||||
_glfwSetError(GLFW_CLIPBOARD_FORMAT_UNAVAILABLE,
|
|
||||||
"X11/GLX: Unavailable clipboard format");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else // Right format, stop checking
|
|
||||||
|
// Successful?
|
||||||
|
if (_glfwLibrary.X11.selection.converted == 1)
|
||||||
{
|
{
|
||||||
_glfwLibrary.X11.selection.converted = 0;
|
_glfwLibrary.X11.selection.converted = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsuccessful conversion, bail with no clipboard data
|
||||||
|
if (_glfwLibrary.X11.selection.converted)
|
||||||
|
{
|
||||||
|
_glfwSetError(GLFW_CLIPBOARD_FORMAT_UNAVAILABLE,
|
||||||
|
"X11/GLX: Unavailable clipboard format");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset for the next selection
|
// Reset for the next selection
|
||||||
_glfwLibrary.X11.selection.converted = 0;
|
_glfwLibrary.X11.selection.converted = 0;
|
||||||
|
|
||||||
// Check the length of data to receive
|
// Check the length of data to receive (rembytes)
|
||||||
XGetWindowProperty(_glfwLibrary.X11.display,
|
XGetWindowProperty(_glfwLibrary.X11.display,
|
||||||
window,
|
window,
|
||||||
*xfmt,
|
*xfmt,
|
||||||
|
@ -446,13 +446,20 @@ static GLboolean initDisplay(void)
|
|||||||
// the keyboard mapping.
|
// the keyboard mapping.
|
||||||
updateKeyCodeLUT();
|
updateKeyCodeLUT();
|
||||||
|
|
||||||
|
// Find or create clipboard atoms
|
||||||
|
_glfwLibrary.X11.selection.atoms.clipboard[_GLFW_CLIPBOARD_ATOM_PRIMARY] =
|
||||||
|
XA_PRIMARY;
|
||||||
|
_glfwLibrary.X11.selection.atoms.clipboard[_GLFW_CLIPBOARD_ATOM_CLIPBOARD] =
|
||||||
|
XInternAtom(_glfwLibrary.X11.display, "CLIPBOARD", False);
|
||||||
|
_glfwLibrary.X11.selection.atoms.clipboard[_GLFW_CLIPBOARD_ATOM_SECONDARY] =
|
||||||
|
XA_SECONDARY;
|
||||||
|
|
||||||
// Find or create selection atoms
|
// Find or create selection atoms
|
||||||
_glfwLibrary.X11.selection.stringatoms[0] =
|
_glfwLibrary.X11.selection.atoms.string[_GLFW_STRING_ATOM_UTF8] =
|
||||||
XInternAtom(_glfwLibrary.X11.display, "UTF8_STRING", False);
|
XInternAtom(_glfwLibrary.X11.display, "UTF8_STRING", False);
|
||||||
_glfwLibrary.X11.selection.stringatoms[1] =
|
_glfwLibrary.X11.selection.atoms.string[_GLFW_STRING_ATOM_COMPOUND] =
|
||||||
XInternAtom(_glfwLibrary.X11.display, "COMPOUND_STRING", False);
|
XInternAtom(_glfwLibrary.X11.display, "COMPOUND_STRING", False);
|
||||||
_glfwLibrary.X11.selection.stringatoms[2] = XA_STRING;
|
_glfwLibrary.X11.selection.atoms.string[_GLFW_STRING_ATOM_STRING] = XA_STRING;
|
||||||
_glfwLibrary.X11.selection.stringatoms[3] = 0;
|
|
||||||
|
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
}
|
}
|
||||||
@ -616,6 +623,10 @@ int _glfwPlatformTerminate(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Free clipboard memory
|
||||||
|
if (_glfwLibrary.X11.selection.clipboard.string)
|
||||||
|
free(_glfwLibrary.X11.selection.clipboard.string);
|
||||||
|
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,17 @@
|
|||||||
#define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11
|
#define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11
|
||||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX
|
||||||
|
|
||||||
// Number of string atoms that will be checked
|
// Clipboard atoms
|
||||||
#define _GLFW_STRING_ATOMS_COUNT 4
|
#define _GLFW_CLIPBOARD_ATOM_PRIMARY 0
|
||||||
|
#define _GLFW_CLIPBOARD_ATOM_CLIPBOARD 1
|
||||||
|
#define _GLFW_CLIPBOARD_ATOM_SECONDARY 2
|
||||||
|
#define _GLFW_CLIPBOARD_ATOM_COUNT 3
|
||||||
|
|
||||||
|
// String atoms
|
||||||
|
#define _GLFW_STRING_ATOM_UTF8 0
|
||||||
|
#define _GLFW_STRING_ATOM_COMPOUND 1
|
||||||
|
#define _GLFW_STRING_ATOM_STRING 2
|
||||||
|
#define _GLFW_STRING_ATOM_COUNT 3
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW platform specific types
|
// GLFW platform specific types
|
||||||
@ -229,7 +238,14 @@ typedef struct _GLFWlibraryX11
|
|||||||
|
|
||||||
// Selection data
|
// Selection data
|
||||||
struct {
|
struct {
|
||||||
Atom stringatoms[_GLFW_STRING_ATOMS_COUNT];
|
struct {
|
||||||
|
Atom clipboard[_GLFW_CLIPBOARD_ATOM_COUNT];
|
||||||
|
Atom string[_GLFW_STRING_ATOM_COUNT];
|
||||||
|
} atoms;
|
||||||
|
struct {
|
||||||
|
size_t stringlen;
|
||||||
|
char *string;
|
||||||
|
} clipboard;
|
||||||
Atom request;
|
Atom request;
|
||||||
int converted;
|
int converted;
|
||||||
} selection;
|
} selection;
|
||||||
@ -273,5 +289,7 @@ void _glfwTerminateJoysticks(void);
|
|||||||
// Unicode support
|
// Unicode support
|
||||||
long _glfwKeySym2Unicode(KeySym keysym);
|
long _glfwKeySym2Unicode(KeySym keysym);
|
||||||
|
|
||||||
|
// Clipboard handling
|
||||||
|
Atom _glfwSelectionRequest(XSelectionRequestEvent *request);
|
||||||
|
|
||||||
#endif // _platform_h_
|
#endif // _platform_h_
|
||||||
|
@ -1394,6 +1394,23 @@ static void processSingleEvent(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SelectionRequest:
|
||||||
|
{
|
||||||
|
XSelectionRequestEvent *request = &event.xselectionrequest;
|
||||||
|
// Construct the response
|
||||||
|
XEvent response;
|
||||||
|
response.xselection.property = _glfwSelectionRequest(request);
|
||||||
|
response.xselection.type = SelectionNotify;
|
||||||
|
response.xselection.display = request->display;
|
||||||
|
response.xselection.requestor = request->requestor;
|
||||||
|
response.xselection.selection = request->selection;
|
||||||
|
response.xselection.target = request->target;
|
||||||
|
response.xselection.time = request->time;
|
||||||
|
// Send off the event
|
||||||
|
XSendEvent(_glfwLibrary.X11.display, request->requestor, 0, 0, &response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Was the window destroyed?
|
// Was the window destroyed?
|
||||||
case DestroyNotify:
|
case DestroyNotify:
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user