summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xlib/qxlibclipboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xlib/qxlibclipboard.cpp')
-rw-r--r--src/plugins/platforms/xlib/qxlibclipboard.cpp676
1 files changed, 0 insertions, 676 deletions
diff --git a/src/plugins/platforms/xlib/qxlibclipboard.cpp b/src/plugins/platforms/xlib/qxlibclipboard.cpp
deleted file mode 100644
index 69a0f20777..0000000000
--- a/src/plugins/platforms/xlib/qxlibclipboard.cpp
+++ /dev/null
@@ -1,676 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qguiapplication_p.h>
-
-#include "qxlibclipboard.h"
-
-#include "qxlibscreen.h"
-#include "qxlibmime.h"
-#include "qxlibdisplay.h"
-
-#include <QtCore/QDebug>
-
-class QXlibClipboardMime : public QXlibMime
-{
- Q_OBJECT
-public:
- QXlibClipboardMime(QClipboard::Mode mode, QXlibClipboard *clipboard)
- : QXlibMime()
- , m_clipboard(clipboard)
- {
- switch (mode) {
- case QClipboard::Selection:
- modeAtom = XA_PRIMARY;
- break;
-
- case QClipboard::Clipboard:
- modeAtom = QXlibStatic::atom(QXlibStatic::CLIPBOARD);
- break;
-
- default:
- qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode");
- break;
- }
- }
-
-protected:
- QStringList formats_sys() const
- {
- if (empty())
- return QStringList();
-
- if (!formatList.count()) {
- QXlibClipboardMime *that = const_cast<QXlibClipboardMime *>(this);
- // get the list of targets from the current clipboard owner - we do this
- // once so that multiple calls to this function don't require multiple
- // server round trips...
- that->format_atoms = m_clipboard->getDataInFormat(modeAtom,QXlibStatic::atom(QXlibStatic::TARGETS));
-
- if (format_atoms.size() > 0) {
- Atom *targets = (Atom *) format_atoms.data();
- int size = format_atoms.size() / sizeof(Atom);
-
- for (int i = 0; i < size; ++i) {
- if (targets[i] == 0)
- continue;
-
- QStringList formatsForAtom = mimeFormatsForAtom(m_clipboard->screen()->display()->nativeDisplay(),targets[i]);
- for (int j = 0; j < formatsForAtom.size(); ++j) {
- if (!formatList.contains(formatsForAtom.at(j)))
- that->formatList.append(formatsForAtom.at(j));
- }
- }
- }
- }
-
- return formatList;
- }
-
- bool hasFormat_sys(const QString &format) const
- {
- QStringList list = formats();
- return list.contains(format);
- }
-
- QVariant retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const
- {
- if (fmt.isEmpty() || empty())
- return QByteArray();
-
- (void)formats(); // trigger update of format list
-
- QList<Atom> atoms;
- Atom *targets = (Atom *) format_atoms.data();
- int size = format_atoms.size() / sizeof(Atom);
- for (int i = 0; i < size; ++i)
- atoms.append(targets[i]);
-
- QByteArray encoding;
- Atom fmtatom = mimeAtomForFormat(m_clipboard->screen()->display()->nativeDisplay(),fmt, requestedType, atoms, &encoding);
-
- if (fmtatom == 0)
- return QVariant();
-
- return mimeConvertToFormat(m_clipboard->screen()->display()->nativeDisplay(),fmtatom, m_clipboard->getDataInFormat(modeAtom,fmtatom), fmt, requestedType, encoding);
- }
-private:
- bool empty() const
- {
- Window win = XGetSelectionOwner(m_clipboard->screen()->display()->nativeDisplay(), modeAtom);
-
- return win == XNone;
- }
-
-
- Atom modeAtom;
- QXlibClipboard *m_clipboard;
- QStringList formatList;
- QByteArray format_atoms;
-};
-
-const int QXlibClipboard::clipboard_timeout = 5000;
-
-QXlibClipboard::QXlibClipboard(QXlibScreen *screen)
- : QPlatformClipboard()
- , m_screen(screen)
- , m_xClipboard(0)
- , m_clientClipboard(0)
- , m_xSelection(0)
- , m_clientSelection(0)
- , m_requestor(XNone)
- , m_owner(XNone)
-{
-}
-
-QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode)
-{
- if (mode == QClipboard::Clipboard) {
- if (!m_xClipboard) {
- m_xClipboard = new QXlibClipboardMime(mode, this);
- }
- Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),QXlibStatic::atom(QXlibStatic::CLIPBOARD));
- if (clipboardOwner == owner()) {
- return m_clientClipboard;
- } else {
- return m_xClipboard;
- }
- } else if (mode == QClipboard::Selection) {
- if (!m_xSelection) {
- m_xSelection = new QXlibClipboardMime(mode, this);
- }
- Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),XA_PRIMARY);
- if (clipboardOwner == owner()) {
- return m_clientSelection;
- } else {
- return m_xSelection;
- }
- }
- return 0;
-}
-
-void QXlibClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
-{
- Atom modeAtom;
- QMimeData **d;
- switch (mode) {
- case QClipboard::Selection:
- modeAtom = XA_PRIMARY;
- d = &m_clientSelection;
- break;
-
- case QClipboard::Clipboard:
- modeAtom = QXlibStatic::atom(QXlibStatic::CLIPBOARD);
- d = &m_clientClipboard;
- break;
-
- default:
- qWarning("QClipboard::setMimeData: unsupported mode '%d'", mode);
- return;
- }
-
- Window newOwner;
-
- if (! data) { // no data, clear clipboard contents
- newOwner = XNone;
- } else {
- newOwner = owner();
-
- *d = data;
- }
-
- XSetSelectionOwner(m_screen->display()->nativeDisplay(), modeAtom, newOwner, CurrentTime);
-
- if (XGetSelectionOwner(m_screen->display()->nativeDisplay(), modeAtom) != newOwner) {
- qWarning("QClipboard::setData: Cannot set X11 selection owner");
- }
-
- emitChanged(mode);
-}
-
-bool QXlibClipboard::supportsMode(QClipboard::Mode mode) const
-{
- if (mode == QClipboard::Clipboard || mode == QClipboard::Selection)
- return true;
- return false;
-}
-
-
-QXlibScreen * QXlibClipboard::screen() const
-{
- return m_screen;
-}
-
-Window QXlibClipboard::requestor() const
-{
- if (!m_requestor) {
- int x = 0, y = 0, w = 3, h = 3;
- QXlibClipboard *that = const_cast<QXlibClipboard *>(this);
- Window window = XCreateSimpleWindow(m_screen->display()->nativeDisplay(), m_screen->rootWindow(),
- x, y, w, h, 0 /*border_width*/,
- m_screen->blackPixel(), m_screen->whitePixel());
- that->setRequestor(window);
- }
- return m_requestor;
-}
-
-void QXlibClipboard::setRequestor(Window window)
-{
- if (m_requestor != XNone) {
- XDestroyWindow(m_screen->display()->nativeDisplay(),m_requestor);
- }
- m_requestor = window;
-}
-
-Window QXlibClipboard::owner() const
-{
- if (!m_owner) {
- int x = 0, y = 0, w = 3, h = 3;
- QXlibClipboard *that = const_cast<QXlibClipboard *>(this);
- Window window = XCreateSimpleWindow(m_screen->display()->nativeDisplay(), m_screen->rootWindow(),
- x, y, w, h, 0 /*border_width*/,
- m_screen->blackPixel(), m_screen->whitePixel());
- that->setOwner(window);
- }
- return m_owner;
-}
-
-void QXlibClipboard::setOwner(Window window)
-{
- if (m_owner != XNone){
- XDestroyWindow(m_screen->display()->nativeDisplay(),m_owner);
- }
- m_owner = window;
-}
-
-Atom QXlibClipboard::sendTargetsSelection(QMimeData *d, Window window, Atom property)
-{
- QVector<Atom> types;
- QStringList formats = QInternalMimeData::formatsHelper(d);
- for (int i = 0; i < formats.size(); ++i) {
- QList<Atom> atoms = QXlibMime::mimeAtomsForFormat(screen()->display()->nativeDisplay(),formats.at(i));
- for (int j = 0; j < atoms.size(); ++j) {
- if (!types.contains(atoms.at(j)))
- types.append(atoms.at(j));
- }
- }
- types.append(QXlibStatic::atom(QXlibStatic::TARGETS));
- types.append(QXlibStatic::atom(QXlibStatic::MULTIPLE));
- types.append(QXlibStatic::atom(QXlibStatic::TIMESTAMP));
- types.append(QXlibStatic::atom(QXlibStatic::SAVE_TARGETS));
-
- XChangeProperty(screen()->display()->nativeDisplay(), window, property, XA_ATOM, 32,
- PropModeReplace, (uchar *) types.data(), types.size());
- return property;
-}
-
-Atom QXlibClipboard::sendSelection(QMimeData *d, Atom target, Window window, Atom property)
-{
- Atom atomFormat = target;
- int dataFormat = 0;
- QByteArray data;
-
- QString fmt = QXlibMime::mimeAtomToString(screen()->display()->nativeDisplay(), target);
- if (fmt.isEmpty()) { // Not a MIME type we have
- qDebug() << "QClipboard: send_selection(): converting to type '%s' is not supported" << fmt.data();
- return XNone;
- }
- qDebug() << "QClipboard: send_selection(): converting to type '%s'" << fmt.data();
-
- if (QXlibMime::mimeDataForAtom(screen()->display()->nativeDisplay(),target, d, &data, &atomFormat, &dataFormat)) {
-
- // don't allow INCR transfers when using MULTIPLE or to
- // Motif clients (since Motif doesn't support INCR)
- static Atom motif_clip_temporary = QXlibStatic::atom(QXlibStatic::CLIP_TEMPORARY);
- bool allow_incr = property != motif_clip_temporary;
-
- // X_ChangeProperty protocol request is 24 bytes
- const int increment = (XMaxRequestSize(screen()->display()->nativeDisplay()) * 4) - 24;
- if (data.size() > increment && allow_incr) {
- long bytes = data.size();
- XChangeProperty(screen()->display()->nativeDisplay(), window, property,
- QXlibStatic::atom(QXlibStatic::INCR), 32, PropModeReplace, (uchar *) &bytes, 1);
-
-// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
- qDebug() << "not implemented INCRT just YET!";
- return property;
- }
-
- // make sure we can perform the XChangeProperty in a single request
- if (data.size() > increment)
- return XNone; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
- int dataSize = data.size() / (dataFormat / 8);
- // use a single request to transfer data
- XChangeProperty(screen()->display()->nativeDisplay(), window, property, atomFormat,
- dataFormat, PropModeReplace, (uchar *) data.data(),
- dataSize);
- }
- return property;
-}
-
-void QXlibClipboard::handleSelectionRequest(XEvent *xevent)
-{
- XSelectionRequestEvent *req = &xevent->xselectionrequest;
-
- if (requestor() && req->requestor == requestor()) {
- qDebug() << "This should be caught before";
- return;
- }
-
- XEvent event;
- event.xselection.type = SelectionNotify;
- event.xselection.display = req->display;
- event.xselection.requestor = req->requestor;
- event.xselection.selection = req->selection;
- event.xselection.target = req->target;
- event.xselection.property = XNone;
- event.xselection.time = req->time;
-
- QMimeData *d;
- if (req->selection == XA_PRIMARY) {
- d = m_clientSelection;
- } else if (req->selection == QXlibStatic::atom(QXlibStatic::CLIPBOARD)) {
- d = m_clientClipboard;
- } else {
- qWarning("QClipboard: Unknown selection '%lx'", req->selection);
- XSendEvent(screen()->display()->nativeDisplay(), req->requestor, False, NoEventMask, &event);
- return;
- }
-
- if (!d) {
- qWarning("QClipboard: Cannot transfer data, no data available");
- XSendEvent(screen()->display()->nativeDisplay(), req->requestor, False, NoEventMask, &event);
- return;
- }
-
- Atom xa_targets = QXlibStatic::atom(QXlibStatic::TARGETS);
- Atom xa_multiple = QXlibStatic::atom(QXlibStatic::MULTIPLE);
- Atom xa_timestamp = QXlibStatic::atom(QXlibStatic::TIMESTAMP);
-
- struct AtomPair { Atom target; Atom property; } *multi = 0;
- Atom multi_type = XNone;
- int multi_format = 0;
- int nmulti = 0;
- int imulti = -1;
- bool multi_writeback = false;
-
- if (req->target == xa_multiple) {
- QByteArray multi_data;
- if (req->property == XNone
- || !clipboardReadProperty(req->requestor, req->property, false, &multi_data,
- 0, &multi_type, &multi_format)
- || multi_format != 32) {
- // MULTIPLE property not formatted correctly
- XSendEvent(screen()->display()->nativeDisplay(), req->requestor, False, NoEventMask, &event);
- return;
- }
- nmulti = multi_data.size()/sizeof(*multi);
- multi = new AtomPair[nmulti];
- memcpy(multi,multi_data.data(),multi_data.size());
- imulti = 0;
- }
-
- for (; imulti < nmulti; ++imulti) {
- Atom target;
- Atom property;
-
- if (multi) {
- target = multi[imulti].target;
- property = multi[imulti].property;
- } else {
- target = req->target;
- property = req->property;
- if (property == XNone) // obsolete client
- property = target;
- }
-
- Atom ret = XNone;
- if (target == XNone || property == XNone) {
- ;
- } else if (target == xa_timestamp) {
-// if (d->timestamp != CurrentTime) {
-// XChangeProperty(screen()->display()->nativeDisplay(), req->requestor, property, XA_INTEGER, 32,
-// PropModeReplace, CurrentTime, 1);
-// ret = property;
-// } else {
-// qWarning("QClipboard: Invalid data timestamp");
-// }
- } else if (target == xa_targets) {
- ret = sendTargetsSelection(d, req->requestor, property);
- } else {
- ret = sendSelection(d, target, req->requestor, property);
- }
-
- if (nmulti > 0) {
- if (ret == XNone) {
- multi[imulti].property = XNone;
- multi_writeback = true;
- }
- } else {
- event.xselection.property = ret;
- break;
- }
- }
-
- if (nmulti > 0) {
- if (multi_writeback) {
- // according to ICCCM 2.6.2 says to put None back
- // into the original property on the requestor window
- XChangeProperty(screen()->display()->nativeDisplay(), req->requestor, req->property, multi_type, 32,
- PropModeReplace, (uchar *) multi, nmulti * 2);
- }
-
- delete [] multi;
- event.xselection.property = req->property;
- }
-
- // send selection notify to requestor
- XSendEvent(screen()->display()->nativeDisplay(), req->requestor, False, NoEventMask, &event);
-}
-
-static inline int maxSelectionIncr(Display *dpy)
-{ return XMaxRequestSize(dpy) > 65536 ? 65536*4 : XMaxRequestSize(dpy)*4 - 100; }
-
-bool QXlibClipboard::clipboardReadProperty(Window win, Atom property, bool deleteProperty, QByteArray *buffer, int *size, Atom *type, int *format) const
-{
- int maxsize = maxSelectionIncr(screen()->display()->nativeDisplay());
- ulong bytes_left; // bytes_after
- ulong length; // nitems
- uchar *data;
- Atom dummy_type;
- int dummy_format;
- int r;
-
- if (!type) // allow null args
- type = &dummy_type;
- if (!format)
- format = &dummy_format;
-
- // Don't read anything, just get the size of the property data
- r = XGetWindowProperty(screen()->display()->nativeDisplay(), win, property, 0, 0, False,
- AnyPropertyType, type, format,
- &length, &bytes_left, &data);
- if (r != Success || (type && *type == XNone)) {
- buffer->resize(0);
- return false;
- }
- XFree((char*)data);
-
- int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
-
- switch (*format) {
- case 8:
- default:
- format_inc = sizeof(char) / 1;
- break;
-
- case 16:
- format_inc = sizeof(short) / 2;
- proplen *= sizeof(short) / 2;
- break;
-
- case 32:
- format_inc = sizeof(long) / 4;
- proplen *= sizeof(long) / 4;
- break;
- }
-
- int newSize = proplen;
- buffer->resize(newSize);
-
- bool ok = (buffer->size() == newSize);
-
- if (ok && newSize) {
- // could allocate buffer
-
- while (bytes_left) {
- // more to read...
-
- r = XGetWindowProperty(screen()->display()->nativeDisplay(), win, property, offset, maxsize/4,
- False, AnyPropertyType, type, format,
- &length, &bytes_left, &data);
- if (r != Success || (type && *type == XNone))
- break;
-
- offset += length / (32 / *format);
- length *= format_inc * (*format) / 8;
-
- // Here we check if we get a buffer overflow and tries to
- // recover -- this shouldn't normally happen, but it doesn't
- // hurt to be defensive
- if ((int)(buffer_offset + length) > buffer->size()) {
- length = buffer->size() - buffer_offset;
-
- // escape loop
- bytes_left = 0;
- }
-
- memcpy(buffer->data() + buffer_offset, data, length);
- buffer_offset += length;
-
- XFree((char*)data);
- }
-
- if (*format == 8 && *type == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) {
- // convert COMPOUND_TEXT to a multibyte string
- XTextProperty textprop;
- textprop.encoding = *type;
- textprop.format = *format;
- textprop.nitems = buffer_offset;
- textprop.value = (unsigned char *) buffer->data();
-
- char **list_ret = 0;
- int count;
- if (XmbTextPropertyToTextList(screen()->display()->nativeDisplay(), &textprop, &list_ret,
- &count) == Success && count && list_ret) {
- offset = buffer_offset = strlen(list_ret[0]);
- buffer->resize(offset);
- memcpy(buffer->data(), list_ret[0], offset);
- }
- if (list_ret) XFreeStringList(list_ret);
- }
- }
-
- // correct size, not 0-term.
- if (size)
- *size = buffer_offset;
-
- if (deleteProperty)
- XDeleteProperty(screen()->display()->nativeDisplay(), win, property);
-
- screen()->display()->flush();
-
- return ok;
-}
-
-QByteArray QXlibClipboard::clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm)
-{
- XEvent event;
-
- QByteArray buf;
- QByteArray tmp_buf;
- bool alloc_error = false;
- int length;
- int offset = 0;
-
- if (nbytes > 0) {
- // Reserve buffer + zero-terminator (for text data)
- // We want to complete the INCR transfer even if we cannot
- // allocate more memory
- buf.resize(nbytes+1);
- alloc_error = buf.size() != nbytes+1;
- }
-
- for (;;) {
- screen()->display()->flush();
- if (!screen()->waitForClipboardEvent(win,PropertyNotify,&event,clipboard_timeout))
- break;
- if (event.xproperty.atom != property ||
- event.xproperty.state != PropertyNewValue)
- continue;
- if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
- if (length == 0) { // no more data, we're done
- if (nullterm) {
- buf.resize(offset+1);
- buf[offset] = '\0';
- } else {
- buf.resize(offset);
- }
- return buf;
- } else if (!alloc_error) {
- if (offset+length > (int)buf.size()) {
- buf.resize(offset+length+65535);
- if (buf.size() != offset+length+65535) {
- alloc_error = true;
- length = buf.size() - offset;
- }
- }
- memcpy(buf.data()+offset, tmp_buf.constData(), length);
- tmp_buf.resize(0);
- offset += length;
- }
- } else {
- break;
- }
- }
-
- // timed out ... create a new requestor window, otherwise the requestor
- // could consider next request to be still part of this timed out request
- setRequestor(0);
-
- return QByteArray();
-}
-
-QByteArray QXlibClipboard::getDataInFormat(Atom modeAtom, Atom fmtatom)
-{
- QByteArray buf;
-
- Window win = requestor();
-
- XSelectInput(screen()->display()->nativeDisplay(), win, NoEventMask); // don't listen for any events
-
- XDeleteProperty(screen()->display()->nativeDisplay(), win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION));
- XConvertSelection(screen()->display()->nativeDisplay(), modeAtom, fmtatom, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), win, CurrentTime);
- screen()->display()->sync();
-
- XEvent xevent;
- if (!screen()->waitForClipboardEvent(win,SelectionNotify,&xevent,clipboard_timeout) ||
- xevent.xselection.property == XNone) {
- return buf;
- }
-
- Atom type;
- XSelectInput(screen()->display()->nativeDisplay(), win, PropertyChangeMask);
-
- if (clipboardReadProperty(win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), true, &buf, 0, &type, 0)) {
- if (type == QXlibStatic::atom(QXlibStatic::INCR)) {
- int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
- buf = clipboardReadIncrementalProperty(win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), nbytes, false);
- }
- }
-
- XSelectInput(screen()->display()->nativeDisplay(), win, NoEventMask);
-
-
- return buf;
-}
-
-#include "qxlibclipboard.moc"