#include "support/filetools.h"
#include "support/gettext.h"
#include "support/lstrings.h"
+#include "support/lyxtime.h"
#ifdef Q_WS_MACX
#include "support/linkback/LinkBackProxy.h"
namespace frontend {
+static QMimeData const * read_clipboard()
+{
+ LYXERR(Debug::ACTION, "Getting Clipboard");
+ QMimeData const * source =
+ qApp->clipboard()->mimeData(QClipboard::Clipboard);
+ if (!source) {
+ LYXERR0("0 bytes (no QMimeData)");
+ return new QMimeData();
+ }
+ // It appears that doing IO between getting a mimeData object
+ // and using it can cause a crash (maybe Qt used IO
+ // as an excuse to free() it? Anyway let's not introduce
+ // any new IO here, so e.g. leave the following line commented.
+ // lyxerr << "Got Clipboard (" << (long) source << ")\n" ;
+ return source;
+}
+
+
+void CacheMimeData::update()
+{
+ time_t const start_time = current_time();
+ LYXERR(Debug::ACTION, "Creating CacheMimeData object");
+ cached_formats_ = read_clipboard()->formats();
+
+ // Qt times out after 5 seconds if it does not recieve a response.
+ if (current_time() - start_time > 3) {
+ lyxerr << "No timely response from clipboard, perhaps process "
+ << "holding clipboard is frozen?" << endl;
+ }
+}
+
+
+QByteArray CacheMimeData::data(QString const & mimeType) const
+{
+ return read_clipboard()->data(mimeType);
+}
+
QString const lyxMimeType(){ return "application/x-lyx"; }
QString const pdfMimeType(){ return "application/pdf"; }
LYXERR(Debug::ACTION, "GuiClipboard::getAsLyX(): `");
// We don't convert encodings here since the encoding of the
// clipboard contents is specified in the data itself
- QMimeData const * source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
- if (!source) {
- LYXERR(Debug::ACTION, "' (no QMimeData)");
- return string();
- }
-
- if (source->hasFormat(lyxMimeType())) {
+ if (cache_.hasFormat(lyxMimeType())) {
// data from ourself or some other LyX instance
- QByteArray const ar = source->data(lyxMimeType());
+ QByteArray const ar = cache_.data(lyxMimeType());
string const s(ar.data(), ar.count());
LYXERR(Debug::ACTION, s << "'");
return s;
return filename;
}
- // get mime data
- QMimeData const * source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
- if (!source) {
- LYXERR(Debug::ACTION, "0 bytes (no QMimeData)");
- return FileName();
- }
-
// get mime for type
QString mime;
switch (type) {
}
// get data
- if (!source->hasFormat(mime))
+ if (!cache_.hasFormat(mime))
return FileName();
// data from ourself or some other LyX instance
- QByteArray const ar = source->data(mime);
+ QByteArray const ar = cache_.data(mime);
LYXERR(Debug::ACTION, "Getting from clipboard: mime = " << mime.data()
<< "length = " << ar.count());
bool GuiClipboard::hasLyXContents() const
{
- QMimeData const * const source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
- return source && source->hasFormat(lyxMimeType());
+ return cache_.hasFormat(lyxMimeType());
}
bool GuiClipboard::hasTextContents() const
{
- QMimeData const * const source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
- return source && source->hasText();
+ return cache_.hasText();
}
|| hasGraphicsContents(LinkBackGraphicsType);
}
- QMimeData const * const source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
-
// handle image cases first
if (type == PngGraphicsType || type == JpegGraphicsType)
- return source->hasImage();
+ return cache_.hasImage();
// handle LinkBack for Mac
if (type == LinkBackGraphicsType)
#endif // Q_WS_MACX
// get mime data
- QStringList const & formats = source->formats();
+ QStringList const & formats = cache_.formats();
LYXERR(Debug::ACTION, "We found " << formats.size() << " formats");
for (int i = 0; i < formats.size(); ++i)
LYXERR(Debug::ACTION, "Found format " << formats[i]);
default: LASSERT(false, /**/);
}
- return source && source->hasFormat(mime);
+ return cache_.hasFormat(mime);
}
void GuiClipboard::on_dataChanged()
{
- QMimeData const * const source =
- qApp->clipboard()->mimeData(QClipboard::Clipboard);
- QStringList l = source->formats();
+ //Note: we do not really need to run cache_.update() unless the
+ //data has been changed *and* the GuiClipboard has been queried.
+ //However if run cache_.update() the moment a process grabs the
+ //clipboard, the process holding the clipboard presumably won't
+ //yet be frozen, and so we won't need to wait 5 seconds for Qt
+ //to time-out waiting for the clipboard.
+ cache_.update();
+ QStringList l = cache_.formats();
LYXERR(Debug::ACTION, "Qt Clipboard changed. We found the following mime types:");
for (int i = 0; i < l.count(); i++)
LYXERR(Debug::ACTION, l.value(i));
#include "frontends/Clipboard.h"
+#include <QMimeData>
#include <QObject>
+#include <QStringList>
namespace lyx {
namespace frontend {
class QMacPasteboardMimeGraphics;
+/**
+ * \class CacheMimeData
+ *
+ * This class is used in order to query the clipboard only once on
+ * startup and once each time the contents of the clipboard changes.
+ */
+class CacheMimeData : public QMimeData
+{
+ Q_OBJECT
+public:
+ // LyX calls "on_dataChanged" on startup, so it is not necessary to
+ // query the clipboard here.
+ CacheMimeData()
+ {}
+
+ /// reads the clipboard and updates the cached_formats_
+ void update();
+ /// returns the cached list of formats supported by the object
+ virtual QStringList formats() const { return cached_formats_; }
+ /// reads the clipboard and returns the data
+ QByteArray data(QString const & mimeType) const;
+
+private:
+ /// the cached list of formats supported by the object
+ QStringList cached_formats_;
+};
+
+
/**
* The Qt4 version of the Clipboard.
*/
bool text_clipboard_empty_;
bool has_lyx_contents_;
bool has_graphics_contents_;
+ /// the cached mime data used to describe the information
+ /// that can be stored in the clipboard
+ CacheMimeData cache_;
};
QString const lyxMimeType();