tags:

views:

282

answers:

2

After recommending uclip I found out that it does not work for copying. I started debugging this, first converting from QT3 to QT4 to see if that helped, but it did not make any difference and eventually I found that it is a know bug but marked as "Won't fix":

This is a side effect of setting the clipboard immediately after creating QApplication. The X11 clipboard is event driven, and as such, relies on current timestamps from the X server. These timestamps are automatically handled by QApplication. However, in this simple example, the event loop is not run, thus we do not get updated timestamps from the X server, which in turn causes QClipboard::ownsClipboard() to return false. Setting the clipboard in response to e.g. a keyboard or mouse event makes this work as expected.

The ideal minimum code to use QClipboard::setText() should be something like the following

#include <qapplication.h>
#include <qclipboard.h>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QClipboard *cb = QApplication::clipboard();
    QString input = "Hello clipboard";
    cb->setText(input);

    return 0;
    //return app.exec(); makes no difference from return 0
}

however as I said, this will not work. Through trial and error I have come up with the the following that will work

#include <qapplication.h>
#include <qclipboard.h>
#include <QTimer>
#include <QtGui>
#include <iostream>

class MyApplication : public QApplication {
    Q_OBJECT
public:
    MyApplication(int & argc, char ** argv) : QApplication(argc, argv)
    {
    }
public slots:
    void setClipboard()
    {
     QClipboard *cb = QApplication::clipboard();
     QString input = "THIS WORKS";
     std::cout << "setText line " << __LINE__+1 << "\n";
     cb->setText(input);
    }
};

class MainWidget:public QMainWindow {
public:
    MainWidget() {
     QClipboard *clipboard = QApplication::clipboard();
     std::cout << "setText line " << __LINE__+1 << "\n";
     clipboard->setText("This will not be copied to the clipboard, apparently also too early");
    }
};


int main(int argc, char *argv[])
{
    MyApplication app(argc, argv);

    QClipboard *cb = QApplication::clipboard();
    QString input = "This will not be copied to the clipboard, too early";
    std::cout << "setText line " << __LINE__+1 << "\n";
    cb->setText(input);

    //QTimer::singleShot(3, &app, SLOT(setClipboard())); // 3 ok, 2 not ok

    MainWidget mainWid;
    //mainWid.show();

    QTimer::singleShot(2, &app, SLOT(setClipboard())); // 2 ok, 1 not ok

    return app.exec();
}
#include "main.moc"

however, I am sure this is neither the minimum nor the best way to do it. So therefore I ask, what will be required to generate such a required X11 timestamp update with minimum effort and impact?

A: 

I would give a try to something like:

QApplication app(argc, argv);
// Paste something to your clipboard
app.processEvents();

This actually makes the event loop of the Qt Application process all pending events something that doesn't happen if you don't call app.exec() as in your first example and is very similar to what you do in your second one were you actually do something equivalent with a timer instead. I haven't tried it though and this is also way off what the documentation suggests (handle the clipboard as a response to user input events).

Yorgos Pagles
Unfortunately that does not help because app.processEvents() only triggers QT's event handling which is dependent on some X11 activity not triggered. I initially used "return app.exec()" instead of "return 0" in the simple example.
hlovdal
So the whatever event loop of X11 has to be triggered in order for the clipboard to work? Can't think of anything on the Qt side.
Yorgos Pagles
Yes, this is probably more an X11 than QT question. The instantiation of MainWidget is apparently enough, but I would like to avoid creating a heavier dummy object than needed, perferably also avoid creating dummy objects if possible.
hlovdal
A: 

I believe you are out of luck on X11. It is up to the application itself to manage the X11 clipboard. So when your application closes the data on the clipboard data is lost.

I think your best bet is to call the command line xclip command. Pipe the text you want on the clipboard into it. I'm not sure how available this command usually is. And it must be doing something that could be recreated with lower level x code?

Peter Shinners