【问题标题】:How to draw on root window with XCB?如何使用 XCB 在根窗口上绘图?
【发布时间】:2015-01-23 11:16:11
【问题描述】:

我有一个使用 XLib 的代码可以正常工作:

    Display *display = XOpenDisplay(NULL);
    int screen_num = DefaultScreen(display);
    Window root_win = RootWindow ( display, screen_num );

    // Create a GC (Graphics Context) for the line
    XGCValues gc_val;
    gc_val.function           = GXxor;
    gc_val.plane_mask         = AllPlanes;
    gc_val.foreground         = WhitePixel(display, screen_num);
    gc_val.background         = BlackPixel(display, screen_num);
    gc_val.line_width         = 4;
    gc_val.line_style         = LineSolid;
    gc_val.cap_style          = CapButt;
    gc_val.join_style         = JoinMiter;
    gc_val.fill_style         = FillOpaqueStippled;
    gc_val.fill_rule          = WindingRule;
    gc_val.graphics_exposures = False;
    gc_val.clip_x_origin      = 0;
    gc_val.clip_y_origin      = 0;
    gc_val.clip_mask          = None;
    gc_val.subwindow_mode     = IncludeInferiors;

    GC gc_line = XCreateGC(display, root_win, GCFunction | GCPlaneMask |  GCForeground | GCBackground | GCLineWidth | GCLineStyle |
                GCCapStyle  | GCJoinStyle  |  GCFillStyle  |  GCFillRule  |  GCGraphicsExposures |
                GCClipXOrigin |  GCClipYOrigin  |  GCClipMask  | GCSubwindowMode, &gc_val);

    //XSetForeground(display, gc_line, some_color);
    XDrawRectangle(display, root_win, gc_line, 50, 50, 400, 400);

    XFlush(display);

...我需要对 XCB 做同样的事情。

我用 XCB 写了尽可能多的类似代码:

xcb_connection_t    *c;
xcb_screen_t        *screen;
xcb_generic_event_t *e;
uint32_t             mask = 0;
xcb_gcontext_t    gc = { 0 };    /* the returned default graphic context */
xcb_drawable_t draw;

xcb_rectangle_t rectangles[] = {
  {0, 0, 100, 100},
};

c = xcb_connect (NULL, NULL);

/* get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;

gc = xcb_generate_id (c);

/* root window */
draw = screen->root;

mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FUNCTION | XCB_GC_CAP_STYLE | XCB_GC_JOIN_STYLE | XCB_GC_FILL_STYLE | XCB_GC_FILL_RULE | XCB_GC_GRAPHICS_EXPOSURES
        | XCB_GC_CLIP_ORIGIN_X | XCB_GC_CLIP_ORIGIN_Y | XCB_GC_CLIP_MASK | XCB_GC_SUBWINDOW_MODE;
uint32_t values[] = {
    screen->black_pixel,
    screen->white_pixel,
    XCB_GX_XOR,
    XCB_CAP_STYLE_BUTT,
    XCB_JOIN_STYLE_MITER,
    XCB_FILL_STYLE_OPAQUE_STIPPLED,
    XCB_FILL_RULE_WINDING,
    1,
    0,
    0,
    XCB_NONE,
    XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS
};

xcb_create_gc (c, gc, draw, mask, values);
xcb_map_window (c, draw);
xcb_flush(c);

while (1)
{
    xcb_poly_rectangle (c, draw, gc, 1, rectangles);
    xcb_flush(c);
}

但在程序开始时我看不到矩形。

我做错了什么?

【问题讨论】:

    标签: c++ c x11 xcb


    【解决方案1】:

    我真的不知道,但是在搜索和修改您的代码后,我能够使用这个简单的代码在根窗口上绘图:

    #include <stdlib.h>
    #include <stdio.h>
    #include <xcb/xcb.h>
    
    int
    main ()
    {
      xcb_connection_t    *c;
      xcb_screen_t        *screen;
      xcb_generic_event_t *e;
      uint32_t             mask = 0;
      xcb_gcontext_t    gc = { 0 };    /* the returned default graphic context */
      xcb_drawable_t draw;
    
      xcb_rectangle_t rectangles[] = {
        { 200, 200, 400, 400 },
      };
    
      c = xcb_connect (NULL, NULL);
    
      /* get the first screen */
      screen = xcb_setup_roots_iterator ( xcb_get_setup ( c ) ).data;
    
      gc = xcb_generate_id ( c );
    
      /* root window */
      draw = screen->root;
    
      mask = XCB_GC_FUNCTION | XCB_GC_FOREGROUND | XCB_GC_BACKGROUND |  XCB_GC_LINE_WIDTH| XCB_GC_LINE_STYLE | XCB_GC_GRAPHICS_EXPOSURES;
      uint32_t values[] = {
          XCB_GX_XOR,
          screen->white_pixel,
          screen->black_pixel,
          1,
          XCB_LINE_STYLE_ON_OFF_DASH,
          0
      };
    
      xcb_create_gc ( c, gc, draw, mask, values );
      xcb_poly_rectangle (c, draw, gc, 3, rectangles);
      xcb_map_window (c, draw);
      xcb_flush(c);
      pause();
      return 0;
    }
    

    我认为您的问题是如何根据需要更新根窗口上的绘图...(也许)。如果您找到解决方案,请向您展示代码。

    我用于测试:

     Xephyr -br -noreset -screen "1024x640" :1&
     DISPLAY=:1.0 ./mylittletest
    

    【讨论】:

    • 首先我想说谢谢你的工作。无限循环重绘矩形是临时解决方案。同样出于某种原因,您的代码无法在我的 PC 上运行。可能我还没有安装一些数据包。
    • 我只想知道为什么?你在编译时有什么错误吗?这对我很重要。
    • 编译日志一目了然。 X11 日志也很清楚。您忘记了应该设置为 XCB_SUBWINDOW_MODE_INCLUDE_INFERIORSXCB_GC_SUBWINDOW_MODE。你可以了解更多关于here的信息。
    • $DISPLAY=:1.0 ./mylittletest -- 你在命令的开头顺便写了一个额外的字符$
    • 是的,这是一个错误。你应该阅读:DISPLAY=:1.0 ./mylittletest
    【解决方案2】:

    我有一些进展。

    看起来是 GC 参数组合的问题。

    截图中显示的代码:

    xcb_connection_t    *c;
    xcb_screen_t        *screen;
    xcb_drawable_t       win;
    xcb_gcontext_t       foreground;
    uint32_t             mask = 0;
    
    xcb_rectangle_t rectangles[] = {
      {50, 50, 600, 400},
    };
    
    c = xcb_connect (NULL, NULL);
    
    /* get the first screen */
    screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
    
    /* root window */
    win = screen->root;
    
    foreground = xcb_generate_id (c);
    mask = XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH | XCB_GC_SUBWINDOW_MODE;
    uint32_t values[] = {
        screen->black_pixel,
        4,
        XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS
    };
    
    xcb_create_gc (c, foreground, win, mask, values);
    
    while(1)
    {
        xcb_poly_rectangle (c, win, foreground, 1, rectangles);
        xcb_flush ( c );
    }
    

    【讨论】:

    • 看了你的截图后,我问你是否在你的开发环境中进行测试。你应该像我在帖子末尾展示的那样使用 Xehyr。例如,桌面管理器或诸如 feh 之类的程序使用根窗口的像素图来设置壁纸。所以你的测试不是很真实。
    • 我的应用程序将在真实用户环境中捕获真实用户窗口。对我来说,最好不要建立合成环境。
    猜你喜欢
    • 2017-08-19
    • 1970-01-01
    • 2018-11-30
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多