-
-
Save je-so/903479 to your computer and use it in GitHub Desktop.
/* | |
____ _____ | |
/\__ \ /\ ___\ | |
\/__/\ \ \ \ \__/_ | |
\ \ \ \ \____ \ | |
_\_\ \ \/__/_\ \ | |
/\ _____\ /\ _____\ | |
\/______/ \/______/ | |
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 ; | |
} |
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) ;
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...
How to remove the title bar and the border of the window?
Add new line
attr.override_redirect = 1;
after attr.border_pixel ...
and add
|CWOverrideRedirect
in same line after CWBorderPixel.
This is the chunk of code that I was looking for, thanks a lot.
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) ?