Empty or transparent window with Xlib showing border lines only - c

Is there a way to create a window with Xlib which only display the border lines, title, close button and that you can move with the mouse? The content of the window must be empty (or "totally transparent", although "transparency" sounds more like an effect I don't need). Basically the window should show the background area.

I'm not sure if it is what you want, but following code creates an X window with transparent background but still using the window decoration of your window manager.
It will only work though if your X11 and graphics hardware configuration supports visuals with a depth of 32 bit.
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(int argc, char* argv[])
{
Display* display = XOpenDisplay(NULL);
XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
Window win = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 300, 200, 0, vinfo.depth, InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);
XSelectInput(display, win, StructureNotifyMask);
GC gc = XCreateGC(display, win, 0, 0);
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
XSetWMProtocols(display, win, &wm_delete_window, 1);
XMapWindow(display, win);
int keep_running = 1;
XEvent event;
while (keep_running) {
XNextEvent(display, &event);
switch(event.type) {
case ClientMessage:
if (event.xclient.message_type == XInternAtom(display, "WM_PROTOCOLS", 1) && (Atom)event.xclient.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", 1))
keep_running = 0;
break;
default:
break;
}
}
XDestroyWindow(display, win);
XCloseDisplay(display);
return 0;
}

Related

X11 how to listen real-time moving window events

I can only get events after the window has moved, not while it is moving.
I want to get moving events in real time. Please,what should I do?
#include <X11/X.h>
#include <X11/Xlib.h>
#include <stdio.h>
int main(int argv, char **agrc)
{
Display *dpy = XOpenDisplay(NULL);
Window w = XCreateSimpleWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), 10, 10, 800, 400, 1, BlackPixel(dpy, DefaultScreen(dpy)), WhitePixel(dpy, DefaultScreen(dpy)));
XSelectInput(dpy, w, StructureNotifyMask);
XMapWindow(dpy, w);
XEvent event;
for (;;)
{
XNextEvent(dpy, &event);
if(event.type == ConfigureNotify)
{
XConfigureEvent x = event.xconfigure;
printf("config[%d]{%d,%d,%d,%d}\n", x.window, x.x, x.y, x.width, x.height);
}
}
XDestroyWindow(dpy, w);
XCloseDisplay(dpy);
return 0;
}

X11 : Cannot draw an image on transparent window created with XCreateWindow

I am trying to create a simple X11 window, which should display a PNG file with transparent areas. I want the window itself to have no (opaque) background, so that the transparent areas in the PNG shows what there is behind the window.
tl;dr I cannot put an image on a semi-transparent window; it gives "Bad Match".
I can successfully create a semi-transparent window using XCreateWindow and XMatchVisualInfo :
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display),
vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80800000; // Red, semi-transparent
Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0,
width, height, 0, vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel, &attr);
(Full source code below)
I then create an image using :
// "image32" is a generated image - see source code below
XImage *ximage = XCreateImage(display, visual, DefaultDepth(display,DefaultScreen(display)),
ZPixmap, 0, image32, width, height, 32, 0);
And display the image during the Expose event :
XPutImage(display, window, DefaultGC(display, 0), ximage,
0, 0, 0, 0, width, height);
I compile with gcc test.c -L/usr/X11R6/lib -lX11 -lXrandr -o test and run with ./test :
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 72 (X_PutImage)
Serial number of failed request: 11
Current serial number in output stream: 12
Note : If I replace the lines creating the window (XCreateWindow) with these :
Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
width, height, 1, 0, 0);
It displays a window correctly; however, there is no transparency.
I read the docs about XCreateWindow, XPutImage, XCreateImage and tried playing around with multiple parameters, unsuccessfully.
I have read this SO question and tried playing around with color depth; since the docs mentionned "Bad Match" can be also thrown for incorrect visual, I have checked that the same visual was sent at all places in my code.
Any help is appreciated.
Thanks!
Full source code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
// Window size
int height = 256, width = 256;
XImage *CreateTrueColorImage(Display *display, Visual *visual)
{
int i, j;
unsigned char *image32=(unsigned char *)malloc(width*height*4);
unsigned char *p=image32;
for(i=0; i<width; i++)
{
for(j=0; j<height;j++)
{
*p++ = i;
*p++ = i;
*p++ = j;
*p++ = j; // alpha channel (should progressively get transparent towards left)
}
}
// Replacing "DefaultDepth(display,DefaultScreen(display))" with a hardcoded
// 24 or 32 still doesn't work with XCreateWindow. XCreateSimpleWindow works
// with hardcoded 24, but not 32.
return XCreateImage(display, visual, DefaultDepth(display,DefaultScreen(display)),
ZPixmap, 0, image32, width, height, 32, 0);
}
int main(int argc, char **argv)
{
XImage *ximage;
Display *display = XOpenDisplay(NULL);
Visual *visual = DefaultVisual(display, 0);
XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display),
vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80800000; // Red, semi-transparent
//Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
// width, height, 1, 0, 0);
Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0,
width, height, 0, vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel, &attr);
ximage = CreateTrueColorImage(display, vinfo.visual);
XSelectInput(display, window, ButtonPressMask|ExposureMask);
XMapWindow(display, window);
while(1)
{
XEvent event;
XNextEvent(display, &event);
switch(event.type)
{
case Expose:
XPutImage(display, window, DefaultGC(display, 0), ximage,
0, 0, 0, 0, width, height);
break;
case ButtonPress:
exit(0);
}
}
}
I managed to make it work by making two changes.
First, instead of using DefaultGC(display, 0) you should create a GC for your specific window.
GC gc = XCreateGC(display, window, 0, 0);
With that if you hardcode the depth of XCreateImage to 32 it should work correctly.
And you can also use the depth provided by XVisualInfo like so
XCreateImage(display, vinfo.visual, vinfo.depth,
ZPixmap, 0, image32, width, height, 32, 0);

Open a dock type window with x11 and capture key press

I would like to open a "dock type" window without its title bar with x11 in C and I want to capture a key press (Ctrl-q) to close it. The actual code does not capture the key presses to the active window as they are all sent and printed in the terminal. Almost all the Ctrl key presses are somehow not detected. The only key presses that actually work on the opened window are Ctrl-c. I am aware of the _MOTIF_WM_HINTS property but it has the disadvantage to display a window icon in the panel to show a new opened window.
How can I have a "dock type" window while not losing the ability to detect key presses to the active window?
Here is the code basically copied from two other posts here and here
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
int main(int argc, char **argv)
{
Display *dpy = XOpenDisplay(0);
int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
200, 100, 0, blackColor, blackColor);
//Tell X Server to send MapNotify events
XSelectInput(dpy, w, StructureNotifyMask | KeyPressMask);
Atom window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
long value = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(dpy, w, window_type, 4, 32,
PropModeReplace,
(unsigned char *)&value, 1);
//Make window appear
XMapWindow(dpy, w);
//Graphics Context
GC gc = XCreateGC(dpy, w, 0, 0);
//Set white color for drawing
XSetForeground(dpy, gc, whiteColor);
//Wait for the MapNotify event
for(;;) {
XEvent e;
XNextEvent(dpy, &e);
if (e.type == MapNotify) {
break;
}
}
//Draw the line
XDrawLine(dpy, w, gc, 10, 60, 180, 20);
//Send the "DrawLine" request to the server
XFlush(dpy);
char text[255];
XEvent e;
KeySym key;
int numKeys = 0;
for(;;) {
XNextEvent(dpy, &e);
if(e.type == KeyPress) {
if((numKeys = XLookupString(&e.xkey, text, 255, &key, 0))) {
if(e.xkey.state == ControlMask && key == XK_q) {
printf("CTRL-Q\n");
break;
}
}
}
}
if (dpy && gc) XFreeGC(dpy, gc);
if (dpy && w) XDestroyWindow(dpy, w);
if (dpy) XCloseDisplay(dpy);
return 0;
}
Compiled with:
gcc main.c -L/usr/X11R6/lib -lX11 -lm && ./a.out
I've also looked at the _NET_WM_STRUT_PARTIAL property but I haven't been succesful at implementing it.

Linux Xlib erroneous alpha handling [duplicate]

I would like to create a semi transparent white window in XLib, but the window is not semi translucent, it remains fully opaque. I use the compton compositor and there are transparent windows in the system, so the problem is in the code:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
Display* display = XOpenDisplay(NULL);
XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80ffffff;
Window win = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 300, 200, 0, vinfo.depth, InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);
XSelectInput(display, win, StructureNotifyMask);
GC gc = XCreateGC(display, win, 0, 0);
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
XSetWMProtocols(display, win, &wm_delete_window, 1);
XMapWindow(display, win);
int keep_running = 1;
XEvent event;
while (keep_running) {
XNextEvent(display, &event);
switch(event.type) {
case ClientMessage:
if (event.xclient.message_type == XInternAtom(display, "WM_PROTOCOLS", 1) && (Atom)event.xclient.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", 1))
keep_running = 0;
break;
default:
break;
}
}
XDestroyWindow(display, win);
XCloseDisplay(display);
return 0;
}
X11 expects pre-multiplied colours, i.e. real opaque colours need to be multiplied by the alpha value (and scaled accordingly, i.e. divided by 256 when channel widths is 8 bits). This format is easier to work with when you need to combine many levels. See formulas here. There's less computation when everything is pre-multiplied.
So you need to multiply each of your R, G and B channels by the alpha value (0x80) and divide by 256.
Setting the background to 0x80808080 gives the desired result:
Note the result is different from what #patthoyts suggests: here only the window proper is semi-transparent, the WM decoration stays opaque; there both the window proper and the decoration are made transparent by the WM (and the WM does the necessary colour blending).
You need to set _NET_WM_WINDOW_OPACITY. Here is a snippet to add in before you map the window:
double alpha = 0.8;
unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha);
Atom XA_NET_WM_WINDOW_OPACITY = XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False);
XChangeProperty(display, win, XA_NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&opacity, 1L);
Note you should add #include <X11/Xatom.h> to get the declaration of XA_CARDINAL.
I'm not entirely sure how stable this interface is. This appears to be a proposed extension to the Extended Window Manager Hints specification but has not made it into any final revision from what I can see. I know that this is how Tk implements transparency support on unix though.
The result looks like:

SDL2 window size is bigger than it should be

I'm trying to create a window, let's say 400x400:
SDL_Init(SDL_INIT_VIDEO);
Uint32 mode = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
SDL_Window* window;
SDL_Renderer* renderer;
if (SDL_CreateWindowAndRenderer(400, 400, mode, &window, &renderer))
return 2;
if (!window || !renderer)
return 2;
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Event event;
int quit = 0;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = 1;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
I see a window filled with black pixels. However, the window's size is 500x500 withouth borders, and 502x540 with them, but why?
On Windows, the OS may stretch your window in the case when you are using a high DPI monitor. You can disable this stretching using:
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1")

Resources