2011-09-21 09:09:47 +00:00
|
|
|
//========================================================================
|
|
|
|
// GLFW - An OpenGL library
|
2012-08-28 13:03:57 +00:00
|
|
|
// Platform: X11
|
2011-09-21 09:09:47 +00:00
|
|
|
// API version: 3.0
|
|
|
|
// WWW: http://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"
|
|
|
|
|
2011-09-21 14:43:28 +00:00
|
|
|
#include <stdio.h>
|
2011-09-21 09:09:47 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
2011-09-21 14:43:28 +00:00
|
|
|
#include <stdlib.h>
|
2011-09-21 09:09:47 +00:00
|
|
|
|
|
|
|
|
2012-03-28 13:05:17 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
////// GLFW internal API //////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2012-04-11 21:32:50 +00:00
|
|
|
// Set the specified property to the contents of the requested selection
|
2013-02-04 12:22:10 +00:00
|
|
|
//
|
2012-04-11 21:32:50 +00:00
|
|
|
Atom _glfwWriteSelection(XSelectionRequestEvent* request)
|
|
|
|
{
|
|
|
|
int i;
|
2013-04-29 10:43:54 +00:00
|
|
|
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
|
|
|
_glfw.x11.COMPOUND_STRING,
|
|
|
|
XA_STRING };
|
|
|
|
const int formatCount = sizeof(formats) / sizeof(formats[0]);
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
if (request->property == None)
|
|
|
|
{
|
|
|
|
// The requestor is a legacy client (ICCCM section 2.2)
|
|
|
|
return None;
|
|
|
|
}
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-29 01:45:08 +00:00
|
|
|
if (request->target == _glfw.x11.TARGETS)
|
2011-09-22 11:03:45 +00:00
|
|
|
{
|
2012-04-11 21:32:50 +00:00
|
|
|
// The list of supported targets was requested
|
|
|
|
|
2013-04-29 10:43:54 +00:00
|
|
|
const Atom targets[] = { _glfw.x11.TARGETS,
|
|
|
|
_glfw.x11.MULTIPLE,
|
|
|
|
_glfw.x11.UTF8_STRING,
|
|
|
|
_glfw.x11.COMPOUND_STRING,
|
|
|
|
XA_STRING };
|
|
|
|
|
2013-01-02 00:40:42 +00:00
|
|
|
XChangeProperty(_glfw.x11.display,
|
2012-04-09 13:12:59 +00:00
|
|
|
request->requestor,
|
2013-01-30 23:26:37 +00:00
|
|
|
request->property,
|
2012-04-11 21:32:50 +00:00
|
|
|
XA_ATOM,
|
|
|
|
32,
|
2012-04-09 13:12:59 +00:00
|
|
|
PropModeReplace,
|
2013-04-29 10:43:54 +00:00
|
|
|
(unsigned char*) targets,
|
|
|
|
sizeof(targets) / sizeof(targets[0]));
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
return request->property;
|
2011-09-22 11:03:45 +00:00
|
|
|
}
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-04-29 10:26:25 +00:00
|
|
|
if (request->target == _glfw.x11.MULTIPLE)
|
|
|
|
{
|
|
|
|
// Multiple conversions were requested
|
|
|
|
|
|
|
|
Atom* targets;
|
|
|
|
unsigned long i, count;
|
|
|
|
|
|
|
|
count = _glfwGetWindowProperty(request->requestor,
|
|
|
|
request->property,
|
|
|
|
XA_ATOM,
|
|
|
|
(unsigned char**) &targets);
|
|
|
|
|
|
|
|
for (i = 0; i < count; i += 2)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
|
2013-04-29 10:43:54 +00:00
|
|
|
for (j = 0; j < formatCount; j++)
|
2013-04-29 10:26:25 +00:00
|
|
|
{
|
2013-04-29 10:43:54 +00:00
|
|
|
if (targets[i] == formats[j])
|
2013-04-29 10:26:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-04-29 10:43:54 +00:00
|
|
|
if (j < formatCount)
|
2013-04-29 10:26:25 +00:00
|
|
|
{
|
|
|
|
XChangeProperty(_glfw.x11.display,
|
|
|
|
request->requestor,
|
|
|
|
targets[i + 1],
|
|
|
|
targets[i],
|
|
|
|
8,
|
|
|
|
PropModeReplace,
|
|
|
|
(unsigned char*) _glfw.x11.selection.string,
|
|
|
|
strlen(_glfw.x11.selection.string));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
targets[i + 1] = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
XChangeProperty(_glfw.x11.display,
|
|
|
|
request->requestor,
|
|
|
|
request->property,
|
|
|
|
request->target,
|
|
|
|
32,
|
|
|
|
PropModeReplace,
|
|
|
|
(unsigned char*) targets,
|
|
|
|
count);
|
|
|
|
|
|
|
|
XFree(targets);
|
|
|
|
|
|
|
|
return request->property;
|
|
|
|
}
|
|
|
|
|
2013-04-29 10:43:54 +00:00
|
|
|
for (i = 0; i < formatCount; i++)
|
2011-09-22 11:03:45 +00:00
|
|
|
{
|
2013-04-29 10:43:54 +00:00
|
|
|
if (request->target == formats[i])
|
2012-04-11 21:32:50 +00:00
|
|
|
{
|
2012-04-11 21:53:47 +00:00
|
|
|
// The requested target is one we support
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-02 00:40:42 +00:00
|
|
|
XChangeProperty(_glfw.x11.display,
|
2012-04-11 21:32:50 +00:00
|
|
|
request->requestor,
|
2013-01-30 23:26:37 +00:00
|
|
|
request->property,
|
2012-04-11 21:32:50 +00:00
|
|
|
request->target,
|
|
|
|
8,
|
|
|
|
PropModeReplace,
|
2013-01-02 00:40:42 +00:00
|
|
|
(unsigned char*) _glfw.x11.selection.string,
|
|
|
|
strlen(_glfw.x11.selection.string));
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
return request->property;
|
2012-04-11 21:32:50 +00:00
|
|
|
}
|
2011-09-22 11:03:45 +00:00
|
|
|
}
|
2012-03-28 13:05:17 +00:00
|
|
|
|
2012-04-11 21:32:50 +00:00
|
|
|
return None;
|
2011-09-22 11:03:45 +00:00
|
|
|
}
|
|
|
|
|
2012-03-28 13:05:17 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
////// GLFW platform API //////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2012-04-09 14:00:54 +00:00
|
|
|
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
2011-09-21 09:09:47 +00:00
|
|
|
{
|
2013-01-02 00:40:42 +00:00
|
|
|
free(_glfw.x11.selection.string);
|
|
|
|
_glfw.x11.selection.string = strdup(string);
|
2011-09-22 11:03:45 +00:00
|
|
|
|
2013-01-02 00:40:42 +00:00
|
|
|
XSetSelectionOwner(_glfw.x11.display,
|
2013-01-29 01:45:08 +00:00
|
|
|
_glfw.x11.CLIPBOARD,
|
2013-01-02 00:40:42 +00:00
|
|
|
window->x11.handle, CurrentTime);
|
2013-01-30 23:26:37 +00:00
|
|
|
|
|
|
|
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
|
|
|
|
window->x11.handle)
|
|
|
|
{
|
|
|
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
|
"X11: Failed to become owner of the clipboard selection");
|
|
|
|
}
|
2011-09-21 09:09:47 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 22:51:58 +00:00
|
|
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
2011-09-21 09:09:47 +00:00
|
|
|
{
|
2012-04-11 21:32:50 +00:00
|
|
|
int i;
|
2013-04-29 10:43:54 +00:00
|
|
|
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
|
|
|
_glfw.x11.COMPOUND_STRING,
|
|
|
|
XA_STRING };
|
2012-04-11 21:32:50 +00:00
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
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.selection.string;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(_glfw.x11.selection.string);
|
|
|
|
_glfw.x11.selection.string = NULL;
|
2011-09-22 11:03:45 +00:00
|
|
|
|
2013-04-29 10:43:54 +00:00
|
|
|
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++)
|
2011-09-21 14:43:28 +00:00
|
|
|
{
|
2013-01-30 23:26:37 +00:00
|
|
|
char* data;
|
|
|
|
XEvent event;
|
2011-09-22 11:03:45 +00:00
|
|
|
|
2013-01-02 00:40:42 +00:00
|
|
|
XConvertSelection(_glfw.x11.display,
|
2013-01-29 01:45:08 +00:00
|
|
|
_glfw.x11.CLIPBOARD,
|
2013-04-29 10:43:54 +00:00
|
|
|
formats[i],
|
2013-01-02 00:40:42 +00:00
|
|
|
_glfw.x11.selection.property,
|
|
|
|
window->x11.handle, CurrentTime);
|
2011-09-22 11:03:45 +00:00
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
// 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;
|
|
|
|
|
2013-04-29 10:33:27 +00:00
|
|
|
if (_glfwGetWindowProperty(event.xselection.requestor,
|
|
|
|
event.xselection.property,
|
|
|
|
event.xselection.target,
|
|
|
|
(unsigned char**) &data))
|
|
|
|
{
|
|
|
|
_glfw.x11.selection.string = strdup(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFree(data);
|
2013-01-30 23:26:37 +00:00
|
|
|
|
|
|
|
XDeleteProperty(_glfw.x11.display,
|
|
|
|
event.xselection.requestor,
|
|
|
|
event.xselection.property);
|
|
|
|
|
|
|
|
if (_glfw.x11.selection.string)
|
2011-09-21 14:43:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-30 23:26:37 +00:00
|
|
|
if (_glfw.x11.selection.string == NULL)
|
2011-09-22 11:03:45 +00:00
|
|
|
{
|
2012-12-31 20:05:28 +00:00
|
|
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
|
|
|
"X11: Failed to convert selection to string");
|
2011-09-22 11:03:45 +00:00
|
|
|
}
|
|
|
|
|
2013-01-02 00:40:42 +00:00
|
|
|
return _glfw.x11.selection.string;
|
2011-09-21 09:09:47 +00:00
|
|
|
}
|
|
|
|
|