summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qdnd_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qdnd_x11.cpp')
-rw-r--r--src/gui/kernel/qdnd_x11.cpp2072
1 files changed, 0 insertions, 2072 deletions
diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp
deleted file mode 100644
index 9ff1543e51..0000000000
--- a/src/gui/kernel/qdnd_x11.cpp
+++ /dev/null
@@ -1,2072 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, 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.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qplatformdefs.h"
-
-#include "qapplication.h"
-
-#ifndef QT_NO_DRAGANDDROP
-
-#include "qwidget.h"
-#include "qpainter.h"
-#include "qpixmap.h"
-#include "qbitmap.h"
-#include "qdesktopwidget.h"
-#include "qevent.h"
-#include "qiodevice.h"
-#include "qpointer.h"
-#include "qcursor.h"
-#include "qelapsedtimer.h"
-#include "qvariant.h"
-#include "qvector.h"
-#include "qurl.h"
-#include "qdebug.h"
-#include "qimagewriter.h"
-#include "qbuffer.h"
-#include "qtextcodec.h"
-
-#include "qdnd_p.h"
-#include "qapplication_p.h"
-#include "qt_x11_p.h"
-#include "qx11info_x11.h"
-
-#include "qwidget_p.h"
-#include "qcursor_p.h"
-
-QT_BEGIN_NAMESPACE
-
-// #define DND_DEBUG
-#ifdef DND_DEBUG
-#define DEBUG qDebug
-#else
-#define DEBUG if(0) qDebug
-#endif
-
-#ifdef DND_DEBUG
-#define DNDDEBUG qDebug()
-#else
-#define DNDDEBUG if(0) qDebug()
-#endif
-
-static int findXdndDropTransactionByWindow(Window window)
-{
- int at = -1;
- for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
- const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
- if (t.target == window || t.proxy_target == window) {
- at = i;
- break;
- }
- }
- return at;
-}
-
-static int findXdndDropTransactionByTime(Time timestamp)
-{
- int at = -1;
- for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
- const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
- if (t.timestamp == timestamp) {
- at = i;
- break;
- }
- }
- return at;
-}
-
-// timer used to discard old XdndDrop transactions
-static int transaction_expiry_timer = -1;
-enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds
-
-static void restartXdndDropExpiryTimer()
-{
- if (transaction_expiry_timer != -1)
- QDragManager::self()->killTimer(transaction_expiry_timer);
- transaction_expiry_timer = QDragManager::self()->startTimer(XdndDropTransactionTimeout);
-}
-
-
-// find an ancestor with XdndAware on it
-static Window findXdndAwareParent(Window window)
-{
- Window target = 0;
- forever {
- // check if window has XdndAware
- Atom type = 0;
- int f;
- unsigned long n, a;
- unsigned char *data = 0;
- if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False,
- AnyPropertyType, &type, &f,&n,&a,&data) == Success) {
- if (data)
- XFree(data);
- if (type) {
- target = window;
- break;
- }
- }
-
- // try window's parent
- Window root;
- Window parent;
- Window *children;
- uint unused;
- if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused))
- break;
- if (children)
- XFree(children);
- if (window == root)
- break;
- window = parent;
- }
- return target;
-}
-
-
-
-
-// and all this stuff is copied -into- qapp_x11.cpp
-
-static void handle_xdnd_position(QWidget *, const XEvent *, bool);
-static void handle_xdnd_status(QWidget * w, const XEvent * xe, bool /*passive*/);
-
-const int xdnd_version = 5;
-
-static Qt::DropAction xdndaction_to_qtaction(Atom atom)
-{
- if (atom == ATOM(XdndActionCopy) || atom == 0)
- return Qt::CopyAction;
- if (atom == ATOM(XdndActionLink))
- return Qt::LinkAction;
- if (atom == ATOM(XdndActionMove))
- return Qt::MoveAction;
- return Qt::CopyAction;
-}
-
-static int qtaction_to_xdndaction(Qt::DropAction a)
-{
- switch (a) {
- case Qt::CopyAction:
- return ATOM(XdndActionCopy);
- case Qt::LinkAction:
- return ATOM(XdndActionLink);
- case Qt::MoveAction:
- case Qt::TargetMoveAction:
- return ATOM(XdndActionMove);
- case Qt::IgnoreAction:
- return XNone;
- default:
- return ATOM(XdndActionCopy);
- }
-}
-
-// clean up the stuff used.
-static void qt_xdnd_cleanup();
-
-static void qt_xdnd_send_leave();
-
-// real variables:
-// xid of current drag source
-static Atom qt_xdnd_dragsource_xid = 0;
-
-// the types in this drop. 100 is no good, but at least it's big.
-const int qt_xdnd_max_type = 100;
-static Atom qt_xdnd_types[qt_xdnd_max_type + 1];
-
-// timer used when target wants "continuous" move messages (eg. scroll)
-static int heartbeat = -1;
-// rectangle in which the answer will be the same
-static QRect qt_xdnd_source_sameanswer;
-// top-level window we sent position to last.
-static Window qt_xdnd_current_target;
-// window to send events to (always valid if qt_xdnd_current_target)
-static Window qt_xdnd_current_proxy_target;
-static Time qt_xdnd_source_current_time;
-
-// widget we forwarded position to last, and local position
-static QPointer<QWidget> qt_xdnd_current_widget;
-static QPoint qt_xdnd_current_position;
-// timestamp from the XdndPosition and XdndDrop
-static Time qt_xdnd_target_current_time;
-// screen number containing the pointer... -1 means default
-static int qt_xdnd_current_screen = -1;
-// state of dragging... true if dragging, false if not
-bool qt_xdnd_dragging = false;
-
-static bool waiting_for_status = false;
-
-// used to preset each new QDragMoveEvent
-static Qt::DropAction last_target_accepted_action = Qt::IgnoreAction;
-
-// Shift/Ctrl handling, and final drop status
-static Qt::DropAction global_accepted_action = Qt::CopyAction;
-static Qt::DropActions possible_actions = Qt::IgnoreAction;
-
-// for embedding only
-static QWidget* current_embedding_widget = 0;
-static XEvent last_enter_event;
-
-// cursors
-static QCursor *noDropCursor = 0;
-static QCursor *moveCursor = 0;
-static QCursor *copyCursor = 0;
-static QCursor *linkCursor = 0;
-
-static QPixmap *defaultPm = 0;
-
-static const int default_pm_hotx = -2;
-static const int default_pm_hoty = -16;
-static const char* const default_pm[] = {
-"13 9 3 1",
-". c None",
-" c #000000",
-"X c #FFFFFF",
-"X X X X X X X",
-" X X X X X X ",
-"X ......... X",
-" X.........X ",
-"X ......... X",
-" X.........X ",
-"X ......... X",
-" X X X X X X ",
-"X X X X X X X"
-};
-
-class QShapedPixmapWidget : public QWidget
-{
- Q_OBJECT
-public:
- QShapedPixmapWidget(QWidget* w) :
- QWidget(w,
- Qt::Tool | Qt::FramelessWindowHint
- | Qt::X11BypassWindowManagerHint
- | Qt::BypassGraphicsProxyWidget)
- {
- setAttribute(Qt::WA_X11NetWmWindowTypeDND);
- }
-
- void setPixmap(const QPixmap &pm)
- {
- QBitmap mask = pm.mask();
- if (!mask.isNull()) {
- setMask(mask);
- } else {
- clearMask();
- }
- resize(pm.width(),pm.height());
- pixmap = pm;
- update();
- }
- QPoint pm_hot;
-
-protected:
- QPixmap pixmap;
- void paintEvent(QPaintEvent*)
- {
- QPainter p(this);
- p.drawPixmap(0, 0, pixmap);
- }
-};
-
-#include "qdnd_x11.moc"
-
-struct XdndData {
- QShapedPixmapWidget *deco;
- QWidget* desktop_proxy;
-};
-
-static XdndData xdnd_data = { 0, 0 };
-
-class QExtraWidget : public QWidget
-{
- Q_DECLARE_PRIVATE(QWidget)
-public:
- inline QWExtra* extraData();
- inline QTLWExtra* topData();
-};
-
-inline QWExtra* QExtraWidget::extraData() { return d_func()->extraData(); }
-inline QTLWExtra* QExtraWidget::topData() { return d_func()->topData(); }
-
-
-static WId xdndProxy(WId w)
-{
- Atom type = XNone;
- int f;
- unsigned long n, a;
- unsigned char *retval = 0;
- XGetWindowProperty(X11->display, w, ATOM(XdndProxy), 0, 1, False,
- XA_WINDOW, &type, &f,&n,&a,&retval);
- WId *proxy_id_ptr = (WId *)retval;
- WId proxy_id = 0;
- if (type == XA_WINDOW && proxy_id_ptr) {
- proxy_id = *proxy_id_ptr;
- XFree(proxy_id_ptr);
- proxy_id_ptr = 0;
- // Already exists. Real?
- X11->ignoreBadwindow();
- XGetWindowProperty(X11->display, proxy_id, ATOM(XdndProxy), 0, 1, False,
- XA_WINDOW, &type, &f,&n,&a,&retval);
- proxy_id_ptr = (WId *)retval;
- if (X11->badwindow() || type != XA_WINDOW || !proxy_id_ptr || *proxy_id_ptr != proxy_id)
- // Bogus - we will overwrite.
- proxy_id = 0;
- }
- if (proxy_id_ptr)
- XFree(proxy_id_ptr);
- return proxy_id;
-}
-
-static bool xdndEnable(QWidget* w, bool on)
-{
- DNDDEBUG << "xdndEnable" << w << on;
- if (on) {
- QWidget * xdnd_widget = 0;
- if ((w->windowType() == Qt::Desktop)) {
- if (xdnd_data.desktop_proxy) // *WE* already have one.
- return false;
-
- // As per Xdnd4, use XdndProxy
- XGrabServer(X11->display);
- Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
- WId proxy_id = xdndProxy(w->effectiveWinId());
-
- if (!proxy_id) {
- xdnd_widget = xdnd_data.desktop_proxy = new QWidget;
- proxy_id = xdnd_data.desktop_proxy->effectiveWinId();
- XChangeProperty (X11->display, w->effectiveWinId(), ATOM(XdndProxy),
- XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
- XChangeProperty (X11->display, proxy_id, ATOM(XdndProxy),
- XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
- }
-
- XUngrabServer(X11->display);
- } else {
- xdnd_widget = w->window();
- }
- if (xdnd_widget) {
- DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->effectiveWinId();
- Atom atm = (Atom)xdnd_version;
- Q_ASSERT(xdnd_widget->testAttribute(Qt::WA_WState_Created));
- XChangeProperty(X11->display, xdnd_widget->effectiveWinId(), ATOM(XdndAware),
- XA_ATOM, 32, PropModeReplace, (unsigned char *)&atm, 1);
- return true;
- } else {
- return false;
- }
- } else {
- if ((w->windowType() == Qt::Desktop)) {
- XDeleteProperty(X11->display, w->internalWinId(), ATOM(XdndProxy));
- delete xdnd_data.desktop_proxy;
- xdnd_data.desktop_proxy = 0;
- } else {
- DNDDEBUG << "not deleting XDndAware";
- }
- return true;
- }
-}
-
-QByteArray QX11Data::xdndAtomToString(Atom a)
-{
- if (!a) return 0;
-
- if (a == XA_STRING || a == ATOM(UTF8_STRING)) {
- return "text/plain"; // some Xdnd clients are dumb
- }
- char *atom = XGetAtomName(display, a);
- QByteArray result = atom;
- XFree(atom);
- return result;
-}
-
-Atom QX11Data::xdndStringToAtom(const char *mimeType)
-{
- if (!mimeType || !*mimeType)
- return 0;
- return XInternAtom(display, mimeType, False);
-}
-
-//$$$
-QString QX11Data::xdndMimeAtomToString(Atom a)
-{
- QString atomName;
- if (a) {
- char *atom = XGetAtomName(display, a);
- atomName = QString::fromLatin1(atom);
- XFree(atom);
- }
- return atomName;
-}
-
-//$$$
-Atom QX11Data::xdndMimeStringToAtom(const QString &mimeType)
-{
- if (mimeType.isEmpty())
- return 0;
- return XInternAtom(display, mimeType.toLatin1().constData(), False);
-}
-
-//$$$ replace ccxdndAtomToString()
-QStringList QX11Data::xdndMimeFormatsForAtom(Atom a)
-{
- QStringList formats;
- if (a) {
- QString atomName = xdndMimeAtomToString(a);
- formats.append(atomName);
-
- // special cases for string type
- if (a == ATOM(UTF8_STRING) || a == XA_STRING
- || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
- formats.append(QLatin1String("text/plain"));
-
- // special cases for uris
- if (atomName == QLatin1String("text/x-moz-url"))
- formats.append(QLatin1String("text/uri-list"));
-
- // special case for images
- if (a == XA_PIXMAP)
- formats.append(QLatin1String("image/ppm"));
- }
- return formats;
-}
-
-//$$$
-bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat)
-{
- bool ret = false;
- *atomFormat = a;
- *dataFormat = 8;
- QString atomName = xdndMimeAtomToString(a);
- if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) {
- *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
- if (atomName == QLatin1String("application/x-color"))
- *dataFormat = 16;
- ret = true;
- } else {
- if ((a == ATOM(UTF8_STRING) || a == XA_STRING
- || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
- && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) {
- if (a == ATOM(UTF8_STRING)){
- *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData);
- ret = true;
- } else if (a == XA_STRING) {
- *data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
- QLatin1String("text/plain"), mimeData)).toLocal8Bit();
- ret = true;
- } else if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT)) {
- // the ICCCM states that TEXT and COMPOUND_TEXT are in the
- // encoding of choice, so we choose the encoding of the locale
- QByteArray strData = QString::fromUtf8(QInternalMimeData::renderDataHelper(
- QLatin1String("text/plain"), mimeData)).toLocal8Bit();
- char *list[] = { strData.data(), NULL };
-
- XICCEncodingStyle style = (a == ATOM(COMPOUND_TEXT))
- ? XCompoundTextStyle : XStdICCTextStyle;
- XTextProperty textprop;
- if (list[0] != NULL
- && XmbTextListToTextProperty(X11->display, list, 1, style,
- &textprop) == Success) {
- *atomFormat = textprop.encoding;
- *dataFormat = textprop.format;
- *data = QByteArray((const char *) textprop.value, textprop.nitems * textprop.format / 8);
- ret = true;
-
- DEBUG(" textprop type %lx\n"
- " textprop name '%s'\n"
- " format %d\n"
- " %ld items\n"
- " %d bytes\n",
- textprop.encoding,
- X11->xdndMimeAtomToString(textprop.encoding).toLatin1().data(),
- textprop.format, textprop.nitems, data->size());
-
- XFree(textprop.value);
- }
- }
- } else if (atomName == QLatin1String("text/x-moz-url") &&
- QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) {
- QByteArray uri = QInternalMimeData::renderDataHelper(
- QLatin1String("text/uri-list"), mimeData).split('\n').first();
- QString mozUri = QString::fromLatin1(uri, uri.size());
- mozUri += QLatin1Char('\n');
- *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2);
- ret = true;
- } else if ((a == XA_PIXMAP || a == XA_BITMAP) && mimeData->hasImage()) {
- QPixmap pm = qvariant_cast<QPixmap>(mimeData->imageData());
- if (a == XA_BITMAP && pm.depth() != 1) {
- QImage img = pm.toImage();
- img = img.convertToFormat(QImage::Format_MonoLSB);
- pm = QPixmap::fromImage(img);
- }
- QDragManager *dm = QDragManager::self();
- if (dm) {
- Pixmap handle = pm.handle();
- *data = QByteArray((const char *) &handle, sizeof(Pixmap));
- dm->xdndMimeTransferedPixmap[dm->xdndMimeTransferedPixmapIndex] = pm;
- dm->xdndMimeTransferedPixmapIndex =
- (dm->xdndMimeTransferedPixmapIndex + 1) % 2;
- ret = true;
- }
- } else {
- DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", qPrintable(atomName));
- }
- }
- return ret && data != 0;
-}
-
-//$$$
-QList<Atom> QX11Data::xdndMimeAtomsForFormat(const QString &format)
-{
- QList<Atom> atoms;
- atoms.append(xdndMimeStringToAtom(format));
-
- // special cases for strings
- if (format == QLatin1String("text/plain")) {
- atoms.append(ATOM(UTF8_STRING));
- atoms.append(XA_STRING);
- atoms.append(ATOM(TEXT));
- atoms.append(ATOM(COMPOUND_TEXT));
- }
-
- // special cases for uris
- if (format == QLatin1String("text/uri-list")) {
- atoms.append(xdndMimeStringToAtom(QLatin1String("text/x-moz-url")));
- }
-
- //special cases for images
- if (format == QLatin1String("image/ppm"))
- atoms.append(XA_PIXMAP);
- if (format == QLatin1String("image/pbm"))
- atoms.append(XA_BITMAP);
-
- return atoms;
-}
-
-//$$$
-QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding)
-{
- QString atomName = xdndMimeAtomToString(a);
- if (atomName == format)
- return data;
-
- if (!encoding.isEmpty()
- && atomName == format + QLatin1String(";charset=") + QString::fromLatin1(encoding)) {
-
- if (requestedType == QVariant::String) {
- QTextCodec *codec = QTextCodec::codecForName(encoding);
- if (codec)
- return codec->toUnicode(data);
- }
-
- return data;
- }
-
- // special cases for string types
- if (format == QLatin1String("text/plain")) {
- if (a == ATOM(UTF8_STRING))
- return QString::fromUtf8(data);
- if (a == XA_STRING)
- return QString::fromLatin1(data);
- if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
- // #### might be wrong for COMPUND_TEXT
- return QString::fromLocal8Bit(data, data.size());
- }
-
- // special case for uri types
- if (format == QLatin1String("text/uri-list")) {
- if (atomName == QLatin1String("text/x-moz-url")) {
- // we expect this as utf16 <url><space><title>
- // the first part is a url that should only contain ascci char
- // so it should be safe to check that the second char is 0
- // to verify that it is utf16
- if (data.size() > 1 && data.at(1) == 0)
- return QString::fromRawData((const QChar *)data.constData(),
- data.size() / 2).split(QLatin1Char('\n')).first().toLatin1();
- }
- }
-
- // special cas for images
- if (format == QLatin1String("image/ppm")) {
- if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) {
- Pixmap xpm = *((Pixmap*)data.data());
- if (!xpm)
- return QByteArray();
- QPixmap qpm = QPixmap::fromX11Pixmap(xpm);
- QImageWriter imageWriter;
- imageWriter.setFormat("PPMRAW");
- QImage imageToWrite = qpm.toImage();
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- imageWriter.setDevice(&buf);
- imageWriter.write(imageToWrite);
- return buf.buffer();
- }
- }
- return QVariant();
-}
-
-//$$$ middle of xdndObtainData
-Atom QX11Data::xdndMimeAtomForFormat(const QString &format, QVariant::Type requestedType, const QList<Atom> &atoms, QByteArray *encoding)
-{
- encoding->clear();
-
- // find matches for string types
- if (format == QLatin1String("text/plain")) {
- if (atoms.contains(ATOM(UTF8_STRING)))
- return ATOM(UTF8_STRING);
- if (atoms.contains(ATOM(COMPOUND_TEXT)))
- return ATOM(COMPOUND_TEXT);
- if (atoms.contains(ATOM(TEXT)))
- return ATOM(TEXT);
- if (atoms.contains(XA_STRING))
- return XA_STRING;
- }
-
- // find matches for uri types
- if (format == QLatin1String("text/uri-list")) {
- Atom a = xdndMimeStringToAtom(format);
- if (a && atoms.contains(a))
- return a;
- a = xdndMimeStringToAtom(QLatin1String("text/x-moz-url"));
- if (a && atoms.contains(a))
- return a;
- }
-
- // find match for image
- if (format == QLatin1String("image/ppm")) {
- if (atoms.contains(XA_PIXMAP))
- return XA_PIXMAP;
- }
-
- // for string/text requests try to use a format with a well-defined charset
- // first to avoid encoding problems
- if (requestedType == QVariant::String
- && format.startsWith(QLatin1String("text/"))
- && !format.contains(QLatin1String("charset="))) {
-
- QString formatWithCharset = format;
- formatWithCharset.append(QLatin1String(";charset=utf-8"));
-
- Atom a = xdndMimeStringToAtom(formatWithCharset);
- if (a && atoms.contains(a)) {
- *encoding = "utf-8";
- return a;
- }
- }
-
- Atom a = xdndMimeStringToAtom(format);
- if (a && atoms.contains(a))
- return a;
-
- return 0;
-}
-
-void QX11Data::xdndSetup() {
- QCursorData::initialize();
- qAddPostRoutine(qt_xdnd_cleanup);
-}
-
-
-void qt_xdnd_cleanup()
-{
- delete noDropCursor;
- noDropCursor = 0;
- delete copyCursor;
- copyCursor = 0;
- delete moveCursor;
- moveCursor = 0;
- delete linkCursor;
- linkCursor = 0;
- delete defaultPm;
- defaultPm = 0;
- delete xdnd_data.desktop_proxy;
- xdnd_data.desktop_proxy = 0;
- delete xdnd_data.deco;
- xdnd_data.deco = 0;
-}
-
-
-static QWidget *find_child(QWidget *tlw, QPoint & p)
-{
- QWidget *widget = tlw;
-
- p = widget->mapFromGlobal(p);
- bool done = false;
- while (!done) {
- done = true;
- if (((QExtraWidget*)widget)->extraData() &&
- ((QExtraWidget*)widget)->extraData()->xDndProxy != 0)
- break; // stop searching for widgets under the mouse cursor if found widget is a proxy.
- QObjectList children = widget->children();
- if (!children.isEmpty()) {
- for(int i = children.size(); i > 0;) {
- --i;
- QWidget *w = qobject_cast<QWidget *>(children.at(i));
- if (!w)
- continue;
- if (w->testAttribute(Qt::WA_TransparentForMouseEvents))
- continue;
- if (w->isVisible() &&
- w->geometry().contains(p) &&
- !w->isWindow()) {
- widget = w;
- done = false;
- p = widget->mapFromParent(p);
- break;
- }
- }
- }
- }
- return widget;
-}
-
-
-static bool checkEmbedded(QWidget* w, const XEvent* xe)
-{
- if (!w)
- return false;
-
- if (current_embedding_widget != 0 && current_embedding_widget != w) {
- qt_xdnd_current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy;
- qt_xdnd_current_proxy_target = qt_xdnd_current_target;
- qt_xdnd_send_leave();
- qt_xdnd_current_target = 0;
- qt_xdnd_current_proxy_target = 0;
- current_embedding_widget = 0;
- }
-
- QWExtra* extra = ((QExtraWidget*)w)->extraData();
- if (extra && extra->xDndProxy != 0) {
-
- if (current_embedding_widget != w) {
-
- last_enter_event.xany.window = extra->xDndProxy;
- XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event);
- current_embedding_widget = w;
- }
-
- ((XEvent*)xe)->xany.window = extra->xDndProxy;
- XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe);
- if (qt_xdnd_current_widget != w) {
- qt_xdnd_current_widget = w;
- }
- return true;
- }
- current_embedding_widget = 0;
- return false;
-}
-
-void QX11Data::xdndHandleEnter(QWidget *, const XEvent * xe, bool /*passive*/)
-{
- motifdnd_active = false;
-
- last_enter_event.xclient = xe->xclient;
-
- const long *l = xe->xclient.data.l;
- int version = (int)(((unsigned long)(l[1])) >> 24);
-
- if (version > xdnd_version)
- return;
-
- qt_xdnd_dragsource_xid = l[0];
-
- int j = 0;
- if (l[1] & 1) {
- // get the types from XdndTypeList
- Atom type = XNone;
- int f;
- unsigned long n, a;
- unsigned char *retval = 0;
- XGetWindowProperty(X11->display, qt_xdnd_dragsource_xid, ATOM(XdndTypelist), 0,
- qt_xdnd_max_type, False, XA_ATOM, &type, &f,&n,&a,&retval);
- if (retval) {
- Atom *data = (Atom *)retval;
- for (; j<qt_xdnd_max_type && j < (int)n; j++) {
- qt_xdnd_types[j] = data[j];
- }
- XFree((uchar*)data);
- }
- } else {
- // get the types from the message
- int i;
- for(i=2; i < 5; i++) {
- qt_xdnd_types[j++] = l[i];
- }
- }
- qt_xdnd_types[j] = 0;
-}
-
-static void handle_xdnd_position(QWidget *w, const XEvent * xe, bool passive)
-{
- const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
-
- QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
- QWidget * c = find_child(w, p); // changes p to to c-local coordinates
-
- if (!passive && checkEmbedded(c, xe))
- return;
-
- if (!c || (!c->acceptDrops() && (c->windowType() == Qt::Desktop)))
- return;
-
- if (l[0] != qt_xdnd_dragsource_xid) {
- DEBUG("xdnd drag position from unexpected source (%08lx not %08lx)", l[0], qt_xdnd_dragsource_xid);
- return;
- }
-
- // timestamp from the source
- if (l[3] != 0) {
- // Some X server/client combination swallow the first 32 bit and
- // interpret a set bit 31 as negative sign.
- qt_xdnd_target_current_time = X11->userTime =
- ((sizeof(Time) == 8 && xe->xclient.data.l[3] < 0)
- ? uint(l[3])
- : l[3]);
- }
-
- QDragManager *manager = QDragManager::self();
- QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
-
- XClientMessageEvent response;
- response.type = ClientMessage;
- response.window = qt_xdnd_dragsource_xid;
- response.format = 32;
- response.message_type = ATOM(XdndStatus);
- response.data.l[0] = w->effectiveWinId();
- response.data.l[1] = 0; // flags
- response.data.l[2] = 0; // x, y
- response.data.l[3] = 0; // w, h
- response.data.l[4] = 0; // action
-
- if (!passive) { // otherwise just reject
- while (c && !c->acceptDrops() && !c->isWindow()) {
- p = c->mapToParent(p);
- c = c->parentWidget();
- }
- QWidget *target_widget = c && c->acceptDrops() ? c : 0;
-
- QRect answerRect(c->mapToGlobal(p), QSize(1,1));
-
- if (manager->object) {
- possible_actions = manager->dragPrivate()->possible_actions;
- } else {
- possible_actions = Qt::DropActions(xdndaction_to_qtaction(l[4]));
-// possible_actions |= Qt::CopyAction;
- }
- QDragMoveEvent me(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
-
- Qt::DropAction accepted_action = Qt::IgnoreAction;
-
-
- if (target_widget != qt_xdnd_current_widget) {
- if (qt_xdnd_current_widget) {
- QDragLeaveEvent e;
- QApplication::sendEvent(qt_xdnd_current_widget, &e);
- }
- if (qt_xdnd_current_widget != target_widget) {
- qt_xdnd_current_widget = target_widget;
- }
- if (target_widget) {
- qt_xdnd_current_position = p;
-
- last_target_accepted_action = Qt::IgnoreAction;
- QDragEnterEvent de(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
- QApplication::sendEvent(target_widget, &de);
- if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction)
- last_target_accepted_action = de.dropAction();
- }
- }
-
- DEBUG() << "qt_handle_xdnd_position action=" << X11->xdndAtomToString(l[4]);
- if (!target_widget) {
- answerRect = QRect(p, QSize(1, 1));
- } else {
- qt_xdnd_current_widget = c;
- qt_xdnd_current_position = p;
-
- if (last_target_accepted_action != Qt::IgnoreAction) {
- me.setDropAction(last_target_accepted_action);
- me.accept();
- }
- QApplication::sendEvent(c, &me);
- if (me.isAccepted()) {
- response.data.l[1] = 1; // yes
- accepted_action = me.dropAction();
- last_target_accepted_action = accepted_action;
- } else {
- response.data.l[0] = 0;
- last_target_accepted_action = Qt::IgnoreAction;
- }
- answerRect = me.answerRect().intersected(c->rect());
- }
- answerRect = QRect(c->mapToGlobal(answerRect.topLeft()), answerRect.size());
-
- if (answerRect.left() < 0)
- answerRect.setLeft(0);
- if (answerRect.right() > 4096)
- answerRect.setRight(4096);
- if (answerRect.top() < 0)
- answerRect.setTop(0);
- if (answerRect.bottom() > 4096)
- answerRect.setBottom(4096);
- if (answerRect.width() < 0)
- answerRect.setWidth(0);
- if (answerRect.height() < 0)
- answerRect.setHeight(0);
-
- response.data.l[2] = (answerRect.x() << 16) + answerRect.y();
- response.data.l[3] = (answerRect.width() << 16) + answerRect.height();
- response.data.l[4] = qtaction_to_xdndaction(accepted_action);
- }
-
- // reset
- qt_xdnd_target_current_time = CurrentTime;
-
- QWidget * source = QWidget::find(qt_xdnd_dragsource_xid);
- if (source && (source->windowType() == Qt::Desktop) && !source->acceptDrops())
- source = 0;
-
- DEBUG() << "sending XdndStatus";
- if (source)
- handle_xdnd_status(source, (const XEvent *)&response, passive);
- else
- XSendEvent(X11->display, qt_xdnd_dragsource_xid, False, NoEventMask, (XEvent*)&response);
-}
-
-static Bool xdnd_position_scanner(Display *, XEvent *event, XPointer)
-{
- if (event->type != ClientMessage)
- return false;
- XClientMessageEvent *ev = &event->xclient;
-
- if (ev->message_type == ATOM(XdndPosition))
- return true;
-
- return false;
-}
-
-void QX11Data::xdndHandlePosition(QWidget * w, const XEvent * xe, bool passive)
-{
- DEBUG("xdndHandlePosition");
- while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_position_scanner, 0))
- ;
-
- handle_xdnd_position(w, xe, passive);
-}
-
-
-static void handle_xdnd_status(QWidget *, const XEvent * xe, bool)
-{
- const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
- // ignore late status messages
- if (l[0] && l[0] != qt_xdnd_current_proxy_target)
- return;
- Qt::DropAction newAction = (l[1] & 0x1) ? xdndaction_to_qtaction(l[4]) : Qt::IgnoreAction;
-
- if ((int)(l[1] & 2) == 0) {
- QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
- QSize s((l[3] & 0xffff0000) >> 16, l[3] & 0x0000ffff);
- qt_xdnd_source_sameanswer = QRect(p, s);
- } else {
- qt_xdnd_source_sameanswer = QRect();
- }
- QDragManager *manager = QDragManager::self();
- manager->willDrop = (l[1] & 0x1);
- if (global_accepted_action != newAction)
- manager->emitActionChanged(newAction);
- global_accepted_action = newAction;
- manager->updateCursor();
- waiting_for_status = false;
-}
-
-static Bool xdnd_status_scanner(Display *, XEvent *event, XPointer)
-{
- if (event->type != ClientMessage)
- return false;
- XClientMessageEvent *ev = &event->xclient;
-
- if (ev->message_type == ATOM(XdndStatus))
- return true;
-
- return false;
-}
-
-void QX11Data::xdndHandleStatus(QWidget * w, const XEvent * xe, bool passive)
-{
- DEBUG("xdndHandleStatus");
- while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_status_scanner, 0))
- ;
-
- handle_xdnd_status(w, xe, passive);
- DEBUG("xdndHandleStatus end");
-}
-
-void QX11Data::xdndHandleLeave(QWidget *w, const XEvent * xe, bool /*passive*/)
-{
- DEBUG("xdnd leave");
- if (!qt_xdnd_current_widget ||
- w->window() != qt_xdnd_current_widget->window()) {
- return; // sanity
- }
-
- if (checkEmbedded(current_embedding_widget, xe)) {
- current_embedding_widget = 0;
- qt_xdnd_current_widget = 0;
- return;
- }
-
- const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
-
- QDragLeaveEvent e;
- QApplication::sendEvent(qt_xdnd_current_widget, &e);
-
- if (l[0] != qt_xdnd_dragsource_xid) {
- // This often happens - leave other-process window quickly
- DEBUG("xdnd drag leave from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
- qt_xdnd_current_widget = 0;
- return;
- }
-
- qt_xdnd_dragsource_xid = 0;
- qt_xdnd_types[0] = 0;
- qt_xdnd_current_widget = 0;
-}
-
-
-void qt_xdnd_send_leave()
-{
- if (!qt_xdnd_current_target)
- return;
-
- QDragManager *manager = QDragManager::self();
-
- XClientMessageEvent leave;
- leave.type = ClientMessage;
- leave.window = qt_xdnd_current_target;
- leave.format = 32;
- leave.message_type = ATOM(XdndLeave);
- leave.data.l[0] = manager->dragPrivate()->source->effectiveWinId();
- leave.data.l[1] = 0; // flags
- leave.data.l[2] = 0; // x, y
- leave.data.l[3] = 0; // w, h
- leave.data.l[4] = 0; // just null
-
- QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
-
- if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
- w = 0;
-
- if (w)
- X11->xdndHandleLeave(w, (const XEvent *)&leave, false);
- else
- XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
- NoEventMask, (XEvent*)&leave);
-
- // reset the drag manager state
- manager->willDrop = false;
- if (global_accepted_action != Qt::IgnoreAction)
- manager->emitActionChanged(Qt::IgnoreAction);
- global_accepted_action = Qt::IgnoreAction;
- manager->updateCursor();
- qt_xdnd_current_target = 0;
- qt_xdnd_current_proxy_target = 0;
- qt_xdnd_source_current_time = 0;
- waiting_for_status = false;
-}
-
-// TODO: remove and use QApplication::currentKeyboardModifiers() in Qt 4.8.
-static Qt::KeyboardModifiers currentKeyboardModifiers()
-{
- Window root;
- Window child;
- int root_x, root_y, win_x, win_y;
- uint keybstate;
- for (int i = 0; i < ScreenCount(X11->display); ++i) {
- if (XQueryPointer(X11->display, QX11Info::appRootWindow(i), &root, &child,
- &root_x, &root_y, &win_x, &win_y, &keybstate))
- return X11->translateModifiers(keybstate & 0x00ff);
- }
- return 0;
-}
-
-void QX11Data::xdndHandleDrop(QWidget *, const XEvent * xe, bool passive)
-{
- DEBUG("xdndHandleDrop");
- if (!qt_xdnd_current_widget) {
- qt_xdnd_dragsource_xid = 0;
- return; // sanity
- }
-
- if (!passive && checkEmbedded(qt_xdnd_current_widget, xe)){
- current_embedding_widget = 0;
- qt_xdnd_dragsource_xid = 0;
- qt_xdnd_current_widget = 0;
- return;
- }
- const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
-
- QDragManager *manager = QDragManager::self();
- DEBUG("xdnd drop");
-
- if (l[0] != qt_xdnd_dragsource_xid) {
- DEBUG("xdnd drop from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
- return;
- }
-
- // update the "user time" from the timestamp in the event.
- if (l[2] != 0) {
- // Some X server/client combination swallow the first 32 bit and
- // interpret a set bit 31 as negative sign.
- qt_xdnd_target_current_time = X11->userTime =
- ((sizeof(Time) == 8 && xe->xclient.data.l[2] < 0)
- ? uint(l[2])
- : l[2]);
- }
-
- if (!passive) {
- // this could be a same-application drop, just proxied due to
- // some XEMBEDding, so try to find the real QMimeData used
- // based on the timestamp for this drop.
- QMimeData *dropData = 0;
- int at = findXdndDropTransactionByTime(qt_xdnd_target_current_time);
- if (at != -1)
- dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
- // if we can't find it, then use the data in the drag manager
- if (!dropData)
- dropData = (manager->object) ? manager->dragPrivate()->data : manager->dropData;
-
- // Drop coming from another app? Update keyboard modifiers.
- if (!qt_xdnd_dragging) {
- QApplicationPrivate::modifier_buttons = currentKeyboardModifiers();
- }
-
- QDropEvent de(qt_xdnd_current_position, possible_actions, dropData,
- QApplication::mouseButtons(), QApplication::keyboardModifiers());
- QApplication::sendEvent(qt_xdnd_current_widget, &de);
- if (!de.isAccepted()) {
- // Ignore a failed drag
- global_accepted_action = Qt::IgnoreAction;
- } else {
- global_accepted_action = de.dropAction();
- }
- XClientMessageEvent finished;
- finished.type = ClientMessage;
- finished.window = qt_xdnd_dragsource_xid;
- finished.format = 32;
- finished.message_type = ATOM(XdndFinished);
- DNDDEBUG << "xdndHandleDrop"
- << "qt_xdnd_current_widget" << qt_xdnd_current_widget
- << (qt_xdnd_current_widget ? qt_xdnd_current_widget->effectiveWinId() : 0)
- << "t_xdnd_current_widget->window()"
- << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window() : 0)
- << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window()->internalWinId() : 0);
- finished.data.l[0] = qt_xdnd_current_widget?qt_xdnd_current_widget->window()->internalWinId():0;
- finished.data.l[1] = de.isAccepted() ? 1 : 0; // flags
- finished.data.l[2] = qtaction_to_xdndaction(global_accepted_action);
- XSendEvent(X11->display, qt_xdnd_dragsource_xid, False,
- NoEventMask, (XEvent*)&finished);
- } else {
- QDragLeaveEvent e;
- QApplication::sendEvent(qt_xdnd_current_widget, &e);
- }
- qt_xdnd_dragsource_xid = 0;
- qt_xdnd_current_widget = 0;
- waiting_for_status = false;
-
- // reset
- qt_xdnd_target_current_time = CurrentTime;
-}
-
-
-void QX11Data::xdndHandleFinished(QWidget *, const XEvent * xe, bool passive)
-{
- DEBUG("xdndHandleFinished");
- const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
-
- DNDDEBUG << "xdndHandleFinished, l[0]" << l[0]
- << "qt_xdnd_current_target" << qt_xdnd_current_target
- << "qt_xdnd_current_proxy_targe" << qt_xdnd_current_proxy_target;
-
- if (l[0]) {
- int at = findXdndDropTransactionByWindow(l[0]);
- if (at != -1) {
- restartXdndDropExpiryTimer();
-
- QXdndDropTransaction t = X11->dndDropTransactions.takeAt(at);
- QDragManager *manager = QDragManager::self();
-
- Window target = qt_xdnd_current_target;
- Window proxy_target = qt_xdnd_current_proxy_target;
- QWidget *embedding_widget = current_embedding_widget;
- QDrag *currentObject = manager->object;
-
- qt_xdnd_current_target = t.target;
- qt_xdnd_current_proxy_target = t.proxy_target;
- current_embedding_widget = t.embedding_widget;
- manager->object = t.object;
-
- if (!passive)
- (void) checkEmbedded(qt_xdnd_current_widget, xe);
-
- current_embedding_widget = 0;
- qt_xdnd_current_target = 0;
- qt_xdnd_current_proxy_target = 0;
-
- if (t.object)
- t.object->deleteLater();
-
- qt_xdnd_current_target = target;
- qt_xdnd_current_proxy_target = proxy_target;
- current_embedding_widget = embedding_widget;
- manager->object = currentObject;
- }
- }
- waiting_for_status = false;
-}
-
-
-void QDragManager::timerEvent(QTimerEvent* e)
-{
- if (e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull()) {
- move(QCursor::pos());
- } else if (e->timerId() == transaction_expiry_timer) {
- for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
- const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
- if (t.targetWidget) {
- // dnd within the same process, don't delete these
- continue;
- }
- t.object->deleteLater();
- X11->dndDropTransactions.removeAt(i--);
- }
-
- killTimer(transaction_expiry_timer);
- transaction_expiry_timer = -1;
- }
-}
-
-bool QDragManager::eventFilter(QObject * o, QEvent * e)
-{
- if (beingCancelled) {
- if (e->type() == QEvent::KeyRelease && ((QKeyEvent*)e)->key() == Qt::Key_Escape) {
- qApp->removeEventFilter(this);
- Q_ASSERT(object == 0);
- beingCancelled = false;
- eventLoop->exit();
- return true; // block the key release
- }
- return false;
- }
-
- Q_ASSERT(object != 0);
-
- if (!o->isWidgetType())
- return false;
-
- if (e->type() == QEvent::MouseMove) {
- QMouseEvent* me = (QMouseEvent *)e;
- move(me->globalPos());
- return true;
- } else if (e->type() == QEvent::MouseButtonRelease) {
- DEBUG("pre drop");
- qApp->removeEventFilter(this);
- if (willDrop)
- drop();
- else
- cancel();
- DEBUG("drop, resetting object");
- beingCancelled = false;
- eventLoop->exit();
- return true;
- }
-
- if (e->type() == QEvent::ShortcutOverride) {
- // prevent accelerators from firing while dragging
- e->accept();
- return true;
- }
-
- if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
- QKeyEvent *ke = ((QKeyEvent*)e);
- if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
- cancel();
- qApp->removeEventFilter(this);
- beingCancelled = false;
- eventLoop->exit();
- } else {
- qt_xdnd_source_sameanswer = QRect(); // force move
- move(QCursor::pos());
- }
- return true; // Eat all key events
- }
-
- // ### We bind modality to widgets, so we have to do this
- // ### "manually".
- // DnD is modal - eat all other interactive events
- switch (e->type()) {
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- case QEvent::MouseButtonDblClick:
- case QEvent::MouseMove:
- case QEvent::KeyPress:
- case QEvent::KeyRelease:
- case QEvent::Wheel:
- case QEvent::ShortcutOverride:
- return true;
- default:
- return false;
- }
-}
-
-void QDragManager::updateCursor()
-{
- if (!noDropCursor) {
-#ifndef QT_NO_CURSOR
- noDropCursor = new QCursor(Qt::ForbiddenCursor);
- moveCursor = new QCursor(Qt::DragMoveCursor);
- copyCursor = new QCursor(Qt::DragCopyCursor);
- linkCursor = new QCursor(Qt::DragLinkCursor);
-#endif
- }
-
- QCursor *c;
- if (willDrop) {
- if (global_accepted_action == Qt::CopyAction) {
- c = copyCursor;
- } else if (global_accepted_action == Qt::LinkAction) {
- c = linkCursor;
- } else {
- c = moveCursor;
- }
- if (xdnd_data.deco) {
- xdnd_data.deco->show();
- xdnd_data.deco->raise();
- }
- } else {
- c = noDropCursor;
- //if (qt_xdnd_deco)
- // qt_xdnd_deco->hide();
- }
-#ifndef QT_NO_CURSOR
- if (c)
- qApp->changeOverrideCursor(*c);
-#endif
-}
-
-
-void QDragManager::cancel(bool deleteSource)
-{
- DEBUG("QDragManager::cancel");
- Q_ASSERT(heartbeat != -1);
- killTimer(heartbeat);
- heartbeat = -1;
- beingCancelled = true;
- qt_xdnd_dragging = false;
-
- if (qt_xdnd_current_target)
- qt_xdnd_send_leave();
-
-#ifndef QT_NO_CURSOR
- if (restoreCursor) {
- QApplication::restoreOverrideCursor();
- restoreCursor = false;
- }
-#endif
-
- if (deleteSource && object)
- object->deleteLater();
- object = 0;
- qDeleteInEventHandler(xdnd_data.deco);
- xdnd_data.deco = 0;
-
- global_accepted_action = Qt::IgnoreAction;
-}
-
-static
-Window findRealWindow(const QPoint & pos, Window w, int md)
-{
- if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId())
- return 0;
-
- if (md) {
- X11->ignoreBadwindow();
- XWindowAttributes attr;
- XGetWindowAttributes(X11->display, w, &attr);
- if (X11->badwindow())
- return 0;
-
- if (attr.map_state == IsViewable
- && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) {
- {
- Atom type = XNone;
- int f;
- unsigned long n, a;
- unsigned char *data;
-
- XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False,
- AnyPropertyType, &type, &f,&n,&a,&data);
- if (data) XFree(data);
- if (type)
- return w;
- }
-
- Window r, p;
- Window* c;
- uint nc;
- if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
- r=0;
- for (uint i=nc; !r && i--;) {
- r = findRealWindow(pos-QPoint(attr.x,attr.y),
- c[i], md-1);
- }
- XFree(c);
- if (r)
- return r;
-
- // We didn't find a client window! Just use the
- // innermost window.
- }
-
- // No children!
- return w;
- }
- }
- return 0;
-}
-
-void QDragManager::move(const QPoint & globalPos)
-{
-#ifdef QT_NO_CURSOR
- Q_UNUSED(globalPos);
- return;
-#else
- DEBUG() << "QDragManager::move enter";
- if (!object) {
- // perhaps the target crashed?
- return;
- }
-
- int screen = QCursor::x11Screen();
- if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
- // recreate the pixmap on the new screen...
- delete xdnd_data.deco;
- QWidget* parent = object->source()->window()->x11Info().screen() == screen
- ? object->source()->window() : QApplication::desktop()->screen(screen);
- xdnd_data.deco = new QShapedPixmapWidget(parent);
- if (!QWidget::mouseGrabber()) {
- updatePixmap();
- xdnd_data.deco->grabMouse();
- }
- }
- xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
-
- if (qt_xdnd_source_sameanswer.contains(globalPos) && qt_xdnd_source_sameanswer.isValid())
- return;
-
- qt_xdnd_current_screen = screen;
- Window rootwin = QX11Info::appRootWindow(qt_xdnd_current_screen);
- Window target = 0;
- int lx = 0, ly = 0;
- if (!XTranslateCoordinates(X11->display, rootwin, rootwin, globalPos.x(), globalPos.y(), &lx, &ly, &target))
- // some weird error...
- return;
-
- if (target == rootwin) {
- // Ok.
- } else if (target) {
- //me
- Window src = rootwin;
- while (target != 0) {
- DNDDEBUG << "checking target for XdndAware" << QWidget::find(target) << target;
- int lx2, ly2;
- Window t;
- // translate coordinates
- if (!XTranslateCoordinates(X11->display, src, target, lx, ly, &lx2, &ly2, &t)) {
- target = 0;
- break;
- }
- lx = lx2;
- ly = ly2;
- src = target;
-
- // check if it has XdndAware
- Atom type = 0;
- int f;
- unsigned long n, a;
- unsigned char *data = 0;
- XGetWindowProperty(X11->display, target, ATOM(XdndAware), 0, 0, False,
- AnyPropertyType, &type, &f,&n,&a,&data);
- if (data)
- XFree(data);
- if (type) {
- DNDDEBUG << "Found XdndAware on " << QWidget::find(target) << target;
- break;
- }
-
- // find child at the coordinates
- if (!XTranslateCoordinates(X11->display, src, src, lx, ly, &lx2, &ly2, &target)) {
- target = 0;
- break;
- }
- }
- if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) {
- DNDDEBUG << "need to find real window";
- target = findRealWindow(globalPos, rootwin, 6);
- DNDDEBUG << "real window found" << QWidget::find(target) << target;
- }
- }
-
- QWidget* w;
- if (target) {
- w = QWidget::find((WId)target);
- if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
- w = 0;
- } else {
- w = 0;
- target = rootwin;
- }
-
- DNDDEBUG << "and the final target is " << QWidget::find(target) << target;
- DNDDEBUG << "the widget w is" << w;
-
- WId proxy_target = xdndProxy(target);
- if (!proxy_target)
- proxy_target = target;
- int target_version = 1;
-
- if (proxy_target) {
- Atom type = XNone;
- int r, f;
- unsigned long n, a;
- unsigned char *retval;
- X11->ignoreBadwindow();
- r = XGetWindowProperty(X11->display, proxy_target, ATOM(XdndAware), 0,
- 1, False, AnyPropertyType, &type, &f,&n,&a,&retval);
- int *tv = (int *)retval;
- if (r != Success || X11->badwindow()) {
- target = 0;
- } else {
- target_version = qMin(xdnd_version,tv ? *tv : 1);
- if (tv)
- XFree(tv);
-// if (!(!X11->badwindow() && type))
-// target = 0;
- }
- }
-
- if (target != qt_xdnd_current_target) {
- if (qt_xdnd_current_target)
- qt_xdnd_send_leave();
-
- qt_xdnd_current_target = target;
- qt_xdnd_current_proxy_target = proxy_target;
- if (target) {
- QVector<Atom> types;
- int flags = target_version << 24;
- QStringList fmts = QInternalMimeData::formatsHelper(dragPrivate()->data);
- for (int i = 0; i < fmts.size(); ++i) {
- QList<Atom> atoms = X11->xdndMimeAtomsForFormat(fmts.at(i));
- for (int j = 0; j < atoms.size(); ++j) {
- if (!types.contains(atoms.at(j)))
- types.append(atoms.at(j));
- }
- }
- if (types.size() > 3) {
- XChangeProperty(X11->display,
- dragPrivate()->source->effectiveWinId(), ATOM(XdndTypelist),
- XA_ATOM, 32, PropModeReplace,
- (unsigned char *)types.data(),
- types.size());
- flags |= 0x0001;
- }
- XClientMessageEvent enter;
- enter.type = ClientMessage;
- enter.window = target;
- enter.format = 32;
- enter.message_type = ATOM(XdndEnter);
- enter.data.l[0] = dragPrivate()->source->effectiveWinId();
- enter.data.l[1] = flags;
- enter.data.l[2] = types.size()>0 ? types.at(0) : 0;
- enter.data.l[3] = types.size()>1 ? types.at(1) : 0;
- enter.data.l[4] = types.size()>2 ? types.at(2) : 0;
- // provisionally set the rectangle to 5x5 pixels...
- qt_xdnd_source_sameanswer = QRect(globalPos.x() - 2,
- globalPos.y() -2 , 5, 5);
-
- DEBUG("sending Xdnd enter");
- if (w)
- X11->xdndHandleEnter(w, (const XEvent *)&enter, false);
- else if (target)
- XSendEvent(X11->display, proxy_target, False, NoEventMask, (XEvent*)&enter);
- waiting_for_status = false;
- }
- }
- if (waiting_for_status)
- return;
-
- if (target) {
- waiting_for_status = true;
-
- XClientMessageEvent move;
- move.type = ClientMessage;
- move.window = target;
- move.format = 32;
- move.message_type = ATOM(XdndPosition);
- move.window = target;
- move.data.l[0] = dragPrivate()->source->effectiveWinId();
- move.data.l[1] = 0; // flags
- move.data.l[2] = (globalPos.x() << 16) + globalPos.y();
- move.data.l[3] = X11->time;
- move.data.l[4] = qtaction_to_xdndaction(defaultAction(dragPrivate()->possible_actions, QApplication::keyboardModifiers()));
- DEBUG("sending Xdnd position");
-
- qt_xdnd_source_current_time = X11->time;
-
- if (w)
- handle_xdnd_position(w, (const XEvent *)&move, false);
- else
- XSendEvent(X11->display, proxy_target, False, NoEventMask,
- (XEvent*)&move);
- } else {
- if (willDrop) {
- willDrop = false;
- updateCursor();
- }
- }
- DEBUG() << "QDragManager::move leave";
-#endif
-}
-
-
-void QDragManager::drop()
-{
- Q_ASSERT(heartbeat != -1);
- killTimer(heartbeat);
- heartbeat = -1;
- qt_xdnd_dragging = false;
-
- if (!qt_xdnd_current_target)
- return;
-
- qDeleteInEventHandler(xdnd_data.deco);
- xdnd_data.deco = 0;
-
- XClientMessageEvent drop;
- drop.type = ClientMessage;
- drop.window = qt_xdnd_current_target;
- drop.format = 32;
- drop.message_type = ATOM(XdndDrop);
- drop.data.l[0] = dragPrivate()->source->effectiveWinId();
- drop.data.l[1] = 0; // flags
- drop.data.l[2] = X11->time;
-
- drop.data.l[3] = 0;
- drop.data.l[4] = 0;
-
- QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
-
- if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
- w = 0;
-
- QXdndDropTransaction t = {
- X11->time,
- qt_xdnd_current_target,
- qt_xdnd_current_proxy_target,
- w,
- current_embedding_widget,
- object
- };
- X11->dndDropTransactions.append(t);
- restartXdndDropExpiryTimer();
-
- if (w)
- X11->xdndHandleDrop(w, (const XEvent *)&drop, false);
- else
- XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
- NoEventMask, (XEvent*)&drop);
-
- qt_xdnd_current_target = 0;
- qt_xdnd_current_proxy_target = 0;
- qt_xdnd_source_current_time = 0;
- current_embedding_widget = 0;
- object = 0;
-
-#ifndef QT_NO_CURSOR
- if (restoreCursor) {
- QApplication::restoreOverrideCursor();
- restoreCursor = false;
- }
-#endif
-}
-
-
-
-bool QX11Data::xdndHandleBadwindow()
-{
- if (qt_xdnd_current_target) {
- QDragManager *manager = QDragManager::self();
- if (manager->object) {
- qt_xdnd_current_target = 0;
- qt_xdnd_current_proxy_target = 0;
- manager->object->deleteLater();
- manager->object = 0;
- delete xdnd_data.deco;
- xdnd_data.deco = 0;
- return true;
- }
- }
- if (qt_xdnd_dragsource_xid) {
- qt_xdnd_dragsource_xid = 0;
- if (qt_xdnd_current_widget) {
- QApplication::postEvent(qt_xdnd_current_widget, new QDragLeaveEvent);
- qt_xdnd_current_widget = 0;
- }
- return true;
- }
- return false;
-}
-
-void QX11Data::xdndHandleSelectionRequest(const XSelectionRequestEvent * req)
-{
- if (!req)
- return;
- XEvent evt;
- evt.xselection.type = SelectionNotify;
- evt.xselection.display = req->display;
- evt.xselection.requestor = req->requestor;
- evt.xselection.selection = req->selection;
- evt.xselection.target = XNone;
- evt.xselection.property = XNone;
- evt.xselection.time = req->time;
-
- QDragManager *manager = QDragManager::self();
- QDrag *currentObject = manager->object;
-
- // which transaction do we use? (note: -2 means use current manager->object)
- int at = -1;
-
- // figure out which data the requestor is really interested in
- if (manager->object && req->time == qt_xdnd_source_current_time) {
- // requestor wants the current drag data
- at = -2;
- } else {
- // if someone has requested data in response to XdndDrop, find the corresponding transaction. the
- // spec says to call XConvertSelection() using the timestamp from the XdndDrop
- at = findXdndDropTransactionByTime(req->time);
- if (at == -1) {
- // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection()
- // that we sent the XdndDrop event to.
- at = findXdndDropTransactionByWindow(req->requestor);
- }
- if (at == -1 && req->time == CurrentTime) {
- // previous Qt versions always requested the data on a child of the target window
- // using CurrentTime... but it could be asking for either drop data or the current drag's data
- Window target = findXdndAwareParent(req->requestor);
- if (target) {
- if (qt_xdnd_current_target && qt_xdnd_current_target == target)
- at = -2;
- else
- at = findXdndDropTransactionByWindow(target);
- }
- }
- }
- if (at >= 0) {
- restartXdndDropExpiryTimer();
-
- // use the drag object from an XdndDrop tansaction
- manager->object = X11->dndDropTransactions.at(at).object;
- } else if (at != -2) {
- // no transaction found, we'll have to reject the request
- manager->object = 0;
- }
- if (manager->object) {
- Atom atomFormat = req->target;
- int dataFormat = 0;
- QByteArray data;
- if (X11->xdndMimeDataForAtom(req->target, manager->dragPrivate()->data,
- &data, &atomFormat, &dataFormat)) {
- int dataSize = data.size() / (dataFormat / 8);
- XChangeProperty (X11->display, req->requestor, req->property,
- atomFormat, dataFormat, PropModeReplace,
- (unsigned char *)data.data(), dataSize);
- evt.xselection.property = req->property;
- evt.xselection.target = atomFormat;
- }
- }
-
- // reset manager->object in case we modified it above
- manager->object = currentObject;
-
- // ### this can die if req->requestor crashes at the wrong
- // ### moment
- XSendEvent(X11->display, req->requestor, False, 0, &evt);
-}
-
-static QVariant xdndObtainData(const char *format, QVariant::Type requestedType)
-{
- QByteArray result;
-
- QWidget* w;
- QDragManager *manager = QDragManager::self();
- if (qt_xdnd_dragsource_xid && manager->object &&
- (w=QWidget::find(qt_xdnd_dragsource_xid))
- && (!(w->windowType() == Qt::Desktop) || w->acceptDrops()))
- {
- QDragPrivate * o = QDragManager::self()->dragPrivate();
- if (o->data->hasFormat(QLatin1String(format)))
- result = o->data->data(QLatin1String(format));
- return result;
- }
-
- QList<Atom> atoms;
- int i = 0;
- while ((qt_xdnd_types[i])) {
- atoms.append(qt_xdnd_types[i]);
- ++i;
- }
- QByteArray encoding;
- Atom a = X11->xdndMimeAtomForFormat(QLatin1String(format), requestedType, atoms, &encoding);
- if (!a)
- return result;
-
- if (XGetSelectionOwner(X11->display, ATOM(XdndSelection)) == XNone)
- return result; // should never happen?
-
- QWidget* tw = qt_xdnd_current_widget;
- if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
- tw = new QWidget;
-
- XConvertSelection(X11->display, ATOM(XdndSelection), a, ATOM(XdndSelection), tw->effectiveWinId(),
- qt_xdnd_target_current_time);
- XFlush(X11->display);
-
- XEvent xevent;
- bool got=X11->clipboardWaitForEvent(tw->effectiveWinId(), SelectionNotify, &xevent, 5000);
- if (got) {
- Atom type;
-
- if (X11->clipboardReadProperty(tw->effectiveWinId(), ATOM(XdndSelection), true, &result, 0, &type, 0)) {
- if (type == ATOM(INCR)) {
- int nbytes = result.size() >= 4 ? *((int*)result.data()) : 0;
- result = X11->clipboardReadIncrementalProperty(tw->effectiveWinId(), ATOM(XdndSelection), nbytes, false);
- } else if (type != a && type != XNone) {
- DEBUG("Qt clipboard: unknown atom %ld", type);
- }
- }
- }
- if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
- delete tw;
-
- return X11->xdndMimeConvertToFormat(a, result, QLatin1String(format), requestedType, encoding);
-}
-
-
-/*
- Enable drag and drop for widget w by installing the proper
- properties on w's toplevel widget.
-*/
-bool QX11Data::dndEnable(QWidget* w, bool on)
-{
- w = w->window();
-
- if (bool(((QExtraWidget*)w)->topData()->dnd) == on)
- return true; // been there, done that
- ((QExtraWidget*)w)->topData()->dnd = on ? 1 : 0;
-
- motifdndEnable(w, on);
- return xdndEnable(w, on);
-}
-
-Qt::DropAction QDragManager::drag(QDrag * o)
-{
- if (object == o || !o || !o->d_func()->source)
- return Qt::IgnoreAction;
-
- if (object) {
- cancel();
- qApp->removeEventFilter(this);
- beingCancelled = false;
- }
-
- if (object) {
- // the last drag and drop operation hasn't finished, so we are going to wait
- // for one second to see if it does... if the finish message comes after this,
- // then we could still have problems, but this is highly unlikely
- QApplication::flush();
-
- QElapsedTimer timer;
- timer.start();
- do {
- XEvent event;
- if (XCheckTypedEvent(X11->display, ClientMessage, &event))
- qApp->x11ProcessEvent(&event);
-
- // sleep 50 ms, so we don't use up CPU cycles all the time.
- struct timeval usleep_tv;
- usleep_tv.tv_sec = 0;
- usleep_tv.tv_usec = 50000;
- select(0, 0, 0, 0, &usleep_tv);
- } while (object && timer.hasExpired(1000));
- }
-
- object = o;
- object->d_func()->target = 0;
- xdnd_data.deco = new QShapedPixmapWidget(object->source()->window());
-
- willDrop = false;
-
- updatePixmap();
-
- qApp->installEventFilter(this);
- XSetSelectionOwner(X11->display, ATOM(XdndSelection), dragPrivate()->source->window()->internalWinId(), X11->time);
- global_accepted_action = Qt::CopyAction;
- qt_xdnd_source_sameanswer = QRect();
-#ifndef QT_NO_CURSOR
- // set the override cursor (must be done here, since it is updated
- // in the call to move() below)
- qApp->setOverrideCursor(Qt::ArrowCursor);
- restoreCursor = true;
-#endif
- move(QCursor::pos());
- heartbeat = startTimer(200);
-
- qt_xdnd_dragging = true;
-
- if (!QWidget::mouseGrabber())
- xdnd_data.deco->grabMouse();
-
- eventLoop = new QEventLoop;
- (void) eventLoop->exec();
- delete eventLoop;
- eventLoop = 0;
-
-#ifndef QT_NO_CURSOR
- if (restoreCursor) {
- qApp->restoreOverrideCursor();
- restoreCursor = false;
- }
-#endif
-
- // delete cursors as they may be different next drag.
- delete noDropCursor;
- noDropCursor = 0;
- delete copyCursor;
- copyCursor = 0;
- delete moveCursor;
- moveCursor = 0;
- delete linkCursor;
- linkCursor = 0;
-
- delete xdnd_data.deco;
- xdnd_data.deco = 0;
- if (heartbeat != -1)
- killTimer(heartbeat);
- heartbeat = -1;
- qt_xdnd_current_screen = -1;
- qt_xdnd_dragging = false;
-
- return global_accepted_action;
- // object persists until we get an xdnd_finish message
-}
-
-void QDragManager::updatePixmap()
-{
- if (xdnd_data.deco) {
- QPixmap pm;
- QPoint pm_hot(default_pm_hotx,default_pm_hoty);
- if (object) {
- pm = dragPrivate()->pixmap;
- if (!pm.isNull())
- pm_hot = dragPrivate()->hotspot;
- }
- if (pm.isNull()) {
- if (!defaultPm)
- defaultPm = new QPixmap(default_pm);
- pm = *defaultPm;
- }
- xdnd_data.deco->pm_hot = pm_hot;
- xdnd_data.deco->setPixmap(pm);
- xdnd_data.deco->move(QCursor::pos()-pm_hot);
- xdnd_data.deco->show();
- }
-}
-
-QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
-{
- QByteArray mime = mimetype.toLatin1();
- QVariant data = X11->motifdnd_active
- ? X11->motifdndObtainData(mime)
- : xdndObtainData(mime, requestedType);
- return data;
-}
-
-bool QDropData::hasFormat_sys(const QString &format) const
-{
- return formats().contains(format);
-}
-
-QStringList QDropData::formats_sys() const
-{
- QStringList formats;
- if (X11->motifdnd_active) {
- int i = 0;
- QByteArray fmt;
- while (!(fmt = X11->motifdndFormat(i)).isEmpty()) {
- formats.append(QLatin1String(fmt));
- ++i;
- }
- } else {
- int i = 0;
- while ((qt_xdnd_types[i])) {
- QStringList formatsForAtom = X11->xdndMimeFormatsForAtom(qt_xdnd_types[i]);
- for (int j = 0; j < formatsForAtom.size(); ++j) {
- if (!formats.contains(formatsForAtom.at(j)))
- formats.append(formatsForAtom.at(j));
- }
- ++i;
- }
- }
- return formats;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DRAGANDDROP