Skip to content

Instantly share code, notes, and snippets.

@je-so
Last active October 21, 2024 22:39
Show Gist options
  • Save je-so/903479 to your computer and use it in GitHub Desktop.
Save je-so/903479 to your computer and use it in GitHub Desktop.
Xlib transparent window with OpenGL support
/*
____ _____
/\__ \ /\ ___\
\/__/\ \ \ \ \__/_
\ \ \ \ \____ \
_\_\ \ \/__/_\ \
/\ _____\ /\ _____\
\/______/ \/______/
Copyright (C) 2011 Joerg Seebohn
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program demonstrates how an X11 window with OpenGL support
can be drawn transparent.
The title bar and window border drawn by the window manager are
drawn opaque.
Only the background of the window which is drawn with OpenGL
glClearColor( 0.7, 0.7, 0.7, 0.7) ;
glClear(GL_COLOR_BUFFER_BIT) ;
is 30% transparent.
Compile it with:
gcc -std=gnu99 -o test testprogram.c -lX11 -lGL
*/
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
Display * display = XOpenDisplay( 0 ) ;
const char * xserver = getenv( "DISPLAY" ) ;
if (display == 0)
{
printf("Could not establish a connection to X-server '%s'\n", xserver ) ;
exit(1) ;
}
// query Visual for "TrueColor" and 32 bits depth (RGBA)
XVisualInfo visualinfo ;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &visualinfo);
// create window
Window win ;
GC gc ;
XSetWindowAttributes attr ;
attr.colormap = XCreateColormap( display, DefaultRootWindow(display), visualinfo.visual, AllocNone) ;
attr.event_mask = ExposureMask | KeyPressMask ;
attr.background_pixmap = None ;
attr.border_pixel = 0 ;
win = XCreateWindow( display, DefaultRootWindow(display),
50, 300, 400, 100, // x,y,width,height : are possibly opverwriteen by window manager
0,
visualinfo.depth,
InputOutput,
visualinfo.visual,
CWColormap|CWEventMask|CWBackPixmap|CWBorderPixel,
&attr
) ;
gc = XCreateGC( display, win, 0, 0) ;
// set title bar name of window
XStoreName( display, win, "Transparent Window with OpenGL Support" ) ;
// say window manager which position we would prefer
XSizeHints sizehints ;
sizehints.flags = PPosition | PSize ;
sizehints.x = 50 ; sizehints.y = 300 ;
sizehints.width = 400 ; sizehints.height = 100 ;
XSetWMNormalHints( display, win, &sizehints ) ;
// Switch On >> If user pressed close key let window manager only send notification >>
Atom wm_delete_window = XInternAtom( display, "WM_DELETE_WINDOW", 0) ;
XSetWMProtocols( display, win, &wm_delete_window, 1) ;
{
// change foreground color to brown
XColor xcol ;
xcol.red = 153 * 256 ; // X11 uses 16 bit colors !
xcol.green = 116 * 256 ;
xcol.blue = 65 * 256 ;
XAllocColor( display, attr.colormap, &xcol) ;
XGCValues gcvalues ;
gcvalues.foreground = xcol.pixel ;
XChangeGC( display, gc, GCForeground, &gcvalues) ;
}
// create OpenGL context
GLXContext glcontext = glXCreateContext( display, &visualinfo, 0, True ) ;
if (!glcontext)
{
printf("X11 server '%s' does not support OpenGL\n", xserver ) ;
exit(1) ;
}
glXMakeCurrent( display, win, glcontext ) ;
// now let the window appear to the user
XMapWindow( display, win) ;
int isUserWantsWindowToClose = 0 ;
while( !isUserWantsWindowToClose )
{
int isRedraw = 0 ;
/* XPending returns number of already queued events.
* If no events are queued XPending sends all queued requests to the X-server
* and tries to read new incoming events. */
while( XPending(display) > 0 )
{
// process event
XEvent event ;
XNextEvent( display, &event) ;
switch(event.type)
{ // see 'man XAnyEvent' for a list of available events
case ClientMessage:
// check if the client message was send by window manager to indicate user wants to close the window
if ( event.xclient.message_type == XInternAtom( display, "WM_PROTOCOLS", 1)
&& event.xclient.data.l[0] == XInternAtom( display, "WM_DELETE_WINDOW", 1)
)
{
isUserWantsWindowToClose = 1 ;
}
case KeyPress:
if (XLookupKeysym(&event.xkey, 0) == XK_Escape)
{
isUserWantsWindowToClose = 1 ;
}
break ;
case Expose:
isRedraw = 1 ;
break ;
default:
// do no thing
break ;
}
}
// ... all events processed, now do other stuff ...
if (isRedraw)
{ // needs redraw
// use opengl to clear background in (transparent) light grey
glClearColor( 0.7, 0.7, 0.7, 0.7) ;
glClear(GL_COLOR_BUFFER_BIT) ;
glXSwapBuffers( display, win) ;
glXWaitGL() ;
// draw string with X11
XDrawString( display, win, gc, 10, 20, "Hello ! ", 7) ;
}
// ... do something else ...
}
XDestroyWindow( display, win ) ;
win = 0 ;
XCloseDisplay( display ) ;
display = 0 ;
return 0 ;
}
@vfekete
Copy link

vfekete commented Jan 2, 2013

I know it's 2yo code, but. I'm trying to achieve similar thing - drawing with OpenGL on transparent window so I bumped into it.

I don't understand what's the reason for the "OpenGL" part. When I compile your code without lines : 101 - 109 and 159 - 164 I get exactly same result as with them. (so transparency has nothing to do with the OpenGL part ? (that's real question, I don't understand xlib so deep I could know the answer)).

Question number two (since I want to use OpenGL for drawing stuff into transparent window) : When I change line 169 to :

glClearColor( 0.0, 0.0, 0.0, 0.0, 1.0);

I should see black window, but I dont. I see transparent window (as in case of alpha = 0.0). Somwhere I read I should enable glBlend and set glBlendFunc correctly, but none of it helped. Don't you know what could be a reson for strange alpha/color mixing and more important how to change it (desired result : when I write something into backbuffer it should be with my color and with my alpha, without any additional color/alpha mixing) ?

@je-so
Copy link
Author

je-so commented Jan 24, 2013

Switching to "glClearColor( 0.0, 0.0, 0.0, 0.0, 1.0);" produces a non transparent black window (Ubuntu 12.04).

In this case you need OpenGL to get the transparency effect. Without it you would need X11 extensions.

If you do not want to use OpenGL use the following code snippet which produces a transparent window
including the title bar and the window borders. It uses the X11 window manager but not every manager
supports this protocol.

include <stdint.h>

...
// insert code after XSetWMProtocols( display, win, &wm_delete_window, 1) ;

uint32_t cardinal_alpha = (uint32_t) (0.5/transpareny/ * (uint32_t)-1) ;
XChangeProperty(display, win,
XInternAtom(display, "_NET_WM_WINDOW_OPACITY", 0),
XA_CARDINAL, 32, PropModeReplace, (uint8_t*) &cardinal_alpha,1) ;

@GitHubIsToxic
Copy link

I believe I've spotted a minor bug. There's a missing "break" statement (line ~138) after "case ClientMessage", so it falls through to "case KeyPress". It appears to be relatively harmless, however it doesn't seem intended.

Thanks...

@chaosink
Copy link

How to remove the title bar and the border of the window?

@je-so
Copy link
Author

je-so commented Apr 28, 2015

Add new line
attr.override_redirect = 1;
after attr.border_pixel ...
and add
|CWOverrideRedirect
in same line after CWBorderPixel.

@nikp123
Copy link

nikp123 commented Aug 29, 2017

This is the chunk of code that I was looking for, thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment