Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make an X11 window OpenGL capable after it has been created?

Tags:

x11

opengl

I want to be able to render to an X Window given just its id.

In this case I have a window created in python by gtk.

I can get the window ID of a gtk.Drawable and pass it into my C python module, but can I then make OpenGL calls render to it?

I am aware of gtkglext, but would rather not use it if possible.

Update 1:

Ok, so (rather obviously now that I see it) You just do an XCreateWindow with a parent of the Window id that you get from gtk.window.xid, using the correct flags for an opengl window, and hey presto.

The only problem is I can't get it to work if there are not multiple widgets in the window, otherwise it seems that the xid represents a window that covers the entire toplevel window. Not sure how to rectify this.

Update 2: It turns out that if you have a gl window that is the same size as the toplevel then the toplevel window will not get expose events until the gl window has its buffers swapped. You just have to keep swapping the buffers and things wil be fine.

Update 3:

To answer @babele's comment:

This page in the python gtk docs say how to make a gtk window from an existing xid. After that you just have to remeber to keep calling glXSwapBuffers for that window (if it is an opengl buffered window, otherwise it should just work when you use window_foreign_new).

So the process goes:

  1. Create a gtk widget that will contain your OpenGL window (a DrawingArea is a good choice - you can't use eg a label as it won't have its own xid)
  2. Get the widget's gtk.gdk.Window (docs)
  3. Get the xid from the gtk.gdk.Window (call this window W1)
  4. Pass it to your C/C++ code
  5. Create the opengl capable window (W2) as a child of W1
  6. Pass the xid of W2 back to python
  7. Use window_foreign_new with W2's xid to create the new gtk.gdk.window object
  8. Each time you call glXSwapBuffers on W2 gtk should then be able to react to expose events.

One bit that really threw me is that if W2 covers the whole of W1 then W1 won't receive events until W2's buffers get swapped. This is particularly confusing if W1 is a top-level window as it can be that nothing appears on your screen at all (the window is there but it looks like whatever is behind it until it gets painted to, which won't happen until it gets an expose event).

Also note that you'll have to manually manage the resizing of W2 by connecting to the gtk resize events. You can do this by connecting to this signal, then calling this function in the handler and passing the results to your c/c++ module where you can resize W2 appropriately. Its a good idea to request a minimum size.

like image 437
DaedalusFall Avatar asked Feb 11 '10 22:02

DaedalusFall


1 Answers

You don't need to create a new window, you pass an existing window to glXMakeCurrent().
In your current setup you'd need to:

  1. XGetWindowAttributes() to retrieve the visual the window was created with
  2. glXCreateContext() using this visual
  3. glXMakeCurrent() using this context and the window id

However, this is doing it backwards, forcing OpenGL to use the visual used for CreateWindow. This often works because the default visual has sane GLX properties, but a correct application will glXChooseVisual with desired GLX properties, then use that visual to create the window.

like image 160
Nathan Kidd Avatar answered Oct 11 '22 09:10

Nathan Kidd