Add clipboard support for X11.
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5890 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
c8beeaff83
commit
0f46539a45
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
This file is part of Warzone 2100.
|
||||
Copyright (C) 2008 Freddie Witherden
|
||||
Copyright (C) 2008 Warzone Resurrection Project
|
||||
|
||||
Warzone 2100 is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Warzone 2100 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// Something wicked this way comes...
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <SDL_syswm.h>
|
||||
#include <SDL.h>
|
||||
|
||||
static SDL_SysWMinfo info;
|
||||
static Atom clipboardAtom;
|
||||
static Atom compoundTextAtom;
|
||||
static Atom utf8StringAtom;
|
||||
static Atom targetsAtom;
|
||||
|
||||
/**
|
||||
* Filters through SDL_Events searching for clipboard requests from the X
|
||||
* server.
|
||||
*
|
||||
* @param evt The event to filter.
|
||||
*/
|
||||
static int widgetClipboardFilterX11(const SDL_Event *evt)
|
||||
{
|
||||
// We are only interested in window manager events
|
||||
if (evt->type == SDL_SYSWMEVENT)
|
||||
{
|
||||
XEvent xevent = evt->syswm.msg->event.xevent;
|
||||
|
||||
// See if the event is a selection/clipboard request
|
||||
if (xevent.type == SelectionRequest)
|
||||
{
|
||||
// Get the request in question
|
||||
XSelectionRequestEvent *request = &xevent.xselectionrequest;
|
||||
|
||||
// Generate a reply to the selection request
|
||||
XSelectionEvent reply;
|
||||
|
||||
reply.type = SelectionNotify;
|
||||
reply.serial = xevent.xany.send_event;
|
||||
reply.send_event = True;
|
||||
reply.display = info.info.x11.display;
|
||||
reply.requestor = request->requestor;
|
||||
reply.selection = request->selection;
|
||||
reply.property = request->property;
|
||||
reply.target = None;
|
||||
reply.time = request->time;
|
||||
|
||||
printf("It is: %s\n", XGetAtomName(info.info.x11.display, request->target));
|
||||
|
||||
// They want to know what we can provide/offer
|
||||
if (request->target == targetsAtom)
|
||||
{
|
||||
Atom possibleTargets[] =
|
||||
{
|
||||
XA_STRING,
|
||||
utf8StringAtom,
|
||||
compoundTextAtom
|
||||
};
|
||||
|
||||
XChangeProperty(info.info.x11.display, request->requestor,
|
||||
request->property, XA_ATOM, 32, PropModeReplace,
|
||||
(unsigned char *) possibleTargets, 3);
|
||||
}
|
||||
// They want a string (all we can provide)
|
||||
else if (request->target == XA_STRING
|
||||
|| request->target == utf8StringAtom
|
||||
|| request->target == compoundTextAtom)
|
||||
{
|
||||
int len;
|
||||
char *xdata = XFetchBytes(info.info.x11.display, &len);
|
||||
|
||||
XChangeProperty(info.info.x11.display, request->requestor,
|
||||
request->property, request->target, 8,
|
||||
PropModeReplace, (unsigned char *) xdata,
|
||||
len);
|
||||
XFree(xdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did not have what they wanted, so no property set
|
||||
reply.property = None;
|
||||
}
|
||||
|
||||
// Dispatch the event
|
||||
XSendEvent(request->display, request->requestor, 0, NoEventMask,
|
||||
(XEvent *) &reply);
|
||||
XSync(info.info.x11.display, False);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void widgetInitialiseClipboardX11()
|
||||
{
|
||||
static bool initialised = false;
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
// Make sure we have not already been initialised
|
||||
assert(initialised == false);
|
||||
|
||||
// Get the window manager information
|
||||
SDL_GetWMInfo(&info);
|
||||
|
||||
// Ensure we're running under X11
|
||||
assert(info.subsystem == SDL_SYSWM_X11);
|
||||
|
||||
// Register the event filter
|
||||
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
|
||||
SDL_SetEventFilter(widgetClipboardFilterX11);
|
||||
|
||||
// Lock the connection to the X server
|
||||
info.info.x11.lock_func();
|
||||
|
||||
// Get the clipboard atom (it is not defined by default)
|
||||
clipboardAtom = XInternAtom(info.info.x11.display, "CLIPBOARD", True);
|
||||
|
||||
// Get the compound text type atom
|
||||
compoundTextAtom = XInternAtom(info.info.x11.display, "COMPOUND_TEXT",
|
||||
True);
|
||||
|
||||
// UTF-8 string atom
|
||||
utf8StringAtom = XInternAtom(info.info.x11.display, "UTF8_STRING",
|
||||
True);
|
||||
|
||||
// TARGETS atom
|
||||
targetsAtom = XInternAtom(info.info.x11.display, "TARGETS", True);
|
||||
|
||||
// Unlock the connection
|
||||
info.info.x11.unlock_func();
|
||||
|
||||
// We are initialised
|
||||
initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
char *widgetGetClipboardText()
|
||||
{
|
||||
char *text = NULL;
|
||||
unsigned char *data = NULL;
|
||||
Atom type;
|
||||
int format, result;
|
||||
unsigned long len, bytesLeft, dummy;
|
||||
Window selectionOwner;
|
||||
|
||||
// Make sure we are initialised
|
||||
widgetInitialiseClipboardX11();
|
||||
|
||||
// Lock the connection
|
||||
info.info.x11.lock_func();
|
||||
|
||||
// Get the owner of the clipboard selection
|
||||
selectionOwner = XGetSelectionOwner(info.info.x11.display, clipboardAtom);
|
||||
|
||||
// If there is a selection (and therefore owner) fetch it
|
||||
if (selectionOwner != None)
|
||||
{
|
||||
// Convert the selection to a string
|
||||
XConvertSelection(info.info.x11.display, clipboardAtom, XA_STRING, None,
|
||||
selectionOwner, CurrentTime);
|
||||
XFlush(info.info.x11.display);
|
||||
|
||||
// See how much data is there
|
||||
XGetWindowProperty(info.info.x11.display, selectionOwner, XA_STRING, 0,
|
||||
0, False, AnyPropertyType, &type, &format, &len,
|
||||
&bytesLeft, &data);
|
||||
|
||||
// If any 0-length data was returned, free it
|
||||
if (data)
|
||||
{
|
||||
XFree(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
// If there is any data
|
||||
if (bytesLeft)
|
||||
{
|
||||
result = XGetWindowProperty(info.info.x11.display, selectionOwner,
|
||||
XA_STRING, 0, bytesLeft, False,
|
||||
AnyPropertyType, &type, &format, &len,
|
||||
&dummy, &data);
|
||||
|
||||
// If we got some data, duplicate it
|
||||
if (result == Success)
|
||||
{
|
||||
text = strdup((char *) data);
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the property now that we are finished with it
|
||||
XDeleteProperty(info.info.x11.display, selectionOwner, XA_STRING);
|
||||
}
|
||||
|
||||
// Unlock the connection
|
||||
info.info.x11.unlock_func();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool widgetSetClipboardText(const char *text)
|
||||
{
|
||||
Window selectionOwner;
|
||||
|
||||
// Make sure we are initialised
|
||||
widgetInitialiseClipboardX11();
|
||||
|
||||
// Lock the connection
|
||||
info.info.x11.lock_func();
|
||||
|
||||
// Copy the text into the root windows cut buffer (for Xterm compatibility)
|
||||
XStoreBytes(info.info.x11.display, text, strlen(text) + 1);
|
||||
|
||||
// Set ourself as the owner of the CLIPBOARD atom
|
||||
XSetSelectionOwner(info.info.x11.display, clipboardAtom,
|
||||
info.info.x11.window, CurrentTime);
|
||||
|
||||
// Check if we acquired ownership or not
|
||||
selectionOwner = XGetSelectionOwner(info.info.x11.display, clipboardAtom);
|
||||
|
||||
// We got ownership
|
||||
if (selectionOwner == info.info.x11.window)
|
||||
{
|
||||
info.info.x11.unlock_func();
|
||||
return true;
|
||||
}
|
||||
// We did not get ownership
|
||||
else
|
||||
{
|
||||
info.info.x11.unlock_func();
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue