📄 qdnd_x11.cpp
字号:
(XEvent*)&move); } else { if (willDrop) { willDrop = false; updateCursor(); } } DEBUG() << "QDragManager::move leave";}void QDragManager::drop(){ Q_ASSERT(heartbeat != -1); killTimer(heartbeat); heartbeat = -1; 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->winId(); 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, 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 = req->target; evt.xselection.property = XNone; evt.xselection.time = req->time; QByteArray format; if (req->target == XA_STRING || req->target == ATOM(UTF8_STRING)) format = "text/plain"; else format = X11->xdndAtomToString(req->target); 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) { // bastards! 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) { QDragPrivate* dp = QDragManager::self()->dragPrivate(); if (!format.isEmpty() && QInternalMimeData::hasFormatHelper(QLatin1String(format), dp->data)) { QByteArray a = QInternalMimeData::renderDataHelper(QLatin1String(format), dp->data); int dataFormat = 8; int dataSize = a.size(); if (format == "application/x-color") { dataFormat = 16; dataSize = a.size() / 2; } XChangeProperty (X11->display, req->requestor, req->property, req->target, dataFormat, PropModeReplace, (unsigned char *)a.data(), dataSize); evt.xselection.property = req->property; } } // 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 QByteArray xdndObtainData(const char *format){ 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; } Atom a = X11->xdndStringToAtom(format); if (!a) return result; // if a is not provided then find best match int i = 0; bool found = false; while ((qt_xdnd_types[i])) { if (qt_xdnd_types[i] == a) { found = true; break; } ++i; } if (!found && strcmp(format, "text/plain") == 0) { int i = 0; while ((qt_xdnd_types[i])) { if (qt_xdnd_types[i] == ATOM(UTF8_STRING)) { a = ATOM(UTF8_STRING); break; } else if (qt_xdnd_types[i] == XA_STRING) { a = XA_STRING; break; } ++i; } } 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->winId(), qt_xdnd_target_current_time); XFlush(X11->display); XEvent xevent; bool got=X11->clipboardWaitForEvent(tw->winId(), SelectionNotify, &xevent, 5000); if (got) { Atom type; if (X11->clipboardReadProperty(tw->winId(), 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->winId(), 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 result;}/* 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 (on) { if (((QExtraWidget*)w)->topData()->dnd) return true; // been there, done that ((QExtraWidget*)w)->topData()->dnd = 1; } 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 50ms, 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()->winId(), 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) const{ QByteArray mime = mimetype.toLatin1(); QByteArray data = X11->motifdnd_active ? X11->motifdndObtainData(mime) : xdndObtainData(mime); 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])) { QString f = QLatin1String(X11->xdndAtomToString(qt_xdnd_types[i])); if (!formats.contains(f)) formats.append(f); ++i; } } return formats;}#endif // QT_NO_DRAGANDDROP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -