码迷,mamicode.com
首页 > Windows程序 > 详细

使用XCB编写X Window程序(05):使用异步的方式和X Server通讯及获取和设置窗口的属性

时间:2014-07-22 00:03:35      阅读:839      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   使用   os   数据   

  在前面的例子中,我们从来没有关心过调用XCB函数时,该函数和X Server的通讯是同步的还是异步的。因为在前面的例子中,我们基本上不关心XCB函数的返回值,只有在上一篇中,由于某些操作需要关心它们是否成功(比如是否成功打开字体、是否成功创建GC等),才涉及到XCB函数的返回值。

  在这一篇中会更进一步,因为是获取窗口的属性,所以肯定要关注从X Server获取的数据,这时,将会涉及到XCB函数同X Server的通讯是同步的还是异步的。什么是同步?就是说调用一个函数向X Server发出一个请求后,该函数要一直等到X Server回复的数据函数才返回。什么是异步?就是说调用一个XCB函数向X Server发出一个请求后,不用等X Server回复的数据,该函数直接返回。传统的Xlib使用的是同步的方式,而XCB则是使用的异步方式。很显然,使用异步的方式可以获得更好的效率。这也是XCB取代Xlib的一个主要原因。

  那么既然XCB使用的是异步的方式,调用一个XCB函数后没有等到X Server的回复该函数就已经返回了,那么我们真的需要X Server回复的数据怎么办呢?对于这个问题,在XCB中使用的是这样一种解决方式:XCB函数先返回一个cookie,数据传输在后台进行,由XCB自动处理,当需要使用从X Server获取的数据时,再调用另外一个函数通过该cookie获取数据。后面将会看到具体的示例。

 

操控窗口的属性

  前面展示了怎么创建窗口以及怎么在窗口中画图。其实对于窗口,还可以有更多的操作。可以认为这些操作都是通过获取和设置窗口的属性来进行。窗口可以有很多的属性,而且这些属性的设置方式还不一样。下面来回顾一下创建窗口的函数:

xcb_void_cookie_t xcb_create_window (
    xcb_connection_t *connection,    /* Pointer to the xcb_connection_t structure */
    uint8_t           depth,         /* Depth of the screen */
    xcb_window_t      wid,           /* Id of the window */
    xcb_window_t      parent,        /* Id of an existing window that should be the parent of the new window */
    int16_t           x,             /* X position of the top-left corner of the window (in pixels) */
    int16_t           y,             /* Y position of the top-left corner of the window (in pixels) */
    uint16_t          width,         /* Width of the window (in pixels) */
    uint16_t          height,        /* Height of the window (in pixels) */
    uint16_t          border_width,  /* Width of the window‘s border (in pixels) */
    uint16_t          _class,
    xcb_visualid_t    visual,
    uint32_t          value_mask,
    const uint32_t   *value_list 
);

  可以看到:1、有一部分属性是直接通过xcb_create_window的参数设置的,比如窗口的颜色深度、位置、大小、边框宽度等;2、一部分窗口的属性通过mask、values的方式设置,比如前景色、背景色、需要关注的事件等;3、还有一部分属性需要通过另外一种方式来设置,这种方式我之前没有展示过,那就是通过xcb_change_property函数来设置,这些属性比较特别,每一个都称之为atom。从xcb_create_window的函数签名还可以看出,xcb_create_window确实是返回一个xcb_void_cookie_t类型的值,也就是返回一个cookie。这验证了我之前关于XCB函数是异步的这个说法。

  xcb_change_property的函数签名如下:

xcb_void_cookie_t xcb_change_property (
    xcb_connection_t *c,       /* Connection to the X server */
    uint8_t          mode,     /* Property mode */
    xcb_window_t     window,   /* Window */
    xcb_atom_t       property, /* Property to change */
    xcb_atom_t       type,     /* Type of the property */
    uint8_t          format,   /* Format of the property (8, 16, 32) */
    uint32_t         data_len, /* Length of the data parameter */
    const void       *data     /* Data */
); 

  可以看出,该函数要同时关注atom的id、atom的类型及atom的值,还要关注该值的格式和长度。也就是说,每一个atom由一个id标识,它可以有自己的类型和值。比如一个atom可能是一个数字,而另一atom可能是一个字符串。该函数的mode参数可以取下面值中的一个:

XCB_PROP_MODE_REPLACE
XCB_PROP_MODE_PREPEND
XCB_PROP_MODE_APPEND

 

  使用atom来表示窗口的属性主要是为了和别的程序之间进行沟通,比如和窗口管理器沟通。下面是一个设置窗口标题以及窗口最小化后任务栏标题的示例:

    #include <string.h>

    #include <xcb/xcb.h>
    #include <xcb/xcb_atom.h>

    int
    main ()
    {
        /* open the connection to the X server */
        xcb_connection_t *connection = xcb_connect (NULL, NULL);


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


        /* create the window */

        xcb_window_t window = xcb_generate_id (connection);
        xcb_create_window (connection, 
                           0,                             /* depth               */
                           window,
                           screen->root,                  /* parent window       */
                           0, 0,                          /* x, y                */
                           250, 150,                      /* width, height       */
                           10,                            /* border_width        */
                           XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */
                           screen->root_visual,           /* visual              */
                           0, NULL );                     /* masks, not used     */


        /* set the title of the window */

        char *title = "Hello World !";
        xcb_change_property (connection,
                             XCB_PROP_MODE_REPLACE,
                             window,
                             XCB_ATOM_WM_NAME,
                             XCB_ATOM_STRING,
                             8,
                             strlen (title),
                             title );


        /* set the title of the window icon */

        char *iconTitle = "Hello World ! (iconified)";
        xcb_change_property (connection,
                             XCB_PROP_MODE_REPLACE,
                             window,
                             XCB_ATOM_WM_ICON_NAME,
                             XCB_ATOM_STRING,
                             8,
                             strlen(iconTitle),
                             iconTitle);


        /* map the window on the screen */

        xcb_map_window (connection, window);
        xcb_flush (connection);


        /* event loop (in this case, no events to handle) */ 
        while (1) {}

        return 0;
    }

  如果想更改窗口的大小、位置、边框宽度等属性的话,可以通过如下函数进行:

xcb_void_cookie_t xcb_configure_window (
    xcb_connection_t *c,            /* The connection to the X server*/
    xcb_window_t      window,       /* The window to configure */
    uint16_t          value_mask,   /* The mask */
    const uint32_t   *value_list    /* The values to set */
);

  可以看到,该函数再次用到了mask、valuelist这种模式。该函数可操作的属性有如下这些:

    XCB_CONFIG_WINDOW_X             // new x coordinate of the window‘s top left corner
    XCB_CONFIG_WINDOW_Y             // new y coordinate of the window‘s top left corner
    XCB_CONFIG_WINDOW_WIDTH         // new width of the window
    XCB_CONFIG_WINDOW_HEIGHT        // new height of the window
    XCB_CONFIG_WINDOW_BORDER_WIDTH  // new width of the border of the window
    XCB_CONFIG_WINDOW_SIBLING
    XCB_CONFIG_WINDOW_STACK_MODE    // the new stacking order

  写了半天也还没写到XCB函数和X Server异步通讯的用法。为了不把这篇随笔写得又臭又长,xcb_configure_window具体怎么用我就不举例了。大家可以自行阅读XCB的官方教程。下面来看什么是异步。

 

获取窗口的属性

  有很多函数可以获取窗口的属性,比如最常见的 xcb_get_geometry 和 xcb_get_geometry_reply ,看到geometry肯定会想到长宽高、横坐标纵坐标什么的。确实,这两个函数就是用来获取窗口的位置、大小这样一些信息的。而且这两个函数总是成对出现。因为xcb_get_geometry被调用后,它是马上返回的,这时X Server的数据还没传回来呢,所以,等数据传回来了,还得调用xcb_get_geometry_reply把这些数据读出来。这两个函数的签名如下:

xcb_get_geometry_cookie_t xcb_get_geometry (
    xcb_connection_t *connection,
    xcb_drawable_t    drawable 
);

xcb_get_geometry_reply_t *xcb_get_geometry_reply (
    xcb_connection_t          *connection,
    xcb_get_geometry_cookie_t  cookie,
    xcb_generic_error_t      **error
);

  可以看到,第一个函数返回一个类型为xcb_get_geometry_cookie_t的cookie,第二个函数再以该cookie为参数,返回具体的geometry信息,这就是异步。该信息是一个类型为xcb_get_geometry_reply_t的指针,该类型定义如下:

typedef struct {
        uint8_t      response_type;
        uint8_t      depth;         /* depth of the window */
        uint16_t     sequence;
        uint32_t     length;
        xcb_window_t root;          /* Id of the root window *>
        int16_t      x;             /* X coordinate of the window‘s location */
        int16_t      y;             /* Y coordinate of the window‘s location */
        uint16_t     width;         /* Width of the window */
        uint16_t     height;        /* Height of the window */
        uint16_t     border_width;  /* Width of the window‘s border */
    } xcb_get_geometry_reply_t;

  前面说过,窗口有很多属性。geometry属性指示窗口属性的一部分,所以,还有一对更猛的获取窗口属性的函数及其使用到的数据结构,如下:

typedef struct {
        uint8_t        response_type;
        uint8_t        backing_store;
        uint16_t       sequence;
        uint32_t       length;
        xcb_visualid_t visual;                /* Visual of the window */
        uint16_t       _class;
        uint8_t        bit_gravity;
        uint8_t        win_gravity;
        uint32_t       backing_planes;
        uint32_t       backing_pixel;
        uint8_t        save_under;
        uint8_t        map_is_installed;
        uint8_t        map_state;             /* Map state of the window */
        uint8_t        override_redirect;
        xcb_colormap_t colormap;              /* Colormap of the window */
        uint32_t       all_event_masks;
        uint32_t       your_event_mask;
        uint16_t       do_not_propagate_mask;
} xcb_get_window_attributes_reply_t;


xcb_get_window_attributes_cookie_t xcb_get_window_attributes (
    xcb_connection_t *connection,
    xcb_window_t      window 
);

xcb_get_window_attributes_reply_t *xcb_get_window_attributes_reply (
    xcb_connection_t                   *connection,
    xcb_get_window_attributes_cookie_t  cookie,
    xcb_generic_error_t               **e 
);

  这些都还是基本的。编写简单的窗口程序,了解这些基本的方法就够了。但是GUI编程,总还有一些高深的需求,比如枚举系统中所有的窗口。我这里用到了“枚举”这个词,是因为Win32 API用了这个词。而在X Window中,这样的操作叫做“遍历”。很显然,在GUI系统中,所有的窗口都是通过parent、child这样的方式呈树形组织起来的,所以通过“遍历”窗口树来“枚举”系统中的所有窗口,其实也不难。这个任务需要用到这样的函数和数据结构:

typedef struct {
        uint8_t      response_type;
        uint8_t      pad0;
        uint16_t     sequence;
        uint32_t     length;
        xcb_window_t root;
        xcb_window_t parent;       /* Id of the parent window */
        uint16_t     children_len;
        uint8_t      pad1[14];
} xcb_query_tree_reply_t;


xcb_query_tree_cookie_t xcb_query_tree (
    xcb_connection_t        *connection,
    xcb_window_t             window 
);

xcb_query_tree_reply_t *xcb_query_tree_reply (
    xcb_connection_t        *connection,
    xcb_query_tree_cookie_t  cookie,
    xcb_generic_error_t    **error 
);

  不过该函数好像只能从子窗口查找父窗口,很显然要完成遍历,还必须要能从父窗口查找子窗口。X Window中有通过父窗口查找子窗口的方法吗?大家慢慢研究去吧。

(京山游侠于2014-07-21发布于博客园,转载请注明出处。)

使用XCB编写X Window程序(05):使用异步的方式和X Server通讯及获取和设置窗口的属性,布布扣,bubuko.com

使用XCB编写X Window程序(05):使用异步的方式和X Server通讯及获取和设置窗口的属性

标签:style   blog   color   使用   os   数据   

原文地址:http://www.cnblogs.com/youxia/p/gui005.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!