Discussion:
Safe access to QPlatformNativeInterface resources
Harri Porten
2011-09-28 12:38:40 UTC
Permalink
Hi,

this topic was already touched in Holger's "directFB and Lighthouse" mail
but wasn't really resolved. As my concern also applies to Qt 4.8 I'd like
to bring up this topic in a distinct mail.

Usage of the QPlatformNativeInterface class typically looks like this case
from tst_qlistview.cpp:

return static_cast<HWND> (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));

Above code is #ifdef'ed for Windows which makes it safe as there is only a
single platform implementation available (as far as I can tell). But what
about Linux? I count three implementations of "display" resources:

$ git grep \"display\" src/plugins/platforms/*/*.cpp
src/plugins/platforms/wayland/qwaylandnativeinterface.cpp: if (lowerCaseResource == "display")
src/plugins/platforms/xcb/qxcbnativeinterface.cpp: insert("display",QXcbNativeInterface::Display);
src/plugins/platforms/xlib/qxlibnativeinterface.cpp: insert("display",QXlibNativeInterface::Display);

How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?

I know, that ideally Qt should provide a portable API avoid the use of
native resources. But realistically this will never all cases. So what to
do? Add some runtime detection? In the case of nativeResourceForWindow()
I'd say it would already suffice to mandate that the resource names have
to unique. Either by a pure text prefix

nativeResourceForWindow("xlib/display");

or a distinct parameter:

nativeResourceForWindow("xlib", "display");

As it is I foresee weird crashes after casting void* pointers. In our
product's code we already had to take the risk...

Harri.
Thiago Macieira
2011-09-28 14:47:54 UTC
Permalink
Post by Harri Porten
How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?
What are you going to do with this native resource after you get it from
QPlatformNativeInterface? You plan on calling some some function in wayland or
XCB or directfb, right?

Then you need to have code to deal with the many plugins active.

Or was your question asking how to determine which plugin is active? If that's
the case, I support you that we need such a function.
Post by Harri Porten
I know, that ideally Qt should provide a portable API avoid the use of
native resources. But realistically this will never all cases. So what to
do? Add some runtime detection? In the case of nativeResourceForWindow()
I'd say it would already suffice to mandate that the resource names have
to unique. Either by a pure text prefix
nativeResourceForWindow("xlib/display");
nativeResourceForWindow("xlib", "display");
As it is I foresee weird crashes after casting void* pointers. In our
product's code we already had to take the risk...
The only thing this buys us is that you detect which plugin is active by
getting null pointers if you ask resources of the wrong plugin. You will not
get a valid XLib display if the plugin in use is Wayland.

This all boils down to a runtime determination of which plugin is active.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
Harri Porten
2011-09-28 15:12:58 UTC
Permalink
Post by Thiago Macieira
Post by Harri Porten
How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?
What are you going to do with this native resource after you get it from
QPlatformNativeInterface? You plan on calling some some function in wayland or
XCB or directfb, right?
Then you need to have code to deal with the many plugins active.
Yes. That's accepted. It's about replacing an #ifdef solution with an if()
solution for esoteric cases of platform-specific code.
Post by Thiago Macieira
Or was your question asking how to determine which plugin is active? If that's
the case, I support you that we need such a function.
If there'd be such a query that'll do the job of passing on e.g. window
handles to 3rd party functions operating on those.
Post by Thiago Macieira
Post by Harri Porten
I know, that ideally Qt should provide a portable API avoid the use of
native resources. But realistically this will never all cases. So what to
do? Add some runtime detection? In the case of nativeResourceForWindow()
I'd say it would already suffice to mandate that the resource names have
to unique. Either by a pure text prefix
nativeResourceForWindow("xlib/display");
nativeResourceForWindow("xlib", "display");
As it is I foresee weird crashes after casting void* pointers. In our
product's code we already had to take the risk...
The only thing this buys us is that you detect which plugin is active by
getting null pointers if you ask resources of the wrong plugin. You will not
get a valid XLib display if the plugin in use is Wayland.
No. I admit this was proposal was a very local solution that would avoid a
global I'm-running-on-platform-X function - in case this is against Qt 5's
philosophy ;)
Post by Thiago Macieira
This all boils down to a runtime determination of which plugin is active.
An interface exchanging type safety with void* for the purpose of platform
independant API will be fine with a string-based identifier?

Harri.
Thiago Macieira
2011-09-28 16:04:37 UTC
Permalink
Post by Harri Porten
Post by Thiago Macieira
This all boils down to a runtime determination of which plugin is active.
An interface exchanging type safety with void* for the purpose of platform
independant API will be fine with a string-based identifier?
I don't think we can make it any more abstract!

Someone could write a small wrapper class to bring back type safety and
correct spelling of the resources. A "proper OOP" solution would probably be
very heavyweight and you'd *still* have to do casts:

class QNativeDisplay { ... };
class QX11Display : pubilc QNativeDisplay { XDisplay display; };
class QXCBDisplay : public QNativeDisplay { XCBDisplay display; }
...


class QAbstractPlatform
{
public:
enum Platform {
// either this or dynamic_cast to the platform of your choice
Other,
XLib,
XCB,
Wayland,
DirectFB,
Win32,
Cocoa,
EGL,
OpenWF,
NaCl
};
virtual Platform platform() const = 0;

virtual QNativeDisplay *nativeDisplay() const = 0;
virtual QNativeSurface *nativeSurfaceForWidget(const QWidget *ptr) = 0;
virtual QNativePixmap *nativePixmap(const QPixmap &pixmap) = 0;
};

class QXCBPlatform: public QAbstractPlatform
{
// implement common pure virtuals with covariant returns
QXCBDisplay *nativeDisplay() const override;
QXCBPixmap *nativePixmap(const QPixmap &pixmap) override;

// plaform specific (no matching resource elsewhere)
virtual QXCBMITSHMPixmap *nativeMitShmPixmap(const QPixmap &pixmap) new;
};
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
Samuel Rødal
2011-09-28 18:37:09 UTC
Permalink
Post by Harri Porten
Post by Thiago Macieira
Post by Harri Porten
How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?
What are you going to do with this native resource after you get it from
QPlatformNativeInterface? You plan on calling some some function in wayland or
XCB or directfb, right?
Then you need to have code to deal with the many plugins active.
Yes. That's accepted. It's about replacing an #ifdef solution with an if()
solution for esoteric cases of platform-specific code.
Post by Thiago Macieira
Or was your question asking how to determine which plugin is active? If that's
the case, I support you that we need such a function.
If there'd be such a query that'll do the job of passing on e.g. window
handles to 3rd party functions operating on those.
Post by Thiago Macieira
Post by Harri Porten
I know, that ideally Qt should provide a portable API avoid the use of
native resources. But realistically this will never all cases. So what to
do? Add some runtime detection? In the case of nativeResourceForWindow()
I'd say it would already suffice to mandate that the resource names have
to unique. Either by a pure text prefix
nativeResourceForWindow("xlib/display");
nativeResourceForWindow("xlib", "display");
As it is I foresee weird crashes after casting void* pointers. In our
product's code we already had to take the risk...
We were consdering replacing the void * return values with QVariants,
but that doesn't really give much in the case were they're anyway
pointers to some platform specific type. Any thoughts?

Also a comment on the display parameters, in the Xlib and XCB cases
those are the same thing. I also think we have an "EGLDisplay" resource
in several plugins. Many of these are for use in qt-compositor, which
requires some low level hooks to do shared pixmaps or use the wayland
EGL API.
Post by Harri Porten
Post by Thiago Macieira
The only thing this buys us is that you detect which plugin is active by
getting null pointers if you ask resources of the wrong plugin. You will not
get a valid XLib display if the plugin in use is Wayland.
No. I admit this was proposal was a very local solution that would avoid a
global I'm-running-on-platform-X function - in case this is against Qt 5's
philosophy ;)
The platform plugin name should probably be a getter in QGuiApplication.

--
Samuel
Philip Ashmore
2011-09-29 03:13:41 UTC
Permalink
Hi there.

Believe it or not, this issue was thrashed out years ago and the solution still in use
today is called the Component Object Model - COM.

I've written a really simple implementation you can play with called v3c-dcom
http://sourceforge.net/projects/v3c-dcom/

I had a look at some of the other proposals
1. enums identifying the platform
this doesn't cover yet-to-be-developed platforms
2. functions returning void * if the right plug-in is present
this doesn't cover cases where different platforms can support the same interface,
like a pixmap fall-back for the display

Continuing with your current approach you'll get to the stage where you realise that
you don't simply want function pointers, you want interface pointers, with reference
counting - I'm just trying to save you some time.

I'd be happy to change the names of the functions in v3c-dcom should any similarity
to Microsoft's naming scheme cause a fuss.

This could be Qt's new plug-in system.

Regards,
Philip Ashmore
Thiago Macieira
2011-09-29 08:22:50 UTC
Permalink
Post by Philip Ashmore
Hi there.
Believe it or not, this issue was thrashed out years ago and the solution
still in use today is called the Component Object Model - COM.
I've written a really simple implementation you can play with called
v3c-dcom http://sourceforge.net/projects/v3c-dcom/
For those of us not familiar with COM programming, can you briefly explain what
would be necessary to achieve this? What would be in the public headers and
what would the plugins need to do?
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
Harri Porten
2011-09-29 20:52:53 UTC
Permalink
Post by Thiago Macieira
Post by Philip Ashmore
Hi there.
Believe it or not, this issue was thrashed out years ago and the solution
still in use today is called the Component Object Model - COM.
I've written a really simple implementation you can play with called
v3c-dcom http://sourceforge.net/projects/v3c-dcom/
For those of us not familiar with COM programming, can you briefly explain what
would be necessary to achieve this? What would be in the public headers and
what would the plugins need to do?
Unlike the Q_INTERFACES approach such a system would solely rely on .h
files and have no need to pre-process, compile and link anything. And
fwiw, Qt already had a COM-compatible system once that did not survive the
beta phase however:

http://qt.gitorious.org/qt/qt-integrity/blobs/HEAD/dist/changes-3.0.0-beta6

I just don't know whether I wanted to ask for that much as I'd be fine
with evil casts as long as I know what to cast to :)

Harri.
Philip Ashmore
2011-09-30 05:35:58 UTC
Permalink
Post by Harri Porten
Post by Thiago Macieira
Post by Philip Ashmore
Hi there.
Believe it or not, this issue was thrashed out years ago and the solution
still in use today is called the Component Object Model - COM.
I've written a really simple implementation you can play with called
v3c-dcom http://sourceforge.net/projects/v3c-dcom/
For those of us not familiar with COM programming, can you briefly explain what
would be necessary to achieve this? What would be in the public headers and
what would the plugins need to do?
Unlike the Q_INTERFACES approach such a system would solely rely on .h
files and have no need to pre-process, compile and link anything. And
fwiw, Qt already had a COM-compatible system once that did not survive the
http://qt.gitorious.org/qt/qt-integrity/blobs/HEAD/dist/changes-3.0.0-beta6
If I understand correctly, that was a customer API, not part of Qt's implementation,
which is what's being discussed here.

Yes, COM is difficult to pick up, but Qt already provides an ActiveX framework

http://developer.qt.nokia.com/doc/qt-4.7/activeqt.html

although it's Windows only.
Post by Harri Porten
I just don't know whether I wanted to ask for that much as I'd be fine
with evil casts as long as I know what to cast to :)
Which was the case in Windows before COM.
Post by Harri Porten
Harri.
_______________________________________________
Qt5-feedback mailing list
http://lists.qt.nokia.com/mailman/listinfo/qt5-feedback
Girish Ramakrishnan
2011-09-29 03:36:42 UTC
Permalink
Hi,
Post by Harri Porten
Hi,
this topic was already touched in Holger's "directFB and Lighthouse" mail
but wasn't really resolved. As my concern also applies to Qt 4.8 I'd like
to bring up this topic in a distinct mail.
Usage of the QPlatformNativeInterface class typically looks like this case
 return static_cast<HWND> (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
Above code is #ifdef'ed for Windows which makes it safe as there is only a
single platform implementation available (as far as I can tell). But what
$ git grep \"display\" src/plugins/platforms/*/*.cpp
src/plugins/platforms/wayland/qwaylandnativeinterface.cpp:    if (lowerCaseResource == "display")
src/plugins/platforms/xcb/qxcbnativeinterface.cpp:        insert("display",QXcbNativeInterface::Display);
src/plugins/platforms/xlib/qxlibnativeinterface.cpp:        insert("display",QXlibNativeInterface::Display);
How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?
I understand keeping things as plugins makes it very easy to test with
a single build of Qt, but has it been considered to compile platform
support statically into Qt using a configure time option? That way we
can just use ifdef and detect which platform is active at compile
time. Is there a use case at all to have a pluggable platform system
other than for testing? Yes, this does take us back to the _win, _x11
days except now we have a proper platform interface :-)

Also, if an app wants to support multiple platforms, I guess it has to
have ifdefs for including the necessary platform header files. How
does one achieve this right now? App assumes all headers exist, is it?

Girish
Samuel Rødal
2011-09-29 10:56:12 UTC
Permalink
Post by Girish Ramakrishnan
Hi,
Post by Harri Porten
Hi,
this topic was already touched in Holger's "directFB and Lighthouse" mail
but wasn't really resolved. As my concern also applies to Qt 4.8 I'd like
to bring up this topic in a distinct mail.
Usage of the QPlatformNativeInterface class typically looks like this case
return static_cast<HWND> (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
Above code is #ifdef'ed for Windows which makes it safe as there is only a
single platform implementation available (as far as I can tell). But what
$ git grep \"display\" src/plugins/platforms/*/*.cpp
src/plugins/platforms/wayland/qwaylandnativeinterface.cpp: if (lowerCaseResource == "display")
src/plugins/platforms/xcb/qxcbnativeinterface.cpp: insert("display",QXcbNativeInterface::Display);
src/plugins/platforms/xlib/qxlibnativeinterface.cpp: insert("display",QXlibNativeInterface::Display);
How will anyone be able to tell them apart without a way to check which
plugin is active? Or has this changed?
I understand keeping things as plugins makes it very easy to test with
a single build of Qt, but has it been considered to compile platform
support statically into Qt using a configure time option? That way we
can just use ifdef and detect which platform is active at compile
time. Is there a use case at all to have a pluggable platform system
other than for testing? Yes, this does take us back to the _win, _x11
days except now we have a proper platform interface :-)
Also, if an app wants to support multiple platforms, I guess it has to
have ifdefs for including the necessary platform header files. How
does one achieve this right now? App assumes all headers exist, is it?
Girish
There is only the qnativesysteminterface.h header, and the interface
uses strings as identifiers and returns void *.

In the Wayland case we might have the same Qt version being used both
for the Wayland server / compositor and for the Wayland plugins, but
with different platform plugins, so enforcing the platform plugin at
configure time won't work.

--
Samuel
Thiago Macieira
2011-09-29 11:33:28 UTC
Permalink
Post by Samuel Rødal
In the Wayland case we might have the same Qt version being used both
for the Wayland server / compositor and for the Wayland plugins, but
with different platform plugins, so enforcing the platform plugin at
configure time won't work.
Hi Samuel

I think I'm not understanding you...

A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
Post by Samuel Rødal
From the Qt API's point of view, especially from QGuiApplication and
QPlatformNativeInterface, the fact that the current application runs a wayland
server is completely irrelevant.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
Paul Olav Tvete
2011-09-29 11:55:32 UTC
Permalink
Post by Thiago Macieira
A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
The "low-level library" in question is Qt :p

Samuel used this example to show that being able to use two different platform
plugins on the same system, without having to have two separate installations of
Qt, is not just a cool geeky feature: it's absolutely essential for the Wayland
use case.

Once you have chosen to use Qt on Wayland, the only sane choice is to use Qt to
implement your compositor too. I mean, we use Qt because we don't actually enjoy
low-level C programming. The Wayland compositor will then be run with a command
line like

qwindow-compositor -platform eglfs -plugin linuxinputmouse

while the client will do something like

hellowindow -platform wayland

Exactly the same Qt libraries involved, but two different lighthouse back-ends.

- Paul
Girish Ramakrishnan
2011-09-29 12:43:39 UTC
Permalink
Hi,
Post by Paul Olav Tvete
Post by Thiago Macieira
A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
The "low-level library" in question is Qt :p
Samuel used this example to show that being able to use two different platform
plugins on the same system, without having to have two separate installations of
Qt, is not just a cool geeky feature: it's absolutely essential for the Wayland
use case.
Once you have chosen to use Qt on Wayland, the only sane choice is to use Qt to
implement your compositor too. I mean, we use Qt because we don't actually enjoy
low-level C programming. The Wayland compositor will then be run with a command
line like
qwindow-compositor -platform eglfs -plugin linuxinputmouse
while the client will do something like
hellowindow -platform wayland
Exactly the same Qt libraries involved, but two different lighthouse back-ends.
Yes, this is a very good reason to have platform plugins.

As I explained a little more on irc, I wanted to see if we could build
the lighthouse code as (dynamic) plugins with just -nokia-developer
builds. For normal builds, it would compile them statically and an app
could figure which platform was in use using ifdefs. This way I could
do in the app code
#ifdef QPA_X11
#include <Xlib.h>
#elif defined(QPA_XCB)
...
#endif
With the current approach to platforms as plugins, the app has to load
symbols dynamically OR link to both Xlib+Xcb.

Just to take my idea to conclusion before we kill it, can the wayland
and eglfs platforms be merged into one :) ? i.e we have a QPA_WAYLAND
and the platform plugin code itself determines what "mode" it is
(presumably by passing some command line option). In some ways this is
like the -qws option where the server and client reside in same
library.

Girish
Samuel Rødal
2011-09-30 09:03:18 UTC
Permalink
Post by Girish Ramakrishnan
Hi,
Post by Paul Olav Tvete
Post by Thiago Macieira
A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
The "low-level library" in question is Qt :p
Samuel used this example to show that being able to use two different platform
plugins on the same system, without having to have two separate installations of
Qt, is not just a cool geeky feature: it's absolutely essential for the Wayland
use case.
Once you have chosen to use Qt on Wayland, the only sane choice is to use Qt to
implement your compositor too. I mean, we use Qt because we don't actually enjoy
low-level C programming. The Wayland compositor will then be run with a command
line like
qwindow-compositor -platform eglfs -plugin linuxinputmouse
while the client will do something like
hellowindow -platform wayland
Exactly the same Qt libraries involved, but two different lighthouse back-ends.
Yes, this is a very good reason to have platform plugins.
As I explained a little more on irc, I wanted to see if we could build
the lighthouse code as (dynamic) plugins with just -nokia-developer
builds. For normal builds, it would compile them statically and an app
could figure which platform was in use using ifdefs. This way I could
do in the app code
#ifdef QPA_X11
#include<Xlib.h>
#elif defined(QPA_XCB)
...
#endif
With the current approach to platforms as plugins, the app has to load
symbols dynamically OR link to both Xlib+Xcb.
In this case you might be able to use the X display and Xlib whether the
xcb or xlib plugin is being used, since xcb is also using Xlib
internally for _some_ stuff that's not supported by pure xcb (like GLX).
Post by Girish Ramakrishnan
Just to take my idea to conclusion before we kill it, can the wayland
and eglfs platforms be merged into one :) ? i.e we have a QPA_WAYLAND
and the platform plugin code itself determines what "mode" it is
(presumably by passing some command line option). In some ways this is
like the -qws option where the server and client reside in same
library.
It's possible, but might lead to slightly messier plugin code and is
less practical during development since it makes it harder to test the
application against multiple backends (both wayland and using the same
backend the compositor uses to run non-composited). We also test
qt-compositor using at least xcb, xlib, kms, openwf backends, not just
eglfs. And since you're in charge of configuring Qt in this case it's
still up to you to "know" which platform plugin is being used.

In the end, if you have the power to do a static build where the plugin
is known at compile time, you probably also have the power to limit
yourself to that plugin whether it's done statically or dynamically.

--
Samuel

Samuel Rødal
2011-09-29 11:52:19 UTC
Permalink
Post by Thiago Macieira
Post by Samuel Rødal
In the Wayland case we might have the same Qt version being used both
for the Wayland server / compositor and for the Wayland plugins, but
with different platform plugins, so enforcing the platform plugin at
configure time won't work.
Hi Samuel
I think I'm not understanding you...
A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
Post by Samuel Rødal
From the Qt API's point of view, especially from QGuiApplication and
QPlatformNativeInterface, the fact that the current application runs a wayland
server is completely irrelevant.
My point was just that the Qt application running a wayland server also
needs a platform plugin to run (eglfs, kms, xcb, whatever, even wayland
for nested compositors), demonstrating that the same Qt library will in
situations be used with different platform plugins by different Qt
applications running concurrently.

--
Samuel
Thiago Macieira
2011-09-29 12:23:20 UTC
Permalink
Post by Samuel Rødal
Post by Thiago Macieira
A wayland server has nothing to do with the wayland plugin to lighthouse,
aside from the fact that they speak the same protocol and may be using the
same low-level library.
From the Qt API's point of view, especially from QGuiApplication and
QPlatformNativeInterface, the fact that the current application runs a
wayland server is completely irrelevant.
My point was just that the Qt application running a wayland server also
needs a platform plugin to run (eglfs, kms, xcb, whatever, even wayland
for nested compositors), demonstrating that the same Qt library will in
situations be used with different platform plugins by different Qt
applications running concurrently.
Ah, yes, that makes sense. I somehow read as using two plugins at the same
time, in the same application.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
Loading...