PySide Bugzilla Closed for New Bugs

PySide is now a Qt Add-on and uses the Qt Project's JIRA Bug Tracker instead of this Bugzilla instance. This Bugzilla is left for reference purposes.

Bug 523 - QWidget.winId() returns PyCObject (expected unsigned long)
: QWidget.winId() returns PyCObject (expected unsigned long)
Status: CLOSED FIXED
Product: PySide
Classification: Unclassified
Component: Documentation
: HEAD
: Other Other
: P3 normal
Assigned To: Hugo Parente Lima
:
:
:
  Show dependency treegraph
 
Reported: 2010-12-03 11:16 EET by Vladimir Rutsky
Modified: 2011-11-03 18:46 EET (History)
10 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vladimir Rutsky 2010-12-03 11:16:44 EET
According to documentation QWidget.winId() should return unsigned long
(http://www.pyside.org/docs/pyside/PySide/QtGui/QWidget.html#PySide.QtGui.QWidget.winId),
but current implementation returns PyCObject without any method for converting
it to integer type.

Consider following example:


import sys
from PySide import QtCore, QtGui

app = QtGui.QApplication(sys.argv)

win = QtGui.QWidget()

win.resize(320, 240)
win.setWindowTitle("Hello, World!")
win.show()

print win.winId()
print dir(win.winId())

print win.effectiveWinId()
print dir(win.effectiveWinId())

print win.nativeParentWidget()

sys.exit(app.exec_())



output:
<PyCObject object at 0x00A4F2A8>
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setatr__', '__sizeof__', '__str__', '__subclasshook__']
<PyCObject object at 0x00A4F2A8>
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setatr__', '__sizeof__', '__str__', '__subclasshook__']
None
Comment 1 Matti Airas 2010-12-03 12:55:37 EET
Thanks for the bug report! Prioritizing P3 - this will be fixed during our
upcoming sprints. Before the 1.0.0 release, in any case. :-)
Comment 2 Hugo Parente Lima 2010-12-16 15:55:25 EET
winId returns a opaque pointer on Qt, on X11 is valid to cast it to a integer,
but what about Windows? What about Mac?
Comment 3 Vladimir Rutsky 2010-12-17 07:26:29 EET
According to documentation [1] WId is not mandatory integer type (and on some
platforms it is definitely pointer type), so if PySide follows original Qt
winId() meaning, error not in PySide winId() implementation, but in
documentation [2] - it says that winId() returns unsigned long.

On different platforms winId() returns different things (some quotes from Qt
4.7.1 src\gui\kernel\qwindowdefs.h and src\gui\kernel\qwindowdefs_win.h):
Mac: typedef int WId;
Windows: typedef HWND WId;
X11: typedef unsigned long  WId;
Symbian: typedef CCoeControl * WId;

What kind of return object users of winId() expect and how they should use it?

Here is my use case.

Currently I'm developing under Windows. I need to create QWidget, get its HWND,
pass it to C++ wrapper, which will initialize some 3D engine on obtained HWND
so that engine will render into widget.
C++ wrapper is written using Boost.Python, wrapper function accepts result of
winId() as "PyObject *pPyObj", and then converts it like this: 
  hwnd = (HWND)PyCObject_AsVoidPtr(pPyObj)

This looks quite ugly (accepting abstract PyObject and converting it to pointer
with some semantic), any ideas how this should be implemented better?

[1] http://doc.qt.nokia.com/stable/qwidget.html#winId
[2]
http://www.pyside.org/docs/pyside/PySide/QtGui/QWidget.html#PySide.QtGui.QWidget.winId
Comment 4 Hugo Parente Lima 2010-12-17 11:32:28 EET
Yes, it's a doc error.

The documentation was auto-generated on Linux, and the generator resolved the
typedefed type returned by winId().

In other words... we need to change the return value on docs to PyCObject.

About your problem, your solution looks feasible for me, not ugly just
necessary :-).
Comment 5 Vladimir Rutsky 2010-12-17 12:36:27 EET
Ok. Anyway working with winId() result should be additionally documented.

Also, if winId() result will not be convertible to integer type, then this is
another place where PySide differs with PyQt, and also should be documented.
Comment 6 Hugo Parente Lima 2010-12-17 21:08:24 EET
What PyQt4 winId() returns under Windows and Mac?

We can return a unsigned long on X11 and Windows and PyCObject on other
platforms.
Comment 7 Vladimir Rutsky 2010-12-21 14:16:07 EET
(In reply to comment #6)
> What PyQt4 winId() returns under Windows and Mac?

Documentation says "int"
(http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qwidget.html#winId)
but actual result is sip.voidptr.

import sys
from PyQt4 import QtCore, QtGui
from pprint import pprint

app = QtGui.QApplication(sys.argv)

win = QtGui.QWidget()

win.resize(320, 240)
win.setWindowTitle("Hello, World!")
win.show()

w_id = win.winId()
print "w_id:", w_id
print "type(w_id):", type(w_id)
print "dir(w_id):"
pprint(dir(w_id))
print "int(w_id):", int(w_id)

#sys.exit(app.exec_())

produces:

w_id: <sip.voidptr object at 0x00A4F368>
type(w_id): <type 'sip.voidptr'>
dir(w_id):
['__class__',
 '__delattr__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__hex__',
 '__init__',
 '__int__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'ascobject',
 'asstring',
 'getsize',
 'getwriteable',
 'setsize',
 'setwriteable']
int(w_id): 96207802
Comment 8 Hugo Parente Lima 2011-01-13 14:00:59 EET
I fixed the documentation of QWidget::winId() to reflect the reallity.

marking this bug as fixed...

commit:
pyside/a78108efe3a4815226e2fe26713cd0f495d655b7
Comment 9 renato filho 2011-01-21 15:44:40 EET
release beta4
Comment 10 Samu Niveri 2011-02-20 08:15:02 EET
winId() returns PyCObject on wine with python 2.6
Comment 11 Hugo Parente Lima 2011-02-21 15:10:11 EET
(In reply to comment #10)
> winId() returns PyCObject on wine with python 2.6

And what's wrong with that? we can't cast a void pointer to a integer, and on
Windows winId() returns a void pointer.

Re-closing the bug.
Comment 12 Samu Niveri 2011-02-21 15:32:03 EET
(In reply to comment #11)
> And what's wrong with that? we can't cast a void pointer to a integer, and on
> Windows winId() returns a void pointer.

Ok, I was just bit supprised that it worked with 2.7 python + pyside + Windows
Vista, and when changed to python 2.6 + wine then there was no handle for doing
anything useful for Qt-windows. How do I get the handle in windows for now on?
Comment 13 Hugo Parente Lima 2011-02-21 16:22:41 EET
(In reply to comment #12)
> (In reply to comment #11)
> > And what's wrong with that? we can't cast a void pointer to a integer, and on
> > Windows winId() returns a void pointer.
> 
> Ok, I was just bit supprised that it worked with 2.7 python + pyside + Windows
> Vista, and when changed to python 2.6 + wine then there was no handle for doing
> anything useful for Qt-windows. How do I get the handle in windows for now on?

There's a handle, but the problem is that on Windows windows handlers are void
pointers and we can't transform a void pointer to a ordinary number.

What the library that you are using expect to receive as a window handler? a
custom class created by this library? a PyCObject? an integer? We believe that
the safest way is to use PyCObjects as it's part of Python C API and it's
readonly because void pointers are not meant to be touched by Python code, just
passed around to another built-in module.

On X11 window handlers are number, so we can return numbers without problems,
on Mac it can be two different pointer types depending if Qt was linked against
Cocoa or Carbon, so a PyCObject is returned too.
Comment 14 Samu Niveri 2011-02-21 16:33:12 EET
(In reply to comment #13)
> There's a handle, but the problem is that on Windows windows handlers are void
> pointers and we can't transform a void pointer to a ordinary number.
> 
> What the library that you are using expect to receive as a window handler? a
> custom class created by this library? a PyCObject? an integer? We believe that
> the safest way is to use PyCObjects as it's part of Python C API and it's
> readonly because void pointers are not meant to be touched by Python code, just
> passed around to another built-in module.
> 
> On X11 window handlers are number, so we can return numbers without problems,
> on Mac it can be two different pointer types depending if Qt was linked against
> Cocoa or Carbon, so a PyCObject is returned too.

I`m building add-in with python to native windows application, so I want to use
Windows SetParent API that needs integer handle. But if there is smarter way
I`m interested as this SetParent stuff is not good solution, but needed..
Comment 15 Hugo Parente Lima 2011-02-21 17:19:23 EET
(In reply to comment #14)
> I`m building add-in with python to native windows application, so I want to use
> Windows SetParent API that needs integer handle. But if there is smarter way
> I`m interested as this SetParent stuff is not good solution, but needed..

This is the problem, the guys from win32-python uses a integer to store a C
opaque pointer, IMO this is just wrong, but at the same time I can't enforce
them to accept PyCObjects as argument.

OTOH is there's no way at python level to transform a PyCObject into a integer
variable and the python win32 API only accepts integer, the winId() method
would be useless on Windows. IMO is better to raise this question on the
mailing list before change any behaviour, could you do that?
Comment 16 Samu Niveri 2011-02-21 18:22:14 EET
> This is the problem, the guys from win32-python uses a integer to store a C
> opaque pointer, IMO this is just wrong, but at the same time I can't enforce
> them to accept PyCObjects as argument.
> 
> OTOH is there's no way at python level to transform a PyCObject into a integer
> variable and the python win32 API only accepts integer, the winId() method
> would be useless on Windows. IMO is better to raise this question on the
> mailing list before change any behaviour, could you do that?

Maybe I just need to figure out some other way to do this, as the Windows API
is not the best solution..
Comment 17 Hugo Parente Lima 2011-03-04 15:10:40 EET
Closing bug due to 1.0.0 release.
Comment 18 Vladimir Rutsky 2011-11-03 18:46:58 EET
(In reply to comment #15)
> OTOH is there's no way at python level to transform a PyCObject into a integer
> variable and the python win32 API only accepts integer, the winId() method
> would be useless on Windows. IMO is better to raise this question on the
> mailing list before change any behaviour, could you do that?

There is solution for converting PyCObject into integer on Windows (tested on
Python 2.6 and PySide from PySide-1.0.7qt474.win32-py2.6.exe):

    pycobject_hwnd = widget.winId()

    import ctypes
    ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
    ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]

    int_hwnd = ctypes.pythonapi.PyCObject_AsVoidPtr(pycobject_hwnd)

(Based on example from here: http://pygame.org/wiki/PyOgre).