diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h
index 7807edbc..32c3899a 100644
--- a/include/GL/glfw3.h
+++ b/include/GL/glfw3.h
@@ -173,6 +173,10 @@ extern "C" {
#endif
#endif
+/* This is needed for the declaration of size_t.
+ */
+#include
+
/*************************************************************************
* GLFW version
@@ -461,6 +465,7 @@ extern "C" {
#define GLFW_VERSION_UNAVAILABLE 0x00070007
#define GLFW_PLATFORM_ERROR 0x00070008
#define GLFW_WINDOW_NOT_ACTIVE 0x00070009
+#define GLFW_FORMAT_UNAVAILABLE 0x0007000A
/* Gamma ramps */
#define GLFW_GAMMA_RAMP_SIZE 256
@@ -574,6 +579,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 glfwSetClipboardString(GLFWwindow window, const char* string);
+GLFWAPI size_t glfwGetClipboardString(GLFWwindow window, char* string, size_t size);
+
/* Time */
GLFWAPI double glfwGetTime(void);
GLFWAPI void glfwSetTime(double time);
diff --git a/readme.html b/readme.html
index a4ee2c5d..790e5ac7 100644
--- a/readme.html
+++ b/readme.html
@@ -277,6 +277,7 @@ version of GLFW.
Added glfwGetWindowPos
function for querying the position of the specified window
Added glfwSetWindowFocusCallback
function and GLFWwindowfocusfun
type for receiving window focus events
Added glfwSetWindowIconifyCallback
function and GLFWwindowiconifyfun
type for receiving window iconification events
+ Added glfwGetClipboardString
and glfwSetClipboardString
functions for interacting with the system clipboard
Added glfwGetCurrentContext
function for retrieving the window whose OpenGL context is current
Added glfwCopyContext
function for copying OpenGL state categories between contexts
Added GLFW_OPENGL_ES2_PROFILE
profile for creating OpenGL ES 2.0 contexts using the GLX_EXT_create_context_es2_profile
and WGL_EXT_create_context_es2_profile
extensions
@@ -850,7 +851,7 @@ their skills. Special thanks go out to:
adding logic for the GLFW_ICON
resource
Ralph Eastwood, for the initial design and implementation of the gamma
- correction API
+ correction and clipboard APIs
GeO4d, for the implementation of cursor enter/leave notifications on
Win32.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 01ff500c..add05982 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,29 +4,27 @@ include_directories(${GLFW_SOURCE_DIR}/src
${glfw_INCLUDE_DIRS})
set(common_HEADERS ${GLFW_SOURCE_DIR}/include/GL/glfw3.h internal.h)
-set(common_SOURCES error.c fullscreen.c gamma.c init.c input.c
+set(common_SOURCES clipboard.c error.c fullscreen.c gamma.c init.c input.c
joystick.c opengl.c time.c window.c)
if (_GLFW_COCOA_NSGL)
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h)
- set(glfw_SOURCES ${common_SOURCES} cocoa_fullscreen.m cocoa_gamma.c
- cocoa_init.m cocoa_input.m cocoa_joystick.m
+ set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_fullscreen.m
+ cocoa_gamma.c cocoa_init.m cocoa_input.m cocoa_joystick.m
cocoa_opengl.m cocoa_time.c cocoa_window.m)
# For some reason, CMake doesn't know about .m
set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C)
elseif (_GLFW_WIN32_WGL)
set(glfw_HEADERS ${common_HEADERS} win32_platform.h)
- set(glfw_SOURCES ${common_SOURCES} win32_fullscreen.c win32_gamma.c
- win32_init.c win32_input.c win32_joystick.c
- win32_opengl.c win32_time.c win32_window.c
- win32_dllmain.c)
+ set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_fullscreen.c
+ win32_gamma.c win32_init.c win32_input.c win32_joystick.c
+ win32_opengl.c win32_time.c win32_window.c win32_dllmain.c)
elseif (_GLFW_X11_GLX)
set(glfw_HEADERS ${common_HEADERS} x11_platform.h)
- set(glfw_SOURCES ${common_SOURCES} x11_fullscreen.c x11_gamma.c
- x11_init.c x11_input.c x11_joystick.c
- x11_keysym2unicode.c x11_opengl.c x11_time.c
- x11_window.c)
+ set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_fullscreen.c
+ x11_gamma.c x11_init.c x11_input.c x11_joystick.c
+ x11_keysym2unicode.c x11_opengl.c x11_time.c x11_window.c)
endif()
add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS})
diff --git a/src/clipboard.c b/src/clipboard.c
new file mode 100644
index 00000000..b66d5656
--- /dev/null
+++ b/src/clipboard.c
@@ -0,0 +1,77 @@
+//========================================================================
+// 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 glfwSetClipboardString(GLFWwindow handle, const char* string)
+{
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+
+ if (!_glfwInitialized)
+ {
+ _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+ return;
+ }
+
+ _glfwPlatformSetClipboardString(window, string);
+}
+
+
+//========================================================================
+// Return the current clipboard contents
+//========================================================================
+
+GLFWAPI size_t glfwGetClipboardString(GLFWwindow handle, char* string, size_t size)
+{
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+
+ if (!_glfwInitialized)
+ {
+ _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
+ return 0;
+ }
+
+ if (!string || !size)
+ return 0;
+
+ return _glfwPlatformGetClipboardString(window, string, size);
+}
+
diff --git a/src/cocoa_clipboard.m b/src/cocoa_clipboard.m
new file mode 100644
index 00000000..e52b839e
--- /dev/null
+++ b/src/cocoa_clipboard.m
@@ -0,0 +1,87 @@
+//========================================================================
+// 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 _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
+{
+ NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
+
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
+ [pasteboard declareTypes:types owner:nil];
+ [pasteboard setString:[NSString stringWithUTF8String:string]
+ forType:NSStringPboardType];
+}
+
+
+//========================================================================
+// Return the current clipboard contents
+//========================================================================
+
+size_t _glfwPlatformGetClipboardString(_GLFWwindow* window, char* string, size_t size)
+{
+ const char* source;
+ size_t targetSize;
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
+
+ if (![[pasteboard types] containsObject:NSStringPboardType])
+ {
+ _glfwSetError(GLFW_FORMAT_UNAVAILABLE, NULL);
+ return 0;
+ }
+
+ NSString* object = [pasteboard stringForType:NSStringPboardType];
+ if (!object)
+ {
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Cocoa/NSGL: Failed to retrieve object from pasteboard");
+ return 0;
+ }
+
+ source = [object UTF8String];
+ targetSize = strlen(source) + 1;
+ if (targetSize > size)
+ targetSize = size;
+
+ strlcpy(string, source, targetSize);
+ return 0;
+}
+
diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m
index b3bd6e41..97510fdf 100644
--- a/src/cocoa_joystick.m
+++ b/src/cocoa_joystick.m
@@ -572,7 +572,7 @@ int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes)
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numbuttons)
{
- int button;
+ int i, j, button;
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
return 0;
@@ -599,13 +599,13 @@ int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; // Bit fields of button presses for each direction, including nil
- for (int i = 0; i < joystick.numHats; i++)
+ for (i = 0; i < joystick.numHats; i++)
{
_glfwJoystickElement* hat = (_glfwJoystickElement*) CFArrayGetValueAtIndex(joystick.hats, i);
int value = hat->value;
if (value < 0 || value > 8) value = 8;
- for (int j = 0; j < 4 && button < numbuttons; j++)
+ for (j = 0; j < 4 && button < numbuttons; j++)
{
buttons[button++] = directions[value] & (1 << j) ? GLFW_PRESS : GLFW_RELEASE;
}
diff --git a/src/error.c b/src/error.c
index 2b46a72c..062fb76a 100644
--- a/src/error.c
+++ b/src/error.c
@@ -109,6 +109,8 @@ GLFWAPI const char* glfwErrorString(int error)
return "A platform-specific error occurred";
case GLFW_WINDOW_NOT_ACTIVE:
return "The specified window is not active";
+ case GLFW_FORMAT_UNAVAILABLE:
+ return "The requested format is unavailable";
}
return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString";
diff --git a/src/internal.h b/src/internal.h
index 9bfc3f5d..407270ea 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -288,6 +288,10 @@ void _glfwPlatformGetDesktopMode(GLFWvidmode* mode);
void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp);
void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp);
+// Clipboard
+void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string);
+size_t _glfwPlatformGetClipboardString(_GLFWwindow* window, char *data, size_t size);
+
// 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..9b14f158
--- /dev/null
+++ b/src/win32_clipboard.c
@@ -0,0 +1,149 @@
+//========================================================================
+// 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
+#include
+
+
+//////////////////////////////////////////////////////////////////////////
+////// GLFW platform API //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Set the clipboard contents
+//========================================================================
+
+void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
+{
+ WCHAR* wideString;
+ HANDLE stringHandle;
+ size_t wideSize;
+
+ wideString = _glfwCreateWideStringFromUTF8(string);
+ if (!wideString)
+ {
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to convert clipboard string to "
+ "wide string");
+ return;
+ }
+
+ wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR);
+
+ stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize);
+ if (!stringHandle)
+ {
+ free(wideString);
+
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to allocate global handle for clipboard");
+ return;
+ }
+
+ memcpy(GlobalLock(stringHandle), wideString, wideSize);
+ GlobalUnlock(stringHandle);
+
+ if (!OpenClipboard(window->Win32.handle))
+ {
+ GlobalFree(stringHandle);
+ free(wideString);
+
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to open clipboard");
+ return;
+ }
+
+ EmptyClipboard();
+ SetClipboardData(CF_UNICODETEXT, stringHandle);
+ CloseClipboard();
+
+ free(wideString);
+}
+
+
+//========================================================================
+// Return the current clipboard contents
+//========================================================================
+
+size_t _glfwPlatformGetClipboardString(_GLFWwindow* window, char* string, size_t size)
+{
+ HANDLE stringHandle;
+ char* utf8String;
+ size_t utf8Size;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
+ {
+ _glfwSetError(GLFW_FORMAT_UNAVAILABLE, NULL);
+ return 0;
+ }
+
+ if (!OpenClipboard(window->Win32.handle))
+ {
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to open clipboard");
+ return 0;
+ }
+
+ stringHandle = GetClipboardData(CF_UNICODETEXT);
+ if (!stringHandle)
+ {
+ CloseClipboard();
+
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to retrieve clipboard data");
+ return 0;
+ }
+
+ utf8String = _glfwCreateUTF8FromWideString(GlobalLock(stringHandle));
+ GlobalUnlock(stringHandle);
+ CloseClipboard();
+
+ if (!utf8String)
+ {
+ _glfwSetError(GLFW_PLATFORM_ERROR,
+ "Win32/WGL: Failed to convert wide string to UTF-8");
+ return 0;
+ }
+
+ utf8Size = strlen(utf8String) + 1;
+ if (utf8Size > size)
+ {
+ memcpy(string, utf8String, size);
+ string[size - 1] = '\0';
+ }
+ else
+ memcpy(string, utf8String, utf8Size);
+
+ free(utf8String);
+ return utf8Size;
+}
+
diff --git a/src/x11_clipboard.c b/src/x11_clipboard.c
new file mode 100644
index 00000000..1b9e1fa3
--- /dev/null
+++ b/src/x11_clipboard.c
@@ -0,0 +1,201 @@
+//========================================================================
+// 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
+#include
+#include
+
+
+//////////////////////////////////////////////////////////////////////////
+////// GLFW internal API //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Save the contents of the specified property
+//========================================================================
+
+GLboolean _glfwReadSelection(XSelectionEvent* request)
+{
+ Atom actualType;
+ int actualFormat;
+ unsigned long itemCount, bytesAfter;
+ char* data;
+
+ if (request->property == None)
+ return GL_FALSE;
+
+ XGetWindowProperty(_glfwLibrary.X11.display,
+ request->requestor,
+ request->property,
+ 0, LONG_MAX,
+ False,
+ request->target,
+ &actualType,
+ &actualFormat,
+ &itemCount,
+ &bytesAfter,
+ (unsigned char**) &data);
+
+ if (actualType == None)
+ return GL_FALSE;
+
+ free(_glfwLibrary.X11.selection.string);
+ _glfwLibrary.X11.selection.string = strdup(data);
+
+ XFree(data);
+ return GL_TRUE;
+}
+
+
+//========================================================================
+// Set the specified property to the contents of the requested selection
+//========================================================================
+
+Atom _glfwWriteSelection(XSelectionRequestEvent* request)
+{
+ int i;
+ Atom property = request->property;
+
+ if (property == None)
+ property = _glfwLibrary.X11.selection.property;
+
+ if (request->target == _glfwLibrary.X11.selection.targets)
+ {
+ // The list of supported targets was requested
+
+ XChangeProperty(_glfwLibrary.X11.display,
+ request->requestor,
+ property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*) _glfwLibrary.X11.selection.formats,
+ _GLFW_CLIPBOARD_FORMAT_COUNT);
+
+ return property;
+ }
+
+ for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
+ {
+ if (request->target == _glfwLibrary.X11.selection.formats[i])
+ {
+ // The requested format is one we support
+
+ XChangeProperty(_glfwLibrary.X11.display,
+ request->requestor,
+ property,
+ request->target,
+ 8,
+ PropModeReplace,
+ (unsigned char*) _glfwLibrary.X11.selection.string,
+ strlen(_glfwLibrary.X11.selection.string));
+
+ return property;
+ }
+ }
+
+ return None;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+////// GLFW platform API //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Set the clipboard contents
+//========================================================================
+
+void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
+{
+ // Store the new string in preparation for a selection request event
+ free(_glfwLibrary.X11.selection.string);
+ _glfwLibrary.X11.selection.string = strdup(string);
+
+ // Set the specified window as owner of the selection
+ XSetSelectionOwner(_glfwLibrary.X11.display,
+ _glfwLibrary.X11.selection.atom,
+ window->X11.handle, CurrentTime);
+}
+
+
+//========================================================================
+// Return the current clipboard contents
+//========================================================================
+
+size_t _glfwPlatformGetClipboardString(_GLFWwindow* window, char* string, size_t size)
+{
+ int i;
+ size_t sourceSize, targetSize;
+
+ _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_INACTIVE;
+
+ for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
+ {
+ // Request conversion to the selected format
+ _glfwLibrary.X11.selection.target =
+ _glfwLibrary.X11.selection.formats[i];
+
+ XConvertSelection(_glfwLibrary.X11.display,
+ _glfwLibrary.X11.selection.atom,
+ _glfwLibrary.X11.selection.target,
+ _glfwLibrary.X11.selection.property,
+ window->X11.handle, CurrentTime);
+
+ // Process the resulting SelectionNotify event
+ XSync(_glfwLibrary.X11.display, False);
+ while (_glfwLibrary.X11.selection.status == _GLFW_CONVERSION_INACTIVE)
+ _glfwPlatformWaitEvents();
+
+ if (_glfwLibrary.X11.selection.status == _GLFW_CONVERSION_SUCCEEDED)
+ break;
+ }
+
+ if (_glfwLibrary.X11.selection.status == _GLFW_CONVERSION_FAILED)
+ {
+ _glfwSetError(GLFW_FORMAT_UNAVAILABLE,
+ "X11/GLX: Failed to convert selection to string");
+ return 0;
+ }
+
+ sourceSize = strlen(_glfwLibrary.X11.selection.string) + 1;
+
+ targetSize = sourceSize;
+ if (targetSize > size)
+ targetSize = size;
+
+ memcpy(string, _glfwLibrary.X11.selection.string, targetSize);
+ string[targetSize - 1] = '\0';
+
+ return sourceSize;
+}
+
diff --git a/src/x11_init.c b/src/x11_init.c
index 48e48a2c..3af08cf4 100644
--- a/src/x11_init.c
+++ b/src/x11_init.c
@@ -597,6 +597,26 @@ static GLboolean initDisplay(void)
// the keyboard mapping.
updateKeyCodeLUT();
+ // Find or create selection property atom
+ _glfwLibrary.X11.selection.property =
+ XInternAtom(_glfwLibrary.X11.display, "GLFW_SELECTION", False);
+
+ // Find or create clipboard atom
+ _glfwLibrary.X11.selection.atom =
+ XInternAtom(_glfwLibrary.X11.display, "CLIPBOARD", False);
+
+ // Find or create selection target atoms
+ _glfwLibrary.X11.selection.formats[_GLFW_CLIPBOARD_FORMAT_UTF8] =
+ XInternAtom(_glfwLibrary.X11.display, "UTF8_STRING", False);
+ _glfwLibrary.X11.selection.formats[_GLFW_CLIPBOARD_FORMAT_COMPOUND] =
+ XInternAtom(_glfwLibrary.X11.display, "COMPOUND_STRING", False);
+ _glfwLibrary.X11.selection.formats[_GLFW_CLIPBOARD_FORMAT_STRING] =
+ XA_STRING;
+
+ _glfwLibrary.X11.selection.targets = XInternAtom(_glfwLibrary.X11.display,
+ "TARGETS",
+ False);
+
return GL_TRUE;
}
@@ -762,6 +782,10 @@ int _glfwPlatformTerminate(void)
}
#endif
+ // Free clipboard memory
+ if (_glfwLibrary.X11.selection.string)
+ free(_glfwLibrary.X11.selection.string);
+
return GL_TRUE;
}
diff --git a/src/x11_platform.h b/src/x11_platform.h
index b3869bc4..2de3367e 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -85,6 +85,17 @@
#define _GLFW_PLATFORM_LIBRARY_STATE _GLFWlibraryX11 X11
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX GLX
+// Clipboard format atom indices
+#define _GLFW_CLIPBOARD_FORMAT_UTF8 0
+#define _GLFW_CLIPBOARD_FORMAT_COMPOUND 1
+#define _GLFW_CLIPBOARD_FORMAT_STRING 2
+#define _GLFW_CLIPBOARD_FORMAT_COUNT 3
+
+// Clipboard conversion status tokens
+#define _GLFW_CONVERSION_INACTIVE 0
+#define _GLFW_CONVERSION_SUCCEEDED 1
+#define _GLFW_CONVERSION_FAILED 2
+
//========================================================================
// GLFW platform specific types
@@ -226,6 +237,17 @@ typedef struct _GLFWlibraryX11
uint64_t base;
} timer;
+ // Selection data
+ struct {
+ Atom atom;
+ Atom formats[_GLFW_CLIPBOARD_FORMAT_COUNT];
+ char* string;
+ Atom target;
+ Atom targets;
+ Atom property;
+ int status;
+ } selection;
+
#if defined(_GLFW_DLOPEN_LIBGL)
void* libGL; // dlopen handle for libGL.so
#endif
@@ -265,5 +287,11 @@ void _glfwTerminateJoysticks(void);
// Unicode support
long _glfwKeySym2Unicode(KeySym keysym);
+// Clipboard handling
+GLboolean _glfwReadSelection(XSelectionEvent* request);
+Atom _glfwWriteSelection(XSelectionRequestEvent* request);
+
+// Event processing
+void _glfwProcessPendingEvents(void);
#endif // _platform_h_
diff --git a/src/x11_window.c b/src/x11_window.c
index 980fa305..a84e209a 100644
--- a/src/x11_window.c
+++ b/src/x11_window.c
@@ -40,8 +40,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
@@ -1241,6 +1241,52 @@ static void processSingleEvent(void)
break;
}
+ case SelectionClear:
+ {
+ // The ownership of the selection was lost
+
+ free(_glfwLibrary.X11.selection.string);
+ _glfwLibrary.X11.selection.string = NULL;
+ break;
+ }
+
+ case SelectionNotify:
+ {
+ // The selection conversion status is available
+
+ XSelectionEvent* request = &event.xselection;
+
+ if (_glfwReadSelection(request))
+ _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_SUCCEEDED;
+ else
+ _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_FAILED;
+
+ break;
+ }
+
+ case SelectionRequest:
+ {
+ // The contents of the selection was requested
+
+ XSelectionRequestEvent* request = &event.xselectionrequest;
+
+ XEvent response;
+ memset(&response, 0, sizeof(response));
+
+ response.xselection.property = _glfwWriteSelection(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;
+
+ XSendEvent(_glfwLibrary.X11.display,
+ request->requestor,
+ False, 0, &response);
+ break;
+ }
+
// Was the window destroyed?
case DestroyNotify:
return;
@@ -1264,6 +1310,23 @@ static void processSingleEvent(void)
}
+//////////////////////////////////////////////////////////////////////////
+////// GLFW internal API //////
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// Processes all pending events
+//========================================================================
+
+void _glfwProcessPendingEvents(void)
+{
+ int i, count = XPending(_glfwLibrary.X11.display);
+
+ for (i = 0; i < count; i++)
+ processSingleEvent();
+}
+
+
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
@@ -1334,7 +1397,7 @@ int _glfwPlatformOpenWindow(_GLFWwindow* window,
}
// Process the window map event and any other that may have arrived
- _glfwPlatformPollEvents();
+ _glfwProcessPendingEvents();
// Retrieve and set initial cursor position
{
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d016fb0e..daa17a31 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -11,6 +11,8 @@ endif()
include_directories(${GLFW_SOURCE_DIR}/include
${GLFW_SOURCE_DIR}/support
${OPENGL_INCLUDE_DIR})
+add_executable(clipboard clipboard.c)
+target_link_libraries(clipboard ${STATIC_DEPS})
add_executable(defaults defaults.c)
add_executable(events events.c)
diff --git a/tests/clipboard.c b/tests/clipboard.c
new file mode 100644
index 00000000..da776e61
--- /dev/null
+++ b/tests/clipboard.c
@@ -0,0 +1,156 @@
+//========================================================================
+// 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 GLboolean control_is_down(GLFWwindow window)
+{
+ return glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) ||
+ glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL);
+}
+
+static void key_callback(GLFWwindow window, int key, int action)
+{
+ if (action != GLFW_PRESS)
+ return;
+
+ switch (key)
+ {
+ case GLFW_KEY_ESCAPE:
+ glfwCloseWindow(window);
+ break;
+
+ case GLFW_KEY_V:
+ if (control_is_down(window))
+ {
+ char buffer[4096];
+ size_t size;
+
+ printf("Paste test.\n");
+
+ size = glfwGetClipboardString(window, buffer, sizeof(buffer));
+ if (size >= sizeof(buffer))
+ printf("Buffer wasn't big enough to hold clipboard data.\n");
+
+ printf("[%lu]: %s\n", (unsigned long) size, buffer);
+ }
+ break;
+
+ case GLFW_KEY_C:
+ if (control_is_down(window))
+ {
+ const char* string = "Hello GLFW World!";
+ glfwSetClipboardString(window, string);
+ printf("Setting clipboard to: %s\n", string);
+ }
+ break;
+ }
+}
+
+static void size_callback(GLFWwindow window, int width, int height)
+{
+ glViewport(0, 0, width, height);
+}
+
+static void error_callback(int error, const char* description)
+{
+ fprintf(stderr, "Error: %s in %s\n", glfwErrorString(error), description);
+}
+
+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);
+ }
+ }
+
+ glfwSetErrorCallback(error_callback);
+
+ 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);
+}
+