From 31c91545be9c65c7ad3701c71286102e07186bb8 Mon Sep 17 00:00:00 2001 From: Ralph Eastwood Date: Wed, 21 Sep 2011 10:09:47 +0100 Subject: [PATCH 1/7] Added clipboard stubs. --- include/GL/glfw3.h | 8 +++++ src/CMakeLists.txt | 11 ++++--- src/clipboard.c | 68 +++++++++++++++++++++++++++++++++++++++++++ src/cocoa_clipboard.m | 56 +++++++++++++++++++++++++++++++++++ src/internal.h | 4 +++ src/win32_clipboard.c | 56 +++++++++++++++++++++++++++++++++++ src/x11_clipboard.c | 56 +++++++++++++++++++++++++++++++++++ 7 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 src/clipboard.c create mode 100644 src/cocoa_clipboard.m create mode 100644 src/win32_clipboard.c create mode 100644 src/x11_clipboard.c diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index 1f52e742..e3687b5c 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -469,6 +469,10 @@ extern "C" { /* Gamma ramps */ #define GLFW_GAMMA_RAMP_SIZE 256 +/* Clipboard formats */ +#define GLFW_CLIPBOARD_FORMAT_NONE 0 +#define GLFW_CLIPBOARD_FORMAT_STRING 1 + /************************************************************************* * Typedefs *************************************************************************/ @@ -591,6 +595,10 @@ GLFWAPI int glfwGetJoystickParam(int joy, int param); GLFWAPI int glfwGetJoystickPos(int joy, float* pos, int numaxes); GLFWAPI int glfwGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons); +/* Clipboard */ +GLFWAPI void glfwSetClipboardData(void *data, size_t size, int format); +GLFWAPI size_t glfwGetClipboardData(void *data, size_t size, int format); + /* Time */ GLFWAPI double glfwGetTime(void); GLFWAPI void glfwSetTime(double time); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd50b41d..08ce8365 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,23 +27,26 @@ include_directories(${GLFW_SOURCE_DIR}/src ${GLFW_BINARY_DIR}/src ${GLFW_INCLUDE_DIR}) -set(common_SOURCES enable.c error.c fullscreen.c gamma.c init.c input.c +set(common_SOURCES clipboard.c enable.c error.c fullscreen.c gamma.c init.c input.c joystick.c opengl.c time.c window.c) if(_GLFW_COCOA_NSGL) - set(libglfw_SOURCES ${common_SOURCES} cocoa_enable.m cocoa_fullscreen.m + set(libglfw_SOURCES ${common_SOURCES} cocoa_clipboard.c + cocoa_enable.m cocoa_fullscreen.m cocoa_gamma.m cocoa_init.m cocoa_joystick.m cocoa_opengl.m cocoa_time.m cocoa_window.m) # For some reason, CMake doesn't know about .m set_source_files_properties(${libglfw_SOURCES} PROPERTIES LANGUAGE C) elseif(_GLFW_WIN32_WGL) - set(libglfw_SOURCES ${common_SOURCES} win32_enable.c win32_fullscreen.c + set(libglfw_SOURCES ${common_SOURCES} win32_clipboard.c + win32_enable.c win32_fullscreen.c win32_gamma.c win32_init.c win32_joystick.c win32_opengl.c win32_time.c win32_window.c win32_dllmain.c) elseif(_GLFW_X11_GLX) - set(libglfw_SOURCES ${common_SOURCES} x11_enable.c x11_fullscreen.c + set(libglfw_SOURCES ${common_SOURCES} x11_clipboard.c + x11_enable.c x11_fullscreen.c x11_gamma.c x11_init.c x11_joystick.c x11_keysym2unicode.c x11_opengl.c x11_time.c x11_window.c) diff --git a/src/clipboard.c b/src/clipboard.c new file mode 100644 index 00000000..5e38904f --- /dev/null +++ b/src/clipboard.c @@ -0,0 +1,68 @@ +//======================================================================== +// GLFW - An OpenGL library +// Platform: Any +// API version: 3.0 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +//======================================================================== +// Set the clipboard contents +//======================================================================== + +GLFWAPI void glfwSetClipboardData(void *data, size_t size, int format) +{ + if (!_glfwInitialized) + { + _glfwSetError(GLFW_NOT_INITIALIZED, NULL); + return; + } + _glfwPlatformSetClipboardData(data, size, format); +} + + +//======================================================================== +// Return the current clipboard contents +//======================================================================== + +GLFWAPI size_t glfwGetClipboardData(void *data, size_t size, int format) +{ + if (!_glfwInitialized) + { + _glfwSetError(GLFW_NOT_INITIALIZED, NULL); + return 0; + } + + return _glfwPlatformGetClipboardData(data, size, format); +} diff --git a/src/cocoa_clipboard.m b/src/cocoa_clipboard.m new file mode 100644 index 00000000..0f78cf21 --- /dev/null +++ b/src/cocoa_clipboard.m @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW - An OpenGL library +// Platform: Cocoa/NSOpenGL +// API version: 3.0 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +//======================================================================== +// Set the clipboard contents +//======================================================================== + +void _glfwPlatformSetClipboardData(void *data, size_t size, int format) +{ +} + +//======================================================================== +// Return the current clipboard contents +//======================================================================== + +size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format) +{ + return 0; +} + diff --git a/src/internal.h b/src/internal.h index 83559ecc..3b82d47e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -284,6 +284,10 @@ void _glfwPlatformGetDesktopMode(GLFWvidmode* mode); void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp); +// Clipboard +void _glfwPlatformSetClipboardData(void *data, size_t size, int format); +size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format); + // Joystick int _glfwPlatformGetJoystickParam(int joy, int param); int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes); diff --git a/src/win32_clipboard.c b/src/win32_clipboard.c new file mode 100644 index 00000000..b16c51c4 --- /dev/null +++ b/src/win32_clipboard.c @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW - An OpenGL library +// Platform: Win32/WGL +// API version: 3.0 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +//======================================================================== +// Set the clipboard contents +//======================================================================== + +void _glfwPlatformSetClipboardData(void *data, size_t size, int format) +{ +} + +//======================================================================== +// Return the current clipboard contents +//======================================================================== + +size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format) +{ + return 0; +} + diff --git a/src/x11_clipboard.c b/src/x11_clipboard.c new file mode 100644 index 00000000..164bad49 --- /dev/null +++ b/src/x11_clipboard.c @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW - An OpenGL library +// Platform: X11/GLX +// API version: 3.0 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +//======================================================================== +// Set the clipboard contents +//======================================================================== + +void _glfwPlatformSetClipboardData(void *data, size_t size, int format) +{ +} + +//======================================================================== +// Return the current clipboard contents +//======================================================================== + +size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format) +{ + return 0; +} + From 57522db6e2919406efd0d44a170962ed8f480f2f Mon Sep 17 00:00:00 2001 From: Ralph Eastwood Date: Wed, 21 Sep 2011 15:43:28 +0100 Subject: [PATCH 2/7] X11 implementation of clipboard pasting. --- include/GL/glfw3.h | 1 + src/clipboard.c | 9 +++- src/x11_clipboard.c | 107 ++++++++++++++++++++++++++++++++++++++++++- src/x11_init.c | 8 ++++ src/x11_platform.h | 9 ++++ src/x11_window.c | 13 ++++++ tests/CMakeLists.txt | 5 +- 7 files changed, 147 insertions(+), 5 deletions(-) diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index e3687b5c..21ed049a 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -465,6 +465,7 @@ extern "C" { #define GLFW_VERSION_UNAVAILABLE 0x00070007 #define GLFW_PLATFORM_ERROR 0x00070008 #define GLFW_WINDOW_NOT_ACTIVE 0x00070009 +#define GLFW_CLIPBOARD_FORMAT_UNAVAILABLE 0x00070010 /* Gamma ramps */ #define GLFW_GAMMA_RAMP_SIZE 256 diff --git a/src/clipboard.c b/src/clipboard.c index 5e38904f..79cf680c 100644 --- a/src/clipboard.c +++ b/src/clipboard.c @@ -48,6 +48,10 @@ GLFWAPI void glfwSetClipboardData(void *data, size_t size, int format) _glfwSetError(GLFW_NOT_INITIALIZED, NULL); return; } + + if (format == GLFW_CLIPBOARD_FORMAT_NONE) + return; + _glfwPlatformSetClipboardData(data, size, format); } @@ -61,8 +65,11 @@ GLFWAPI size_t glfwGetClipboardData(void *data, size_t size, int format) if (!_glfwInitialized) { _glfwSetError(GLFW_NOT_INITIALIZED, NULL); - return 0; + return 0; } + if (format == GLFW_CLIPBOARD_FORMAT_NONE) + return 0; + return _glfwPlatformGetClipboardData(data, size, format); } diff --git a/src/x11_clipboard.c b/src/x11_clipboard.c index 164bad49..467a0d52 100644 --- a/src/x11_clipboard.c +++ b/src/x11_clipboard.c @@ -29,28 +29,131 @@ #include "internal.h" +#include #include #include - +#include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// +//======================================================================== +// Get the corresponding X11 format for a given GLFW format. +//======================================================================== + +static Atom *getInternalFormat(int fmt) +{ + // Get the necessary atoms + + switch (fmt) + { + case GLFW_CLIPBOARD_FORMAT_STRING: + return _glfwLibrary.X11.selection.stringatoms; + default: + return 0; + } +} + //======================================================================== // Set the clipboard contents //======================================================================== void _glfwPlatformSetClipboardData(void *data, size_t size, int format) { + } //======================================================================== // Return the current clipboard contents +// TODO: Incremental support? Overkill perhaps. //======================================================================== size_t _glfwPlatformGetClipboardData(void *data, size_t size, int format) { - return 0; + size_t len, rembytes, dummy; + unsigned char *d; + int fmt; + Window window; + Atom *xfmt, type; + + // Try different formats that relate to the GLFW format with preference + // for better formats first + for (xfmt = getInternalFormat(format); *xfmt; xfmt++) + { + // Specify the format we would like. + _glfwLibrary.X11.selection.request = *xfmt; + + // Convert the selection into a format we would like. + window = _glfwLibrary.activeWindow->X11.handle; + XConvertSelection(_glfwLibrary.X11.display, XA_PRIMARY, + *xfmt, None, window, + CurrentTime); + XFlush(_glfwLibrary.X11.display); + + // Process pending events until we get a SelectionNotify. + while (!_glfwLibrary.X11.selection.converted) + _glfwPlatformWaitEvents(); + + // If there is no owner to the selection/wrong request, bail out. + if (_glfwLibrary.X11.selection.converted == 2) + { + _glfwLibrary.X11.selection.converted = 0; + _glfwSetError(GLFW_CLIPBOARD_FORMAT_UNAVAILABLE, + "X11/GLX: Unavailable clipboard format"); + return 0; + } + else // Right format, stop checking + { + _glfwLibrary.X11.selection.converted = 0; + break; + } + } + + // Reset for the next selection + _glfwLibrary.X11.selection.converted = 0; + + // Check the length of data to receive + XGetWindowProperty(_glfwLibrary.X11.display, + window, + *xfmt, + 0, 0, + 0, + AnyPropertyType, + &type, + &fmt, + &len, &rembytes, + &d); + + // The number of bytes remaining (which is all of them) + if (rembytes > 0) + { + int result = XGetWindowProperty(_glfwLibrary.X11.display, window, + *xfmt, 0, rembytes, 0, + AnyPropertyType, &type, &fmt, + &len, &dummy, &d); + if (result == Success) + { + size_t s = size - 1 > rembytes ? rembytes : size - 1; + // Copy the data out. + memcpy(data, d, s); + // Null-terminate strings. + if (format == GLFW_CLIPBOARD_FORMAT_STRING) + { + ((char *)data)[s] = '\0'; + } + // Free the data allocated using X11. + XFree(d); + // Return the actual number of bytes. + return rembytes; + } + else + { + // Free the data allocated using X11. + XFree(d); + return 0; + } + } + return 0; } diff --git a/src/x11_init.c b/src/x11_init.c index 9af7783e..a824528b 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -446,6 +446,14 @@ static GLboolean initDisplay(void) // the keyboard mapping. updateKeyCodeLUT(); + // Find or create selection atoms + _glfwLibrary.X11.selection.stringatoms[0] = + XInternAtom(_glfwLibrary.X11.display, "UTF8_STRING", False); + _glfwLibrary.X11.selection.stringatoms[1] = + XInternAtom(_glfwLibrary.X11.display, "COMPOUND_STRING", False); + _glfwLibrary.X11.selection.stringatoms[2] = XA_STRING; + _glfwLibrary.X11.selection.stringatoms[3] = 0; + return GL_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index b3cf642e..90b6e75c 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -89,6 +89,8 @@ #define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX +// Number of string atoms that will be checked +#define _GLFW_STRING_ATOMS_COUNT 4 //======================================================================== // GLFW platform specific types @@ -225,6 +227,13 @@ typedef struct _GLFWlibraryX11 uint64_t t0; } timer; + // Selection data + struct { + Atom stringatoms[_GLFW_STRING_ATOMS_COUNT]; + Atom request; + int converted; + } selection; + #if defined(_GLFW_DLOPEN_LIBGL) void* libGL; // dlopen handle for libGL.so #endif diff --git a/src/x11_window.c b/src/x11_window.c index a05b121c..ff54a11b 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1381,6 +1381,19 @@ static void processSingleEvent(void) break; } + case SelectionNotify: + { + // Selection notification triggered by the XConvertSelection + + // Check if the notification property matches the request + if (event.xselection.property != _glfwLibrary.X11.selection.request) + _glfwLibrary.X11.selection.converted = 2; + else // It was successful + _glfwLibrary.X11.selection.converted = 1; + + break; + } + // Was the window destroyed? case DestroyNotify: return; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ef07acc..23a1ebd0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(${GLFW_SOURCE_DIR}/include ${GLFW_SOURCE_DIR}/support ${OPENGL_INCLUDE_DIR}) +add_executable(clipboard clipboard.c) add_executable(defaults defaults.c) add_executable(events events.c) add_executable(fsaa fsaa.c getopt.c) @@ -32,8 +33,8 @@ else() endif(APPLE) set(WINDOWS_BINARIES accuracy sharing tearing windows) -set(CONSOLE_BINARIES defaults events fsaa fsfocus gamma iconify joysticks - listmodes peter reopen version) +set(CONSOLE_BINARIES clipboard defaults events fsaa fsfocus gamma iconify + joysticks listmodes peter reopen version) if(MSVC) # Tell MSVC to use main instead of WinMain for Windows subsystem executables From 9f41e5b67a89dbd93f96e39d2d1d7d6c79a872c2 Mon Sep 17 00:00:00 2001 From: Ralph Eastwood Date: Thu, 22 Sep 2011 12:03:45 +0100 Subject: [PATCH 3/7] X11 copying code and support PRIMARY & CLIPBOARD clipboards. --- include/GL/glfw3.h | 1 + src/clipboard.c | 3 + src/x11_clipboard.c | 149 +++++++++++++++++++++++++++++++++++--------- src/x11_init.c | 19 ++++-- src/x11_platform.h | 26 ++++++-- src/x11_window.c | 21 ++++++- 6 files changed, 179 insertions(+), 40 deletions(-) diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index 21ed049a..7f054e5f 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -466,6 +466,7 @@ extern "C" { #define GLFW_PLATFORM_ERROR 0x00070008 #define GLFW_WINDOW_NOT_ACTIVE 0x00070009 #define GLFW_CLIPBOARD_FORMAT_UNAVAILABLE 0x00070010 +#define GLFW_CLIPBOARD_CANNOT_OWN 0x00070011 /* Gamma ramps */ #define GLFW_GAMMA_RAMP_SIZE 256 diff --git a/src/clipboard.c b/src/clipboard.c index 79cf680c..b055c168 100644 --- a/src/clipboard.c +++ b/src/clipboard.c @@ -71,5 +71,8 @@ GLFWAPI size_t glfwGetClipboardData(void *data, size_t size, int format) if (format == GLFW_CLIPBOARD_FORMAT_NONE) return 0; + if (!data || !size) + return 0; + return _glfwPlatformGetClipboardData(data, size, format); } diff --git a/src/x11_clipboard.c b/src/x11_clipboard.c index 467a0d52..1be0ac23 100644 --- a/src/x11_clipboard.c +++ b/src/x11_clipboard.c @@ -27,6 +27,8 @@ // //======================================================================== +// TODO: Incremental support? Overkill perhaps. + #include "internal.h" #include @@ -45,28 +47,101 @@ static Atom *getInternalFormat(int fmt) { // Get the necessary atoms - switch (fmt) { case GLFW_CLIPBOARD_FORMAT_STRING: - return _glfwLibrary.X11.selection.stringatoms; + return _glfwLibrary.X11.selection.atoms.string; default: 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 //======================================================================== 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 -// TODO: Incremental support? Overkill perhaps. //======================================================================== 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; unsigned char *d; int fmt; - Window window; - Atom *xfmt, type; + Atom type; - // Try different formats that relate to the GLFW format with preference - // for better formats first - for (xfmt = getInternalFormat(format); *xfmt; xfmt++) + // Try different clipboards and formats that relate to the GLFW + // format with preference for more appropriate formats first + 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++) { - // Specify the format we would like. - _glfwLibrary.X11.selection.request = *xfmt; - - // Convert the selection into a format we would like. - window = _glfwLibrary.activeWindow->X11.handle; - XConvertSelection(_glfwLibrary.X11.display, XA_PRIMARY, - *xfmt, None, window, - CurrentTime); - XFlush(_glfwLibrary.X11.display); - - // Process pending events until we get a SelectionNotify. - while (!_glfwLibrary.X11.selection.converted) - _glfwPlatformWaitEvents(); - - // If there is no owner to the selection/wrong request, bail out. - if (_glfwLibrary.X11.selection.converted == 2) + for (; xfmt != xfmtend; xfmt++) { - _glfwLibrary.X11.selection.converted = 0; - _glfwSetError(GLFW_CLIPBOARD_FORMAT_UNAVAILABLE, - "X11/GLX: Unavailable clipboard format"); - return 0; + // Specify the format we would like. + _glfwLibrary.X11.selection.request = *xfmt; + + // Convert the selection into a format we would like. + XConvertSelection(_glfwLibrary.X11.display, *xcbrd, + *xfmt, None, window, CurrentTime); + XFlush(_glfwLibrary.X11.display); + + // Process pending events until we get a SelectionNotify. + while (!_glfwLibrary.X11.selection.converted) + _glfwPlatformWaitEvents(); + + // Successful? + if (_glfwLibrary.X11.selection.converted == 1) + break; } - else // Right format, stop checking + + // Successful? + if (_glfwLibrary.X11.selection.converted == 1) { _glfwLibrary.X11.selection.converted = 0; 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 _glfwLibrary.X11.selection.converted = 0; - // Check the length of data to receive + // Check the length of data to receive (rembytes) XGetWindowProperty(_glfwLibrary.X11.display, window, *xfmt, diff --git a/src/x11_init.c b/src/x11_init.c index a824528b..1fa549bd 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -446,13 +446,20 @@ static GLboolean initDisplay(void) // the keyboard mapping. 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 - _glfwLibrary.X11.selection.stringatoms[0] = + _glfwLibrary.X11.selection.atoms.string[_GLFW_STRING_ATOM_UTF8] = 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); - _glfwLibrary.X11.selection.stringatoms[2] = XA_STRING; - _glfwLibrary.X11.selection.stringatoms[3] = 0; + _glfwLibrary.X11.selection.atoms.string[_GLFW_STRING_ATOM_STRING] = XA_STRING; return GL_TRUE; } @@ -616,6 +623,10 @@ int _glfwPlatformTerminate(void) } #endif + // Free clipboard memory + if (_glfwLibrary.X11.selection.clipboard.string) + free(_glfwLibrary.X11.selection.clipboard.string); + return GL_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 90b6e75c..6f1bf6a5 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -89,8 +89,17 @@ #define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11 #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX -// Number of string atoms that will be checked -#define _GLFW_STRING_ATOMS_COUNT 4 +// Clipboard atoms +#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 @@ -229,8 +238,15 @@ typedef struct _GLFWlibraryX11 // Selection data struct { - Atom stringatoms[_GLFW_STRING_ATOMS_COUNT]; - Atom request; + struct { + Atom clipboard[_GLFW_CLIPBOARD_ATOM_COUNT]; + Atom string[_GLFW_STRING_ATOM_COUNT]; + } atoms; + struct { + size_t stringlen; + char *string; + } clipboard; + Atom request; int converted; } selection; @@ -273,5 +289,7 @@ void _glfwTerminateJoysticks(void); // Unicode support long _glfwKeySym2Unicode(KeySym keysym); +// Clipboard handling +Atom _glfwSelectionRequest(XSelectionRequestEvent *request); #endif // _platform_h_ diff --git a/src/x11_window.c b/src/x11_window.c index ff54a11b..cfb19980 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -41,8 +41,8 @@ #define _NET_WM_STATE_TOGGLE 2 // Additional mouse button names for XButtonEvent -#define Button6 6 -#define Button7 7 +#define Button6 6 +#define Button7 7 //======================================================================== // Error handler for BadMatch errors when requesting context with @@ -1394,6 +1394,23 @@ static void processSingleEvent(void) 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? case DestroyNotify: return; From a2ffa80e82729afcca0b0929a03b21661c2d00d7 Mon Sep 17 00:00:00 2001 From: Ralph Eastwood Date: Thu, 22 Sep 2011 12:09:01 +0100 Subject: [PATCH 4/7] Some reformatting with new X11 SelectionRequest event. --- src/x11_window.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/x11_window.c b/src/x11_window.c index cfb19980..0fe4db83 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1396,7 +1396,10 @@ static void processSingleEvent(void) case SelectionRequest: { + // Selection request triggered by someone wanting data from the + // X11 clipboard XSelectionRequestEvent *request = &event.xselectionrequest; + // Construct the response XEvent response; response.xselection.property = _glfwSelectionRequest(request); @@ -1406,8 +1409,10 @@ static void processSingleEvent(void) 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; } From f332e0009d46f71ee23e91eafc50821dcc2a0acd Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood Date: Sun, 19 Feb 2012 05:39:21 +0000 Subject: [PATCH 5/7] Add mising clipboard test program. --- tests/clipboard.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 tests/clipboard.c diff --git a/tests/clipboard.c b/tests/clipboard.c new file mode 100644 index 00000000..cdbba6d2 --- /dev/null +++ b/tests/clipboard.c @@ -0,0 +1,147 @@ +//======================================================================== +// Gamma correction test program +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This program is used to test the clipboard functionality. +// +//======================================================================== + +#include + +#include +#include + +#include "getopt.h" + +static void usage(void) +{ + printf("Usage: clipboard [-h]\n"); +} + +static void key_callback(GLFWwindow window, int key, int action) +{ + static int control = GL_FALSE; + if (key == GLFW_KEY_LEFT_CONTROL) + { + control = (action == GLFW_PRESS); + return; + } + + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwCloseWindow(window); + break; + case GLFW_KEY_V: + if (control) + { + char buffer[4096]; + size_t size; + printf("Paste test.\n"); + size = glfwGetClipboardData(buffer, sizeof(buffer), GLFW_CLIPBOARD_FORMAT_STRING); + if (size >= sizeof(buffer)) + { + printf("Buffer wasn't big enough to hold clipboard data.\n"); + } + printf("[%ld]: %s\n", size, buffer); + } + break; + case GLFW_KEY_C: + if (control) + { + glfwSetClipboardData("Hello GLFW World!", sizeof("Hello GLFW World!"), + GLFW_CLIPBOARD_FORMAT_STRING); + printf("Setting clipboard to: %s\n", "Hello GLFW World!"); + } + break; + } +} + +static void size_callback(GLFWwindow window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(int argc, char** argv) +{ + int ch; + GLFWwindow window; + + while ((ch = getopt(argc, argv, "h")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW: %s\n", glfwErrorString(glfwGetError())); + exit(EXIT_FAILURE); + } + + window = glfwOpenWindow(0, 0, GLFW_WINDOWED, "Clipboard Test", NULL); + if (!window) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window: %s\n", glfwErrorString(glfwGetError())); + exit(EXIT_FAILURE); + } + + glfwSwapInterval(1); + glfwSetKeyCallback(key_callback); + glfwSetWindowSizeCallback(size_callback); + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + + glClearColor(0.5f, 0.5f, 0.5f, 0); + + while (glfwIsWindow(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8f, 0.2f, 0.4f); + glRectf(-0.5f, -0.5f, 0.5f, 0.5f); + + glfwSwapBuffers(); + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + From a3430c2dec9991cc9ed2aef2019dd7ce95f4591e Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood Date: Sun, 19 Feb 2012 05:40:11 +0000 Subject: [PATCH 6/7] No idea why this file changed... or should it be changed at all. --- src/libglfw.pc.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libglfw.pc.cmake b/src/libglfw.pc.cmake index 47cfb4f5..7538b885 100644 --- a/src/libglfw.pc.cmake +++ b/src/libglfw.pc.cmake @@ -9,4 +9,5 @@ Version: 3.0.0 URL: http://www.glfw.org/ Requires.private: gl x11 @GLFW_PKGLIBS@ Libs: -L${libdir} -lglfw +Libs.private: @GLFW_LIBRARIES@ Cflags: -I${includedir} From 8b7fc5d6013bf99af5c538dd73d24a38d835cd32 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood Date: Sun, 19 Feb 2012 06:30:45 +0000 Subject: [PATCH 7/7] Trailing whitespace. --- src/libglfw.pc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libglfw.pc.cmake b/src/libglfw.pc.cmake index 7538b885..1a712d9d 100644 --- a/src/libglfw.pc.cmake +++ b/src/libglfw.pc.cmake @@ -8,6 +8,6 @@ Description: A portable library for OpenGL, window and input Version: 3.0.0 URL: http://www.glfw.org/ Requires.private: gl x11 @GLFW_PKGLIBS@ -Libs: -L${libdir} -lglfw +Libs: -L${libdir} -lglfw Libs.private: @GLFW_LIBRARIES@ Cflags: -I${includedir}