📄 qclipboard_x11.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/// #define QCLIPBOARD_DEBUG// #define QCLIPBOARD_DEBUG_VERBOSE#ifdef QCLIPBOARD_DEBUG# define DEBUG qDebug#else# define DEBUG if (false) qDebug#endif#ifdef QCLIPBOARD_DEBUG_VERBOSE# define VDEBUG qDebug#else# define VDEBUG if (false) qDebug#endif#include "qplatformdefs.h"#include "qclipboard.h"#ifndef QT_NO_CLIPBOARD#include "qabstracteventdispatcher.h"#include "qapplication.h"#include "qdesktopwidget.h"#include "qbitmap.h"#include "qdatetime.h"#include "qiodevice.h"#include "qbuffer.h"#include "qtextcodec.h"#include "qlist.h"#include "qmap.h"#include "qapplication_p.h"#include "qevent.h"#include "qt_x11_p.h"#include "qx11info_x11.h"#include "qimagewriter.h"#include "qvariant.h"#include "qdnd_p.h"/***************************************************************************** Internal QClipboard functions for X11. *****************************************************************************/static int clipboard_timeout = 5000; // 5s timeout on clipboard operationsstatic QWidget * owner = 0;static QWidget *requestor = 0;static bool timer_event_clear = false;static int timer_id = 0;static int pending_timer_id = 0;static bool pending_clipboard_changed = false;static bool pending_selection_changed = false;// event capture mechanism for qt_xclb_wait_for_eventstatic bool waiting_for_data = false;static bool has_captured_event = false;static Window capture_event_win = XNone;static int capture_event_type = -1;static XEvent captured_event;class QClipboardWatcher; // forward declstatic QClipboardWatcher *selection_watcher = 0;static QClipboardWatcher *clipboard_watcher = 0;static void cleanup(){ delete owner; delete requestor; owner = 0; requestor = 0;}staticvoid setupOwner(){ if (owner) return; owner = new QWidget(0); owner->setObjectName(QLatin1String("internal clipboard owner")); owner->createWinId(); requestor = new QWidget(0); requestor->createWinId(); requestor->setObjectName(QLatin1String("internal clipboard requestor")); qAddPostRoutine(cleanup);}class QClipboardWatcher : public QInternalMimeData {public: QClipboardWatcher(QClipboard::Mode mode); ~QClipboardWatcher(); bool empty() const; virtual bool hasFormat_sys(const QString &mimetype) const; virtual QStringList formats_sys() const; QVariant retrieveData_sys(const QString &mimetype, QVariant::Type type) const; QByteArray getDataInFormat(Atom fmtatom) const; Atom atom; mutable QStringList formatList; mutable QByteArray format_atoms;};class QClipboardData{public: QClipboardData(); ~QClipboardData(); void setSource(QMimeData* s) { if (s == src) return; delete src; src = s; } QMimeData *source() const { return src; } void clear(); QMimeData *src; Time timestamp;};QClipboardData::QClipboardData(){ src = 0; timestamp = CurrentTime;}QClipboardData::~QClipboardData(){ clear(); }void QClipboardData::clear(){ delete src; src = 0; timestamp = CurrentTime;}static QClipboardData *internalCbData = 0;static QClipboardData *internalSelData = 0;static void cleanupClipboardData(){ delete internalCbData; internalCbData = 0;}static QClipboardData *clipboardData(){ if (internalCbData == 0) { internalCbData = new QClipboardData; qAddPostRoutine(cleanupClipboardData); } return internalCbData;}static void cleanupSelectionData(){ delete internalSelData; internalSelData = 0;}static QClipboardData *selectionData(){ if (internalSelData == 0) { internalSelData = new QClipboardData; qAddPostRoutine(cleanupSelectionData); } return internalSelData;}class QClipboardINCRTransaction{public: QClipboardINCRTransaction(Window w, Atom p, Atom t, int f, QByteArray d, unsigned int i); ~QClipboardINCRTransaction(void); int x11Event(XEvent *event); Window window; Atom property, target; int format; QByteArray data; unsigned int increment; unsigned int offset;};typedef QMap<Window,QClipboardINCRTransaction*> TransactionMap;static TransactionMap *transactions = 0;static QApplication::EventFilter prev_event_filter = 0;static int incr_timer_id = 0;static bool qt_x11_incr_event_filter(void *message, long *result){ XEvent *event = reinterpret_cast<XEvent *>(message); TransactionMap::Iterator it = transactions->find(event->xany.window); if (it != transactions->end()) { if ((*it)->x11Event(event) != 0) return true; } if (prev_event_filter) return prev_event_filter(event, result); return false;}/* called when no INCR activity has happened for 'clipboard_timeout' milliseconds... we assume that all unfinished transactions have timed out and remove everything from the transaction map*/static void qt_xclb_incr_timeout(void){ qWarning("QClipboard: Timed out while sending data"); while (transactions) delete *transactions->begin();}QClipboardINCRTransaction::QClipboardINCRTransaction(Window w, Atom p, Atom t, int f, QByteArray d, unsigned int i) : window(w), property(p), target(t), format(f), data(d), increment(i), offset(0u){ DEBUG("QClipboard: sending %d bytes (INCR transaction %p)", d.size(), this); XSelectInput(X11->display, window, PropertyChangeMask); if (! transactions) { VDEBUG("QClipboard: created INCR transaction map"); transactions = new TransactionMap; prev_event_filter = qApp->setEventFilter(qt_x11_incr_event_filter); incr_timer_id = QApplication::clipboard()->startTimer(clipboard_timeout); } transactions->insert(window, this);}QClipboardINCRTransaction::~QClipboardINCRTransaction(void){ VDEBUG("QClipboard: destroyed INCR transacton %p", this); XSelectInput(X11->display, window, NoEventMask); transactions->remove(window); if (transactions->isEmpty()) { VDEBUG("QClipboard: no more INCR transactions"); delete transactions; transactions = 0; (void)qApp->setEventFilter(prev_event_filter); if (incr_timer_id != 0) { QApplication::clipboard()->killTimer(incr_timer_id); incr_timer_id = 0; } }}int QClipboardINCRTransaction::x11Event(XEvent *event){ if (event->type != PropertyNotify || (event->xproperty.state != PropertyDelete || event->xproperty.atom != property)) return 0; // restart the INCR timer if (incr_timer_id) QApplication::clipboard()->killTimer(incr_timer_id); incr_timer_id = QApplication::clipboard()->startTimer(clipboard_timeout); unsigned int bytes_left = data.size() - offset; if (bytes_left > 0) { unsigned int xfer = qMin(increment, bytes_left); VDEBUG("QClipboard: sending %d bytes, %d remaining (INCR transaction %p)", xfer, bytes_left - xfer, this); XChangeProperty(X11->display, window, property, target, format, PropModeReplace, (uchar *) data.data() + offset, xfer); offset += xfer; } else { // INCR transaction finished... XChangeProperty(X11->display, window, property, target, format, PropModeReplace, (uchar *) data.data(), 0); delete this; } return 1;}/***************************************************************************** QClipboard member functions for X11. *****************************************************************************/void QClipboard::clear(Mode mode){ setMimeData(0, mode);}bool QClipboard::supportsMode(Mode mode) const{ return (mode == Clipboard || mode == Selection);}bool QClipboard::ownsMode(Mode mode) const{ if (mode == Clipboard) return clipboardData()->timestamp != CurrentTime; else if(mode == Selection) return selectionData()->timestamp != CurrentTime; else return false;}// event filter function... captures interesting events while// qt_xclb_wait_for_event is running the event loopstatic bool qt_x11_clipboard_event_filter(void *message, long *){ XEvent *event = reinterpret_cast<XEvent *>(message); if (event->xany.type == capture_event_type && event->xany.window == capture_event_win) { VDEBUG("QClipboard: event_filter(): caught event type %d", event->type); has_captured_event = true; captured_event = *event; return true; } return false;}static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer){ return ((e->type == SelectionRequest && (e->xselectionrequest.selection == XA_PRIMARY || e->xselectionrequest.selection == ATOM(CLIPBOARD))) || (e->type == SelectionClear && (e->xselectionclear.selection == XA_PRIMARY || e->xselectionclear.selection == ATOM(CLIPBOARD))));}bool QX11Data::clipboardWaitForEvent(Window win, int type, XEvent *event, int timeout){ QTime started = QTime::currentTime(); QTime now = started; if (QAbstractEventDispatcher::instance()->inherits("QtMotif")) { if (waiting_for_data) qFatal("QClipboard: internal error, qt_xclb_wait_for_event recursed"); waiting_for_data = true; has_captured_event = false; capture_event_win = win; capture_event_type = type; QApplication::EventFilter old_event_filter = qApp->setEventFilter(qt_x11_clipboard_event_filter); do { if (XCheckTypedWindowEvent(display, win, type, event)) { waiting_for_data = false; qApp->setEventFilter(old_event_filter); return true; } XSync(X11->display, false); usleep(50000); now = QTime::currentTime(); if (started > now) // crossed midnight started = now; QEventLoop::ProcessEventsFlags flags(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers | QEventLoop::WaitForMoreEvents | QEventLoop::X11ExcludeTimers); QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); eventDispatcher->processEvents(flags); if (has_captured_event) { waiting_for_data = false; *event = captured_event; qApp->setEventFilter(old_event_filter); return true; } } while (started.msecsTo(now) < timeout); waiting_for_data = false; qApp->setEventFilter(old_event_filter); } else { do { if (XCheckTypedWindowEvent(X11->display,win,type,event)) return true; // process other clipboard events, since someone is probably requesting data from us XEvent e; if (XCheckIfEvent(X11->display, &e, checkForClipboardEvents, 0)) qApp->x11ProcessEvent(&e); now = QTime::currentTime(); if ( started > now ) // crossed midnight started = now; XFlush(X11->display); // sleep 50 ms, so we don't use up CPU cycles all the time. struct timeval usleep_tv;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -