0

Been working on this for ages, I can finally select a frame buffer, visual and pict format and setup a glx context and draw a triangle.

The only thing I still can not figure out is why the background is black instead of transparent.

Can anyone spot the mistake or suggest how i can debug this ?

I have looked at numerous examples in C and as far as i can tell I have all the steps in place but I am probably missing something simple.

This is what I currently have

import sys
import xcb
import xcb.glx
import xcb.composite
import xcb.xproto as xproto
import struct
import Xlib
from Xlib.display import Display
from ctypes import *


from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL import GLX


try:
    from OpenGL.GLX import struct__XDisplay
except ImportError as err:
    from OpenGL.raw._GLX import struct__XDisplay


class window_example:
    xlib = cdll.LoadLibrary('libX11.so')
    xlib.XOpenDisplay.argtypes = [c_char_p]
    xlib.XOpenDisplay.restype = POINTER(struct__XDisplay)
    xdisplay = xlib.XOpenDisplay(None)
    display = Xlib.display.Display()
    attrs = []

    def __init__(self):
        self.xserver = xcb.connect()
        self.xclient = self.xserver.core
        self.setup = self.xserver.get_setup()
        self.canvas = self.setup.roots[0]
        self.root_window = self.canvas.root
        self.depth = self.setup.roots[0].root_depth
        self.visual = self.setup.roots[0].root_visual

        composite_ext = self.load_extension('Composite', xcb.composite.key)
        render_ext = self.load_extension('RENDER', xcb.render.key)
        glx_ext = self.load_extension('GLX', xcb.glx.key)

        """ lets setup are opengl settings and create the context for our window """
        self.add_attribute(GLX.GLX_RENDER_TYPE, GLX.GLX_RGBA_BIT)
        self.add_attribute(GLX.GLX_DRAWABLE_TYPE, GLX.GLX_WINDOW_BIT)
        self.add_attribute(GLX.GLX_X_RENDERABLE, True)
        self.add_attribute(GLX.GLX_RED_SIZE, 8)
        self.add_attribute(GLX.GLX_GREEN_SIZE, 8)
        self.add_attribute(GLX.GLX_BLUE_SIZE, 8)
        self.add_attribute(GLX.GLX_ALPHA_SIZE, 8)
        self.add_attribute(GLX.GLX_DEPTH_SIZE, 32)
        self.add_attribute(GLX.GLX_DOUBLEBUFFER, True)

        config_count = c_int()
        configs = GLX.glXChooseFBConfig(self.xdisplay, self.display.get_default_screen(), None, byref(config_count))
        if config_count.value is 0 or configs.__class__ is "<class 'OpenGL.raw._GLX.LP_struct_anon_103'>":
            sys.exit('no matching configs found')

        #http://lists.freedesktop.org/archives/xcb/2004-December/000237.html
        picture_formats = render_ext.QueryPictFormats().reply()
        count = 0
        for i in range(0, config_count.value):
            config = configs[i]
            count += 1
            visual = GLX.glXGetVisualFromFBConfig(self.xdisplay, config)
            try:    
                visual.contents
            except ValueError:
                continue

            picture_format = self.match_pict_format_with__visual(picture_formats, visual)
            if not picture_format:
                print 'Unable to match a picture format with a visual format :('

            if visual.contents.visualid == self.visual:
                print 'matched visual'
                self.fbconfig = config
                break

        self.fbconfig = config
        self.visual=visual

        try:    
            self.visual.contents
        except ValueError:
            sys.exit('Could not find visual')

        self.context = GLX.glXCreateContext(self.xdisplay, self.visual, None, True)

        self.glx_colourmap = self.xserver.generate_id()
        cookie = self.xclient.CreateColormapChecked(xproto.ColormapAlloc._None, self.glx_colourmap, self.root_window, self.visual.contents.visualid)

        try:
            print cookie.check()
            #~ print cookie.reply()
        except xproto.BadMatch, e:
            print e.message
            print e.args[0]
            print e.args[0].bad_value

        self.get_fbconfig_attributes(self.fbconfig)
        self.glx_visual_info(self.visual.contents)

        self.create_window()


    def get_fbconfig_attributes(self, config):
        print "***** Frame Buffer Config *****"
        print "\tGLX Render Type = %d" % self.get_fbconfig_attribute(config, GLX.GLX_RGBA_BIT)
        print "\tGLX Drawable Type = %d" % self.get_fbconfig_attribute(config, GLX.GLX_DRAWABLE_TYPE)
        print "\tX Renderable = %d" % self.get_fbconfig_attribute(config, GLX.GLX_X_RENDERABLE)
        print "\tRED Size = %d" % self.get_fbconfig_attribute(config, GLX.GLX_RED_SIZE)
        print "\tGREEN Size = %d" % self.get_fbconfig_attribute(config, GLX.GLX_GREEN_SIZE)
        print "\tBLUE Size = %d" % self.get_fbconfig_attribute(config, GLX.GLX_BLUE_SIZE)
        print "\tALPHA Size = %d" % self.get_fbconfig_attribute(config, GLX.GLX_ALPHA_SIZE)
        print "\tDepth Size = %d" % self.get_fbconfig_attribute(config, GLX.GLX_DEPTH_SIZE)
        print "\tDouble Buffer = %d" % self.get_fbconfig_attribute(config, GLX.GLX_DOUBLEBUFFER)

    def get_fbconfig_attribute(self, config, attrib):
        value = c_int()
        GLX.glXGetFBConfigAttrib(self.xdisplay, config, attrib, byref(value))
        return value.value

    def get_visual_attribute(self):
        value = c_int()
        GLX.glXGetFBConfigAttrib(self.xdisplay, configs[0], GLX.GLX_RED_SIZE, byref(value))
        return value.value

    def match_pict_format_with__visual(self, formats, visual):
        for screen in formats.screens:
            for depth in screen.depths:

                for pict_visual in depth.visuals:
                    if pict_visual.visual == visual.contents.visualid:
                        print 'depth %s' % str(depth.depth)
                        #~ self.glx_visual_info(visual.contents)
                        return visual

    def glx_visual_info(self, visual):
        print('***** GLX Visual Info *****')
        print("\trgb depth = %s" % visual.depth)
        print("\tred mask = %s" % visual.red_mask)
        print("\tgreen mask = %s" % visual.green_mask)
        print("\tblue mask = %s" % visual.blue_mask)
        print("\tcolour map = %s" % visual.colormap_size)
        print("\tscreen id = %s" % visual.screen)
        print("\tbits per rgb = %s" % visual.bits_per_rgb)
        print("\tvisual = %s" % visual.visual)
        print("\tvisual id = %s" % visual.visualid)

    def add_attribute(self, setting, value=None):
        """just to nicely add opengl parameters"""
        self.attrs.append(setting)
        if value:
            self.attrs.append(value)

    def get_attributes(self):
        """ return our parameters in the expected structure"""
        attrs = self.attrs + [0, 0]
        return (c_int * len(attrs))(*attrs)

    def load_extension(self, name, xcb_key):
        # test extension is present
        extension = self.xclient.QueryExtension(len(name), name).reply()
        if extension.present != 1:
            print("%s not available" % name)
            return
        print('Using %s extension' % name)
        return self.xserver(xcb_key)

    def create_window(self):
        # create a new resource id for the window
        self.window = self.xserver.generate_id()

        result = self.xclient.CreateWindowChecked(self.depth, self.window, self.root_window,
            0, 0, 300, 300, 0,
            xproto.WindowClass.InputOutput,
            self.visual.contents.visualid,
            xproto.CW.EventMask | xproto.CW.Colormap,
            [xproto.EventMask.Button1Motion | xproto.EventMask.Exposure | xproto.EventMask.SubstructureNotify, self.glx_colourmap])
        try:
            result.check()
        except xproto.BadMatch, e:
            print e.message
            print e.args[0]
            print e.args[0].bad_value

        GLX.glXCreateWindow(self.xdisplay, self.fbconfig, self.window, byref(c_int()))

        #~ // create OpenGL context
        render_context = GLX.glXCreateNewContext(self.xdisplay, self.fbconfig, GLX.GLX_RGBA_TYPE, None, True)
        #~ GLX.glXCreateContext(self.xdisplay, self.visual, render_context, True)

        if GLX.glXIsDirect(self.xdisplay, render_context) is 1:
            print 'Using Direct Rendering'
        else:
            print 'Using Indirect Rendering'


        #~ GLX.glXMakeContextCurrent(self.xdisplay, self.window, self.window, render_context)
        print GLX.glXMakeCurrent(self.xdisplay, self.window, render_context)

        #lets set a property on the window, this property gives us a window title
        name = 'X Window Example'
        self.xclient.ChangeProperty(xproto.PropMode.Replace, self.window, xproto.Atom.WM_NAME, xproto.Atom.STRING, 8, len(name), name)

        _NET_WM_WINDOW_OPACITY = 528
        buf = struct.pack('I', _NET_WM_WINDOW_OPACITY)
        _NET_WM_WINDOW_OPACITY = self.xclient.InternAtom(True, len('_NET_WM_WINDOW_OPACITY'), '_NET_WM_WINDOW_OPACITY').reply()
        self.xclient.ChangeProperty(xproto.PropMode.Replace, self.window, _NET_WM_WINDOW_OPACITY.atom, xproto.Atom.STRING, 0.5, 1, buf)

        self.xclient.MapWindow(self.window)
        self.xserver.flush()

    def draw(self):
        if(not GLX.glXMakeCurrent(self.xdisplay, self.window, self.context)):
            print ('configure failed running glXMakeCurrent')

        glEnable(GL_BLEND);             
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glBegin(GL_TRIANGLES)
        glIndexi(0)
        glColor3f(1.0, 0.0, 0.0)
        glVertex2i(0, 1)
        glIndexi(0)
        glColor3f(0.0, 1.0, 0.0)
        glVertex2i(-1, -1)
        glIndexi(0)
        glColor3f(0.0, 0.0, 1.0)
        glVertex2i(1, -1)
        glEnd()
        glFlush();

        GLX.glXSwapBuffers(self.xdisplay, self.window)

    def loop(self):
        self.draw()
        while True:
            event = self.xserver.wait_for_event()
            self.draw()
            self.xserver.flush()


if __name__ == "__main__":
    window_example().loop()
Oly
  • 370
  • 5
  • 16
  • Yes so that in essence I can have a floating triangle, I know how to remove the border its just the background. – Oly Dec 01 '15 at 13:35
  • I have not heard of overlay visuals before, the code above is supposed to be using composite plugin with glx and is based on examples i have found but i seem to be missing something. – Oly Dec 01 '15 at 13:59
  • Oh I see you are loading the extension. But you are not doing anything with it. – n. m. could be an AI Dec 01 '15 at 15:34
  • Well from what i have read and looking at other examples like these https://gist.github.com/je-so/903479 https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c it does not look like you need to do anything specific. perhaps I am mistaken. – Oly Dec 01 '15 at 16:11
  • These examples don't work for me. I only have a VNC session to X11 at the moment though. Will check with a real machine later. – n. m. could be an AI Dec 01 '15 at 16:29
  • There are two special steps to be taken: You need a FBConfig with an alpha channel and you need a picture format associated with the corresponding visual that has an alpha mask (l. 159ff in my codesample). With that in place you also need a X compositor running, that actually uses the window's alpha channel (the vanilla `xcompmgr` does this). – datenwolf Dec 01 '15 at 18:09
  • I thought I was doing those things, is an alpha mask separate to an alpha channel. in the code above I select a fbconfig with alpha the loop over them to find a matching visual and the look up a pict format. I am running gnome so i would think i have some compositor running for the effects. I will see if i can find the pict sample id maybe that will help – Oly Dec 01 '15 at 18:58
  • @datenwolf Thanks, I didn't know that compositors do that. How can I tell if a suitable compositor is running? – n. m. could be an AI Dec 01 '15 at 19:23
  • Good question, but if your running a modern desktop with any kind of effect then it must be running. I am running gnome here which uses mutter as the compositor, I am unaware of a command you can run to tell you what your using. but if I drag a window on the overview it goes semi transparent by default. really which there was better documentation on this stuff out there I am trying to improve this as I go but its a bit frustrating to say the least. – Oly Dec 01 '15 at 19:48
  • Heh, I was totally wrong in my first comments and I deleted them. I was sure one needs to provide a separate pixmap for the compositor to act as the alpha channel, which is kinda stupid in hindsight. @datenwolf's code works on a machine that has desktop effects. – n. m. could be an AI Dec 01 '15 at 19:55
  • Your Python program fails on me on glXMakeCurrent in create_window (failed to create drawable) and I have no idea why. I'll try to transcribe the C example to Python when I have more time. – n. m. could be an AI Dec 01 '15 at 20:32
  • Thats interesting, if you get a working sample going that would be awesome I can add it to my X tutorial series I am working on, I will try and get mine going as well :) – Oly Dec 02 '15 at 08:33

0 Answers0