src/gui/kernel/qdnd_x11.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qplatformdefs.h"
00025 
00026 #include "qapplication.h"
00027 
00028 #ifndef QT_NO_DRAGANDDROP
00029 
00030 #include "qwidget.h"
00031 #include "qpixmap.h"
00032 #include "qbitmap.h"
00033 #include "qdesktopwidget.h"
00034 #include "qevent.h"
00035 #include "qdatetime.h"
00036 #include "qiodevice.h"
00037 #include "qpointer.h"
00038 #include "qcursor.h"
00039 #include "qvariant.h"
00040 #include "qvector.h"
00041 #include "qurl.h"
00042 #include "qdebug.h"
00043 #include "qimagewriter.h"
00044 #include "qbuffer.h"
00045 
00046 #include "qdnd_p.h"
00047 #include "qt_x11_p.h"
00048 #include "qx11info_x11.h"
00049 
00050 #include "qwidget_p.h"
00051 #include "qcursor_p.h"
00052 
00053 // #define DND_DEBUG
00054 #ifdef DND_DEBUG
00055 #define DEBUG qDebug
00056 #else
00057 #define DEBUG if(0) qDebug
00058 #endif
00059 
00060 #ifdef DND_DEBUG
00061 #define DNDDEBUG qDebug()
00062 #else
00063 #define DNDDEBUG if(0) qDebug()
00064 #endif
00065 
00066 static int findXdndDropTransactionByWindow(Window window)
00067 {
00068     int at = -1;
00069     for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
00070         const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
00071         if (t.target == window || t.proxy_target == window) {
00072             at = i;
00073             break;
00074         }
00075     }
00076     return at;
00077 }
00078 
00079 static int findXdndDropTransactionByTime(Time timestamp)
00080 {
00081     int at = -1;
00082     for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
00083         const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
00084         if (t.timestamp == timestamp) {
00085             at = i;
00086             break;
00087         }
00088     }
00089     return at;
00090 }
00091 
00092 // timer used to discard old XdndDrop transactions
00093 static int transaction_expiry_timer = -1;
00094 enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds
00095 
00096 static void restartXdndDropExpiryTimer()
00097 {
00098     if (transaction_expiry_timer != -1)
00099         QDragManager::self()->killTimer(transaction_expiry_timer);
00100     transaction_expiry_timer = QDragManager::self()->startTimer(XdndDropTransactionTimeout);
00101 }
00102 
00103 
00104 // find an ancestor with XdndAware on it
00105 static Window findXdndAwareParent(Window window)
00106 {
00107     Window target = 0;
00108     forever {
00109         // check if window has XdndAware
00110         Atom type = 0;
00111         int f;
00112         unsigned long n, a;
00113         unsigned char *data = 0;
00114         if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False,
00115                                AnyPropertyType, &type, &f,&n,&a,&data) == Success) {
00116       if (data)
00117                 XFree(data);
00118       if (type) {
00119                 target = window;
00120                 break;
00121             }
00122         }
00123 
00124         // try window's parent
00125         Window root;
00126         Window parent;
00127         Window *children;
00128         uint unused;
00129         if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused))
00130             break;
00131         if (children)
00132             XFree(children);
00133         if (window == root)
00134             break;
00135         window = parent;
00136     }
00137     return target;
00138 }
00139 
00140 
00141 
00142 
00143 // and all this stuff is copied -into- qapp_x11.cpp
00144 
00145 static void handle_xdnd_position(QWidget *, const XEvent *, bool);
00146 static void handle_xdnd_status(QWidget * w, const XEvent * xe, bool /*passive*/);
00147 
00148 const int xdnd_version = 5;
00149 
00150 static Qt::DropAction xdndaction_to_qtaction(Atom atom)
00151 {
00152     if (atom == ATOM(XdndActionCopy) || atom == 0)
00153         return Qt::CopyAction;
00154     if (atom == ATOM(XdndActionLink))
00155         return Qt::LinkAction;
00156     if (atom == ATOM(XdndActionMove))
00157         return Qt::MoveAction;
00158     return Qt::CopyAction;
00159 }
00160 
00161 static int qtaction_to_xdndaction(Qt::DropAction a)
00162 {
00163     switch (a) {
00164     case Qt::CopyAction:
00165         return ATOM(XdndActionCopy);
00166     case Qt::LinkAction:
00167         return ATOM(XdndActionLink);
00168     case Qt::MoveAction:
00169     case Qt::TargetMoveAction:
00170         return ATOM(XdndActionMove);
00171     case Qt::IgnoreAction:
00172         return XNone;
00173     default:
00174         return ATOM(XdndActionCopy);
00175     }
00176 }
00177 
00178 // clean up the stuff used.
00179 static void qt_xdnd_cleanup();
00180 
00181 static void qt_xdnd_send_leave();
00182 
00183 // real variables:
00184 // xid of current drag source
00185 static Atom qt_xdnd_dragsource_xid = 0;
00186 
00187 // the types in this drop. 100 is no good, but at least it's big.
00188 const int qt_xdnd_max_type = 100;
00189 static Atom qt_xdnd_types[qt_xdnd_max_type + 1];
00190 
00191 // timer used when target wants "continuous" move messages (eg. scroll)
00192 static int heartbeat = -1;
00193 // rectangle in which the answer will be the same
00194 static QRect qt_xdnd_source_sameanswer;
00195 // top-level window we sent position to last.
00196 static Window qt_xdnd_current_target;
00197 // window to send events to (always valid if qt_xdnd_current_target)
00198 static Window qt_xdnd_current_proxy_target;
00199 static Time qt_xdnd_source_current_time;
00200 
00201 // widget we forwarded position to last, and local position
00202 static QPointer<QWidget> qt_xdnd_current_widget;
00203 static QPoint qt_xdnd_current_position;
00204 // timestamp from the XdndPosition and XdndDrop
00205 static Time qt_xdnd_target_current_time;
00206 // screen number containing the pointer... -1 means default
00207 static int qt_xdnd_current_screen = -1;
00208 // state of dragging... true if dragging, false if not
00209 bool qt_xdnd_dragging = false;
00210 
00211 static bool waiting_for_status = false;
00212 
00213 // used to preset each new QDragMoveEvent
00214 static Qt::DropAction last_target_accepted_action = Qt::IgnoreAction;
00215 
00216 // Shift/Ctrl handling, and final drop status
00217 static Qt::DropAction global_accepted_action = Qt::CopyAction;
00218 static Qt::DropActions possible_actions = Qt::IgnoreAction;
00219 
00220 // for embedding only
00221 static QWidget* current_embedding_widget  = 0;
00222 static XEvent last_enter_event;
00223 
00224 // cursors
00225 static QCursor *noDropCursor = 0;
00226 static QCursor *moveCursor = 0;
00227 static QCursor *copyCursor = 0;
00228 static QCursor *linkCursor = 0;
00229 
00230 static QPixmap *defaultPm = 0;
00231 
00232 static const int default_pm_hotx = -2;
00233 static const int default_pm_hoty = -16;
00234 static const char* const default_pm[] = {
00235 "13 9 3 1",
00236 ".      c None",
00237 "       c #000000",
00238 "X      c #FFFFFF",
00239 "X X X X X X X",
00240 " X X X X X X ",
00241 "X ......... X",
00242 " X.........X ",
00243 "X ......... X",
00244 " X.........X ",
00245 "X ......... X",
00246 " X X X X X X ",
00247 "X X X X X X X"
00248 };
00249 
00250 class QShapedPixmapWidget : public QWidget {
00251 
00252 public:
00253     QShapedPixmapWidget(int screen = -1) :
00254         QWidget(QApplication::desktop()->screen(screen),
00255                 Qt::Tool | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint)
00256     {
00257     }
00258 
00259     void setPixmap(const QPixmap &pm)
00260     {
00261         QBitmap mask = pm.mask();
00262         if (!mask.isNull()) {
00263             setMask(mask);
00264         } else {
00265             clearMask();
00266         }
00267         resize(pm.width(),pm.height());
00268   QPalette p = palette();
00269   p.setBrush(backgroundRole(), QBrush(pm));
00270   setPalette(p);
00271         update();
00272     }
00273     QPoint pm_hot;
00274 };
00275 
00276 struct XdndData {
00277     QShapedPixmapWidget *deco;
00278     QWidget* desktop_proxy;
00279 };
00280 
00281 static XdndData xdnd_data = { 0, 0 };
00282 
00283 class QExtraWidget : public QWidget
00284 {
00285     Q_DECLARE_PRIVATE(QWidget)
00286 public:
00287     inline QWExtra* extraData();
00288     inline QTLWExtra* topData();
00289 };
00290 
00291 inline QWExtra* QExtraWidget::extraData() { return d_func()->extraData(); }
00292 inline QTLWExtra* QExtraWidget::topData() { return d_func()->topData(); }
00293 
00294 
00295 static WId xdndProxy(WId w)
00296 {
00297     Atom type = XNone;
00298     int f;
00299     unsigned long n, a;
00300     WId *proxy_id_ptr;
00301     XGetWindowProperty(X11->display, w, ATOM(XdndProxy), 0, 1, False,
00302                        XA_WINDOW, &type, &f,&n,&a,(uchar**)&proxy_id_ptr);
00303     WId proxy_id = 0;
00304     if (type == XA_WINDOW && proxy_id_ptr) {
00305         proxy_id = *proxy_id_ptr;
00306         XFree(proxy_id_ptr);
00307         proxy_id_ptr = 0;
00308         // Already exists. Real?
00309         X11->ignoreBadwindow();
00310         XGetWindowProperty(X11->display, proxy_id, ATOM(XdndProxy), 0, 1, False,
00311                            XA_WINDOW, &type, &f,&n,&a,(uchar**)&proxy_id_ptr);
00312         if (X11->badwindow() || type != XA_WINDOW || !proxy_id_ptr || *proxy_id_ptr != proxy_id)
00313             // Bogus - we will overwrite.
00314             proxy_id = 0;
00315     }
00316     if (proxy_id_ptr)
00317         XFree(proxy_id_ptr);
00318     return proxy_id;
00319 }
00320 
00321 static bool xdndEnable(QWidget* w, bool on)
00322 {
00323     DNDDEBUG << "xdndEnable" << w << on;
00324     if (on) {
00325         QWidget * xdnd_widget = 0;
00326         if ((w->windowType() == Qt::Desktop)) {
00327             if (xdnd_data.desktop_proxy) // *WE* already have one.
00328                 return false;
00329 
00330             // As per Xdnd4, use XdndProxy
00331             XGrabServer(X11->display);
00332             Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
00333             WId proxy_id = xdndProxy(w->internalWinId());
00334 
00335             if (!proxy_id) {
00336                 xdnd_widget = xdnd_data.desktop_proxy = new QWidget;
00337                 proxy_id = xdnd_data.desktop_proxy->internalWinId();
00338                 XChangeProperty (X11->display, w->internalWinId(), ATOM(XdndProxy),
00339                                  XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
00340                 XChangeProperty (X11->display, proxy_id, ATOM(XdndProxy),
00341                                  XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
00342             }
00343 
00344             XUngrabServer(X11->display);
00345         } else {
00346             xdnd_widget = w->window();
00347         }
00348         if (xdnd_widget) {
00349             DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->internalWinId();
00350             Atom atm = (Atom)xdnd_version;
00351             Q_ASSERT(xdnd_widget->testAttribute(Qt::WA_WState_Created));
00352             XChangeProperty(X11->display, xdnd_widget->internalWinId(), ATOM(XdndAware),
00353                              XA_ATOM, 32, PropModeReplace, (unsigned char *)&atm, 1);
00354             return true;
00355         } else {
00356             return false;
00357         }
00358     } else {
00359         if ((w->windowType() == Qt::Desktop)) {
00360             XDeleteProperty(X11->display, w->internalWinId(), ATOM(XdndProxy));
00361             delete xdnd_data.desktop_proxy;
00362             xdnd_data.desktop_proxy = 0;
00363         } else {
00364             DNDDEBUG << "not deleting XDndAware";
00365         }
00366         return true;
00367     }
00368 }
00369 
00370 QByteArray QX11Data::xdndAtomToString(Atom a)
00371 {
00372     if (!a) return 0;
00373 
00374     if (a == XA_STRING || a == ATOM(UTF8_STRING)) {
00375         return "text/plain"; // some Xdnd clients are dumb
00376     }
00377     char *atom = XGetAtomName(display, a);
00378     QByteArray result = atom;
00379     XFree(atom);
00380     return result;
00381 }
00382 
00383 Atom QX11Data::xdndStringToAtom(const char *mimeType)
00384 {
00385     if (!mimeType || !*mimeType)
00386         return 0;
00387     return XInternAtom(display, mimeType, False);
00388 }
00389 
00390 //$$$
00391 QString QX11Data::xdndMimeAtomToString(Atom a)
00392 {
00393     QString atomName;
00394     if (a) {
00395         char *atom = XGetAtomName(display, a);
00396         atomName = QString::fromLatin1(atom);
00397         XFree(atom);
00398     }
00399     return atomName;
00400 }
00401 
00402 //$$$
00403 Atom QX11Data::xdndMimeStringToAtom(const QString &mimeType)
00404 {
00405     if (mimeType.isEmpty())
00406         return 0;
00407     return XInternAtom(display, mimeType.toLatin1().constData(), False);
00408 }
00409 
00410 //$$$ replace ccxdndAtomToString()
00411 QStringList QX11Data::xdndMimeFormatsForAtom(Atom a)
00412 {
00413     QStringList formats;
00414     if (a) {
00415         QString atomName = xdndMimeAtomToString(a);
00416         formats.append(atomName);
00417 
00418         // special cases for string type
00419         if (a == ATOM(UTF8_STRING) || a == XA_STRING
00420             || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
00421             formats.append(QLatin1String("text/plain"));
00422 
00423         // special cases for uris
00424         if (atomName == QLatin1String("text/x-moz-url"))
00425             formats.append(QLatin1String("text/uri-list"));
00426 
00427         // special case for images
00428         if (a == XA_PIXMAP)
00429             formats.append(QLatin1String("image/ppm"));
00430     }
00431     return formats;
00432 }
00433 
00434 //$$$
00435 bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat)
00436 {
00437     bool ret = false;
00438     *atomFormat = a;
00439     *dataFormat = 8;
00440     QString atomName = xdndMimeAtomToString(a);
00441     if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) {
00442         *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
00443         if (atomName == QLatin1String("application/x-color"))
00444             *dataFormat = 16;
00445         ret = true;
00446     } else {
00447         if ((a == ATOM(UTF8_STRING) || a == XA_STRING
00448             || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
00449             && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) {
00450             if (a == ATOM(UTF8_STRING)){
00451                 *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData);
00452                 ret = true;
00453             } else if (a == XA_STRING) {
00454                 *data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
00455                         QLatin1String("text/plain"), mimeData)).toLocal8Bit();
00456                 ret = true;
00457             } else if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT)) {
00458                 // the ICCCM states that TEXT and COMPOUND_TEXT are in the
00459                 // encoding of choice, so we choose the encoding of the locale
00460                 QByteArray strData = QString::fromUtf8(QInternalMimeData::renderDataHelper(
00461                                      QLatin1String("text/plain"), mimeData)).toLocal8Bit();
00462                 char *list[] = { strData.data(), NULL };
00463 
00464                 XICCEncodingStyle style = (a == ATOM(COMPOUND_TEXT))
00465                                         ? XCompoundTextStyle : XStdICCTextStyle;
00466                 XTextProperty textprop;
00467                 if (list[0] != NULL
00468                     && XmbTextListToTextProperty(X11->display, list, 1, style,
00469                                                  &textprop) == Success) {
00470                     *atomFormat = textprop.encoding;
00471                     *dataFormat = textprop.format;
00472                     *data = QByteArray((const char *) textprop.value, textprop.nitems * textprop.format / 8);
00473 
00474                     DEBUG("    textprop type %lx\n"
00475                     "    textprop name '%s'\n"
00476                     "    format %d\n"
00477                     "    %ld items\n"
00478                     "    %d bytes\n",
00479                     textprop.encoding,
00480                     X11->xdndMimeAtomToString(textprop.encoding).toLatin1().data(),
00481                     textprop.format, textprop.nitems, data->size());
00482 
00483                     XFree(textprop.value);
00484                 }
00485             }
00486         } else if (atomName == QLatin1String("text/x-moz-url") &&
00487                    QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) {
00488             QByteArray uri = QInternalMimeData::renderDataHelper(
00489                              QLatin1String("text/uri-list"), mimeData).split('\n').first();
00490             QString mozUri = QString::fromLatin1(uri, uri.size());
00491             mozUri += QLatin1Char('\n');
00492             *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2);
00493             ret = true;
00494         } else if ((a == XA_PIXMAP || a == XA_BITMAP) && mimeData->hasImage()) {
00495             QPixmap pm = qvariant_cast<QPixmap>(mimeData->imageData());
00496             if (a == XA_BITMAP && pm.depth() != 1) {
00497                 QImage img = pm.toImage();
00498                 img = img.convertToFormat(QImage::Format_MonoLSB);
00499                 pm = QPixmap::fromImage(img);
00500             }
00501             QDragManager *dm = QDragManager::self();
00502             if (dm) {
00503                 Pixmap handle = pm.handle();
00504                 *data = QByteArray((const char *) &handle, sizeof(Pixmap));
00505                 dm->xdndMimeTransferedPixmap[dm->xdndMimeTransferedPixmapIndex] = pm;
00506                 dm->xdndMimeTransferedPixmapIndex =
00507                             (dm->xdndMimeTransferedPixmapIndex + 1) % 2;
00508             }
00509         }
00510     }
00511     return data;
00512 }
00513 
00514 //$$$
00515 QList<Atom> QX11Data::xdndMimeAtomsForFormat(const QString &format)
00516 {
00517     QList<Atom> atoms;
00518     atoms.append(xdndMimeStringToAtom(format));
00519 
00520     // special cases for strings
00521     if (format == QLatin1String("text/plain")) {
00522         atoms.append(ATOM(UTF8_STRING));
00523         atoms.append(XA_STRING);
00524         atoms.append(ATOM(TEXT));
00525         atoms.append(ATOM(COMPOUND_TEXT));
00526     }
00527 
00528     // special cases for uris
00529     if (format == QLatin1String("text/uri-list")) {
00530         atoms.append(xdndMimeStringToAtom(QLatin1String("text/x-moz-url")));
00531     }
00532 
00533     //special cases for images
00534     if (format == QLatin1String("image/ppm"))
00535         atoms.append(XA_PIXMAP);
00536     if (format == QLatin1String("image/pbm"))
00537         atoms.append(XA_BITMAP);
00538 
00539     return atoms;
00540 }
00541 
00542 //$$$
00543 QByteArray QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const QString &format)
00544 {
00545     QString atomName = xdndMimeAtomToString(a);
00546     if (atomName == format)
00547         return data;
00548 
00549     // special cases for string types
00550     if (format == QLatin1String("text/plain")) {
00551         if (a == ATOM(UTF8_STRING))
00552             return data;
00553         if (a == XA_STRING)
00554             return QString::fromLatin1(data).toUtf8();
00555         if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
00556             // #### might be wrong for COMPUND_TEXT
00557             return QString::fromLocal8Bit(data, data.size()).toUtf8();
00558     }
00559 
00560     // special case for uri types
00561     if (format == QLatin1String("text/uri-list")) {
00562         if (atomName == QLatin1String("text/x-moz-url")) {
00563             // we expect this as utf16 <url><space><title>
00564             // the first part is a url that should only contain ascci char
00565             // so it should be safe to check that the second char is 0
00566             // to verify that it is utf16
00567             if (data.size() > 1 && data.at(1) == 0)
00568                 return QString::fromUtf16(reinterpret_cast<const ushort *>(data.constData()),
00569                                 data.size() / 2).split(QLatin1Char('\n')).first().toLatin1();
00570         }
00571     }
00572 
00573     // special cas for images
00574     if (format == QLatin1String("image/ppm")) {
00575         if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) {
00576             Pixmap xpm = *((Pixmap*)data.data());
00577             Display *dpy = display;
00578             Window r;
00579             int x,y;
00580             uint w,h,bw,d;
00581             if (!xpm)
00582                 return QByteArray();
00583             XGetGeometry(dpy,xpm, &r,&x,&y,&w,&h,&bw,&d);
00584             QImageWriter imageWriter;
00585             GC gc = XCreateGC(dpy, xpm, 0, 0);
00586             QImage imageToWrite;
00587             if (d == 1) {
00588                 QBitmap qbm(w,h);
00589                 XCopyArea(dpy,xpm,qbm.handle(),gc,0,0,w,h,0,0);
00590                 imageWriter.setFormat("PBMRAW");
00591                 imageToWrite = qbm.toImage();
00592             } else {
00593                 QPixmap qpm(w,h);
00594                 XCopyArea(dpy,xpm,qpm.handle(),gc,0,0,w,h,0,0);
00595                 imageWriter.setFormat("PPMRAW");
00596                 imageToWrite = qpm.toImage();
00597             }
00598             XFreeGC(dpy,gc);
00599             QBuffer buf;
00600             buf.open(QIODevice::WriteOnly);
00601             imageWriter.setDevice(&buf);
00602             imageWriter.write(imageToWrite);
00603             return buf.buffer();
00604         }
00605     }
00606     return QByteArray();
00607 }
00608 
00609 //$$$ middle of xdndObtainData
00610 Atom QX11Data::xdndMimeAtomForFormat(const QString &format, const QList<Atom> &atoms)
00611 {
00612     Atom a = xdndMimeStringToAtom(format);
00613     if (a && atoms.contains(a))
00614         return a;
00615 
00616     // find matches for string types
00617     if (format == QLatin1String("text/plain")) {
00618         if (atoms.contains(ATOM(UTF8_STRING)))
00619             return ATOM(UTF8_STRING);
00620         if (atoms.contains(ATOM(COMPOUND_TEXT)))
00621             return XA_STRING;
00622         if (atoms.contains(ATOM(TEXT)))
00623             return XA_STRING;
00624         if (atoms.contains(XA_STRING))
00625             return XA_STRING;
00626     }
00627 
00628     // find mathes for uri types
00629     if (format == QLatin1String("text/uri-list")) {
00630         Atom a = xdndMimeStringToAtom(QLatin1String("text/x-moz-url"));
00631         if (a && atoms.contains(a))
00632             return a;
00633     }
00634 
00635     // find match for image
00636     if (format == QLatin1String("image/ppm")) {
00637         if (atoms.contains(XA_PIXMAP))
00638             return XA_PIXMAP;
00639     }
00640 
00641     return 0;
00642 }
00643 
00644 void QX11Data::xdndSetup() {
00645     QCursorData::initialize();
00646     qAddPostRoutine(qt_xdnd_cleanup);
00647 }
00648 
00649 
00650 void qt_xdnd_cleanup()
00651 {
00652     delete noDropCursor;
00653     noDropCursor = 0;
00654     delete copyCursor;
00655     copyCursor = 0;
00656     delete moveCursor;
00657     moveCursor = 0;
00658     delete linkCursor;
00659     linkCursor = 0;
00660     delete defaultPm;
00661     defaultPm = 0;
00662     delete xdnd_data.desktop_proxy;
00663     xdnd_data.desktop_proxy = 0;
00664     delete xdnd_data.deco;
00665     xdnd_data.deco = 0;
00666 }
00667 
00668 
00669 static QWidget *find_child(QWidget *tlw, QPoint & p)
00670 {
00671     QWidget *widget = tlw;
00672 
00673     p = widget->mapFromGlobal(p);
00674     bool done = false;
00675     while (!done) {
00676         done = true;
00677         if (((QExtraWidget*)widget)->extraData() &&
00678              ((QExtraWidget*)widget)->extraData()->xDndProxy != 0)
00679             break; // stop searching for widgets under the mouse cursor if found widget is a proxy.
00680         QObjectList children = widget->children();
00681         if (!children.isEmpty()) {
00682             for(int i = children.size(); i > 0;) {
00683                 --i;
00684                 QWidget *w = qobject_cast<QWidget *>(children.at(i));
00685                 if (!w)
00686                     continue;
00687                 if (w->isVisible() &&
00688                      w->geometry().contains(p) &&
00689                      !w->isWindow()) {
00690                     widget = w;
00691                     done = false;
00692                     p = widget->mapFromParent(p);
00693                     break;
00694                 }
00695             }
00696         }
00697     }
00698     return widget;
00699 }
00700 
00701 
00702 static bool checkEmbedded(QWidget* w, const XEvent* xe)
00703 {
00704     if (!w)
00705         return false;
00706 
00707     if (current_embedding_widget != 0 && current_embedding_widget != w) {
00708         qt_xdnd_current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy;
00709         qt_xdnd_current_proxy_target = qt_xdnd_current_target;
00710         qt_xdnd_send_leave();
00711         qt_xdnd_current_target = 0;
00712         qt_xdnd_current_proxy_target = 0;
00713         current_embedding_widget = 0;
00714     }
00715 
00716     QWExtra* extra = ((QExtraWidget*)w)->extraData();
00717     if (extra && extra->xDndProxy != 0) {
00718 
00719         if (current_embedding_widget != w) {
00720 
00721             last_enter_event.xany.window = extra->xDndProxy;
00722             XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event);
00723             current_embedding_widget = w;
00724         }
00725 
00726         ((XEvent*)xe)->xany.window = extra->xDndProxy;
00727         XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe);
00728         if (qt_xdnd_current_widget != w) {
00729             qt_xdnd_current_widget = w;
00730         }
00731         return true;
00732     }
00733     current_embedding_widget = 0;
00734     return false;
00735 }
00736 
00737 void QX11Data::xdndHandleEnter(QWidget *, const XEvent * xe, bool /*passive*/)
00738 {
00739     motifdnd_active = false;
00740 
00741     last_enter_event.xclient = xe->xclient;
00742 
00743     const long *l = xe->xclient.data.l;
00744     int version = (int)(((unsigned long)(l[1])) >> 24);
00745 
00746     if (version > xdnd_version)
00747         return;
00748 
00749     qt_xdnd_dragsource_xid = l[0];
00750 
00751     int j = 0;
00752     if (l[1] & 1) {
00753         // get the types from XdndTypeList
00754         Atom   type = XNone;
00755         int f;
00756         unsigned long n, a;
00757         Atom *data;
00758         XGetWindowProperty(X11->display, qt_xdnd_dragsource_xid, ATOM(XdndTypelist), 0,
00759                            qt_xdnd_max_type, False, XA_ATOM, &type, &f,&n,&a,(uchar**)&data);
00760         for (; j<qt_xdnd_max_type && j < (int)n; j++) {
00761             qt_xdnd_types[j] = data[j];
00762         }
00763         if (data)
00764             XFree((uchar*)data);
00765     } else {
00766         // get the types from the message
00767         int i;
00768         for(i=2; i < 5; i++) {
00769             qt_xdnd_types[j++] = l[i];
00770         }
00771     }
00772     qt_xdnd_types[j] = 0;
00773 }
00774 
00775 static void handle_xdnd_position(QWidget *w, const XEvent * xe, bool passive)
00776 {
00777     const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
00778 
00779     QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
00780     QWidget * c = find_child(w, p); // changes p to to c-local coordinates
00781 
00782     if (!passive && checkEmbedded(c, xe))
00783         return;
00784 
00785     if (!c || !c->acceptDrops() && (c->windowType() == Qt::Desktop))
00786         return;
00787 
00788     if (l[0] != qt_xdnd_dragsource_xid) {
00789         DEBUG("xdnd drag position from unexpected source (%08lx not %08lx)", l[0], qt_xdnd_dragsource_xid);
00790         return;
00791     }
00792 
00793     if (l[3] != 0) {
00794         // timestamp from the source
00795         qt_xdnd_target_current_time = X11->userTime = l[3];
00796     }
00797 
00798     QDragManager *manager = QDragManager::self();
00799     QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
00800 
00801     XClientMessageEvent response;
00802     response.type = ClientMessage;
00803     response.window = qt_xdnd_dragsource_xid;
00804     response.format = 32;
00805     response.message_type = ATOM(XdndStatus);
00806     response.data.l[0] = w->internalWinId();
00807     response.data.l[1] = 0; // flags
00808     response.data.l[2] = 0; // x, y
00809     response.data.l[3] = 0; // w, h
00810     response.data.l[4] = 0; // action
00811 
00812     if (!passive) { // otherwise just reject
00813         while (c && !c->acceptDrops() && !c->isWindow()) {
00814             p = c->mapToParent(p);
00815             c = c->parentWidget();
00816         }
00817         QWidget *target_widget = c && c->acceptDrops() ? c : 0;
00818 
00819         QRect answerRect(c->mapToGlobal(p), QSize(1,1));
00820 
00821         if (manager->object) {
00822             possible_actions = manager->dragPrivate()->possible_actions;
00823         } else {
00824             possible_actions = Qt::DropActions(xdndaction_to_qtaction(l[4]));
00825 //             possible_actions |= Qt::CopyAction;
00826         }
00827         QDragMoveEvent me(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
00828 
00829         Qt::DropAction accepted_action = Qt::IgnoreAction;
00830 
00831 
00832         if (target_widget != qt_xdnd_current_widget) {
00833             if (qt_xdnd_current_widget) {
00834                 QDragLeaveEvent e;
00835                 QApplication::sendEvent(qt_xdnd_current_widget, &e);
00836             }
00837             if (qt_xdnd_current_widget != target_widget) {
00838                 qt_xdnd_current_widget = target_widget;
00839             }
00840             if (target_widget) {
00841                 qt_xdnd_current_position = p;
00842 
00843                 last_target_accepted_action = Qt::IgnoreAction;
00844                 QDragEnterEvent de(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
00845                 QApplication::sendEvent(target_widget, &de);
00846                 if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction)
00847                     last_target_accepted_action = de.dropAction();
00848             }
00849         }
00850 
00851         DEBUG() << "qt_handle_xdnd_position action=" << X11->xdndAtomToString(l[4]);
00852         if (!target_widget) {
00853             answerRect = QRect(p, QSize(1, 1));
00854         } else {
00855             qt_xdnd_current_widget = c;
00856             qt_xdnd_current_position = p;
00857 
00858             if (last_target_accepted_action != Qt::IgnoreAction) {
00859                 me.setDropAction(last_target_accepted_action);
00860                 me.accept();
00861             }
00862             QApplication::sendEvent(c, &me);
00863             if (me.isAccepted()) {
00864                 response.data.l[1] = 1; // yes
00865                 accepted_action = me.dropAction();
00866                 last_target_accepted_action = accepted_action;
00867             } else {
00868                 response.data.l[0] = 0;
00869                 last_target_accepted_action = Qt::IgnoreAction;
00870             }
00871             answerRect = me.answerRect().intersected(c->rect());
00872         }
00873         answerRect = QRect(c->mapToGlobal(answerRect.topLeft()), answerRect.size());
00874 
00875         if (answerRect.left() < 0)
00876             answerRect.setLeft(0);
00877         if (answerRect.right() > 4096)
00878             answerRect.setRight(4096);
00879         if (answerRect.top() < 0)
00880             answerRect.setTop(0);
00881         if (answerRect.bottom() > 4096)
00882             answerRect.setBottom(4096);
00883         if (answerRect.width() < 0)
00884             answerRect.setWidth(0);
00885         if (answerRect.height() < 0)
00886             answerRect.setHeight(0);
00887 
00888         response.data.l[2] = (answerRect.x() << 16) + answerRect.y();
00889         response.data.l[3] = (answerRect.width() << 16) + answerRect.height();
00890         response.data.l[4] = qtaction_to_xdndaction(accepted_action);
00891     }
00892 
00893     // reset
00894     qt_xdnd_target_current_time = CurrentTime;
00895 
00896     QWidget * source = QWidget::find(qt_xdnd_dragsource_xid);
00897     if (source && (source->windowType() == Qt::Desktop) && !source->acceptDrops())
00898         source = 0;
00899 
00900     DEBUG() << "sending XdndStatus";
00901     if (source)
00902         handle_xdnd_status(source, (const XEvent *)&response, passive);
00903     else
00904         XSendEvent(X11->display, qt_xdnd_dragsource_xid, False, NoEventMask, (XEvent*)&response);
00905 }
00906 
00907 static Bool xdnd_position_scanner(Display *, XEvent *event, XPointer)
00908 {
00909     if (event->type != ClientMessage)
00910         return false;
00911     XClientMessageEvent *ev = &event->xclient;
00912 
00913     if (ev->message_type == ATOM(XdndPosition))
00914         return true;
00915 
00916     return false;
00917 }
00918 
00919 void QX11Data::xdndHandlePosition(QWidget * w, const XEvent * xe, bool passive)
00920 {
00921     DEBUG("xdndHandlePosition");
00922     while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_position_scanner, 0))
00923         ;
00924 
00925     handle_xdnd_position(w, xe, passive);
00926 }
00927 
00928 
00929 static void handle_xdnd_status(QWidget *, const XEvent * xe, bool)
00930 {
00931     const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
00932     // ignore late status messages
00933     if (l[0] && l[0] != qt_xdnd_current_proxy_target)
00934         return;
00935     Qt::DropAction newAction = (l[1] & 0x1) ? xdndaction_to_qtaction(l[4]) : Qt::IgnoreAction;
00936 
00937     if ((int)(l[1] & 2) == 0) {
00938         QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
00939         QSize s((l[3] & 0xffff0000) >> 16, l[3] & 0x0000ffff);
00940         qt_xdnd_source_sameanswer = QRect(p, s);
00941     } else {
00942         qt_xdnd_source_sameanswer = QRect();
00943     }
00944     QDragManager *manager = QDragManager::self();
00945     manager->willDrop = (l[1] & 0x1);
00946     if (global_accepted_action != newAction)
00947         manager->emitActionChanged(newAction);
00948     global_accepted_action = newAction;
00949     manager->updateCursor();
00950     waiting_for_status = false;
00951 }
00952 
00953 static Bool xdnd_status_scanner(Display *, XEvent *event, XPointer)
00954 {
00955     if (event->type != ClientMessage)
00956         return false;
00957     XClientMessageEvent *ev = &event->xclient;
00958 
00959     if (ev->message_type == ATOM(XdndStatus))
00960         return true;
00961 
00962     return false;
00963 }
00964 
00965 void QX11Data::xdndHandleStatus(QWidget * w, const XEvent * xe, bool passive)
00966 {
00967     DEBUG("xdndHandleStatus");
00968     while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_status_scanner, 0))
00969         ;
00970 
00971     handle_xdnd_status(w, xe, passive);
00972     DEBUG("xdndHandleStatus end");
00973 }
00974 
00975 void QX11Data::xdndHandleLeave(QWidget *w, const XEvent * xe, bool /*passive*/)
00976 {
00977     DEBUG("xdnd leave");
00978     if (!qt_xdnd_current_widget ||
00979          w->window() != qt_xdnd_current_widget->window()) {
00980         return; // sanity
00981     }
00982 
00983     if (checkEmbedded(current_embedding_widget, xe)) {
00984         current_embedding_widget = 0;
00985         qt_xdnd_current_widget = 0;
00986         return;
00987     }
00988 
00989     const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
00990 
00991     QDragLeaveEvent e;
00992     QApplication::sendEvent(qt_xdnd_current_widget, &e);
00993 
00994     if (l[0] != qt_xdnd_dragsource_xid) {
00995         // This often happens - leave other-process window quickly
00996         DEBUG("xdnd drag leave from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
00997         qt_xdnd_current_widget = 0;
00998         return;
00999     }
01000 
01001     qt_xdnd_dragsource_xid = 0;
01002     qt_xdnd_types[0] = 0;
01003     qt_xdnd_current_widget = 0;
01004 }
01005 
01006 
01007 void qt_xdnd_send_leave()
01008 {
01009     if (!qt_xdnd_current_target)
01010         return;
01011 
01012     XClientMessageEvent leave;
01013     leave.type = ClientMessage;
01014     leave.window = qt_xdnd_current_target;
01015     leave.format = 32;
01016     leave.message_type = ATOM(XdndLeave);
01017     leave.data.l[0] = qt_xdnd_dragsource_xid;
01018     leave.data.l[1] = 0; // flags
01019     leave.data.l[2] = 0; // x, y
01020     leave.data.l[3] = 0; // w, h
01021     leave.data.l[4] = 0; // just null
01022 
01023     QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
01024 
01025     if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
01026         w = 0;
01027 
01028     if (w)
01029         X11->xdndHandleLeave(w, (const XEvent *)&leave, false);
01030     else
01031         XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
01032                     NoEventMask, (XEvent*)&leave);
01033     // reset the drag manager state
01034     QDragManager *manager = QDragManager::self();
01035     manager->willDrop = false;
01036     if (global_accepted_action != Qt::IgnoreAction)
01037         manager->emitActionChanged(Qt::IgnoreAction);
01038     global_accepted_action = Qt::IgnoreAction;
01039     manager->updateCursor();
01040     qt_xdnd_current_target = 0;
01041     qt_xdnd_current_proxy_target = 0;
01042     qt_xdnd_source_current_time = 0;
01043     waiting_for_status = false;
01044 }
01045 
01046 
01047 
01048 void QX11Data::xdndHandleDrop(QWidget *, const XEvent * xe, bool passive)
01049 {
01050     DEBUG("xdndHandleDrop");
01051     if (!qt_xdnd_current_widget) {
01052         qt_xdnd_dragsource_xid = 0;
01053         return; // sanity
01054     }
01055 
01056     if (!passive && checkEmbedded(qt_xdnd_current_widget, xe)){
01057         current_embedding_widget = 0;
01058         qt_xdnd_dragsource_xid = 0;
01059         qt_xdnd_current_widget = 0;
01060         return;
01061     }
01062     const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
01063 
01064     QDragManager *manager = QDragManager::self();
01065     DEBUG("xdnd drop");
01066 
01067     if (l[0] != qt_xdnd_dragsource_xid) {
01068         DEBUG("xdnd drop from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
01069         return;
01070     }
01071 
01072     if (l[2] != 0) {
01073         // update the "user time" from the timestamp in the event.
01074         qt_xdnd_target_current_time = X11->userTime = l[2];
01075     }
01076 
01077     if (!passive) {
01078         QMimeData *dropData = (manager->object) ? manager->dragPrivate()->data : manager->dropData;
01079         QDropEvent de(qt_xdnd_current_position, possible_actions, dropData,
01080                       QApplication::mouseButtons(), QApplication::keyboardModifiers());
01081         QApplication::sendEvent(qt_xdnd_current_widget, &de);
01082         if (!de.isAccepted()) {
01083             // Ignore a failed drag
01084             global_accepted_action = Qt::IgnoreAction;
01085         } else {
01086             global_accepted_action = de.dropAction();
01087         }
01088         XClientMessageEvent finished;
01089         finished.type = ClientMessage;
01090         finished.window = qt_xdnd_dragsource_xid;
01091         finished.format = 32;
01092         finished.message_type = ATOM(XdndFinished);
01093         DNDDEBUG << "xdndHandleDrop"
01094              << "qt_xdnd_current_widget" << qt_xdnd_current_widget
01095              << (qt_xdnd_current_widget ? qt_xdnd_current_widget->internalWinId() : 0)
01096              << "t_xdnd_current_widget->window()"
01097              << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window() : 0)
01098              << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window()->internalWinId() : 0);
01099         finished.data.l[0] = qt_xdnd_current_widget?qt_xdnd_current_widget->window()->internalWinId():0;
01100         finished.data.l[1] = de.isAccepted() ? 1 : 0; // flags
01101         finished.data.l[2] = qtaction_to_xdndaction(global_accepted_action);
01102         XSendEvent(X11->display, qt_xdnd_dragsource_xid, False,
01103                     NoEventMask, (XEvent*)&finished);
01104     } else {
01105         QDragLeaveEvent e;
01106         QApplication::sendEvent(qt_xdnd_current_widget, &e);
01107     }
01108     qt_xdnd_dragsource_xid = 0;
01109     qt_xdnd_current_widget = 0;
01110     waiting_for_status = false;
01111 
01112     // reset
01113     qt_xdnd_target_current_time = CurrentTime;
01114 }
01115 
01116 
01117 void QX11Data::xdndHandleFinished(QWidget *, const XEvent * xe, bool passive)
01118 {
01119     DEBUG("xdndHandleFinished");
01120     const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
01121 
01122     DNDDEBUG << "xdndHandleFinished, l[0]" << l[0]
01123              << "qt_xdnd_current_target" << qt_xdnd_current_target
01124              << "qt_xdnd_current_proxy_targe" << qt_xdnd_current_proxy_target;
01125 
01126     if (l[0]) {
01127         int at = findXdndDropTransactionByWindow(l[0]);
01128         if (at != -1) {
01129             restartXdndDropExpiryTimer();
01130 
01131             QXdndDropTransaction t = X11->dndDropTransactions.takeAt(at);
01132             QDragManager *manager = QDragManager::self();
01133 
01134             Window target = qt_xdnd_current_target;
01135             Window proxy_target = qt_xdnd_current_proxy_target;
01136             QWidget *embedding_widget = current_embedding_widget;
01137             QDrag *currentObject = manager->object;
01138 
01139             qt_xdnd_current_target = t.target;
01140             qt_xdnd_current_proxy_target = t.proxy_target;
01141             current_embedding_widget = t.embedding_widget;
01142             manager->object = t.object;
01143 
01144             if (!passive)
01145                 (void) checkEmbedded(qt_xdnd_current_widget, xe);
01146 
01147             current_embedding_widget = 0;
01148             qt_xdnd_current_target = 0;
01149             qt_xdnd_current_proxy_target = 0;
01150 
01151             if (t.object)
01152                 t.object->deleteLater();
01153 
01154             qt_xdnd_current_target = target;
01155             qt_xdnd_current_proxy_target = proxy_target;
01156             current_embedding_widget = embedding_widget;
01157             manager->object = currentObject;
01158         }
01159     }
01160     waiting_for_status = false;
01161 }
01162 
01163 
01164 void QDragManager::timerEvent(QTimerEvent* e)
01165 {
01166     if (e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull()) {
01167         move(QCursor::pos());
01168     } else if (e->timerId() == transaction_expiry_timer) {
01169         for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
01170             const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
01171             if (t.targetWidget) {
01172                 // dnd within the same process, don't delete these
01173                 continue;
01174             }
01175             t.object->deleteLater();
01176             X11->dndDropTransactions.removeAt(i--);
01177         }
01178 
01179         killTimer(transaction_expiry_timer);
01180         transaction_expiry_timer = -1;
01181     }
01182 }
01183 
01184 bool QDragManager::eventFilter(QObject * o, QEvent * e)
01185 {
01186     if (beingCancelled) {
01187         if (e->type() == QEvent::KeyRelease && ((QKeyEvent*)e)->key() == Qt::Key_Escape) {
01188             qApp->removeEventFilter(this);
01189             Q_ASSERT(object == 0);
01190             beingCancelled = false;
01191             eventLoop->exit();
01192             return true; // block the key release
01193         }
01194         return false;
01195     }
01196 
01197     Q_ASSERT(object != 0);
01198 
01199     if (!o->isWidgetType())
01200         return false;
01201 
01202     if (e->type() == QEvent::MouseMove) {
01203         QMouseEvent* me = (QMouseEvent *)e;
01204         move(me->globalPos());
01205         return true;
01206     } else if (e->type() == QEvent::MouseButtonRelease) {
01207         DEBUG("pre drop");
01208         qApp->removeEventFilter(this);
01209         if (willDrop)
01210             drop();
01211         else
01212             cancel();
01213         DEBUG("drop, resetting object");
01214         beingCancelled = false;
01215         eventLoop->exit();
01216         return true;
01217     }
01218 
01219     if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
01220         QKeyEvent *ke = ((QKeyEvent*)e);
01221         if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
01222             cancel();
01223             qApp->removeEventFilter(this);
01224             beingCancelled = false;
01225             eventLoop->exit();
01226         } else {
01227             qt_xdnd_source_sameanswer = QRect(); // force move
01228             move(QCursor::pos());
01229         }
01230         return true; // Eat all key events
01231     }
01232 
01233     // ### We bind modality to widgets, so we have to do this
01234     // ###  "manually".
01235     // DnD is modal - eat all other interactive events
01236     switch (e->type()) {
01237       case QEvent::MouseButtonPress:
01238       case QEvent::MouseButtonRelease:
01239       case QEvent::MouseButtonDblClick:
01240       case QEvent::MouseMove:
01241       case QEvent::KeyPress:
01242       case QEvent::KeyRelease:
01243       case QEvent::Wheel:
01244       case QEvent::ShortcutOverride:
01245 #ifdef QT3_SUPPORT
01246       case QEvent::Accel:
01247       case QEvent::AccelAvailable:
01248 #endif
01249         return true;
01250       default:
01251         return false;
01252     }
01253 }
01254 
01255 void QDragManager::updateCursor()
01256 {
01257     if (!noDropCursor) {
01258         noDropCursor = new QCursor(Qt::ForbiddenCursor);
01259         moveCursor = new QCursor(dragCursor(Qt::MoveAction), 0,0);
01260         copyCursor = new QCursor(dragCursor(Qt::CopyAction), 0,0);
01261         linkCursor = new QCursor(dragCursor(Qt::LinkAction), 0,0);
01262     }
01263 
01264     QCursor *c;
01265     if (willDrop) {
01266         if (global_accepted_action == Qt::CopyAction) {
01267             c = copyCursor;
01268         } else if (global_accepted_action == Qt::LinkAction) {
01269             c = linkCursor;
01270         } else {
01271             c = moveCursor;
01272         }
01273         if (xdnd_data.deco) {
01274             xdnd_data.deco->show();
01275             xdnd_data.deco->raise();
01276         }
01277     } else {
01278         c = noDropCursor;
01279         //if (qt_xdnd_deco)
01280         //    qt_xdnd_deco->hide();
01281     }
01282 #ifndef QT_NO_CURSOR
01283     if (c)
01284         qApp->changeOverrideCursor(*c);
01285 #endif
01286 }
01287 
01288 
01289 void QDragManager::cancel(bool deleteSource)
01290 {
01291     DEBUG("QDragManager::cancel");
01292     Q_ASSERT(heartbeat != -1);
01293     killTimer(heartbeat);
01294     heartbeat = -1;
01295     beingCancelled = true;
01296     qt_xdnd_dragging = false;
01297 
01298     if (qt_xdnd_current_target)
01299         qt_xdnd_send_leave();
01300 
01301 #ifndef QT_NO_CURSOR
01302     if (restoreCursor) {
01303         QApplication::restoreOverrideCursor();
01304         restoreCursor = false;
01305     }
01306 #endif
01307 
01308     if (deleteSource && object)
01309         object->deleteLater();
01310     object = 0;
01311     delete xdnd_data.deco;
01312     xdnd_data.deco = 0;
01313 
01314     global_accepted_action = Qt::IgnoreAction;
01315 }
01316 
01317 static
01318 Window findRealWindow(const QPoint & pos, Window w, int md)
01319 {
01320     if (xdnd_data.deco && w == xdnd_data.deco->internalWinId())
01321         return 0;
01322 
01323     if (md) {
01324         X11->ignoreBadwindow();
01325         XWindowAttributes attr;
01326         XGetWindowAttributes(X11->display, w, &attr);
01327         if (X11->badwindow())
01328             return 0;
01329 
01330         if (attr.map_state == IsViewable
01331             && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) {
01332             {
01333                 Atom   type = XNone;
01334                 int f;
01335                 unsigned long n, a;
01336                 unsigned char *data;
01337 
01338                 XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False,
01339                                    AnyPropertyType, &type, &f,&n,&a,&data);
01340                 if (data) XFree(data);
01341                 if (type)
01342                     return w;
01343             }
01344 
01345             Window r, p;
01346             Window* c;
01347             uint nc;
01348             if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
01349                 r=0;
01350                 for (uint i=nc; !r && i--;) {
01351                     r = findRealWindow(pos-QPoint(attr.x,attr.y),
01352                                         c[i], md-1);
01353                 }
01354                 XFree(c);
01355                 if (r)
01356                     return r;
01357 
01358                 // We didn't find a client window!  Just use the
01359                 // innermost window.
01360             }
01361 
01362             // No children!
01363             return w;
01364         }
01365     }
01366     return 0;
01367 }
01368 
01369 void QDragManager::move(const QPoint & globalPos)
01370 {
01371     DEBUG() << "QDragManager::move enter";
01372     if (!object) {
01373         // perhaps the target crashed?
01374         return;
01375     }
01376 
01377     int screen = QCursor::x11Screen();
01378     if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
01379         // recreate the pixmap on the new screen...
01380         delete xdnd_data.deco;
01381         xdnd_data.deco = new QShapedPixmapWidget(screen);
01382         if (!QWidget::mouseGrabber()) {
01383             updatePixmap();
01384             xdnd_data.deco->grabMouse();
01385         }
01386     }
01387     xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
01388 
01389     if (qt_xdnd_source_sameanswer.contains(globalPos) && qt_xdnd_source_sameanswer.isValid())
01390         return;
01391 
01392     qt_xdnd_current_screen = screen;
01393     Window rootwin = QX11Info::appRootWindow(qt_xdnd_current_screen);
01394     Window target = 0;
01395     int lx = 0, ly = 0;
01396     if (!XTranslateCoordinates(X11->display, rootwin, rootwin, globalPos.x(), globalPos.y(), &lx, &ly, &target))
01397         // some weird error...
01398         return;
01399 
01400     if (target == rootwin) {
01401         // Ok.
01402     } else if (target) {
01403         //me
01404         Window src = rootwin;
01405         while (target != 0) {
01406             DNDDEBUG << "checking target for XdndAware" << QWidget::find(target) << target;
01407             int lx2, ly2;
01408             Window t;
01409             // translate coordinates
01410             if (!XTranslateCoordinates(X11->display, src, target, lx, ly, &lx2, &ly2, &t)) {
01411                 target = 0;
01412                 break;
01413             }
01414             lx = lx2;
01415             ly = ly2;
01416             src = target;
01417 
01418       // check if it has XdndAware
01419       Atom type = 0;
01420       int f;
01421       unsigned long n, a;
01422       unsigned char *data = 0;
01423       XGetWindowProperty(X11->display, target, ATOM(XdndAware), 0, 0, False,
01424                                AnyPropertyType, &type, &f,&n,&a,&data);
01425       if (data)
01426                 XFree(data);
01427       if (type) {
01428                 DNDDEBUG << "Found XdndAware on " << QWidget::find(target) << target;
01429                 break;
01430             }
01431 
01432             // find child at the coordinates
01433             if (!XTranslateCoordinates(X11->display, src, src, lx, ly, &lx2, &ly2, &target)) {
01434                 target = 0;
01435                 break;
01436             }
01437         }
01438         if (xdnd_data.deco && (!target || target == xdnd_data.deco->internalWinId())) {
01439             DNDDEBUG << "need to find real window";
01440             target = findRealWindow(globalPos, rootwin, 6);
01441             DNDDEBUG << "real window found" << QWidget::find(target) << target;
01442         }
01443     }
01444 
01445     QWidget* w;
01446     if (target) {
01447         w = QWidget::find((WId)target);
01448         if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
01449             w = 0;
01450     } else {
01451         w = 0;
01452         target = rootwin;
01453     }
01454 
01455     DNDDEBUG << "and the final target is " << QWidget::find(target) << target;
01456     DNDDEBUG << "the widget w is" << w;
01457 
01458     WId proxy_target = xdndProxy(target);
01459     if (!proxy_target)
01460         proxy_target = target;
01461     int target_version = 1;
01462 
01463     if (proxy_target) {
01464         Atom   type = XNone;
01465         int r, f;
01466         unsigned long n, a;
01467         int *tv;
01468         X11->ignoreBadwindow();
01469         r = XGetWindowProperty(X11->display, proxy_target, ATOM(XdndAware), 0,
01470                                1, False, AnyPropertyType, &type, &f,&n,&a,(uchar**)&tv);
01471         if (r != Success || X11->badwindow()) {
01472             target = 0;
01473         } else {
01474             target_version = qMin(xdnd_version,tv ? *tv : 1);
01475             if (tv)
01476                 XFree(tv);
01477 //             if (!(!X11->badwindow() && type))
01478 //                 target = 0;
01479         }
01480     }
01481 
01482     if (target != qt_xdnd_current_target) {
01483         if (qt_xdnd_current_target)
01484             qt_xdnd_send_leave();
01485 
01486         qt_xdnd_current_target = target;
01487         qt_xdnd_current_proxy_target = proxy_target;
01488         if (target) {
01489             QVector<Atom> types;
01490             int flags = target_version << 24;
01491             QStringList fmts = QInternalMimeData::formatsHelper(dragPrivate()->data);
01492             for (int i = 0; i < fmts.size(); ++i) {
01493                 QList<Atom> atoms = X11->xdndMimeAtomsForFormat(fmts.at(i));
01494                 for (int j = 0; j < atoms.size(); ++j) {
01495                     if (!types.contains(atoms.at(j)))
01496                         types.append(atoms.at(j));
01497                 }
01498             }
01499             if (types.size() > 3) {
01500                 XChangeProperty(X11->display,
01501                                 dragPrivate()->source->internalWinId(), ATOM(XdndTypelist),
01502                                 XA_ATOM, 32, PropModeReplace,
01503                                 (unsigned char *)types.data(),
01504                                 types.size());
01505                 flags |= 0x0001;
01506             }
01507             XClientMessageEvent enter;
01508             enter.type = ClientMessage;
01509             enter.window = target;
01510             enter.format = 32;
01511             enter.message_type = ATOM(XdndEnter);
01512             enter.data.l[0] = dragPrivate()->source->internalWinId();
01513             enter.data.l[1] = flags;
01514             enter.data.l[2] = types.size()>0 ? types.at(0) : 0;
01515             enter.data.l[3] = types.size()>1 ? types.at(1) : 0;
01516             enter.data.l[4] = types.size()>2 ? types.at(2) : 0;
01517             // provisionally set the rectangle to 5x5 pixels...
01518             qt_xdnd_source_sameanswer = QRect(globalPos.x() - 2,
01519                                               globalPos.y() -2 , 5, 5);
01520 
01521             DEBUG("sending Xdnd enter");
01522             if (w)
01523                 X11->xdndHandleEnter(w, (const XEvent *)&enter, false);
01524             else if (target)
01525                 XSendEvent(X11->display, proxy_target, False, NoEventMask, (XEvent*)&enter);
01526             waiting_for_status = false;
01527         }
01528     }
01529     if (waiting_for_status)
01530         return;
01531 
01532     if (target) {
01533         waiting_for_status = true;
01534 
01535         XClientMessageEvent move;
01536         move.type = ClientMessage;
01537         move.window = target;
01538         move.format = 32;
01539         move.message_type = ATOM(XdndPosition);
01540         move.window = target;
01541         move.data.l[0] = dragPrivate()->source->internalWinId();
01542         move.data.l[1] = 0; // flags
01543         move.data.l[2] = (globalPos.x() << 16) + globalPos.y();
01544         move.data.l[3] = X11->time;
01545         move.data.l[4] = qtaction_to_xdndaction(defaultAction(dragPrivate()->possible_actions, QApplication::keyboardModifiers()));
01546         DEBUG("sending Xdnd position");
01547 
01548         qt_xdnd_source_current_time = X11->time;
01549 
01550         if (w)
01551             handle_xdnd_position(w, (const XEvent *)&move, false);
01552         else
01553             XSendEvent(X11->display, proxy_target, False, NoEventMask,
01554                        (XEvent*)&move);
01555     } else {
01556         if (willDrop) {
01557             willDrop = false;
01558             updateCursor();
01559         }
01560     }
01561     DEBUG() << "QDragManager::move leave";
01562 }
01563 
01564 
01565 void QDragManager::drop()
01566 {
01567     Q_ASSERT(heartbeat != -1);
01568     killTimer(heartbeat);
01569     heartbeat = -1;
01570     qt_xdnd_dragging = false;
01571 
01572     if (!qt_xdnd_current_target)
01573         return;
01574 
01575     delete xdnd_data.deco;
01576     xdnd_data.deco = 0;
01577 
01578     XClientMessageEvent drop;
01579     drop.type = ClientMessage;
01580     drop.window = qt_xdnd_current_target;
01581     drop.format = 32;
01582     drop.message_type = ATOM(XdndDrop);
01583     drop.data.l[0] = dragPrivate()->source->internalWinId();
01584     drop.data.l[1] = 0; // flags
01585     drop.data.l[2] = X11->time;
01586 
01587     drop.data.l[3] = 0;
01588     drop.data.l[4] = 0;
01589 
01590     QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
01591 
01592     if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
01593         w = 0;
01594 
01595     QXdndDropTransaction t = {
01596         X11->time,
01597         qt_xdnd_current_target,
01598         qt_xdnd_current_proxy_target,
01599         w,
01600         current_embedding_widget,
01601         object
01602     };
01603     X11->dndDropTransactions.append(t);
01604     restartXdndDropExpiryTimer();
01605 
01606     if (w)
01607         X11->xdndHandleDrop(w, (const XEvent *)&drop, false);
01608     else
01609         XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
01610                    NoEventMask, (XEvent*)&drop);
01611 
01612     qt_xdnd_current_target = 0;
01613     qt_xdnd_current_proxy_target = 0;
01614     qt_xdnd_source_current_time = 0;
01615     current_embedding_widget = 0;
01616     object = 0;
01617 
01618 #ifndef QT_NO_CURSOR
01619     if (restoreCursor) {
01620         QApplication::restoreOverrideCursor();
01621         restoreCursor = false;
01622     }
01623 #endif
01624 }
01625 
01626 
01627 
01628 bool QX11Data::xdndHandleBadwindow()
01629 {
01630     QDragManager *manager = QDragManager::self();
01631     if (manager->object && qt_xdnd_current_target) {
01632         qt_xdnd_current_target = 0;
01633         qt_xdnd_current_proxy_target = 0;
01634         manager->object->deleteLater();
01635         manager->object = 0;
01636         delete xdnd_data.deco;
01637         xdnd_data.deco = 0;
01638         return true;
01639     }
01640     if (qt_xdnd_dragsource_xid) {
01641         qt_xdnd_dragsource_xid = 0;
01642         if (qt_xdnd_current_widget) {
01643             QDragLeaveEvent e;
01644             QApplication::sendEvent(qt_xdnd_current_widget, &e);
01645             qt_xdnd_current_widget = 0;
01646         }
01647         return true;
01648     }
01649     return false;
01650 }
01651 
01652 void QX11Data::xdndHandleSelectionRequest(const XSelectionRequestEvent * req)
01653 {
01654     if (!req)
01655         return;
01656     XEvent evt;
01657     evt.xselection.type = SelectionNotify;
01658     evt.xselection.display = req->display;
01659     evt.xselection.requestor = req->requestor;
01660     evt.xselection.selection = req->selection;
01661     evt.xselection.target = XNone;
01662     evt.xselection.property = XNone;
01663     evt.xselection.time = req->time;
01664 
01665     QDragManager *manager = QDragManager::self();
01666     QDrag *currentObject = manager->object;
01667 
01668     // which transaction do we use? (note: -2 means use current manager->object)
01669     int at = -1;
01670 
01671     // figure out which data the requestor is really interested in
01672     if (manager->object && req->time == qt_xdnd_source_current_time) {
01673         // requestor wants the current drag data
01674         at = -2;
01675     } else {
01676         // if someone has requested data in response to XdndDrop, find the corresponding transaction. the
01677         // spec says to call XConvertSelection() using the timestamp from the XdndDrop
01678         at = findXdndDropTransactionByTime(req->time);
01679         if (at == -1) {
01680             // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection()
01681             // that we sent the XdndDrop event to.
01682             at = findXdndDropTransactionByWindow(req->requestor);
01683         }
01684         if (at == -1 && req->time == CurrentTime) {
01685             // previous Qt versions always requested the data on a child of the target window
01686             // using CurrentTime... but it could be asking for either drop data or the current drag's data
01687             Window target = findXdndAwareParent(req->requestor);
01688             if (target) {
01689                 if (qt_xdnd_current_target && qt_xdnd_current_target == target)
01690                     at = -2;
01691                 else
01692                     at = findXdndDropTransactionByWindow(target);
01693             }
01694         }
01695     }
01696     if (at >= 0) {
01697         restartXdndDropExpiryTimer();
01698 
01699         // use the drag object from an XdndDrop tansaction
01700         manager->object = X11->dndDropTransactions.at(at).object;
01701     } else if (at != -2) {
01702         // no transaction found, we'll have to reject the request
01703         manager->object = 0;
01704     }
01705     if (manager->object) {
01706         Atom atomFormat = req->target;
01707         int dataFormat = 0;
01708         QByteArray data;
01709         if (X11->xdndMimeDataForAtom(req->target, manager->dragPrivate()->data,
01710                                      &data, &atomFormat, &dataFormat)) {
01711             int dataSize = data.size() / (dataFormat / 8);
01712             XChangeProperty (X11->display, req->requestor, req->property,
01713                              atomFormat, dataFormat, PropModeReplace,
01714                              (unsigned char *)data.data(), dataSize);
01715             evt.xselection.property = req->property;
01716             evt.xselection.target = atomFormat;
01717         }
01718     }
01719 
01720     // reset manager->object in case we modified it above
01721     manager->object = currentObject;
01722 
01723     // ### this can die if req->requestor crashes at the wrong
01724     // ### moment
01725     XSendEvent(X11->display, req->requestor, False, 0, &evt);
01726 }
01727 
01728 static QByteArray xdndObtainData(const char *format)
01729 {
01730     QByteArray result;
01731 
01732     QWidget* w;
01733     QDragManager *manager = QDragManager::self();
01734     if (qt_xdnd_dragsource_xid && manager->object &&
01735          (w=QWidget::find(qt_xdnd_dragsource_xid))
01736          && (!(w->windowType() == Qt::Desktop) || w->acceptDrops()))
01737     {
01738         QDragPrivate * o = QDragManager::self()->dragPrivate();
01739         if (o->data->hasFormat(QLatin1String(format)))
01740             result = o->data->data(QLatin1String(format));
01741         return result;
01742     }
01743 
01744     QList<Atom> atoms;
01745     int i = 0;
01746     while ((qt_xdnd_types[i])) {
01747         atoms.append(qt_xdnd_types[i]);
01748         ++i;
01749     }
01750     Atom a = X11->xdndMimeAtomForFormat(QLatin1String(format), atoms);
01751     if (!a)
01752         return result;
01753 
01754     if (XGetSelectionOwner(X11->display, ATOM(XdndSelection)) == XNone)
01755         return result; // should never happen?
01756 
01757     QWidget* tw = qt_xdnd_current_widget;
01758     if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
01759         tw = new QWidget;
01760 
01761     XConvertSelection(X11->display, ATOM(XdndSelection), a, ATOM(XdndSelection), tw->internalWinId(),
01762                       qt_xdnd_target_current_time);
01763     XFlush(X11->display);
01764 
01765     XEvent xevent;
01766     bool got=X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000);
01767     if (got) {
01768         Atom type;
01769 
01770         if (X11->clipboardReadProperty(tw->internalWinId(), ATOM(XdndSelection), true, &result, 0, &type, 0, false)) {
01771             if (type == ATOM(INCR)) {
01772                 int nbytes = result.size() >= 4 ? *((int*)result.data()) : 0;
01773                 result = X11->clipboardReadIncrementalProperty(tw->internalWinId(), ATOM(XdndSelection), nbytes, false);
01774             } else if (type != a && type != XNone) {
01775                 DEBUG("Qt clipboard: unknown atom %ld", type);
01776             }
01777         }
01778     }
01779     if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
01780         delete tw;
01781 
01782     return X11->xdndMimeConvertToFormat(a, result, QLatin1String(format));
01783 }
01784 
01785 
01786 /*
01787   Enable drag and drop for widget w by installing the proper
01788   properties on w's toplevel widget.
01789 */
01790 bool QX11Data::dndEnable(QWidget* w, bool on)
01791 {
01792     w = w->window();
01793 
01794     if (on) {
01795         if (((QExtraWidget*)w)->topData()->dnd)
01796             return true; // been there, done that
01797         ((QExtraWidget*)w)->topData()->dnd  = 1;
01798     }
01799 
01800     motifdndEnable(w, on);
01801     return xdndEnable(w, on);
01802 }
01803 
01804 Qt::DropAction QDragManager::drag(QDrag * o)
01805 {
01806     if (object == o || !o || !o->d_func()->source)
01807         return Qt::IgnoreAction;
01808 
01809     if (object) {
01810         cancel();
01811         qApp->removeEventFilter(this);
01812         beingCancelled = false;
01813     }
01814 
01815     if (object) {
01816         // the last drag and drop operation hasn't finished, so we are going to wait
01817         // for one second to see if it does... if the finish message comes after this,
01818         // then we could still have problems, but this is highly unlikely
01819         QApplication::flush();
01820 
01821         QTime started = QTime::currentTime();
01822         QTime now = started;
01823         do {
01824             XEvent event;
01825             if (XCheckTypedEvent(X11->display, ClientMessage, &event))
01826                 qApp->x11ProcessEvent(&event);
01827 
01828             now = QTime::currentTime();
01829             if (started > now) // crossed midnight
01830                 started = now;
01831 
01832             // sleep 50 ms, so we don't use up CPU cycles all the time.
01833             struct timeval usleep_tv;
01834             usleep_tv.tv_sec = 0;
01835             usleep_tv.tv_usec = 50000;
01836             select(0, 0, 0, 0, &usleep_tv);
01837         } while (object && started.msecsTo(now) < 1000);
01838     }
01839 
01840     object = o;
01841     object->d_func()->target = 0;
01842     xdnd_data.deco = new QShapedPixmapWidget();
01843 
01844     willDrop = false;
01845 
01846     updatePixmap();
01847 
01848     qApp->installEventFilter(this);
01849     XSetSelectionOwner(X11->display, ATOM(XdndSelection), dragPrivate()->source->window()->internalWinId(), X11->time);
01850     global_accepted_action = Qt::CopyAction;
01851     qt_xdnd_source_sameanswer = QRect();
01852     move(QCursor::pos());
01853     heartbeat = startTimer(200);
01854 
01855 #ifndef QT_NO_CURSOR
01856     qApp->setOverrideCursor(Qt::ArrowCursor);
01857     restoreCursor = true;
01858     updateCursor();
01859 #endif
01860 
01861     qt_xdnd_dragging = true;
01862 
01863     if (!QWidget::mouseGrabber())
01864         xdnd_data.deco->grabMouse();
01865 
01866     eventLoop = new QEventLoop;
01867     (void) eventLoop->exec();
01868     delete eventLoop;
01869     eventLoop = 0;
01870 
01871 #ifndef QT_NO_CURSOR
01872     if (restoreCursor) {
01873         qApp->restoreOverrideCursor();
01874         restoreCursor = false;
01875     }
01876 #endif
01877 
01878     // delete cursors as they may be different next drag.
01879     delete noDropCursor;
01880     noDropCursor = 0;
01881     delete copyCursor;
01882     copyCursor = 0;
01883     delete moveCursor;
01884     moveCursor = 0;
01885     delete linkCursor;
01886     linkCursor = 0;
01887 
01888     delete xdnd_data.deco;
01889     xdnd_data.deco = 0;
01890     if (heartbeat != -1)
01891         killTimer(heartbeat);
01892     heartbeat = -1;
01893     qt_xdnd_current_screen = -1;
01894     qt_xdnd_dragging = false;
01895 
01896     return global_accepted_action;
01897     // object persists until we get an xdnd_finish message
01898 }
01899 
01900 void QDragManager::updatePixmap()
01901 {
01902     if (xdnd_data.deco) {
01903         QPixmap pm;
01904         QPoint pm_hot(default_pm_hotx,default_pm_hoty);
01905         if (object) {
01906             pm = dragPrivate()->pixmap;
01907             if (!pm.isNull())
01908                 pm_hot = dragPrivate()->hotspot;
01909         }
01910         if (pm.isNull()) {
01911             if (!defaultPm)
01912                 defaultPm = new QPixmap(default_pm);
01913             pm = *defaultPm;
01914         }
01915         xdnd_data.deco->pm_hot = pm_hot;
01916         xdnd_data.deco->setPixmap(pm);
01917         xdnd_data.deco->move(QCursor::pos()-pm_hot);
01918         xdnd_data.deco->show();
01919     }
01920 }
01921 
01922 QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type) const
01923 {
01924     QByteArray mime = mimetype.toLatin1();
01925     QByteArray data = X11->motifdnd_active
01926                       ? X11->motifdndObtainData(mime)
01927                       : xdndObtainData(mime);
01928     return data;
01929 }
01930 
01931 bool QDropData::hasFormat_sys(const QString &format) const
01932 {
01933     return formats().contains(format);
01934 }
01935 
01936 QStringList QDropData::formats_sys() const
01937 {
01938     QStringList formats;
01939     if (X11->motifdnd_active) {
01940         int i = 0;
01941         QByteArray fmt;
01942         while (!(fmt = X11->motifdndFormat(i)).isEmpty()) {
01943             formats.append(QLatin1String(fmt));
01944             ++i;
01945         }
01946     } else {
01947         int i = 0;
01948         while ((qt_xdnd_types[i])) {
01949             QStringList formatsForAtom = X11->xdndMimeFormatsForAtom(qt_xdnd_types[i]);
01950             for (int j = 0; j < formatsForAtom.size(); ++j) {
01951                 if (!formats.contains(formatsForAtom.at(j)))
01952                     formats.append(formatsForAtom.at(j));
01953             }
01954             ++i;
01955         }
01956     }
01957     return formats;
01958 }
01959 
01960 #endif // QT_NO_DRAGANDDROP

Generated on Thu Mar 15 11:55:06 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1