📄 qmotifdnd_x11.cpp
字号:
XFree((char*)targets_table); return tmp; // targets_table->entries[index].num_targets;}QByteArray QX11Data::motifdndFormat(int n){ if (!motifdnd_active) return 0; // should not happen if (n >= num_src_targets) return 0; Atom target = src_targets[n]; if (target == XA_STRING) return "text/plain;charset=ISO-8859-1"; if (target == ATOM(UTF8_STRING)) return "text/plain;charset=UTF-8"; if (target == ATOM(COMPOUND_TEXT)) return QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name(); if (target == ATOM(TEXT)) return "text/plain"; return ("x-motif-dnd/" + X11->xdndAtomToString(target));}QVariant QX11Data::motifdndObtainData(const char *mimeType){ QByteArray result; if (Dnd_selection == 0 || !dropWidget) return result; // try to convert the selection to the requested property // qDebug("trying to convert to '%s'", mimeType); int n=0; QByteArray f; do { f = motifdndFormat(n); if (f.isEmpty()) return result; n++; } while(qstricmp(mimeType, f.data())); Atom conversion_type = XNone; if (f == "text/plain;charset=ISO-8859-1") { conversion_type = XA_STRING; } else if (f == "text/plain;charset=UTF-8") { conversion_type = ATOM(UTF8_STRING); } else if (f == (QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name())) { conversion_type = ATOM(COMPOUND_TEXT); } else if (f == "text/plain") { conversion_type = ATOM(TEXT); } else if (f.startsWith("x-motif-dnd/")) { // strip off the "x-motif-dnd/" prefix conversion_type = X11->xdndStringToAtom(f.remove(0, 12)); } if (XGetSelectionOwner(X11->display, Dnd_selection) == XNone) { return result; // should never happen? } QWidget* tw = dropWidget; if ((dropWidget->windowType() == Qt::Desktop)) { tw = new QWidget; } // convert selection to the appropriate type XConvertSelection (X11->display, Dnd_selection, conversion_type, Dnd_selection, tw->internalWinId(), Dnd_selection_time); XFlush(X11->display); XEvent xevent; bool got=X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000); if (got) { Atom type; if (X11->clipboardReadProperty(tw->internalWinId(), Dnd_selection, true, &result, 0, &type, 0, false)) { } } // we have to convert selection in order to indicate success to the initiator XConvertSelection (X11->display, Dnd_selection, ATOM(XmTRANSFER_SUCCESS), Dnd_selection, tw->internalWinId(), Dnd_selection_time); // wait again for SelectionNotify event X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000); if ((dropWidget->windowType() == Qt::Desktop)) { delete tw; } return result;}void QX11Data::motifdndEnable(QWidget *widget, bool){ DndWriteReceiverProperty(display, widget->internalWinId(), DND_DRAG_DYNAMIC);}void QX11Data::motifdndHandle(QWidget *widget, const XEvent * xe, bool /* passive */){ XEvent event = *xe; XClientMessageEvent cm ; DndData dnd_data ; char receiver ; if (!(DndParseClientMessage ((XClientMessageEvent*)&event, &dnd_data, &receiver))) { return; } switch (dnd_data.reason) { case DND_DRAG_MOTION: { QPoint p = widget->mapFromGlobal(QPoint(dnd_data.x, dnd_data.y)); QWidget *c = widget->childAt(p); if (!c || !c->acceptDrops()) { // not over a drop site if (dropWidget) { QDragLeaveEvent dragLeaveEvent; QApplication::sendEvent(dropWidget, &dragLeaveEvent); dropWidget = 0; lastAcceptedAction = Qt::IgnoreAction; dnd_data.reason = DND_DROP_SITE_LEAVE; dnd_data.time = X11->time; DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ; } else { dnd_data.reason = DND_DRAG_MOTION; dnd_data.status = DND_NO_DROP_SITE; dnd_data.time = X11->time; dnd_data.operation = DND_NOOP; dnd_data.operations = DND_NOOP; DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ; } } else { Q_ASSERT(c != 0); p = c->mapFrom(widget, p); if (dropWidget != c) { if (dropWidget) { QDragLeaveEvent le; QApplication::sendEvent(dropWidget, &le); } dropWidget = c; lastAcceptedAction = Qt::IgnoreAction; const Qt::DropActions possibleActions = DndOperationsToQtDropActions(dnd_data.operations); QDragEnterEvent de(p, possibleActions, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); QApplication::sendEvent(dropWidget, &de); dnd_data.reason = DND_DROP_SITE_ENTER; dnd_data.time = X11->time; if (de.isAccepted()) { lastAcceptedAction = de.dropAction(); dnd_data.status = DND_VALID_DROP_SITE; dnd_data.operation = QtDropActionToDndOperation(lastAcceptedAction); } else { dnd_data.status = DND_INVALID_DROP_SITE; dnd_data.operation = DND_NOOP; dnd_data.operations = DND_NOOP; } DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm); } else { const Qt::DropActions possibleActions = DndOperationsToQtDropActions(dnd_data.operations); QDragMoveEvent me(p, possibleActions, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); if (lastAcceptedAction != Qt::IgnoreAction) { me.setDropAction(lastAcceptedAction); me.accept(); } QApplication::sendEvent(dropWidget, &me); dnd_data.reason = DND_DRAG_MOTION; dnd_data.time = X11->time; if (me.isAccepted()) { lastAcceptedAction = me.dropAction(); dnd_data.status = DND_VALID_DROP_SITE; dnd_data.operation = QtDropActionToDndOperation(lastAcceptedAction); } else { dnd_data.status = DND_INVALID_DROP_SITE; dnd_data.operation = DND_NOOP; dnd_data.operations = DND_NOOP; } DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm); } } break; } case DND_TOP_LEVEL_ENTER: { /* get the size of our drop site for later use */ motifdnd_active = true; sourceWindow = dnd_data.src_window; /* no answer needed, just read source property */ DndReadSourceProperty (event.xclient.display, sourceWindow, dnd_data.property, &src_targets, &num_src_targets); break; } case DND_TOP_LEVEL_LEAVE: { XEvent nextEvent; if (XCheckTypedWindowEvent(X11->display, widget->winId(), ClientMessage, &nextEvent)) { // we just want to check, not eat (should use XPeekIfEvent) XPutBackEvent(X11->display, &nextEvent); if (DndParseClientMessage (&nextEvent.xclient, &dnd_data, &receiver) && dnd_data.reason == DND_DROP_START) { // expecting drop next, keeping DnD alive break; } } // not expecting drop, need to send drag leave events and such here if (dropWidget) { QDragLeaveEvent le; QApplication::sendEvent(dropWidget, &le); } sourceWindow = XNone; dropWidget = 0; lastAcceptedAction = Qt::IgnoreAction; motifdnd_active = false; break; } case DND_OPERATION_CHANGED: // ### need to echo break; case DND_DROP_START: { Q_ASSERT(motifdnd_active); Q_ASSERT(sourceWindow == dnd_data.src_window); if (!dropWidget || lastAcceptedAction == Qt::IgnoreAction) { // echo DROP_START dnd_data.reason = DND_DROP_START; dnd_data.status = DND_NO_DROP_SITE; dnd_data.operation = DND_NOOP; dnd_data.operations = DND_NOOP; DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm); // we have to convert selection in order to indicate failure to the initiator XConvertSelection (X11->display, dnd_data.property, ATOM(XmTRANSFER_FAILURE), dnd_data.property, dnd_data.src_window, dnd_data.time); if (dropWidget) { QDragLeaveEvent e; QApplication::sendEvent(dropWidget, &e); } motifdnd_active = false; sourceWindow = XNone; dropWidget = 0; lastAcceptedAction = Qt::IgnoreAction; return; } // store selection and its time Dnd_selection = dnd_data.property; Dnd_selection_time = dnd_data.time; QPoint p(dnd_data.x, dnd_data.y); QDropEvent de(dropWidget->mapFromGlobal(p), Qt::CopyAction, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); if (lastAcceptedAction != Qt::IgnoreAction) { de.setDropAction(lastAcceptedAction); de.accept(); } QApplication::sendEvent(dropWidget, &de); // reset Dnd_selection = XNone; Dnd_selection_time = 0; // echo DROP_START depending on the result of the dropEvent if (de.isAccepted()) { dnd_data.reason = DND_DROP_START; dnd_data.status = DND_VALID_DROP_SITE; dnd_data.operation = QtDropActionToDndOperation(de.dropAction()); } else { dnd_data.reason = DND_DROP_START; dnd_data.status = DND_NO_DROP_SITE; dnd_data.operation = DND_NOOP; dnd_data.operations = DND_NOOP; } DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm); sourceWindow = XNone; dropWidget = 0; lastAcceptedAction = Qt::IgnoreAction; motifdnd_active = false; break; } default: break; } // end of switch (dnd_data.reason)}#endif // QT_NO_DRAGANDDROP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -