[added]Embedded Window on X11

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

[added]Embedded Window on X11

Post by cyberwan »

Hi everyone !

I was trying to embed an Irrlicht Window in a Qt Widget under Linux, but it didn't work first. I looked on the forum, where I found several topics, and tried to do as indicated, but nothing worked. So I decided to look at the Irrlicht code, and discovered that it was just not implemented. It seems that the provided patches have not been included in the repository. So I made some modifications, and managed to have something working. I also had to add an attribute in the SExposedVideoData.OpenGLLinux struct so that I could get the XWindow id, and resize the window when my widget is resized.
Now, an embedded window can be created this way, with a Qt Widget :

Code: Select all

irr::SIrrlichtCreationParameters params;
params.WindowId = (void*)winId();	
params.DriverType = irr::video::EDT_OPENGL;

_device = irr::createDeviceEx(params);
And the window has to be resized when needed :

Code: Select all

void IrrlichtContainer::resizeEvent(QResizeEvent * event)
{
	if(getDevice())
	{
		XResizeWindow((Display*)(getDevice()->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display),
					  getDevice()->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Window,
					  property("width").toInt(),
					  property("height").toInt());
		
		getDevice()->getVideoDriver()->setViewPort(irr::core::rect<irr::s32>(0, 0, property("width").toInt(), property("height").toInt()));
	}
}
Finally, here is the path I provide, and hope it will be included in the main repository ! If something shocks you, please tell me and I will do other modifications

Code: Select all

diff -r -x '*.o' irrlicht-1.4/include/SExposedVideoData.h irrlicht-1.4_old/include/SExposedVideoData.h
76d75
< 			//! The used display
78,79d76
< 			
< 			//! The drawing window ID
81,83d77
< 			
< 			//! The drawable area ID
< 			unsigned long X11Drawable;
diff -r -x '*.o' irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.cpp irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.cpp
27c27
< 		IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize, Window window,
---
> 		IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize,
45d44
< 	Window externalWindow,
83c82
< 		if (!createWindow(windowSize, bits, externalWindow))
---
> 		if (!createWindow(windowSize, bits))
163c162,163
< bool CIrrDeviceLinux::createWindow(const core::dimension2d<s32>& windowSize, u32 bits, Window externalWindow)
---
> bool CIrrDeviceLinux::createWindow(const core::dimension2d<s32>& windowSize,
> 						u32 bits)
511,513c511
< 		if(!externalWindow)
< 		{
< 			window = XCreateWindow(display,
---
> 		window = XCreateWindow(display,
519,528d516
< 		}
< 		else
< 		{
< 			window = XCreateWindow(display,
< 				externalWindow,
< 				0, 0, Width, Height, 0, visual->depth,
< 				InputOutput, visual->visual,
< 				CWBorderPixel | CWColormap | CWEventMask,
< 				&attributes);
< 		}
642c630
< 			VideoDriver = video::createOpenGLDriver(windowSize, window, Fullscreen, StencilBuffer, FileSystem, vsync, AntiAlias);
---
> 			VideoDriver = video::createOpenGLDriver(windowSize, Fullscreen, StencilBuffer, FileSystem, vsync, AntiAlias);
1336d1323
< 		(Window)(param.WindowId),
diff -r -x '*.o' irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.h irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.h
53c53
< 			Window window, const char* version);
---
> 			const char* version);
93c93
< 		bool createWindow(const core::dimension2d<s32>& windowSize, u32 bits, Window externalWindow);
---
> 		bool createWindow(const core::dimension2d<s32>& windowSize, u32 bits);
diff -r -x '*.o' irrlicht-1.4/source/Irrlicht/COpenGLDriver.cpp irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.cpp
1d0
< 
183c182
< COpenGLDriver::COpenGLDriver(const core::dimension2d<s32>& screenSize, Window window, bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias)
---
> COpenGLDriver::COpenGLDriver(const core::dimension2d<s32>& screenSize, bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias)
195,196c194
< 	ExposedData.OpenGLLinux.X11Drawable = XWindow;
< 	ExposedData.OpenGLLinux.X11Window = window;
---
> 	ExposedData.OpenGLLinux.X11Window = XWindow;
2387c2385
< IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize, Window window,	
---
> IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize,
2391c2389
< 	return new COpenGLDriver(screenSize, window, fullscreen, stencilBuffer,
---
> 	return new COpenGLDriver(screenSize, fullscreen, stencilBuffer,
diff -r -x '*.o' irrlicht-1.4/source/Irrlicht/COpenGLDriver.h irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.h
83c83
< 		COpenGLDriver(const core::dimension2d<s32>& screenSize, Window window, bool fullscreen,
---
> 		COpenGLDriver(const core::dimension2d<s32>& screenSize, bool fullscreen,
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Please try to make the diff the other way round (first old, then new files) and use -Naurp as parameters (with an optional -x if you need it).
What does winId() do?
But yeah, a good working solution will definitely make it into the library.
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

OK, I've made a diff irrlicht-1.4_old irrlicht-1.4 -aurp -x "*.o" | grep -v Only > patch. I didn't use the -N option because it gives me an enormous binary result, but I suppose this is enough. Here is the new patch :

Code: Select all

diff -aurp -x '*.o' irrlicht-1.4_old/include/SExposedVideoData.h irrlicht-1.4/include/SExposedVideoData.h
--- irrlicht-1.4_old/include/SExposedVideoData.h	2007-11-17 07:38:42.000000000 +0100
+++ irrlicht-1.4/include/SExposedVideoData.h	2008-01-05 14:24:15.000000000 +0100
@@ -73,8 +73,14 @@ struct SExposedVideoData
 		struct 
 		{
 			// XWindow handles
+			//! The used display
 			void* X11Display;
+			
+			//! The drawing window ID
 			unsigned long X11Window;
+			
+			//! The drawable area ID
+			unsigned long X11Drawable;
 		} OpenGLLinux;
 	};
 };
diff -aurp -x '*.o' irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.cpp irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.cpp
--- irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.cpp	2007-11-17 07:38:32.000000000 +0100
+++ irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.cpp	2008-01-05 14:35:12.000000000 +0100
@@ -24,7 +24,7 @@ namespace irr
 {
 	namespace video
 	{
-		IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize,
+		IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize, Window window,
 			bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias);
 	}
 } // end namespace irr
@@ -42,6 +42,7 @@ CIrrDeviceLinux::CIrrDeviceLinux(video::
 	u32 bits, bool fullscreen,
 	bool sbuffer, bool vsync, bool antiAlias,
 	IEventReceiver* receiver,
+	Window externalWindow,
 	const char* version)
  : CIrrDeviceStub(version, receiver),
 #ifdef _IRR_COMPILE_WITH_X11_
@@ -79,7 +80,7 @@ CIrrDeviceLinux::CIrrDeviceLinux(video::
 	if (driverType != video::EDT_NULL)
 	{
 		// create the window, only if we do not use the null device
-		if (!createWindow(windowSize, bits))
+		if (!createWindow(windowSize, bits, externalWindow))
 			return;
 	}
 
@@ -159,8 +160,7 @@ int IrrPrintXError(Display *display, XEr
 
 
 
-bool CIrrDeviceLinux::createWindow(const core::dimension2d<s32>& windowSize,
-						u32 bits)
+bool CIrrDeviceLinux::createWindow(const core::dimension2d<s32>& windowSize, u32 bits, Window externalWindow)
 {
 	Width = windowSize.Width;
 	Height = windowSize.Height;
@@ -494,7 +494,7 @@ bool CIrrDeviceLinux::createWindow(const
 				0, 0, Width, Height, 0, visual->depth,
 				InputOutput, visual->visual,
 				CWBorderPixel | CWColormap | CWEventMask |
-				CWOverrideRedirect, &attributes);
+				CWOverrideRedirect, &attributes);	
 
 		XWarpPointer(display, None, window, 0, 0, 0, 0, 0, 0);
 		XMapRaised(display, window);
@@ -508,12 +508,24 @@ bool CIrrDeviceLinux::createWindow(const
 		attributes.event_mask |= ExposureMask;
 		attributes.event_mask |= FocusChangeMask;
 
-		window = XCreateWindow(display,
+		if(!externalWindow)
+		{
+			window = XCreateWindow(display,
 				RootWindow(display, visual->screen),
 				0, 0, Width, Height, 0, visual->depth,
 				InputOutput, visual->visual,
 				CWBorderPixel | CWColormap | CWEventMask,
 				&attributes);
+		}
+		else
+		{
+			window = XCreateWindow(display,
+				externalWindow,
+				0, 0, Width, Height, 0, visual->depth,
+				InputOutput, visual->visual,
+				CWBorderPixel | CWColormap | CWEventMask,
+				&attributes);
+		}
 
 		Atom wmDelete;
 		wmDelete = XInternAtom(display, wmDeleteWindow, True);
@@ -627,7 +639,7 @@ void CIrrDeviceLinux::createDriver(const
 	case video::EDT_OPENGL:
 	#ifdef _IRR_COMPILE_WITH_OPENGL_
 		if (Context)
-			VideoDriver = video::createOpenGLDriver(windowSize, Fullscreen, StencilBuffer, FileSystem, vsync, AntiAlias);
+			VideoDriver = video::createOpenGLDriver(windowSize, window, Fullscreen, StencilBuffer, FileSystem, vsync, AntiAlias);
 	#else
 		os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
 	#endif
@@ -1321,6 +1333,7 @@ IRRLICHT_API IrrlichtDevice* IRRCALLCONV
 		param.Vsync,
 		param.AntiAlias,
 		param.EventReceiver,
+		(Window)(param.WindowId),
 		param.SDK_version_do_not_use);
 	
 	if (dev && !dev->getVideoDriver() && param.DriverType != video::EDT_NULL)
diff -aurp -x '*.o' irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.h irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.h
--- irrlicht-1.4_old/source/Irrlicht/CIrrDeviceLinux.h	2007-11-17 07:38:34.000000000 +0100
+++ irrlicht-1.4/source/Irrlicht/CIrrDeviceLinux.h	2008-01-04 20:11:32.000000000 +0100
@@ -50,7 +50,7 @@ namespace irr
 		CIrrDeviceLinux(video::E_DRIVER_TYPE deviceType,
 			const core::dimension2d<s32>& windowSize, u32 bits,
 			bool fullscreen, bool stencilbuffer, bool vsync, bool antiAlias, IEventReceiver* receiver,
-			const char* version);
+			Window window, const char* version);
 
 		//! destructor
 		virtual ~CIrrDeviceLinux();
@@ -90,7 +90,7 @@ namespace irr
 		void createDriver(const core::dimension2d<s32>& windowSize,
 					bool vsync);
 
-		bool createWindow(const core::dimension2d<s32>& windowSize, u32 bits);
+		bool createWindow(const core::dimension2d<s32>& windowSize, u32 bits, Window externalWindow);
 
 		void createKeyMap();
 
diff -aurp -x '*.o' irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.cpp irrlicht-1.4/source/Irrlicht/COpenGLDriver.cpp
--- irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.cpp	2007-11-17 07:38:34.000000000 +0100
+++ irrlicht-1.4/source/Irrlicht/COpenGLDriver.cpp	2008-01-05 14:11:47.000000000 +0100
@@ -1,3 +1,4 @@
+
 // Copyright (C) 2002-2007 Nikolaus Gebhardt
 // This file is part of the "Irrlicht Engine".
 // For conditions of distribution and use, see copyright notice in irrlicht.h
@@ -179,7 +180,7 @@ COpenGLDriver::COpenGLDriver(const core:
 // -----------------------------------------------------------------------
 #ifdef _IRR_USE_LINUX_DEVICE_
 //! Linux constructor and init code
-COpenGLDriver::COpenGLDriver(const core::dimension2d<s32>& screenSize, bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias)
+COpenGLDriver::COpenGLDriver(const core::dimension2d<s32>& screenSize, Window window, bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias)
 : CNullDriver(io, screenSize), COpenGLExtensionHandler(),
 	CurrentRenderMode(ERM_NONE), ResetRenderStates(true),
 	Transformation3DChanged(true), AntiAlias(antiAlias),
@@ -191,7 +192,8 @@ COpenGLDriver::COpenGLDriver(const core:
 	XWindow = glXGetCurrentDrawable();
 	XDisplay = glXGetCurrentDisplay();
 	ExposedData.OpenGLLinux.X11Display = XDisplay;
-	ExposedData.OpenGLLinux.X11Window = XWindow;
+	ExposedData.OpenGLLinux.X11Drawable = XWindow;
+	ExposedData.OpenGLLinux.X11Window = window;
 	genericDriverInit(screenSize, stencilBuffer);
 
 	// set vsync
@@ -2382,11 +2384,11 @@ IVideoDriver* createOpenGLDriver(const c
 // LINUX VERSION
 // -----------------------------------
 #ifdef _IRR_USE_LINUX_DEVICE_
-IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize,
+IVideoDriver* createOpenGLDriver(const core::dimension2d<s32>& screenSize, Window window,	
 		bool fullscreen, bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias)
 {
 #ifdef _IRR_COMPILE_WITH_OPENGL_
-	return new COpenGLDriver(screenSize, fullscreen, stencilBuffer,
+	return new COpenGLDriver(screenSize, window, fullscreen, stencilBuffer,
 		io, vsync, antiAlias);
 #else
 	return 0;
diff -aurp -x '*.o' irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.h irrlicht-1.4/source/Irrlicht/COpenGLDriver.h
--- irrlicht-1.4_old/source/Irrlicht/COpenGLDriver.h	2007-11-17 07:38:34.000000000 +0100
+++ irrlicht-1.4/source/Irrlicht/COpenGLDriver.h	2008-01-05 13:56:23.000000000 +0100
@@ -80,7 +80,7 @@ namespace video
 		#endif
 
 		#ifdef _IRR_USE_LINUX_DEVICE_
-		COpenGLDriver(const core::dimension2d<s32>& screenSize, bool fullscreen,
+		COpenGLDriver(const core::dimension2d<s32>& screenSize, Window window, bool fullscreen,
 			bool stencilBuffer, io::IFileSystem* io, bool vsync, bool antiAlias);
 		#endif
The WinId() is a method of QWidget which returns the window identifier used by the widget, and it is platform-dependant :).

One other good thing would be to add the XResizeWindow function somewhere in Irrlicht, because this is not something one is not supposed to call when using high-level libraries. Currently, a window can't be resized using an Irrlicht function, I heard about setViewPort, but it just affects the OpenGL drawing area on the window. Any idea ?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The patch looks ok (yes, -N is only needed when new files are added and binary files are regarded as new because the old directory does not contain them usually). Should work from what I saw, but with some limitations (which should be ok for the beginning and because the win32 version also contains similar restrictions IMHO). The problem arises when the Window is hosted on another Display. This can happen on multi-head displays. You'd need more information then (maybe the full SExposedVideoData struct).

The XWindowResize shouldn't be necessary if the QWidget and the X11 Window are properly parented. The size change should send a ConfigureNotify to the Irrlicht Window, which resizes the VideoDriver. If this does not happen some events are missing in the setup.
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

hybrid wrote:The problem arises when the Window is hosted on another Display. This can happen on multi-head displays. You'd need more information then (maybe the full SExposedVideoData struct).
Yes, probably some informations are missing, but actually I don't know enough about X11 to add them, and I don't event know how I could test it..
hybrid wrote:The XWindowResize shouldn't be necessary if the QWidget and the X11 Window are properly parented. The size change should send a ConfigureNotify to the Irrlicht Window, which resizes the VideoDriver. If this does not happen some events are missing in the setup.
I thought first that the window would be resized, as it is correcty positioned on the parent QWidget, but as you say, some events must be missing. I had a look on the XCreateWindow attributes, but couldn't find the corresponding argument to give. A deeper inquiry would be needed.. Or does someone know more about this ?
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

OK, I think this is gonna wail until someone really needs more !
Anyway, did you include the patch ?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

No, it's not yet commited, but it will be :)
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

Great ! I will check the next release :wink:
QuantumLeap
Posts: 38
Joined: Mon Sep 25, 2006 6:31 pm
Location: San Francisco, California

Post by QuantumLeap »

Cyberwan, did you manage to actually receive mouse and keyboard events within the Irrlicht widget created like this?

The standard way to handle this with Qt is to redefine

Code: Select all

 virtual void keyPressEvent ( QKeyEvent * event )
virtual void keyReleaseEvent ( QKeyEvent * event )
virtual void mousePressEvent ( QMouseEvent * event )
virtual void mouseReleaseEvent ( QMouseEvent * event )
and
virtual void mouseMoveEvent ( QMouseEvent * event )
However these are not called EVER when the QWidget in cause is an instance of Irrlicht. To test we can for example invoke a standard Qt::Beep() from within the redefinition of mousePressEvent. However if we comment

Code: Select all

params.WindowId = (void*)winId();
the events start being processed normally (however the Irrlicht frame is not displayed, despite being active and running because there's no handle).

How did you solve this problem?
It's easier to curse a candle than light the darkness
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

How did you solve this problem?
Well, I recently discovered that the behaviour was different under Windows and Linux. Under linux, the events on the 3D window are caught directly by the Irrlicht engine, using an IEventReceiver. Under windows, they are caught by the Qt engine, so I had to make a wrapper on my widget by reimplementing the "virtual bool event(QEvent *event);" method. Do you need the code ?
No, it's not yet commited, but it will be
I just downloaded the 1.4.1 version, and the patch is not included :(
Can someone fix this ?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

It could be only in SVN trunk, i.e. for Irrlicht 1.5. But this patch shoudl be commited AFAIK.
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

It could be only in SVN trunk, i.e. for Irrlicht 1.5. But this patch shoudl be commited AFAIK.
OK, sorry :wink:
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Edit: I didn't spot the proper code, but it's indeed already in SVN 8) But, as said, only in trunk, so ready for Irrlicht 1.5!
cyberwan
Posts: 40
Joined: Mon May 14, 2007 12:18 pm
Location: Rennes, France

Post by cyberwan »

OK, great ;)
Post Reply