asdf
asdf

Reputation: 460

Create a 32-bit root window in xlib

I've been at this for days now, but i just can't seem to figure out how to create a 32 bit root window so that I can use RGBA colors on the child window, and the child window cannot use 32-bit color depth (24-bit for RGB, and 8-bit for Alpha channel) if the parent, or in this case root window, does not have 32-bit color depth. I am using the following code to set the background of the root window to an RGB image which has a color depth of 24-bit, thus when I set XCreatePixmap to a color depth of 24 bit it just works, but i need this root window to have a color depth of 32-bit for alpha compositing:

/* displays an image or sets root background
 * PUBLIC DOMAIN - CC0 http://creativecommons.org/publicdomain/zero/1.0/
 * J.Mayo 2013
 *
 * gcc -Wall -W -g3 -o background background.c -lX11 -lImlib2
 *
 */
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <Imlib2.h>


struct screenAttributes {
    int height;
    int width;
};
struct screenAttributes screenAttr;
void initializeScreenAttributes(Screen *screen) {
    screenAttr.height=screen->height;
    screenAttr.width=screen->width;
}



int main(int argc, char **argv)
{
    Imlib_Image img;
    Display *dpy;
    Pixmap pix;
    Window root;
    Screen *scn;

   // Window topPanel;

    int width, height;
    const char *filename = "/sampleImage.png";


    img = imlib_load_image(filename);
    if (!img) {
        fprintf(stderr, "%s:Unable to load image\n", filename);
        goto usage;
    }
    imlib_context_set_image(img);
    width = imlib_image_get_width();
    height = imlib_image_get_height();

    dpy = XOpenDisplay(NULL);
    if (!dpy) return 0;

    scn = DefaultScreenOfDisplay(dpy);
    root = DefaultRootWindow(dpy);

    pix = XCreatePixmap(dpy, root, width, height,32); //when depth is set to 24 it just works, but when it is set to 32 it fails.



    //scale the image
    initializeScreenAttributes(scn);
    imlib_blend_image_onto_image(img,0,0,0,width,height,0,0,
                                screenAttr.width, screenAttr.height);



    imlib_context_set_display(dpy);
    imlib_context_set_visual(DefaultVisualOfScreen(scn));
    imlib_context_set_colormap(DefaultColormapOfScreen(scn));
    imlib_context_set_drawable(pix);

    imlib_render_image_on_drawable(0, 0);
    XSetWindowBackgroundPixmap(dpy, root, pix);
    XClearWindow(dpy, root);



    while (XPending(dpy)) {
        XEvent ev;
        XNextEvent(dpy, &ev);
    }
    XFreePixmap(dpy, pix);
    imlib_free_image();
    sleep(10);
    //XFreePixmap(dpy, pix);
    //imlib_free_image();
    XCloseDisplay(dpy);
    return 0;
usage:
    fprintf(stderr, "usage: %s <image_file>\n", argv[0]);
    return 1;
}

when I set XCreapePixmap to a color depth of 32-bit, I get:

       X Error of failed request: BadMatch (invalid parameter attributes)
    Major opcode of failed request: 130 (MIT-SHM)
    Minor Opcode of failed request: 3 (X_ShmPutImage)
    Serial number of failed request : 28 
Current serial number in output stream: 29 xinit: connection to X server lost

So, In other words I'm not quite sure as to how to set the color depth of the root window to 32-bit and have a 24-bit RGB image set as the background of the root window.

Thanks!

P.S. I do not have any window managers or any desktop environment installed, so using any of the available tools in those is out of the question.

Upvotes: 2

Views: 3275

Answers (4)

Asad-ullah Khan
Asad-ullah Khan

Reputation: 1833

Would like to offer a simpler solution (basically the same as @n.m. solution, but has some more code):

Display *d = XOpenDisplay(NULL);
Window root = DefaultRootWindow(d);
int default_screen = XDefaultScreen(d);


XSetWindowAttributes attrs;
attrs.override_redirect = true;

XVisualInfo vinfo;
if (!XMatchVisualInfo(d, DefaultScreen(d), 32, TrueColor, &vinfo)) {
    printf("No visual found supporting 32 bit color, terminating\n");
    exit(EXIT_FAILURE);
}

attrs.colormap = XCreateColormap(d, root, vinfo.visual, AllocNone);
attrs.background_pixel = 0;
attrs.border_pixel = 0;

// Window XCreateWindow(
//     Display *display, Window parent,
//     int x, int y, unsigned int width, unsigned int height, unsigned int border_width,
//     int depth, unsigned int class, 
//     Visual *visual,
//     unsigned long valuemask, XSetWindowAttributes *attributes
// );
Window overlay = XCreateWindow(
    d, root,
    0, 0, 200, 200, 0,
    vinfo.depth, InputOutput, 
    vinfo.visual,
    CWOverrideRedirect | CWColormap | CWBackPixel | CWBorderPixel, &attrs
);

Basically, you need to specify a color map, background pixel (CWBackPixel) and border pixel, in addition to getting the proper visual. Instead of looping over all available visuals with XGetVisualInfo, XMatchVisualInfo does the work for you. Note that I am not performing error checks for this process, which you should implement in production

Upvotes: 0

n. m. could be an AI
n. m. could be an AI

Reputation: 119857

The easiest way to create a 32-bit-deep window:

XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
Window win = XCreateWindow(display, DefaultRootWindow(display),
                           0, 0, width, height, 0, 
                           vinfo.depth,    // <---------------!!!
                           InputOutput, 
                           vinfo.visual,   // <---------------!!!
                           mask, &attr);

You cannot have the root window to have the depth you want — it already exists and has the depth it has.

Upvotes: 1

Andrey Sidorov
Andrey Sidorov

Reputation: 25456

Looks like you have exactly the same problem as I described here: How to upload 32 bit image to server-side pixmap

If you create 32-bit window and you have 24 bit root, you can't use DefaultVisualOfScreen / DefaultColormapOfScreen - they'l set visual/colormap that are valid for root (and thus, 24 bit).

imlib_context_set_visual(DefaultVisualOfScreen(scn));
imlib_context_set_colormap(DefaultColormapOfScreen(scn));

I'm not very familiar with imlib api, but it looks you should be able to create colormap for your window/pixmap manually and pass it to imlib

Upvotes: 2

Carsten Haitzler
Carsten Haitzler

Reputation: 46

No. You don't have to have root window be depth 32 to have children be depth 32 too. Otherwise how on earth do you think windows can have alpha channels in a compositor? How do you think this:

http://www.enlightenment.org/ss/e-5872c6ec3ddce1.54730231.png

is possible without 2 of those windows having 32bit depth? (the 2 on the left - clock and translucent terminal). :)

The way translucency WORKS is a compositor intervenes (these days usually your window manager) and is composites the 32bit windows on top (also possibly deals with redrawing root window too at the bottom - it may depend though). so saying "I don't have a compositor/window manager so that's out of the question" is basically saying "I don't want to do the one and only thing I HAVE TO DO in order to get translucency" so I suggest you re-evaluate that position.

So what you want really is a compositor AND 32bit windows. Either use a compositing window manager and then create 32bit windows, OR run a separate compositor and your existing WM, or write your own compositor... (not going to be much fun to get this right AND fast)...

Now to create an ARGB window you'll need help from XRender for the visual. Like the below where disp is your Xlib Display and parent is the parent Window (e.g. root):

Window win;
XSetWindowAttributes attr;
XWindowAttributes att;
XVisualInfo *xvi;
XVisualInfo vi_in;
int nvi, i, scr = 0;
XRenderPictFormat *fmt;
Visual *vis;

vi_in.screen = scr;
vi_in.depth = 32;
vi_in.class = TrueColor;
xvi = XGetVisualInfo(disp,
                     VisualScreenMask |
                     VisualDepthMask |
                     VisualClassMask,
                     &vi_in,
                     &nvi);
if (!xvi) return 0;

vis = NULL;
for (i = 0; i < nvi; i++)
  {
     fmt = XRenderFindVisualFormat(disp, xvi[i].visual);
     if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask))
       {
          vis = xvi[i].visual;
          break;
       }
  }
XFree (xvi);

attr.backing_store = NotUseful;
attr.override_redirect = 0;
attr.colormap = XCreateColormap(disp, parent,
                                vis, AllocNone);
attr.border_pixel = 0;
attr.background_pixmap = None;
attr.bit_gravity = NorthWestGravity;
attr.win_gravity = NorthWestGravity;
attr.save_under = 0;
attr.do_not_propagate_mask = NoEventMask;
attr.event_mask = KeyPressMask |
  KeyReleaseMask |
  ButtonPressMask |
  ButtonReleaseMask |
  EnterWindowMask |
  LeaveWindowMask |
  PointerMotionMask |
  ExposureMask |
  VisibilityChangeMask |
  StructureNotifyMask |
  FocusChangeMask |
  PropertyChangeMask |
  ColormapChangeMask;
win = XCreateWindow(disp, parent,
                    x, y, w, h, 0,
                    32,
                    InputOutput,
                    vis,
                    CWBackingStore |
                    CWOverrideRedirect |
                    CWColormap |
                    CWBorderPixel |
                    CWBackPixmap |
                    CWSaveUnder |
                    CWDontPropagate |
                    CWEventMask |
                    CWBitGravity |
                    CWWinGravity,
                    &attr);

Code comes from here: https://git.enlightenment.org/core/efl.git/tree/src/lib/ecore_x/ecore_x_window.c#n1644

We used to have an XCB back-end and all this code in XCB, but we've given up on XCB after a decade or so. If you clone the above and dig through history you'll fine the ecore_x dir used to have xlib and xcb sub-dirs if you really want to dig that out.

This is why I wrote an xlib abstractor/detail filler because it's a lot less code to write if you hide common verbose Xlib usage behind simpler APIs.

Upvotes: 3

Related Questions