[PyKDE] custom clipboard types broken?

Phil Thompson phil at riverbankcomputing.co.uk
Sat Oct 8 23:30:59 BST 2005


On Thursday 06 October 2005 4:54 am, Anthony Heading wrote:
> Hi,
>
> Attached is a program which I believe worked perfectly in
> earlier versions of pyqt, but now no longer functions.  The
> program is supposed to put data onto the windows clipboard
> in 'CSV' format  (the clipboard id that seems to correspond
> to CSV format is hardwired in the example, but in reality I
> call the Win32 API to obtain the right value).
>
> The point of failure appears to be around the callback
> from qt's renderFormat() into sipQMimeSource::format() -
> the variable sipPySelf is for some reason NULL, causing
> the sipIsPyMethod to return false and the function to
> return NULL, thus terminating any attempts to encode
> the clipboard data.
>
>
> const char * sipQMimeSource::format(int a0) const
> {
>     extern const char * sipVH_qt_189(sip_gilstate_t,PyObject *,int);
>
>     sip_gilstate_t sipGILState;
>     PyObject *meth;
>
>     meth = sipIsPyMethod(&sipGILState,const_cast<sipMethodCache
> *>(&sipPyMethods[0]),sipPySelf,sipNm_qt_QMimeSource,sipNm_qt_format);
>
>     if (!meth)
> 	return 0;
>
>     return sipVH_qt_189(sipGILState,meth,a0);
> }
>
> Rgds
>
> Anthony
>
>
> #!/usr/bin/env python
>
> from qt import *
> import winfuncs
> import sys
>
> class WindowsMimeCSV(QWindowsMime):
>     def __init__(self, *args):
> 	QWindowsMime.__init__(self)
> 	self.cfnum = 49638  # Csv
>
>     def canConvert(self, mime, cf):
> 	return mime == "text/csv" and cf == self.cfnum
>
>     def cf(self, pos):
> 	return self.cfnum
>
>     def cfFor(self, mime):
> 	if mime == "text/csv":
> 	    return self.cfnum
> 	return 0
>
>     def convertFromMime(self, data, mime, cf):
> 	return str(data)
>
>     def convertToMime(self, data, mine, cf):
> 	return str(data)
>
>     def convertorName(self):
> 	return "Csv"
>
>     def countCf(self):
> 	return 1
>
>     def mimeFor(self, cf):
> 	if cf == self.cfnum:
> 	    return "text/csv"
> 	return None
>
> _WindowsMimeCSV = None
>
> def RegisterCSV():
>     global _WindowsMimeCSV
>     if _WindowsMimeCSV is None:
> 	_WindowsMimeCSV = WindowsMimeCSV()
>
> class CSVMimeSource(QMimeSource):
>     def __init__(self, data):
> 	QMimeSource.__init__(self)
> 	RegisterCSV()
> 	self.data = data
>
>     def encodedData(self, mime):
> 	lines = []
> 	for row in self.data:
> 	    fields = []
> 	    for field in row:
> 		x = str(field)
> 		if "," in x: x = '"%s"' % x
> 		fields.append(x)
> 	    lines.append(",".join(fields))
> 	csv = "\n".join(lines)
> 	return csv
>
>     def format(self, i):
> 	if i == 0:
> 	    return "text/csv"
> 	return None
>
>     def provides(self, mime):
> 	if mime == "text/csv":
> 	    return true
> 	return false
>
>
> def CSVExport(data):
>     mimeSource = CSVMimeSource (data)
>     clipboard  = QApplication.clipboard()
>     clipboard.setData (mimeSource, QClipboard.Clipboard)
>
> def example():
>     CSVExport([[1,2],[3,4]])
>
>
> app = QApplication(sys.argv)
>
> button = QPushButton("Copy", None)
>
> QObject.connect(button, SIGNAL("clicked()"), example)
>
> button.show()
>
> sys.exit(app.exec_loop())

The problem is the changes in SIP 4.3 that support the cyclic garbage 
collector. QClipboard.setData() takes ownership of the data (the mime 
source).

In previous versions the CSVMimeSource instance would never be garbage 
collected. With 4.3 the object gets attached to the clipboard Python object 
(ie. that returned by QApplication.clipboard()).

When the clipboard object is garbage collected (when it goes out of scope when 
CSVExport() returns) the CSVMimeSource instance gets garbage collected as 
well.

I need to think a bit more about what the correct solution is. Perhaps I 
introduce another transfer type - TransferAndForget - or maybe it's possible 
to be clever and work out automatically what the appropriate action is.

In the meantime a workaround should be to add the following line after the 
call to QApplication()...

cb = QApplication.clipboard()

Phil




More information about the PyQt mailing list