Jump to content

Xcb: Difference between revisions

From KDE Community Wiki
Fredrik (talk | contribs)
No edit summary
Fredrik (talk | contribs)
No edit summary
Line 151: Line 151:
         xcb_xfixes_create_region(c, region, 1, &rect);
         xcb_xfixes_create_region(c, region, 1, &rect);
</syntaxhighlight>
</syntaxhighlight>
== KXErrorHandler ==
The KXErrorHandler class is used when you need to check if an asychronous Xlib call succeeded
or generated an an error. The following example shows how it is typically used.
<syntaxhighlight lang="cpp">
    KXerrorHandler handler;
    XMapWindow(dpy, window);
    if (handler.error(true)) {
        kDebug() << "XMapWindow() failed!";
    }
</syntaxhighlight>
<br/>
Unfortunately KXErrorHandler cannot be ported to xcb. The good news however is that with xcb you don't
need KXErrorHandler to do this.
You may have noticed that xcb functions that don't generate a reply come in two versions; a regular version
and a version with ''_checked()'' appended to the name:
<syntaxhighlight lang="cpp">
    xcb_void_cookie_t xcb_map_window(xcb_connection_t *c, xcb_window_t window);
    xcb_void_cookie_t xcb_map_window_checked(xcb_connection_t *c, xcb_window_t window);
</syntaxhighlight>
<br/>
The xcb_void_cookie_t returned by the _checked() version of the function can be used
to check if the function succeeded or not by passing the cookie to xcb_request_check().
The following example shows how this works:
<syntaxhighlight lang="cpp">
    xcb_void_cookie_t cookie = xcb_map_window_checked(c, window);
    xcb_generic_error_t *error = xcb_request_check(c, cookie);
    if (error) {
        kDebug() << "xcb_map_window() failed!";
        free(error);
    }
</syntaxhighlight>
<br/>
Like KXErrorHandler, xcb_request_check() needs to synchronize with the X server to know
that the X server has processed the request(s). For this reason you should only use
xcb_request_check() when it is necessary to know that a request succeeded before
proceeding with other calls.

Revision as of 22:33, 25 July 2012

Introduction

Porting Xlib calls to xcb is fairly straightfoward, since most of the time it's a matter of replacing a call to an Xlib function with a call to the equivalent xcb function. This page mainly deals with exceptions to that rule, and things that might not be obvious even if you are familiar with Xlib.

Porting can be done gradually, since you can mix xcb and Xlib calls. The only exception is event processing. The event queue is managed either by xcb or Xlib, not both at the same time.

Macros

RootWindow(), DisplayWidth(), DisplayHeight(), DefaultDepth() etc.

Xlib code
    Window root = RootWindow(dpy, screen);
    int depth = DefaultDepth(dpy, screen);
    int width = DisplayWidth(dpy, screen);
    int height = DisplayHeight(dpy, screen);
xcb equivalent
    xcb_screen_t *screen = xcb_aux_get_screen(c, screen);
    xcb_window_t root = screen->root;
    int depth = screen->root_depth;
    int width = screen->width;
    int height = screen->height;


If you need a pointer to the xcb_screen_t for the default screen, call QPlatformNativeInterface::nativeResourceForWindow("screen", 0)) and cast the returned pointer to xcb_screen_t *.

DefaultRootWindow(), DefaultVisual(), DefaultDepth(), DefaultColormap()

See the previous section and the comment about obtaining a pointer to the xcb_screen_t for the default screen.

Functions

XSelectInput()

XSelectInput() is a convenience function that uses the ChangeWindowAttributes request to change the event mask for a window. The xcb equivalent of XSelectInput() is thus xcb_change_window_attributes().

Xlib example
XSelectInput(dpy, window, PropertyChangeMask);
xcb equivalent
uint32_t mask = XCB_EVENT_MASK_PROPERTY_CHANGE;
xcb_change_window_attributes(c, window, XCB_CW_EVENT_MASK, &mask);


Note that this applies only to XSelectInput(), not other input selection functions added by extensions.

XSync()

The xcb equivalent of XSync() is xcb_aux_sync(), which is in xcb-utils.

The reason you won't find a sync function in libxcb is that there is no sync request in the X protocol. Calling XSync() or xcb_aux_sync() is equivalent to calling XGetInputFocus() and throwing away the reply.

XMoveWindow(), XResizeWindow(), XMoveResizeWindow(), XSetWindowBorderWidth(), XRaiseWindow(), XLowerWindow(), XRestackWindows()

These functions are Xlib convenience functions that translate to the same X request; ConfigureWindow. The xcb equivalent is thus xcb_configure_window().

XMoveResize() example
    XMoveWindow(dpy, window, x, y);

    uint32_t values[] = { x, y };
    xcb_configure_window(c, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
XRaiseWindow() example
    XRaiseWindow(dpy, window);

    uint32_t value = XCB_STACK_MODE_ABOVE;
    xcb_configure_window(c, window, XCB_CONFIG_STACK_MODE, &value);


Multiple calls to these functions can be combined into single call to xcb_configure_window():

    XMoveWindow(dpy, window, x, y);
    XResizeWindow(dpy, window, width, height);
    XRaiseWindow(dpy, window);

    uint32_t values[] = { x, y, width, height, XCB_STACK_MODE_ABOVE };
    xcb_configure_window(c, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
                         XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_STACK_MODE,
                         values);


Note that the order of the values in the values array must match the order in the xcb_config_window_t enum.

Creating Resources

In this example we're going to look at how to create a pixmap in Xlib and in xcb, and look at the differences.

Xlib example
    Pixmap pixmap = XCreatePixmap(dpy, root, width, height, depth);
xcb equivalent
    xcb_pixmap_t pixmap = xcb_generate_id();
    xcb_create_pixmap(c, depth, pixmap, root, width, height);


XCreatePixmap() creates a pixmap with the specified width, height and depth, and returns a handle to the newly created pixmap.

In the xcb version we call xcb_generate_id() to create the pixmap handle, and then we pass the handle to the xcb_create_pixmap() function.

When a client connects to the X server it is given a range of unique global ID's that can be assigned to new resources. XCreatePixmap() picks the first unused ID in this range, and tells the X server to assign that ID to the pixmap when it creates it. After sending the request, XCreatePixmap() returns the ID to the caller.

Unlike Xlib, xcb doesn't hide these details from us. Whenever you create a new resource, you start by calling xcb_generate_id() to get an ID that can be assigned to the resource. The ID is always passed as a parameter to the function that creates the resource.

The advantage of this design is that creating resources is asynchronous, since the client doesn't have to wait for the X server to send back the ID after creating the resource. The disadvantage is that if resource creation fails for any reason, the ID will never become valid and we won't find out about it until later.

A different example that creates a region:

        xcb_rectangle_t rect = { 0, 0, 100, 100 };

        xcb_xfixes_region_t region = xcb_generate_id();
        xcb_xfixes_create_region(c, region, 1, &rect);

KXErrorHandler

The KXErrorHandler class is used when you need to check if an asychronous Xlib call succeeded or generated an an error. The following example shows how it is typically used.

    KXerrorHandler handler;

    XMapWindow(dpy, window);

    if (handler.error(true)) {
        kDebug() << "XMapWindow() failed!";
    }


Unfortunately KXErrorHandler cannot be ported to xcb. The good news however is that with xcb you don't need KXErrorHandler to do this.

You may have noticed that xcb functions that don't generate a reply come in two versions; a regular version and a version with _checked() appended to the name:

    xcb_void_cookie_t xcb_map_window(xcb_connection_t *c, xcb_window_t window);

    xcb_void_cookie_t xcb_map_window_checked(xcb_connection_t *c, xcb_window_t window);


The xcb_void_cookie_t returned by the _checked() version of the function can be used to check if the function succeeded or not by passing the cookie to xcb_request_check().

The following example shows how this works:

    xcb_void_cookie_t cookie = xcb_map_window_checked(c, window);
    xcb_generic_error_t *error = xcb_request_check(c, cookie);

    if (error) {
        kDebug() << "xcb_map_window() failed!";
        free(error);
    }


Like KXErrorHandler, xcb_request_check() needs to synchronize with the X server to know that the X server has processed the request(s). For this reason you should only use xcb_request_check() when it is necessary to know that a request succeeded before proceeding with other calls.