Package: xcompmgr
Version: 1.1.5-1

Hi!

I'm writing a program that uses the SHAPE extensions to give a window a
non-rectangular shape. This works up to the point where I try to modify
the shape at runtime. The attached example program creates a simple
window of 50x50 pixels. It then creates a moving square of 10x10 pixels
inside that window which is not part of the window, using the SHAPE
extension, so that you can watch the background or underlying window
through this hole.

While xcompmgr is running, the window isn't updated correctly. I tried
this using fluxbox (which itself has some problems with X11 SHAPE), but
it also happens with openbox, icewm or windowmaker, it even happens when
not using any windowmanager at all. I tried using compiz as compositing
and window manager, but failed getting it to run even halfway. 


The system is an old Mac Mini, using an ATI Radeon videochip and running
a current Debian/testing system.

Give me some feedback if you can't reproduce this, I'll try to circle
in the other factors then.

Cheers!

Uli


-- System Information:
Debian Release: squeeze/sid
  APT prefers testing
  APT policy: (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: powerpc (ppc)

Kernel: Linux 2.6.32-5-powerpc
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages xcompmgr depends on:
ii  libc6                         2.11.2-2   Embedded GNU C Library: Shared lib
ii  libx11-6                      2:1.3.3-3  X11 client-side library
ii  libxcomposite1                1:0.4.2-1  X11 Composite extension library
ii  libxdamage1                   1:1.1.3-1  X11 damaged region extension libra
ii  libxfixes3                    1:4.0.5-1  X11 miscellaneous 'fixes' extensio
ii  libxrender1                   1:0.9.6-1  X Rendering Extension client libra

// Example program for bug in xcompmgr
//
// This should display a window with a moving hole in it, but with xcompmgr
// running, it isn't updated correctly.
//
// g++ -Wall `pkg-config xcb xcb-shape --cflags --libs` bug-shape-changer.cpp -o bug-shape-changer
//

#include <stdlib.h>
#include <string.h>
#include <xcb/xcb.h>
#include <xcb/shape.h>
#include <iostream>
#include <stdexcept>
#include <assert.h>

/* global objects, the connection to the X server and the window
created there. */
xcb_connection_t* connection = 0;
xcb_window_t win;
unsigned const window_size = 50;

unsigned const hole_size = 10;
int hole_position = 0;

void
init_connection()
{
    /* open connection to the server */
    connection = xcb_connect(NULL,NULL);
    if (xcb_connection_has_error(connection))
        throw std::runtime_error("xcb_connect() failed");
}


void
check_shape_extension()
{
    // query for availability
    xcb_query_extension_reply_t const* reply = xcb_get_extension_data(
        connection, &xcb_shape_id);
    if(!reply)
        throw std::runtime_error("xcb_get_extension_data failed");
    if(!reply->present)
        throw std::runtime_error("X11 shape extension not present");

    // query version
    xcb_shape_query_version_cookie_t cookie = xcb_shape_query_version_unchecked(connection);
    xcb_shape_query_version_reply_t* version = xcb_shape_query_version_reply(connection,
        cookie, 0);
    if(!version)
        throw std::runtime_error("xcb_shape_query_version failed");
}


void
create_window(int16_t x, int16_t y, uint16_t width, uint16_t height)
{
    /* retrieve the first screen from the setup */
    xcb_setup_t const* setup = xcb_get_setup(connection);
    if(!setup)
        throw std::runtime_error("xcb_get_setup() failed");
    xcb_screen_t* screen = xcb_setup_roots_iterator(setup).data;
    if(!screen)
        throw std::runtime_error("missing root screen");

    // create window
    xcb_window_t id = xcb_generate_id(connection);
    uint32_t const win_values[] =
    {
        screen->black_pixel,
        XCB_EVENT_MASK_EXPOSURE
    };
    xcb_create_window(connection,
        XCB_COPY_FROM_PARENT, // depth
        id,
        screen->root, // parent
        x, y, width, height, // position, size
        0, // border width
        XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
        XCB_COPY_FROM_PARENT, // visual
        XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, win_values);
    win = id;
}

void
set_window_mask()
{
    // set rectangualar base outline first
    xcb_rectangle_t const rect = {0, 0, window_size, window_size};
    xcb_shape_rectangles(connection,
        XCB_SHAPE_SO_SET,
        XCB_SHAPE_SK_BOUNDING,
        0,
        win,
        0, 0, // offset
        1, &rect);

    // cut out moving rectangle
    xcb_rectangle_t const hole = {hole_position, hole_position, hole_size, hole_size};
    xcb_shape_rectangles(connection,
        XCB_SHAPE_SO_SUBTRACT,
        XCB_SHAPE_SK_BOUNDING,
        0,
        win,
        0, 0, // offset
        1, &hole);
    xcb_flush(connection);
}

int
main(int argc, char** argv)
{
    try
    {
        init_connection();

        create_window(0, 0, window_size, window_size);

        set_window_mask();
        
        // actually display window
        xcb_map_window(connection, win);

        int const e = xcb_flush(connection);
        if(e<=0)
            // TODO: provide more detailed diagnostics if possible
            throw std::runtime_error("xcb_flush failed");

        // poll connection's file descriptor for events
        int const ss = xcb_get_file_descriptor(connection);
        while(true)
        {
            // wait on the connection socket
            fd_set fd;
            FD_ZERO(&fd);
            FD_SET( ss, &fd);
            timeval timeout;
            timeout.tv_usec = 100000;
            timeout.tv_sec = 0;
            switch(select( ss+1, &fd, 0, 0, &timeout))
            {
            case -1:
                throw std::runtime_error("select failed");
            case 0:
                std::cout << "select timed out" << std::endl;
                ++hole_position;
                if(hole_position==window_size)
                    hole_position = -hole_size;
                set_window_mask();
                break;
            case 1:
                break;
            default:
                std::cout << "select return unexpected value" << std::endl;
                break;
            }

            // handle all available events
            xcb_generic_event_t* e = 0;
            while((e = xcb_poll_for_event(connection)))
            {
                switch (e->response_type & ~0x80)
                {
                case XCB_EXPOSE:
                    {
                        /* Note: Filling the whole window with background color is done
                        automatically, so we don't have to do anything here at all. */
                        xcb_expose_event_t const& expose = (xcb_expose_event_t const&)*e;
                        std::cout << "expose_event x=" << expose.x
                            << ", y=" << expose.y
                            << ", width=" << expose.width
                            << ", height=" << expose.height
                            << ", count=" << expose.count
                            << std::endl;
                    }
                    break;
                default:
                    std::cout << "received response " << unsigned(e->response_type) << std::endl;
                    break;
                }
                free(e);
            }

            // check for connection errors
            if (xcb_connection_has_error(connection))
                throw std::runtime_error("connection lost");
        }

        return EXIT_SUCCESS;
    }
    catch(std::exception const& e)
    {
        std::cerr << "error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

Reply via email to