📄 qclipboard_x11.cpp
字号:
{ if (empty()) return QStringList(); if (!formatList.count()) { // get the list of targets from the current clipboard owner - we do this // once so that multiple calls to this function don't require multiple // server round trips... format_atoms = getDataInFormat(ATOM(TARGETS)); if (format_atoms.size() > 0) { Atom *targets = (Atom *) format_atoms.data(); int size = format_atoms.size() / sizeof(Atom); for (int i = 0; i < size; ++i) { if (targets[i] == 0) continue; VDEBUG(" format: %s", X11->xdndAtomToString(targets[i]).data()); if (targets[i] == XA_PIXMAP) formatList.append("image/ppm"); else if (targets[i] == XA_STRING || targets[i] == ATOM(UTF8_STRING) || targets[i] == ATOM(TEXT) || targets[i] == ATOM(COMPOUND_TEXT)) formatList.append("text/plain"); else formatList.append(X11->xdndAtomToString(targets[i])); VDEBUG(" data:\n%s\n", getDataInFormat(targets[i]).data()); } DEBUG("QClipboardWatcher::format: %d formats available", formatList.count()); } } return formatList;}bool QClipboardWatcher::hasFormat_sys(const QString &format) const{ QStringList list = formats(); return list.contains(format);}QVariant QClipboardWatcher::retrieveData_sys(const QString &fmt, QVariant::Type type) const{ if (fmt.isEmpty() || empty()) return QByteArray(); (void)formats(); // trigger update of format list DEBUG("QClipboardWatcher::data: fetching format '%s'", fmt.toLatin1().data()); Atom fmtatom = 0; if (fmt == QLatin1String("text/plain")) { Atom *targets = (Atom *) format_atoms.data(); int size = format_atoms.size() / sizeof(Atom); // find best available text format for (int i = 0; i < size; ++i) { VDEBUG(" format: %s", X11->xdndAtomToString(targets[i]).data()); if (targets[i] == XA_STRING) { if (fmtatom == 0) fmtatom = targets[i]; } else if (targets[i] == ATOM(TEXT)) { if (fmtatom == 0 || fmtatom == XA_STRING) fmtatom = targets[i]; } else if (targets[i] == ATOM(COMPOUND_TEXT)) { if (fmtatom == 0 || fmtatom == XA_STRING || fmtatom == ATOM(TEXT)) fmtatom = targets[i];// } else if (targets[i] == ATOM("text/plain;charset=ISO-10646-UCS-2"))) { } else if (targets[i] == ATOM(UTF8_STRING)) { if (fmtatom == 0 || fmtatom == XA_STRING || fmtatom == ATOM(TEXT) || fmtatom == ATOM(COMPOUND_TEXT)) fmtatom = targets[i]; } } if (fmtatom == 0) return QVariant(); QByteArray data = getDataInFormat(fmtatom); QString result; if (fmtatom == XA_STRING) result = QString::fromLatin1(data); else if (fmtatom == ATOM(TEXT) || fmtatom == ATOM(COMPOUND_TEXT)) { // #### might be wrong for COMPUND_TEXT result = QString::fromLocal8Bit(data); } else if (fmtatom == ATOM(UTF8_STRING)) { result = QString::fromUtf8(data); } DEBUG("got plain text '%s'", result.toUtf8().data()); if (type == QVariant::String) return result; return result.toUtf8(); } if (fmt == QLatin1String("image/ppm")) { fmtatom = XA_PIXMAP; QByteArray pmd = getDataInFormat(fmtatom); if (pmd.size() == sizeof(Pixmap)) { Pixmap xpm = *((Pixmap*)pmd.data()); Display *dpy = X11->display; Window r; int x,y; uint w,h,bw,d; if (! xpm) return QByteArray(); XGetGeometry(dpy,xpm, &r,&x,&y,&w,&h,&bw,&d); QImageWriter imageWriter; GC gc = XCreateGC(dpy, xpm, 0, 0); QImage imageToWrite; if (d == 1) { QBitmap qbm(w,h); XCopyArea(dpy,xpm,qbm.handle(),gc,0,0,w,h,0,0); if (type == QVariant::Bitmap) return qbm; if (type == QVariant::Pixmap) return QPixmap(qbm); imageWriter.setFormat("PBMRAW"); imageToWrite = qbm.toImage(); } else { QPixmap qpm(w,h); XCopyArea(dpy,xpm,qpm.handle(),gc,0,0,w,h,0,0); if (type == QVariant::Pixmap) return qpm; imageWriter.setFormat("PPMRAW"); imageToWrite = qpm.toImage(); } XFreeGC(dpy,gc); QBuffer buf; buf.open(QIODevice::WriteOnly); imageWriter.setDevice(&buf); imageWriter.write(imageToWrite); return buf.buffer(); } else { fmtatom = X11->xdndStringToAtom(fmt.toLatin1().data()); } } else { fmtatom = X11->xdndStringToAtom(fmt.toLatin1().data()); } return getDataInFormat(fmtatom);}QByteArray QClipboardWatcher::getDataInFormat(Atom fmtatom) const{ QByteArray buf; Display *dpy = X11->display; Window win = requestor->winId(); DEBUG("QClipboardWatcher::getDataInFormat: selection '%s' format '%s'", X11->xdndAtomToString(atom).data(), X11->xdndAtomToString(fmtatom).data()); XSelectInput(dpy, win, NoEventMask); // don't listen for any events XDeleteProperty(dpy, win, ATOM(_QT_SELECTION)); XConvertSelection(dpy, atom, fmtatom, ATOM(_QT_SELECTION), win, X11->time); XSync(dpy, false); VDEBUG("QClipboardWatcher::getDataInFormat: waiting for SelectionNotify event"); XEvent xevent; if (!X11->clipboardWaitForEvent(win,SelectionNotify,&xevent,clipboard_timeout) || xevent.xselection.property == XNone) { DEBUG("QClipboardWatcher::getDataInFormat: format not available"); return buf; } VDEBUG("QClipboardWatcher::getDataInFormat: fetching data..."); Atom type; XSelectInput(dpy, win, PropertyChangeMask); if (X11->clipboardReadProperty(win, ATOM(_QT_SELECTION), true, &buf, 0, &type, 0, false)) { if (type == ATOM(INCR)) { int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0; buf = X11->clipboardReadIncrementalProperty(win, ATOM(_QT_SELECTION), nbytes, false); } } XSelectInput(dpy, win, NoEventMask); DEBUG("QClipboardWatcher::getDataInFormat: %d bytes received", buf.size()); return buf;}const QMimeData* QClipboard::mimeData(Mode mode) const{ QClipboardData *d = 0; switch (mode) { case Selection: d = selectionData(); break; case Clipboard: d = clipboardData(); break; } if (! d->source() && ! timer_event_clear) { if (mode == Selection) { if (! selection_watcher) selection_watcher = new QClipboardWatcher(mode); d->setSource(selection_watcher); } else { if (! clipboard_watcher) clipboard_watcher = new QClipboardWatcher(mode); d->setSource(clipboard_watcher); } if (! timer_id) { // start a zero timer - we will clear cached data when the timer // times out, which will be the next time we hit the event loop... // that way, the data is cached long enough for calls within a single // loop/function, but the data doesn't linger around in case the selection // changes QClipboard *that = ((QClipboard *) this); timer_id = that->startTimer(0); } } return d->source();}void QClipboard::setMimeData(QMimeData* src, Mode mode){ Atom atom, sentinel_atom; QClipboardData *d; switch (mode) { case Selection: atom = XA_PRIMARY; sentinel_atom = ATOM(_QT_SELECTION_SENTINEL); d = selectionData(); break; case Clipboard: atom = ATOM(CLIPBOARD); sentinel_atom = ATOM(_QT_CLIPBOARD_SENTINEL); d = clipboardData(); break; default: qWarning("QClipboard::data: invalid mode '%d'", mode); return; } Display *dpy = X11->display; Window newOwner; if (! src) { // no data, clear clipboard contents newOwner = XNone; d->clear(); } else { setupOwner(); newOwner = owner->winId(); d->setSource(src); d->timestamp = X11->time; } Window prevOwner = XGetSelectionOwner(dpy, atom); // use X11->time, since d->timestamp == CurrentTime when clearing XSetSelectionOwner(dpy, atom, newOwner, X11->time); if (mode == Selection) emit selectionChanged(); else emit dataChanged(); if (XGetSelectionOwner(dpy, atom) != newOwner) { qWarning("QClipboard::setData: Cannot set X11 selection owner for %s", X11->xdndAtomToString(atom).data()); d->clear(); return; } // Signal to other Qt processes that the selection has changed Window owners[2]; owners[0] = newOwner; owners[1] = prevOwner; XChangeProperty(dpy, QApplication::desktop()->screen(0)->winId(), sentinel_atom, XA_WINDOW, 32, PropModeReplace, (unsigned char*)&owners, 2);}/* Called by the main event loop in qapplication_x11.cpp when the _QT_SELECTION_SENTINEL property has been changed (i.e. when some Qt process has performed QClipboard::setData(). If it returns true, the QClipBoard dataChanged() signal should be emitted.*/bool qt_check_selection_sentinel(){ bool doIt = true; if (owner) { /* Since the X selection mechanism cannot give any signal when the selection has changed, we emulate it (for Qt processes) here. The notification should be ignored in case of either a) This is the process that did setData (because setData() then has already emitted dataChanged()) b) This is the process that owned the selection when dataChanged() was called (because we have then received a SelectionClear event, and have already emitted dataChanged() as a result of that) */ Window* owners; Atom actualType; int actualFormat; ulong nitems; ulong bytesLeft; if (XGetWindowProperty(X11->display, QApplication::desktop()->screen(0)->winId(), ATOM(_QT_SELECTION_SENTINEL), 0, 2, False, XA_WINDOW, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char**)&owners) == Success) { if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) { Window win = owner->winId(); if (owners[0] == win || owners[1] == win) doIt = false; } XFree(owners); } } if (doIt) { if (waiting_for_data) { pending_selection_changed = true; if (! pending_timer_id) pending_timer_id = QApplication::clipboard()->startTimer(0); doIt = false; } else { selectionData()->clear(); } } return doIt;}bool qt_check_clipboard_sentinel(){ bool doIt = true; if (owner) { Window *owners; Atom actualType; int actualFormat; unsigned long nitems, bytesLeft; if (XGetWindowProperty(X11->display, QApplication::desktop()->screen(0)->winId(), ATOM(_QT_CLIPBOARD_SENTINEL), 0, 2, False, XA_WINDOW, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char **) &owners) == Success) { if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) { Window win = owner->winId(); if (owners[0] == win || owners[1] == win) doIt = false; } XFree(owners); } } if (doIt) { if (waiting_for_data) { pending_clipboard_changed = true; if (! pending_timer_id) pending_timer_id = QApplication::clipboard()->startTimer(0); doIt = false; } else { clipboardData()->clear(); } } return doIt;}#endif // QT_NO_CLIPBOARD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -