在xlib中创建一个32位的根窗口

时间:2017-01-07 18:16:59

标签: c++ x11 xlib xserver

我已经在这几天了,但我似乎无法弄清楚如何创建一个32位的根窗口,以便我可以在子窗口上使用RGBA颜色,以及孩子如果父窗口(或在本例中为根窗口)不具有32位颜色深度,则窗口不能使用32位颜色深度(RGB为24位,Alpha通道为8位)。我使用以下代码将根窗口的背景设置为RGB图像,其颜色深度为24位,因此当我将XCreatePixmap设置为24位的颜色深度时,它只是工作,但我需要这个根窗口为alpha合成设置颜色深度为32位:

/* 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;
}

当我将XCreapePixmap设置为32位的颜色深度时,我得到:

       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

因此,换句话说,我不太确定如何将根窗口的颜色深度设置为32位,并将24位RGB图像设置为根窗口的背景。 / p>

谢谢!

P.S。我没有安装任何窗口管理器或任何桌面环境,因此使用这些中的任何可用工具都是不可能的。

4 个答案:

答案 0 :(得分:2)

没有。您不必将根窗口设置为深度32以使子项为深度32 太。否则你怎么认为Windows可以有一个alpha通道 合成?你觉得这个怎么样:

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

是否可能没有2个具有32位深度的窗口? (左边的2个 - 时钟和半透明终端)。 :)

半透明的作品是一个合成者介入的方式(这些天通常是你的 窗口管理器)并在顶部组合32位窗口(也可能是交易 在底部也重新绘制根窗口 - 它可能依赖于)。所以说“我没有一个合成器/窗口管理器,所以这是不可能的”基本上说“我不想做我唯一的事情必须做,以便得到半透明“所以我建议你重新评估那个位置。

所以你想要的是一个合成器和32位窗口。要么使用a 合成窗口管理器然后创建32位窗口,或单独运行 合成器和你现有的WM,或者写你自己的合成器......(不会去 能够快速实现这一目标非常有趣... ...

现在要创建一个ARGB窗口,您需要XRender的视觉帮助。如下所示 disp 是您的Xlib 显示是父窗口(例如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);

代码来自此处:https://git.enlightenment.org/core/efl.git/tree/src/lib/ecore_x/ecore_x_window.c#n1644

我们以前在XCB中有一个XCB后端和所有这些代码,但是在十年左右之后我们已经放弃了XCB。如果你克隆上面的内容并深入研究历史记录,那么如果你真的想要挖掘它,那么你可以使用ecore_x目录来制作xlib和xcb子目录。

这就是为什么我编写了一个xlib抽象/详细信息填充程序,因为如果隐藏更简单的API背后的常见详细Xlib用法,则编写的代码要少得多。

答案 1 :(得分:1)

您的问题与我在此处描述的完全相同:How to upload 32 bit image to server-side pixmap

如果你创建32位窗口并且你有24位root,你就不能使用DefaultVisualOfScreen / DefaultColormapOfScreen - 他们设置了对root有效的visual / colormap (因此,24位)。

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

我对imlib api不太熟悉,但看起来你应该能够手动为你的窗口/像素图创建色彩映射并将其传递给imlib

答案 2 :(得分:1)

创建32位深度窗口的最简单方法:

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);

你不能让根窗口拥有你想要的深度 - 它已经存在并具有它所具有的深度。

答案 3 :(得分:0)

想提供一个更简单的解决方案(与@ n.m。解决方案基本相同,但是有更多代码):

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
);

基本上,除了获得适当的视觉效果之外,还需要指定颜色图,背景像素(CWBackPixel)和边框像素。 XGetVisualInfo可以帮您完成工作,而不是用XMatchVisualInfo遍历所有可用的视觉效果。请注意,我没有对此过程执行错误检查,您应该在生产中实施