📄 qdnd_x11.cpp
字号:
} } DEBUG() << "QDragManager::move leave";}void QDragManager::drop(){ Q_ASSERT(heartbeat != -1); killTimer(heartbeat); heartbeat = -1; qt_xdnd_dragging = false; if (!qt_xdnd_current_target) return; delete 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->internalWinId(); 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(){ QDragManager *manager = QDragManager::self(); if (manager->object && qt_xdnd_current_target) { 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) { QDragLeaveEvent e; QApplication::sendEvent(qt_xdnd_current_widget, &e); 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->internalWinId(), qt_xdnd_target_current_time); XFlush(X11->display); XEvent xevent; bool got=X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000); if (got) { Atom type; if (X11->clipboardReadProperty(tw->internalWinId(), ATOM(XdndSelection), true, &result, 0, &type, 0, false)) { if (type == ATOM(INCR)) { int nbytes = result.size() >= 4 ? *((int*)result.data()) : 0; result = X11->clipboardReadIncrementalProperty(tw->internalWinId(), 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(); QTime started = QTime::currentTime(); QTime now = started; do { XEvent event; if (XCheckTypedEvent(X11->display, ClientMessage, &event)) qApp->x11ProcessEvent(&event); now = QTime::currentTime(); if (started > now) // crossed midnight started = now; // 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 && started.msecsTo(now) < 1000); } object = o; object->d_func()->target = 0; xdnd_data.deco = new QShapedPixmapWidget(); 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(); move(QCursor::pos()); heartbeat = startTimer(200);#ifndef QT_NO_CURSOR qApp->setOverrideCursor(Qt::ArrowCursor); restoreCursor = true; updateCursor();#endif 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;}#endif // QT_NO_DRAGANDDROP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -