Add clipboard support for X11.

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5890 4a71c877-e1ca-e34f-864e-861f7616d084
master
Freddie Witherden 2008-08-29 18:42:54 +00:00
parent c8beeaff83
commit 0f46539a45
1 changed files with 253 additions and 0 deletions

View File

@ -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;
}
}