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); +} +