mirror of
https://github.com/glfw/glfw.git
synced 2024-11-26 03:52:01 +00:00
Merged clipboard code into input.
This commit is contained in:
parent
66c3af7628
commit
8d170c7f47
@ -38,8 +38,6 @@ extern "C" {
|
|||||||
* Doxygen documentation
|
* Doxygen documentation
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
/*! @defgroup clipboard Clipboard support
|
|
||||||
*/
|
|
||||||
/*! @defgroup context Context handling
|
/*! @defgroup context Context handling
|
||||||
*/
|
*/
|
||||||
/*! @defgroup error Error handling
|
/*! @defgroup error Error handling
|
||||||
@ -2418,7 +2416,7 @@ GLFWAPI const char* glfwGetJoystickName(int joy);
|
|||||||
*
|
*
|
||||||
* @sa glfwGetClipboardString
|
* @sa glfwGetClipboardString
|
||||||
*
|
*
|
||||||
* @ingroup clipboard
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
||||||
|
|
||||||
@ -2442,7 +2440,7 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
|||||||
*
|
*
|
||||||
* @sa glfwSetClipboardString
|
* @sa glfwSetClipboardString
|
||||||
*
|
*
|
||||||
* @ingroup clipboard
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
|
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
|
||||||
|
|
||||||
|
@ -8,33 +8,29 @@ add_definitions(-D_GLFW_USE_CONFIG_H)
|
|||||||
set(common_HEADERS "${GLFW_BINARY_DIR}/src/glfw_config.h" internal.h
|
set(common_HEADERS "${GLFW_BINARY_DIR}/src/glfw_config.h" internal.h
|
||||||
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
|
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
|
||||||
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h")
|
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h")
|
||||||
set(common_SOURCES clipboard.c context.c init.c input.c joystick.c
|
set(common_SOURCES context.c init.c input.c joystick.c monitor.c time.c
|
||||||
monitor.c time.c window.c)
|
window.c)
|
||||||
|
|
||||||
if (_GLFW_COCOA)
|
if (_GLFW_COCOA)
|
||||||
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h iokit_joystick.h
|
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h iokit_joystick.h
|
||||||
posix_tls.h)
|
posix_tls.h)
|
||||||
set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_init.m
|
set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_monitor.m
|
||||||
cocoa_monitor.m cocoa_window.m iokit_joystick.m mach_time.c
|
cocoa_window.m iokit_joystick.m mach_time.c posix_tls.c)
|
||||||
posix_tls.c)
|
|
||||||
elseif (_GLFW_WIN32)
|
elseif (_GLFW_WIN32)
|
||||||
set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_tls.h
|
set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_tls.h
|
||||||
winmm_joystick.h)
|
winmm_joystick.h)
|
||||||
set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_init.c
|
set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_monitor.c win32_time.c
|
||||||
win32_monitor.c win32_time.c win32_tls.c win32_window.c
|
win32_tls.c win32_window.c winmm_joystick.c)
|
||||||
winmm_joystick.c)
|
|
||||||
elseif (_GLFW_X11)
|
elseif (_GLFW_X11)
|
||||||
set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h
|
set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h
|
||||||
linux_joystick.h posix_time.h posix_tls.h)
|
linux_joystick.h posix_time.h posix_tls.h)
|
||||||
set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_init.c x11_monitor.c
|
set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c
|
||||||
x11_window.c xkb_unicode.c linux_joystick.c posix_time.c
|
xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c)
|
||||||
posix_tls.c)
|
|
||||||
elseif (_GLFW_WAYLAND)
|
elseif (_GLFW_WAYLAND)
|
||||||
set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h
|
set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h
|
||||||
posix_time.h posix_tls.h xkb_unicode.h)
|
posix_time.h posix_tls.h xkb_unicode.h)
|
||||||
set(glfw_SOURCES ${common_SOURCES} wl_clipboard.c wl_init.c wl_monitor.c
|
set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c
|
||||||
wl_window.c linux_joystick.c posix_time.c posix_tls.c
|
linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c)
|
||||||
xkb_unicode.c)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (_GLFW_EGL)
|
if (_GLFW_EGL)
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.1 - www.glfw.org
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2010 Camilla Berglund <elmindreda@elmindreda.org>
|
|
||||||
//
|
|
||||||
// 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 <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW public API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
|
||||||
{
|
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
|
||||||
_GLFW_REQUIRE_INIT();
|
|
||||||
_glfwPlatformSetClipboardString(window, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
|
||||||
{
|
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
|
||||||
return _glfwPlatformGetClipboardString(window);
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.1 OS X - www.glfw.org
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2010 Camilla Berglund <elmindreda@elmindreda.org>
|
|
||||||
//
|
|
||||||
// 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 <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
|
||||||
|
|
||||||
if (![[pasteboard types] containsObject:NSStringPboardType])
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString* object = [pasteboard stringForType:NSStringPboardType];
|
|
||||||
if (!object)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Cocoa: Failed to retrieve object from pasteboard");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(_glfw.ns.clipboardString);
|
|
||||||
_glfw.ns.clipboardString = strdup([object UTF8String]);
|
|
||||||
|
|
||||||
return _glfw.ns.clipboardString;
|
|
||||||
}
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// Needed for _NSGetProgname
|
// Needed for _NSGetProgname
|
||||||
#include <crt_externs.h>
|
#include <crt_externs.h>
|
||||||
|
|
||||||
@ -1295,6 +1297,40 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||||
|
|
||||||
|
if (![[pasteboard types] containsObject:NSStringPboardType])
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* object = [pasteboard stringForType:NSStringPboardType];
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to retrieve object from pasteboard");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.ns.clipboardString);
|
||||||
|
_glfw.ns.clipboardString = strdup([object UTF8String]);
|
||||||
|
|
||||||
|
return _glfw.ns.clipboardString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
14
src/input.c
14
src/input.c
@ -497,3 +497,17 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
|
|||||||
return cbfun;
|
return cbfun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformSetClipboardString(window, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return _glfwPlatformGetClipboardString(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.1 Win32 - www.glfw.org
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2010 Camilla Berglund <elmindreda@elmindreda.org>
|
|
||||||
//
|
|
||||||
// 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 <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
|
||||||
{
|
|
||||||
WCHAR* wideString;
|
|
||||||
HANDLE stringHandle;
|
|
||||||
size_t wideSize;
|
|
||||||
|
|
||||||
wideString = _glfwCreateWideStringFromUTF8(string);
|
|
||||||
if (!wideString)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Win32: Failed to convert clipboard string to "
|
|
||||||
"wide string");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR);
|
|
||||||
|
|
||||||
stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize);
|
|
||||||
if (!stringHandle)
|
|
||||||
{
|
|
||||||
free(wideString);
|
|
||||||
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Win32: Failed to allocate global handle for clipboard");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(GlobalLock(stringHandle), wideString, wideSize);
|
|
||||||
GlobalUnlock(stringHandle);
|
|
||||||
|
|
||||||
if (!OpenClipboard(window->win32.handle))
|
|
||||||
{
|
|
||||||
GlobalFree(stringHandle);
|
|
||||||
free(wideString);
|
|
||||||
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyClipboard();
|
|
||||||
SetClipboardData(CF_UNICODETEXT, stringHandle);
|
|
||||||
CloseClipboard();
|
|
||||||
|
|
||||||
free(wideString);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
HANDLE stringHandle;
|
|
||||||
|
|
||||||
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OpenClipboard(window->win32.handle))
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringHandle = GetClipboardData(CF_UNICODETEXT);
|
|
||||||
if (!stringHandle)
|
|
||||||
{
|
|
||||||
CloseClipboard();
|
|
||||||
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Win32: Failed to retrieve clipboard data");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(_glfw.win32.clipboardString);
|
|
||||||
_glfw.win32.clipboardString =
|
|
||||||
_glfwCreateUTF8FromWideString(GlobalLock(stringHandle));
|
|
||||||
|
|
||||||
GlobalUnlock(stringHandle);
|
|
||||||
CloseClipboard();
|
|
||||||
|
|
||||||
if (!_glfw.win32.clipboardString)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Win32: Failed to convert wide string to UTF-8");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _glfw.win32.clipboardString;
|
|
||||||
}
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
@ -1372,6 +1373,95 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||||
|
{
|
||||||
|
WCHAR* wideString;
|
||||||
|
HANDLE stringHandle;
|
||||||
|
size_t wideSize;
|
||||||
|
|
||||||
|
wideString = _glfwCreateWideStringFromUTF8(string);
|
||||||
|
if (!wideString)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to convert clipboard string to "
|
||||||
|
"wide string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR);
|
||||||
|
|
||||||
|
stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize);
|
||||||
|
if (!stringHandle)
|
||||||
|
{
|
||||||
|
free(wideString);
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to allocate global handle for clipboard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(GlobalLock(stringHandle), wideString, wideSize);
|
||||||
|
GlobalUnlock(stringHandle);
|
||||||
|
|
||||||
|
if (!OpenClipboard(window->win32.handle))
|
||||||
|
{
|
||||||
|
GlobalFree(stringHandle);
|
||||||
|
free(wideString);
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyClipboard();
|
||||||
|
SetClipboardData(CF_UNICODETEXT, stringHandle);
|
||||||
|
CloseClipboard();
|
||||||
|
|
||||||
|
free(wideString);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
HANDLE stringHandle;
|
||||||
|
|
||||||
|
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!OpenClipboard(window->win32.handle))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringHandle = GetClipboardData(CF_UNICODETEXT);
|
||||||
|
if (!stringHandle)
|
||||||
|
{
|
||||||
|
CloseClipboard();
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to retrieve clipboard data");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.win32.clipboardString);
|
||||||
|
_glfw.win32.clipboardString =
|
||||||
|
_glfwCreateUTF8FromWideString(GlobalLock(stringHandle));
|
||||||
|
|
||||||
|
GlobalUnlock(stringHandle);
|
||||||
|
CloseClipboard();
|
||||||
|
|
||||||
|
if (!_glfw.win32.clipboardString)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to convert wide string to UTF-8");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfw.win32.clipboardString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.1 Wayland - www.glfw.org
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
|
||||||
//
|
|
||||||
// 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 <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -312,3 +312,16 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
fprintf(stderr, "_glfwPlatformSetCursor not implemented yet\n");
|
fprintf(stderr, "_glfwPlatformSetCursor not implemented yet\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,335 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.1 X11 - www.glfw.org
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2010 Camilla Berglund <elmindreda@elmindreda.org>
|
|
||||||
//
|
|
||||||
// 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 <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Returns whether the event is a selection event
|
|
||||||
//
|
|
||||||
static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
|
|
||||||
{
|
|
||||||
return event->type == SelectionRequest ||
|
|
||||||
event->type == SelectionNotify ||
|
|
||||||
event->type == SelectionClear;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the specified property to the selection converted to the requested target
|
|
||||||
//
|
|
||||||
static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
|
||||||
_glfw.x11.COMPOUND_STRING,
|
|
||||||
XA_STRING };
|
|
||||||
const int formatCount = sizeof(formats) / sizeof(formats[0]);
|
|
||||||
|
|
||||||
if (request->property == None)
|
|
||||||
{
|
|
||||||
// The requestor is a legacy client (ICCCM section 2.2)
|
|
||||||
// We don't support legacy clients, so fail here
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->target == _glfw.x11.TARGETS)
|
|
||||||
{
|
|
||||||
// The list of supported targets was requested
|
|
||||||
|
|
||||||
const Atom targets[] = { _glfw.x11.TARGETS,
|
|
||||||
_glfw.x11.MULTIPLE,
|
|
||||||
_glfw.x11.UTF8_STRING,
|
|
||||||
_glfw.x11.COMPOUND_STRING,
|
|
||||||
XA_STRING };
|
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
|
||||||
request->requestor,
|
|
||||||
request->property,
|
|
||||||
XA_ATOM,
|
|
||||||
32,
|
|
||||||
PropModeReplace,
|
|
||||||
(unsigned char*) targets,
|
|
||||||
sizeof(targets) / sizeof(targets[0]));
|
|
||||||
|
|
||||||
return request->property;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->target == _glfw.x11.MULTIPLE)
|
|
||||||
{
|
|
||||||
// Multiple conversions were requested
|
|
||||||
|
|
||||||
Atom* targets;
|
|
||||||
unsigned long i, count;
|
|
||||||
|
|
||||||
count = _glfwGetWindowProperty(request->requestor,
|
|
||||||
request->property,
|
|
||||||
_glfw.x11.ATOM_PAIR,
|
|
||||||
(unsigned char**) &targets);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i += 2)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; j < formatCount; j++)
|
|
||||||
{
|
|
||||||
if (targets[i] == formats[j])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j < formatCount)
|
|
||||||
{
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
|
||||||
request->requestor,
|
|
||||||
targets[i + 1],
|
|
||||||
targets[i],
|
|
||||||
8,
|
|
||||||
PropModeReplace,
|
|
||||||
(unsigned char*) _glfw.x11.clipboardString,
|
|
||||||
strlen(_glfw.x11.clipboardString));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
targets[i + 1] = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
|
||||||
request->requestor,
|
|
||||||
request->property,
|
|
||||||
_glfw.x11.ATOM_PAIR,
|
|
||||||
32,
|
|
||||||
PropModeReplace,
|
|
||||||
(unsigned char*) targets,
|
|
||||||
count);
|
|
||||||
|
|
||||||
XFree(targets);
|
|
||||||
|
|
||||||
return request->property;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->target == _glfw.x11.SAVE_TARGETS)
|
|
||||||
{
|
|
||||||
// The request is a check whether we support SAVE_TARGETS
|
|
||||||
// It should be handled as a no-op side effect target
|
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
|
||||||
request->requestor,
|
|
||||||
request->property,
|
|
||||||
_glfw.x11._NULL,
|
|
||||||
32,
|
|
||||||
PropModeReplace,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
return request->property;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conversion to a data target was requested
|
|
||||||
|
|
||||||
for (i = 0; i < formatCount; i++)
|
|
||||||
{
|
|
||||||
if (request->target == formats[i])
|
|
||||||
{
|
|
||||||
// The requested target is one we support
|
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
|
||||||
request->requestor,
|
|
||||||
request->property,
|
|
||||||
request->target,
|
|
||||||
8,
|
|
||||||
PropModeReplace,
|
|
||||||
(unsigned char*) _glfw.x11.clipboardString,
|
|
||||||
strlen(_glfw.x11.clipboardString));
|
|
||||||
|
|
||||||
return request->property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The requested target is not supported
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW internal API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void _glfwHandleSelectionClear(XEvent* event)
|
|
||||||
{
|
|
||||||
free(_glfw.x11.clipboardString);
|
|
||||||
_glfw.x11.clipboardString = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwHandleSelectionRequest(XEvent* event)
|
|
||||||
{
|
|
||||||
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
|
||||||
|
|
||||||
XEvent response;
|
|
||||||
memset(&response, 0, sizeof(response));
|
|
||||||
|
|
||||||
response.xselection.property = writeTargetToProperty(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(_glfw.x11.display, request->requestor, False, 0, &response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPushSelectionToManager(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
XConvertSelection(_glfw.x11.display,
|
|
||||||
_glfw.x11.CLIPBOARD_MANAGER,
|
|
||||||
_glfw.x11.SAVE_TARGETS,
|
|
||||||
None,
|
|
||||||
window->x11.handle,
|
|
||||||
CurrentTime);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
XEvent event;
|
|
||||||
|
|
||||||
if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (event.type)
|
|
||||||
{
|
|
||||||
case SelectionRequest:
|
|
||||||
_glfwHandleSelectionRequest(&event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SelectionClear:
|
|
||||||
_glfwHandleSelectionClear(&event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SelectionNotify:
|
|
||||||
{
|
|
||||||
if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
|
|
||||||
{
|
|
||||||
// This means one of two things; either the selection was
|
|
||||||
// not owned, which means there is no clipboard manager, or
|
|
||||||
// the transfer to the clipboard manager has completed
|
|
||||||
// In either case, it means we are done here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
|
||||||
{
|
|
||||||
free(_glfw.x11.clipboardString);
|
|
||||||
_glfw.x11.clipboardString = strdup(string);
|
|
||||||
|
|
||||||
XSetSelectionOwner(_glfw.x11.display,
|
|
||||||
_glfw.x11.CLIPBOARD,
|
|
||||||
window->x11.handle, CurrentTime);
|
|
||||||
|
|
||||||
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
|
|
||||||
window->x11.handle)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"X11: Failed to become owner of the clipboard selection");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
|
||||||
_glfw.x11.COMPOUND_STRING,
|
|
||||||
XA_STRING };
|
|
||||||
const size_t formatCount = sizeof(formats) / sizeof(formats[0]);
|
|
||||||
|
|
||||||
if (_glfwFindWindowByHandle(XGetSelectionOwner(_glfw.x11.display,
|
|
||||||
_glfw.x11.CLIPBOARD)))
|
|
||||||
{
|
|
||||||
// Instead of doing a large number of X round-trips just to put this
|
|
||||||
// string into a window property and then read it back, just return it
|
|
||||||
return _glfw.x11.clipboardString;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(_glfw.x11.clipboardString);
|
|
||||||
_glfw.x11.clipboardString = NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < formatCount; i++)
|
|
||||||
{
|
|
||||||
char* data;
|
|
||||||
XEvent event;
|
|
||||||
|
|
||||||
XConvertSelection(_glfw.x11.display,
|
|
||||||
_glfw.x11.CLIPBOARD,
|
|
||||||
formats[i],
|
|
||||||
_glfw.x11.GLFW_SELECTION,
|
|
||||||
window->x11.handle, CurrentTime);
|
|
||||||
|
|
||||||
// XCheckTypedEvent is used instead of XIfEvent in order not to lock
|
|
||||||
// other threads out from the display during the entire wait period
|
|
||||||
while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
|
|
||||||
;
|
|
||||||
|
|
||||||
if (event.xselection.property == None)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (_glfwGetWindowProperty(event.xselection.requestor,
|
|
||||||
event.xselection.property,
|
|
||||||
event.xselection.target,
|
|
||||||
(unsigned char**) &data))
|
|
||||||
{
|
|
||||||
_glfw.x11.clipboardString = strdup(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(data);
|
|
||||||
|
|
||||||
XDeleteProperty(_glfw.x11.display,
|
|
||||||
event.xselection.requestor,
|
|
||||||
event.xselection.property);
|
|
||||||
|
|
||||||
if (_glfw.x11.clipboardString)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_glfw.x11.clipboardString == NULL)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
|
||||||
"X11: Failed to convert selection to string");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _glfw.x11.clipboardString;
|
|
||||||
}
|
|
||||||
|
|
@ -228,13 +228,8 @@ typedef struct _GLFWcursorX11
|
|||||||
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
|
void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
|
||||||
|
|
||||||
void _glfwHandleSelectionClear(XEvent* event);
|
|
||||||
void _glfwHandleSelectionRequest(XEvent* event);
|
|
||||||
void _glfwPushSelectionToManager(_GLFWwindow* window);
|
|
||||||
|
|
||||||
Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
|
Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
|
||||||
|
|
||||||
_GLFWwindow* _glfwFindWindowByHandle(Window handle);
|
|
||||||
unsigned long _glfwGetWindowProperty(Window window,
|
unsigned long _glfwGetWindowProperty(Window window,
|
||||||
Atom property,
|
Atom property,
|
||||||
Atom type,
|
Atom type,
|
||||||
|
335
src/x11_window.c
335
src/x11_window.c
@ -108,6 +108,23 @@ static int translateChar(XKeyEvent* event)
|
|||||||
return (int) _glfwKeySym2Unicode(keysym);
|
return (int) _glfwKeySym2Unicode(keysym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the GLFW window corresponding to the specified X11 window
|
||||||
|
//
|
||||||
|
static _GLFWwindow* findWindowByHandle(Window handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
if (XFindContext(_glfw.x11.display,
|
||||||
|
handle,
|
||||||
|
_glfw.x11.context,
|
||||||
|
(XPointer*) &window) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds or removes an EWMH state to a window
|
// Adds or removes an EWMH state to a window
|
||||||
//
|
//
|
||||||
static void changeWindowState(_GLFWwindow* window, Atom state, int action)
|
static void changeWindowState(_GLFWwindow* window, Atom state, int action)
|
||||||
@ -459,6 +476,215 @@ static void restoreCursor(_GLFWwindow* window)
|
|||||||
XUndefineCursor(_glfw.x11.display, window->x11.handle);
|
XUndefineCursor(_glfw.x11.display, window->x11.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns whether the event is a selection event
|
||||||
|
//
|
||||||
|
static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
|
||||||
|
{
|
||||||
|
return event->type == SelectionRequest ||
|
||||||
|
event->type == SelectionNotify ||
|
||||||
|
event->type == SelectionClear;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the specified property to the selection converted to the requested target
|
||||||
|
//
|
||||||
|
static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
||||||
|
_glfw.x11.COMPOUND_STRING,
|
||||||
|
XA_STRING };
|
||||||
|
const int formatCount = sizeof(formats) / sizeof(formats[0]);
|
||||||
|
|
||||||
|
if (request->property == None)
|
||||||
|
{
|
||||||
|
// The requestor is a legacy client (ICCCM section 2.2)
|
||||||
|
// We don't support legacy clients, so fail here
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->target == _glfw.x11.TARGETS)
|
||||||
|
{
|
||||||
|
// The list of supported targets was requested
|
||||||
|
|
||||||
|
const Atom targets[] = { _glfw.x11.TARGETS,
|
||||||
|
_glfw.x11.MULTIPLE,
|
||||||
|
_glfw.x11.UTF8_STRING,
|
||||||
|
_glfw.x11.COMPOUND_STRING,
|
||||||
|
XA_STRING };
|
||||||
|
|
||||||
|
XChangeProperty(_glfw.x11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->property,
|
||||||
|
XA_ATOM,
|
||||||
|
32,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*) targets,
|
||||||
|
sizeof(targets) / sizeof(targets[0]));
|
||||||
|
|
||||||
|
return request->property;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->target == _glfw.x11.MULTIPLE)
|
||||||
|
{
|
||||||
|
// Multiple conversions were requested
|
||||||
|
|
||||||
|
Atom* targets;
|
||||||
|
unsigned long i, count;
|
||||||
|
|
||||||
|
count = _glfwGetWindowProperty(request->requestor,
|
||||||
|
request->property,
|
||||||
|
_glfw.x11.ATOM_PAIR,
|
||||||
|
(unsigned char**) &targets);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i += 2)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < formatCount; j++)
|
||||||
|
{
|
||||||
|
if (targets[i] == formats[j])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j < formatCount)
|
||||||
|
{
|
||||||
|
XChangeProperty(_glfw.x11.display,
|
||||||
|
request->requestor,
|
||||||
|
targets[i + 1],
|
||||||
|
targets[i],
|
||||||
|
8,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*) _glfw.x11.clipboardString,
|
||||||
|
strlen(_glfw.x11.clipboardString));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
targets[i + 1] = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
XChangeProperty(_glfw.x11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->property,
|
||||||
|
_glfw.x11.ATOM_PAIR,
|
||||||
|
32,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*) targets,
|
||||||
|
count);
|
||||||
|
|
||||||
|
XFree(targets);
|
||||||
|
|
||||||
|
return request->property;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->target == _glfw.x11.SAVE_TARGETS)
|
||||||
|
{
|
||||||
|
// The request is a check whether we support SAVE_TARGETS
|
||||||
|
// It should be handled as a no-op side effect target
|
||||||
|
|
||||||
|
XChangeProperty(_glfw.x11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->property,
|
||||||
|
_glfw.x11._NULL,
|
||||||
|
32,
|
||||||
|
PropModeReplace,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
return request->property;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion to a data target was requested
|
||||||
|
|
||||||
|
for (i = 0; i < formatCount; i++)
|
||||||
|
{
|
||||||
|
if (request->target == formats[i])
|
||||||
|
{
|
||||||
|
// The requested target is one we support
|
||||||
|
|
||||||
|
XChangeProperty(_glfw.x11.display,
|
||||||
|
request->requestor,
|
||||||
|
request->property,
|
||||||
|
request->target,
|
||||||
|
8,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*) _glfw.x11.clipboardString,
|
||||||
|
strlen(_glfw.x11.clipboardString));
|
||||||
|
|
||||||
|
return request->property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The requested target is not supported
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleSelectionClear(XEvent* event)
|
||||||
|
{
|
||||||
|
free(_glfw.x11.clipboardString);
|
||||||
|
_glfw.x11.clipboardString = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleSelectionRequest(XEvent* event)
|
||||||
|
{
|
||||||
|
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
||||||
|
|
||||||
|
XEvent response;
|
||||||
|
memset(&response, 0, sizeof(response));
|
||||||
|
|
||||||
|
response.xselection.property = writeTargetToProperty(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(_glfw.x11.display, request->requestor, False, 0, &response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pushSelectionToManager(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
XConvertSelection(_glfw.x11.display,
|
||||||
|
_glfw.x11.CLIPBOARD_MANAGER,
|
||||||
|
_glfw.x11.SAVE_TARGETS,
|
||||||
|
None,
|
||||||
|
window->x11.handle,
|
||||||
|
CurrentTime);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
XEvent event;
|
||||||
|
|
||||||
|
if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case SelectionRequest:
|
||||||
|
handleSelectionRequest(&event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectionClear:
|
||||||
|
handleSelectionClear(&event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectionNotify:
|
||||||
|
{
|
||||||
|
if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
|
||||||
|
{
|
||||||
|
// This means one of two things; either the selection was
|
||||||
|
// not owned, which means there is no clipboard manager, or
|
||||||
|
// the transfer to the clipboard manager has completed
|
||||||
|
// In either case, it means we are done here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enter fullscreen mode
|
// Enter fullscreen mode
|
||||||
//
|
//
|
||||||
static void enterFullscreenMode(_GLFWwindow* window)
|
static void enterFullscreenMode(_GLFWwindow* window)
|
||||||
@ -590,7 +816,7 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
if (event->type != GenericEvent)
|
if (event->type != GenericEvent)
|
||||||
{
|
{
|
||||||
window = _glfwFindWindowByHandle(event->xany.window);
|
window = findWindowByHandle(event->xany.window);
|
||||||
if (window == NULL)
|
if (window == NULL)
|
||||||
{
|
{
|
||||||
// This is an event for a window that has already been destroyed
|
// This is an event for a window that has already been destroyed
|
||||||
@ -1000,13 +1226,13 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
case SelectionClear:
|
case SelectionClear:
|
||||||
{
|
{
|
||||||
_glfwHandleSelectionClear(event);
|
handleSelectionClear(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectionRequest:
|
case SelectionRequest:
|
||||||
{
|
{
|
||||||
_glfwHandleSelectionRequest(event);
|
handleSelectionRequest(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1022,7 +1248,7 @@ static void processEvent(XEvent *event)
|
|||||||
{
|
{
|
||||||
XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data;
|
XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data;
|
||||||
|
|
||||||
window = _glfwFindWindowByHandle(data->event);
|
window = findWindowByHandle(data->event);
|
||||||
if (window)
|
if (window)
|
||||||
{
|
{
|
||||||
if (data->event_x != window->x11.warpPosX ||
|
if (data->event_x != window->x11.warpPosX ||
|
||||||
@ -1080,23 +1306,6 @@ static void processEvent(XEvent *event)
|
|||||||
////// GLFW internal API //////
|
////// GLFW internal API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Return the GLFW window corresponding to the specified X11 window
|
|
||||||
//
|
|
||||||
_GLFWwindow* _glfwFindWindowByHandle(Window handle)
|
|
||||||
{
|
|
||||||
_GLFWwindow* window;
|
|
||||||
|
|
||||||
if (XFindContext(_glfw.x11.display,
|
|
||||||
handle,
|
|
||||||
_glfw.x11.context,
|
|
||||||
(XPointer*) &window) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a single window property of the specified type
|
// Retrieve a single window property of the specified type
|
||||||
// Inspired by fghGetWindowProperty from freeglut
|
// Inspired by fghGetWindowProperty from freeglut
|
||||||
//
|
//
|
||||||
@ -1165,7 +1374,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
if (window->x11.handle ==
|
if (window->x11.handle ==
|
||||||
XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD))
|
XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD))
|
||||||
{
|
{
|
||||||
_glfwPushSelectionToManager(window);
|
pushSelectionToManager(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context);
|
XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context);
|
||||||
@ -1484,6 +1693,88 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||||
|
{
|
||||||
|
free(_glfw.x11.clipboardString);
|
||||||
|
_glfw.x11.clipboardString = strdup(string);
|
||||||
|
|
||||||
|
XSetSelectionOwner(_glfw.x11.display,
|
||||||
|
_glfw.x11.CLIPBOARD,
|
||||||
|
window->x11.handle, CurrentTime);
|
||||||
|
|
||||||
|
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
|
||||||
|
window->x11.handle)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Failed to become owner of the clipboard selection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
||||||
|
_glfw.x11.COMPOUND_STRING,
|
||||||
|
XA_STRING };
|
||||||
|
const size_t formatCount = sizeof(formats) / sizeof(formats[0]);
|
||||||
|
|
||||||
|
if (findWindowByHandle(XGetSelectionOwner(_glfw.x11.display,
|
||||||
|
_glfw.x11.CLIPBOARD)))
|
||||||
|
{
|
||||||
|
// Instead of doing a large number of X round-trips just to put this
|
||||||
|
// string into a window property and then read it back, just return it
|
||||||
|
return _glfw.x11.clipboardString;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.x11.clipboardString);
|
||||||
|
_glfw.x11.clipboardString = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < formatCount; i++)
|
||||||
|
{
|
||||||
|
char* data;
|
||||||
|
XEvent event;
|
||||||
|
|
||||||
|
XConvertSelection(_glfw.x11.display,
|
||||||
|
_glfw.x11.CLIPBOARD,
|
||||||
|
formats[i],
|
||||||
|
_glfw.x11.GLFW_SELECTION,
|
||||||
|
window->x11.handle, CurrentTime);
|
||||||
|
|
||||||
|
// XCheckTypedEvent is used instead of XIfEvent in order not to lock
|
||||||
|
// other threads out from the display during the entire wait period
|
||||||
|
while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
|
||||||
|
;
|
||||||
|
|
||||||
|
if (event.xselection.property == None)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_glfwGetWindowProperty(event.xselection.requestor,
|
||||||
|
event.xselection.property,
|
||||||
|
event.xselection.target,
|
||||||
|
(unsigned char**) &data))
|
||||||
|
{
|
||||||
|
_glfw.x11.clipboardString = strdup(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(data);
|
||||||
|
|
||||||
|
XDeleteProperty(_glfw.x11.display,
|
||||||
|
event.xselection.requestor,
|
||||||
|
event.xselection.property);
|
||||||
|
|
||||||
|
if (_glfw.x11.clipboardString)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.x11.clipboardString == NULL)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"X11: Failed to convert selection to string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfw.x11.clipboardString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
Loading…
Reference in New Issue
Block a user