📄 qmotifdnd_x11.cpp
字号:
SWAP2BYTES(dnd_message->data.pot.y); SWAP4BYTES(dnd_message->data.pot.property); SWAP4BYTES(dnd_message->data.pot.src_window); } dnd_data->x = dnd_message->data.pot.x ; dnd_data->y = dnd_message->data.pot.y ; dnd_data->property = dnd_message->data.pot.property ; dnd_data->src_window = dnd_message->data.pot.src_window ; break ; case DND_DROP_SITE_LEAVE: break; default: break ; } return True ;}static Window MotifWindow(Display *display){ Atom type; int format; unsigned long size; unsigned long bytes_after; Window *property = 0; Window motif_window ; /* this version does no caching, so it's slow: round trip each time */ if ((XGetWindowProperty (display, DefaultRootWindow(display), ATOM(_MOTIF_DRAG_WINDOW), 0L, 100000L, False, AnyPropertyType, &type, &format, &size, &bytes_after, (unsigned char **) &property) == Success) && (type != XNone)) { motif_window = *property; } else { XSetWindowAttributes sAttributes; /* really, this should be done on a separate connection, with XSetCloseDownMode (RetainPermanent), so that others don't have to recreate it; hopefully, some real Motif application will be around to do it */ sAttributes.override_redirect = True; sAttributes.event_mask = PropertyChangeMask; motif_window = XCreateWindow (display, DefaultRootWindow (display), -170, -560, 1, 1, 0, 0, InputOnly, CopyFromParent, (CWOverrideRedirect |CWEventMask), &sAttributes); XMapWindow (display, motif_window); } if (property) { XFree ((char *)property); } return (motif_window);}static DndTargetsTable TargetsTable(Display *display){ Atom type; int format; unsigned long size; unsigned long bytes_after; Window motif_window = MotifWindow(display) ; DndTargets * target_prop; DndTargetsTable targets_table ; int i,j ; char * target_data ; /* this version does no caching, so it's slow: round trip each time */ /* ideally, register for property notify on this target_list atom and update when necessary only */ if ((XGetWindowProperty (display, motif_window, ATOM(_MOTIF_DRAG_TARGETS), 0L, 100000L, False, ATOM(_MOTIF_DRAG_TARGETS), &type, &format, &size, &bytes_after, (unsigned char **) &target_prop) != Success) || type == XNone) { qWarning("QMotifDND: cannot get property on motif window"); return 0; } if (target_prop->protocol_version != DND_PROTOCOL_VERSION) { qWarning("QMotifDND: protocol mismatch"); } if (target_prop->byte_order != DndByteOrder()) { /* need to swap num_target_lists and size */ SWAP2BYTES(target_prop->num_target_lists); SWAP4BYTES(target_prop->data_size); } /* now parse DndTarget prop data in a TargetsTable */ targets_table = (DndTargetsTable)malloc(sizeof(DndTargetsTableRec)); targets_table->num_entries = target_prop->num_target_lists ; targets_table->entries = (DndTargetsTableEntry) malloc(sizeof(DndTargetsTableEntryRec) * target_prop->num_target_lists); target_data = (char*)target_prop + sizeof(*target_prop) ; for (i = 0 ; i < targets_table->num_entries; i++) { CARD16 num_targets ; CARD32 atom ; memcpy(&num_targets, target_data, 2); target_data += 2; /* potential swap needed here */ if (target_prop->byte_order != DndByteOrder()) SWAP2BYTES(num_targets); targets_table->entries[i].num_targets = num_targets ; targets_table->entries[i].targets = (Atom *) malloc(sizeof(Atom) * targets_table->entries[i].num_targets); for (j = 0; j < num_targets; j++) { memcpy(&atom, target_data, 4); target_data += 4; /* another potential swap needed here */ if (target_prop->byte_order != DndByteOrder()) SWAP4BYTES(atom); targets_table->entries[i].targets[j] = (Atom) atom ; } } if (target_prop) { XFree((char *)target_prop); } return targets_table ;}static int _DndIndexToTargets(Display * display, int index, Atom ** targets){ DndTargetsTable targets_table; int i ; /* again, slow: no caching here, alloc/free each time */ if (!(targets_table = TargetsTable (display)) || (index >= targets_table->num_entries)) { if (targets_table) XFree((char*)targets_table); return -1; } /* transfer the correct target list index */ *targets = (Atom*)malloc(sizeof(Atom)*targets_table-> entries[index].num_targets); memcpy((char*)*targets, (char*)targets_table->entries[index].targets, sizeof(Atom)*targets_table->entries[index].num_targets); /* free the target table and its guts */ for (i=0 ; i < targets_table->num_entries; i++) XFree((char*)targets_table->entries[i].targets); int tmp = targets_table->entries[index].num_targets; 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 == 0) return "text/plain"; if (n == 1) return "text/uri-list"; n -= 2; 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(TEXT) || target == ATOM(COMPOUND_TEXT)) return "text/plain"; return X11->xdndAtomToString(target);}QByteArray QX11Data::motifdndObtainData(const char *mimeType){ QByteArray result; if (Dnd_selection == 0) 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())); // found one Atom conversion_type; if (qstrnicmp(f, "text/", 5) == 0) { // always convert text to XA_STRING for compatibility with // prior Qt versions conversion_type = XA_STRING; } else { conversion_type = X11->xdndStringToAtom(f); // qDebug("found format '%s' 0x%lx '%s'", f, conversion_type, // X11->xdndAtomToString(conversion_type)); } if (XGetSelectionOwner(X11->display, Dnd_selection) == XNone) { return result; // should never happen? } QWidget* tw = drop_widget; if ((drop_widget->windowType() == Qt::Desktop)) { tw = new QWidget; } // convert selection to the appropriate type XConvertSelection (X11->display, Dnd_selection, conversion_type, Dnd_selection, tw->winId(), Dnd_selection_time); XFlush(X11->display); XEvent xevent; bool got=X11->clipboardWaitForEvent(tw->winId(), SelectionNotify, &xevent, 5000); if (got) { Atom type; if (X11->clipboardReadProperty(tw->winId(), Dnd_selection, true, &result, 0, &type, 0, true)) { } } // we have to convert selection in order to indicate success to the initiator XConvertSelection (X11->display, Dnd_selection, ATOM(XmTRANSFER_SUCCESS), Dnd_selection, tw->winId(), Dnd_selection_time); // wait again for SelectionNotify event X11->clipboardWaitForEvent(tw->winId(), SelectionNotify, &xevent, 5000); if ((drop_widget->windowType() == Qt::Desktop)) { delete tw; } return result;}void QX11Data::motifdndEnable(QWidget *widget, bool){ DndWriteReceiverProperty(display, widget->winId(), DND_DRAG_DYNAMIC);}void QX11Data::motifdndHandle(QWidget * /* w */ , 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: { /* check if in drop site, and depending on the state, send a drop site enter or drop site leave or echo */ QPoint p(dnd_data.x, dnd_data.y); QWidget *c = QApplication::widgetAt(p); if (c) p = c->mapFromGlobal(p); while (c && !c->acceptDrops() && !c->isWindow()) { p = c->mapToParent(p); c = c->parentWidget(); } QDragMoveEvent me(p, Qt::CopyAction, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); if (c != 0L && c->acceptDrops()) { if (drop_widget != 0L && drop_widget->acceptDrops() && drop_widget != c) { QDragLeaveEvent e; QApplication::sendEvent(drop_widget, &e); QDragEnterEvent de(p, Qt::CopyAction, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); QApplication::sendEvent(c, &de); } drop_widget = c; if (!in_drop_site) { in_drop_site = True ; dnd_data.reason = DND_DROP_SITE_ENTER ; dnd_data.time = CurrentTime ; dnd_data.operation = DND_MOVE|DND_COPY; dnd_data.operations = DND_MOVE|DND_COPY; DndFillClientMessage (event.xclient.display, cur_window, &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, cur_window, False, 0, (XEvent *)&cm) ; QDragEnterEvent de(p, Qt::CopyAction, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); QApplication::sendEvent(drop_widget, &de); if (de.isAccepted()) { me.accept(de.answerRect()); } else { me.ignore(de.answerRect()); } } else { dnd_data.reason = DND_DRAG_MOTION ; dnd_data.time = CurrentTime ; dnd_data.operation = DND_MOVE|DND_COPY; dnd_data.operations = DND_MOVE|DND_COPY; DndFillClientMessage (event.xclient.display, cur_window, &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, cur_window, False, 0, (XEvent *)&cm) ; QApplication::sendEvent(drop_widget, &me); } } else { if (in_drop_site) { in_drop_site = False ; dnd_data.reason = DND_DROP_SITE_LEAVE ; dnd_data.time = CurrentTime ; DndFillClientMessage (event.xclient.display, cur_window, &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, cur_window, False, 0, (XEvent *)&cm) ; QDragLeaveEvent e; QApplication::sendEvent(drop_widget, &e); } } } break; case DND_TOP_LEVEL_ENTER: /* get the size of our drop site for later use */ cur_window = dnd_data.src_window ; motifdnd_active = true; /* no answer needed, just read source property */ DndReadSourceProperty (event.xclient.display, cur_window, dnd_data.property, &src_targets, &num_src_targets); break; case DND_TOP_LEVEL_LEAVE: /* no need to do anything */ break; case DND_OPERATION_CHANGED: /* need to echo */ break; case DND_DROP_START: if (!in_drop_site) { // 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, cur_window, dnd_data.time); if (drop_widget) { QDragLeaveEvent e; QApplication::sendEvent(drop_widget, &e); drop_widget = 0; } return; } /* need to echo and then request a convert */ dnd_data.reason = DND_DROP_START ; DndFillClientMessage (event.xclient.display, drop_widget->winId(), &cm, &dnd_data, 0); XSendEvent(event.xbutton.display, cur_window, False, 0, (XEvent *)&cm) ; // 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(drop_widget->mapFromGlobal(p), Qt::CopyAction, QDragManager::self()->dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers()); QApplication::sendEvent(drop_widget, &de); if (in_drop_site) in_drop_site = False ; drop_widget = 0; cur_window = 0; break; } // end of switch (dnd_data.reason)}#endif // QT_NO_DRAGANDDROP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -