Ejemplo n.º 1
0
void
x_client_icon::update_default_icon(void)
{
  xcb_free_pixmap(m_c(), m_default_icon);
  m_default_icon = XCB_NONE;

  const uint32_t width = default_application_icon.width;
  const uint32_t height = default_application_icon.width;

  m_icon_geometry.first = width;
  m_icon_geometry.second = height;

  m_default_icon = xcb_generate_id(m_c());
  xcb_create_pixmap(
      m_c(), 32, m_default_icon, m_c.root_window(), width, height);

  xcb_image_t * image = xcb_image_create_native(
      m_c(), width, height, XCB_IMAGE_FORMAT_Z_PIXMAP, 32, NULL, 0, NULL);

  image->data = (uint8_t *)default_application_icon.pixel_data;;

  xcb_gcontext_t gc = xcb_generate_id(m_c());
  xcb_create_gc(m_c(), gc, m_default_icon, 0, NULL);

  xcb_image_put(m_c(), m_default_icon, gc, image, 0, 0, 0);

  xcb_image_destroy(image);
  xcb_free_gc(m_c(), gc);
}
int main(int argc, char **argv) {
    uint32_t width = test_width - 2 * INSET_X;
    uint32_t height = test_height - 2 * INSET_Y;
    int snum;
    xcb_void_cookie_t check_cookie;
    xcb_window_t w;
    xcb_gcontext_t gc;
    xcb_pixmap_t pix;
    xcb_connection_t *c = xcb_connect(0, &snum);
    xcb_screen_t *s = xcb_aux_get_screen(c, snum);
    xcb_alloc_named_color_cookie_t bg_cookie =
	xcb_alloc_named_color(c, s->default_colormap,
			      strlen("white"), "white");
    xcb_alloc_named_color_cookie_t fg_cookie =
	xcb_alloc_named_color(c, s->default_colormap,
			      strlen("black"), "black");
    xcb_alloc_named_color_reply_t *bg_reply =
	xcb_alloc_named_color_reply(c, bg_cookie, 0);
    xcb_alloc_named_color_reply_t *fg_reply =
	xcb_alloc_named_color_reply(c, fg_cookie, 0);
    uint32_t fg, bg;
    xcb_image_t *image, *native_image, *subimage;
    uint32_t mask = 0;
    xcb_params_gc_t gcv;

    assert(bg_reply && fg_reply);
    bg = bg_reply->pixel;
    fg = fg_reply->pixel;
    free(bg_reply);
    free(fg_reply);
    w = make_window(c, s, bg, fg, width, height);
    gc = xcb_generate_id(c);
    check_cookie = xcb_create_gc_checked(c, gc, w, 0, 0);
    assert(!xcb_request_check(c, check_cookie));
    image = xcb_image_create_from_bitmap_data((uint8_t *)test_bits,
					      test_width, test_height);
    native_image = xcb_image_native(c, image, 1);
    assert(native_image);
    if (native_image != image)
	xcb_image_destroy(image);
    subimage = xcb_image_subimage(native_image, INSET_X, INSET_Y,
				  width, height,
				  0, 0, 0);
    assert(subimage);
    xcb_image_destroy(native_image);
    subimage->format = XCB_IMAGE_FORMAT_XY_BITMAP;
    pix = xcb_generate_id(c);
    xcb_create_pixmap(c, s->root_depth, pix, w,
		      subimage->width, subimage->height);
    gc = xcb_generate_id(c);
    XCB_AUX_ADD_PARAM(&mask, &gcv, foreground, fg);
    XCB_AUX_ADD_PARAM(&mask, &gcv, background, bg);
    xcb_aux_create_gc(c, gc, pix, mask, &gcv);
    xcb_image_put(c, pix, gc, subimage, 0, 0, 0);
    process_events(c, gc, w, pix, width, height);
    xcb_disconnect(c);
    return 1;
}
Ejemplo n.º 3
0
void
x_client_icon::update_net_wm_icon(void)
{
  xcb_free_pixmap(m_c(), m_net_wm_icon);
  m_net_wm_icon = XCB_NONE;

  xcb_generic_error_t * error;
  xcb_get_property_cookie_t c =
    xcb_ewmh_get_wm_icon(m_c.ewmh(), m_x_client.window());

  xcb_ewmh_get_wm_icon_reply_t wm_icon;
  std::memset(&wm_icon, 0, sizeof(xcb_ewmh_get_wm_icon_reply_t));
  xcb_ewmh_get_wm_icon_reply(m_c.ewmh(), c, &wm_icon, &error);

  if (error) {
    std::free(error);

  } else if (0 < xcb_ewmh_get_wm_icon_length(&wm_icon)) {

    uint32_t width = 0;
    uint32_t height = 0;
    uint32_t * data = NULL;

    xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&wm_icon);
    for (; iter.rem; xcb_ewmh_get_wm_icon_next(&iter)) {
      if (iter.width > width) {
        width = iter.width;
        height = iter.height;
        data = iter.data;
      }
    }

    m_icon_geometry.first = width;
    m_icon_geometry.second = height;

    m_net_wm_icon = xcb_generate_id(m_c());
    xcb_create_pixmap(
        m_c(), 32, m_net_wm_icon, m_c.root_window(), width, height);

    xcb_image_t * image = xcb_image_create_native(
        m_c(), width, height, XCB_IMAGE_FORMAT_Z_PIXMAP, 32, NULL, 0, NULL);

    image->data = (uint8_t *)data;

    alpha_transform(image->data, width, height);

    xcb_gcontext_t gc = xcb_generate_id(m_c());
    xcb_create_gc(m_c(), gc, m_net_wm_icon, 0, NULL);

    xcb_image_put(m_c(), m_net_wm_icon, gc, image, 0, 0, 0);

    xcb_image_destroy(image);
    xcb_free_gc(m_c(), gc);

    xcb_ewmh_get_wm_icon_reply_wipe(&wm_icon);
  }
}
Ejemplo n.º 4
0
void
xpost_view_page_display(Xpost_View_Window *win,
                        const void *buffer)
{
    xcb_image_t *image;

    image = xcb_image_create_native(win->c, win->width, win->height,
                                    XCB_IMAGE_FORMAT_Z_PIXMAP,
                                    win->depth, (void *)buffer,
                                    4 * win->width * win->height, NULL);
    xcb_image_put(win->c, win->window, win->gc, image, 0, 0, 0);
    win->image = image;
}
Ejemplo n.º 5
0
static xcb_pixmap_t image_to_pixmap(xcb_connection_t *conn, xcb_screen_t *screen, xcb_image_t *image) {
    xcb_pixmap_t pixmap = xcb_generate_id(conn);
    xcb_create_pixmap(conn, 24, pixmap, screen->root, image->width, image->height);

    xcb_gcontext_t gc = xcb_generate_id(conn);
    xcb_create_gc(conn, gc, pixmap,
        XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
        (uint32_t[]){ screen->black_pixel, 0xffffff });

    xcb_image_put(conn, pixmap, gc, image, 0, 0, 0);

    return pixmap;
}
Ejemplo n.º 6
0
void
xpost_view_main_loop(const Xpost_View_Window *win)
{
    xcb_intern_atom_cookie_t cookie1;
    xcb_intern_atom_cookie_t cookie2;
    xcb_intern_atom_reply_t* reply1;
    xcb_intern_atom_reply_t* reply2;
    int finished;

    /*
     * Listen to X client messages in order to be able to pickup
     * the "delete window" message that is generated for example
     * when someone clicks the top-right X button within the window
     * manager decoration (or when user hits ALT-F4).
     */
    cookie1 = xcb_intern_atom(win->c, 1,
                              sizeof("WM_DELETE_WINDOW") - 1, "WM_DELETE_WINDOW");
    cookie2 = xcb_intern_atom(win->c, 1,
                              sizeof("WM_PROTOCOLS") - 1, "WM_PROTOCOLS");
    reply1 = xcb_intern_atom_reply(win->c, cookie1, 0);
    reply2 = xcb_intern_atom_reply(win->c, cookie2, 0);
    xcb_change_property(win->c, XCB_PROP_MODE_REPLACE, win->window, reply2->atom, 4, 32, 1,
                        &reply1->atom);

    finished = 0;
    while (!finished)
    {
        xcb_generic_event_t *e;

        if ((e = xcb_poll_for_event(win->c)))
        {
            switch (XCB_EVENT_RESPONSE_TYPE(e))
            {
                case XCB_EXPOSE:
                    xcb_image_put(win->c, win->window, win->gc, win->image, 0, 0, 0);
                    xcb_flush(win->c);
                    break;
                case XCB_CLIENT_MESSAGE:
                {
                    xcb_client_message_event_t *event;

                    printf("client message\n");
                    event = (xcb_client_message_event_t *)e;
                    if (event->data.data32[0] == reply1->atom)
                        finished = 1;
                    break;
                }
                case XCB_BUTTON_PRESS:
                    printf("button pressed\n");
                    finished = 1;
                    break;
                case XCB_KEY_RELEASE:
                {
                    xcb_key_release_event_t *event;

                    event = (xcb_key_release_event_t *)e;
                    if (event->detail == 113)
                        xpost_view_page_change(-1);
                    if (event->detail == 114)
                        xpost_view_page_change(1);
                    break;
                }
            }
            free (e);
        }

        xcb_flush (win->c);
    }

    free(reply2);
    free(reply1);
}
Ejemplo n.º 7
0
void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source)
{
    Q_XCB_NOOP(connection());
    if (m_gc_window != window) {
        if (m_gc)
            Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc));

        m_gc = xcb_generate_id(xcb_connection());
        Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, 0, 0));

        m_gc_window = window;
    }

    Q_XCB_NOOP(connection());
    if (m_shm_info.shmaddr) {
        xcb_image_shm_put(xcb_connection(),
                          window,
                          m_gc,
                          m_xcb_image,
                          m_shm_info,
                          source.x(),
                          source.y(),
                          target.x(),
                          target.y(),
                          source.width(),
                          source.height(),
                          false);
    } else {
        // If we upload the whole image in a single chunk, the result might be
        // larger than the server's maximum request size and stuff breaks.
        // To work around that, we upload the image in chunks where each chunk
        // is small enough for a single request.
        int src_x = source.x();
        int src_y = source.y();
        int target_x = target.x();
        int target_y = target.y();
        int width = source.width();
        int height = source.height();

        // We must make sure that each request is not larger than max_req_size.
        // Each request takes req_size + m_xcb_image->stride * height bytes.
        uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection());
        uint32_t req_size = sizeof(xcb_put_image_request_t);
        int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride;

        // This assert could trigger if a single row has more pixels than fit in
        // a single PutImage request. However, max_req_size is guaranteed to be
        // at least 16384 bytes. That should be enough for quite large images.
        Q_ASSERT(rows_per_put > 0);

        while (height > 0) {
            int rows = std::min(height, rows_per_put);

            xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, src_x, src_y, width, rows,
                                                       0, 0, 0);
            xcb_image_put(xcb_connection(),
                          window,
                          m_gc,
                          subimage,
                          target_x,
                          target_y,
                          0);

            xcb_image_destroy(subimage);

            src_y += rows;
            target_y += rows;
            height -= rows;
        }
    }
    Q_XCB_NOOP(connection());

    m_dirty = m_dirty | source;

    xcb_flush(xcb_connection());
    Q_XCB_NOOP(connection());
}
Ejemplo n.º 8
0
int main(int arg, char **argv)
{
	srand(time(NULL));
	xcb_connection_t *connection = xcb_connect(NULL, NULL);

	xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;

	xcb_colormap_t colormap = screen->default_colormap;

	xcb_drawable_t window = xcb_generate_id(connection);
	uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	uint32_t values[] = {screen->black_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS};
	xcb_create_window(connection,
			/*screen->root_depth,*/
			24,
			window,
			screen->root,
			0, 0,
			WIDTH, HEIGHT,
			1,
			XCB_WINDOW_CLASS_INPUT_OUTPUT,
			screen->root_visual,
			mask, values);

	xcb_pixmap_t pixmap = xcb_generate_id(connection);
	xcb_create_pixmap(connection,
			24,
			pixmap,
			window,
			WIDTH, HEIGHT);

	uint8_t *img = malloc(WIDTH * HEIGHT * 4);

	uint8_t *limg = img;
	/*for (int y = 0; y < HEIGHT; y++)*/
	/*for (int x = 0; x < WIDTH; x++) {*/
	/**(limg++) = 128;*/
	/**(limg++) = 128;*/
	/**(limg++) = 128;*/
	/*limg++;*/
	/*}*/
	perlin(img, WIDTH, HEIGHT);

	xcb_image_t *image = xcb_image_create(WIDTH, HEIGHT,
			XCB_IMAGE_FORMAT_Z_PIXMAP,
			8, 24, 32,
			0,
			/*xcb_get_setup(connection)->image_byte_order,*/
			XCB_IMAGE_ORDER_MSB_FIRST,
			XCB_IMAGE_ORDER_LSB_FIRST,
			img,
			WIDTH * HEIGHT * 4,
			img);

	xcb_gcontext_t gc = xcb_generate_id(connection);
	xcb_create_gc(connection,
			gc,
			pixmap,
			0, NULL);

	xcb_image_put(connection, pixmap, gc, image, 0, 0, 0);

	xif_write(image, "test.xif");

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

	xcb_generic_event_t *event;
	xcb_expose_event_t *expose;
	while ((event = xcb_wait_for_event(connection))) {
		switch (event->response_type & ~0x80) {
			case XCB_EXPOSE:
					expose = (xcb_expose_event_t *)event;
					xcb_copy_area(connection,
							pixmap,
							window,
							gc,
							expose->x, expose->y,
							expose->x, expose->y,
							expose->width, expose->height);
					xcb_flush(connection);
					break;
			case XCB_BUTTON_PRESS:
					goto end;
					break;
			default:
					break;
		}
		free(event);
	}
end:

	xcb_free_pixmap(connection, pixmap);
	xcb_disconnect(connection);

	xcb_image_destroy(image);

	return 0;
}
Ejemplo n.º 9
0
int main(int argc, char **argv)
{
	xcb_connection_t *connection = xcb_connect(NULL, NULL);

	xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;

	uint32_t mask = XCB_CW_BACK_PIXEL;
	uint32_t values[] = {screen->black_pixel};

	xcb_drawable_t window = xcb_generate_id(connection);
	xcb_create_window(connection,
			24,
			window,
			screen->root,
			0, 0,
			WIDTH, HEIGHT,
			1,
			XCB_WINDOW_CLASS_INPUT_OUTPUT,
			screen->root_visual,
			mask, values);
	xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window,
			XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
			strlen(argv[0]), argv[0]);

	xcb_pixmap_t pixmap = xcb_generate_id(connection);
	xcb_create_pixmap(connection,
			24,
			pixmap,
			window,
			WIDTH, HEIGHT);

	uint8_t *img = malloc(WIDTH * HEIGHT * 4);
	xcb_image_t *image = xcb_image_create(WIDTH, HEIGHT,
			XCB_IMAGE_FORMAT_Z_PIXMAP,
			8, 24, 32,
			0,
			XCB_IMAGE_ORDER_MSB_FIRST,
			XCB_IMAGE_ORDER_LSB_FIRST,
			img,
			WIDTH * HEIGHT * 4,
			img);

	mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
	values[0] = screen->black_pixel;
	values[1] = 0xFFFFFF;

	xcb_gcontext_t gc = xcb_generate_id(connection);
	xcb_create_gc(connection,
			gc,
			pixmap,
			mask, values);

	xcb_image_put(connection, pixmap, gc, image, 0, 0, 0);

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

	uint8_t value = 0;

	uint32_t *limg;

	Gol *gol = gol_new(BOARD_WIDTH, BOARD_HEIGHT);
	gol_random(gol, time(NULL));

	while (1) {
		limg = (uint32_t *)image->data;

		for (int i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; i++)
			*(limg++) = gol->buffers[gol->front][i] ? 0x00FFFF00 : 0x00000000;

		xcb_image_put(connection, pixmap, gc, image, 0, 0, 0);

		xcb_copy_area(connection,
				pixmap,
				window,
				gc,
				0, 0,
				0, 0,
				WIDTH, HEIGHT);
		xcb_flush(connection);
		value++;

		gol_simulate(gol);
	}
	return 0;
}
Ejemplo n.º 10
0
void
x_client_icon::update_wm_hints_icon(void)
{
  xcb_free_pixmap(m_c(), m_wm_hints_icon);
  m_wm_hints_icon = XCB_NONE;

  xcb_generic_error_t * error;

  xcb_get_property_cookie_t c =
    xcb_icccm_get_wm_hints(m_c(), m_x_client.window());
  xcb_get_property_reply_t * r = xcb_get_property_reply(m_c(), c, &error);

  if (error) {
    std::free(error);

  } else {
    xcb_icccm_wm_hints_t wm_hints;
    xcb_icccm_get_wm_hints_from_reply(&wm_hints, r);

    if (wm_hints.flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP) {
      unsigned int width, height;

      {
        Window root;
        int x, y;
        unsigned int border_width, depth;
        XGetGeometry(m_c.dpy(), wm_hints.icon_pixmap, &root,
            &x, &y, &width, &height, &border_width, &depth);
        m_icon_geometry.first = width;
        m_icon_geometry.second = height;
      }

      xcb_image_t * icon_rgb = xcb_image_get(m_c(), wm_hints.icon_pixmap,
          0, 0, width, height, 0xffffffff, XCB_IMAGE_FORMAT_XY_PIXMAP);

      xcb_image_t * icon_mask;
      if (wm_hints.flags & XCB_ICCCM_WM_HINT_ICON_MASK) {
        icon_mask = xcb_image_get(m_c(), wm_hints.icon_mask,
            0, 0, width, height, 0xffffffff, XCB_IMAGE_FORMAT_XY_PIXMAP);

      } else {
        icon_mask = xcb_image_create_native(
            m_c(), width, height, XCB_IMAGE_FORMAT_Z_PIXMAP, 32, NULL, 0, NULL);
        std::memset(icon_mask->data, 0xff,
                    width * height * (icon_mask->bpp / icon_mask->stride));
      }

      xcb_image_t * icon_rgba = xcb_image_create_native(
          m_c(), width, height, XCB_IMAGE_FORMAT_Z_PIXMAP, 32, NULL, 0, NULL);

      for (std::size_t x = 0; x < width; ++x) {
        for (std::size_t y = 0; y < height; ++y) {
          uint32_t rgba = 0;

          if (xcb_image_get_pixel(icon_mask, x, y)) {
            uint32_t rgb = xcb_image_get_pixel(icon_rgb, x, y);
            uint8_t * s = (uint8_t *)&rgb;
            uint8_t * d = (uint8_t *)&rgba;

            d[0] = s[0];
            d[1] = s[1];
            d[2] = s[2];
            d[3] = 0xff;
          }

          xcb_image_put_pixel(icon_rgba, x, y, rgba);
        }
      }

      m_wm_hints_icon = xcb_generate_id(m_c());
      xcb_create_pixmap(
          m_c(), 32, m_wm_hints_icon, m_c.root_window(), width, height);

      xcb_gcontext_t gc = xcb_generate_id(m_c());
      xcb_create_gc(m_c(), gc, m_wm_hints_icon, 0, NULL);

      xcb_image_put(m_c(), m_wm_hints_icon, gc, icon_rgba, 0, 0, 0);

      xcb_image_destroy(icon_rgb);
      xcb_image_destroy(icon_mask);
      xcb_image_destroy(icon_rgba);
      xcb_free_gc(m_c(), gc);
    }
  }

  if (r) std::free(r);
}
Ejemplo n.º 11
0
int
main()
{

    hhxcb_state state = {};
    hhxcb_get_binary_name(&state);

    char source_game_code_library_path[HHXCB_STATE_FILE_NAME_LENGTH];
    char *game_code_filename = (char *) _HHXCB_QUOTE(GAME_CODE_FILENAME);
    hhxcb_build_full_filename(&state, game_code_filename,
            sizeof(source_game_code_library_path),
            source_game_code_library_path);
    hhxcb_game_code game_code = {};
    hhxcb_load_game(&game_code, source_game_code_library_path);

    hhxcb_context context = {};

    /* Open the connection to the X server. Use the DISPLAY environment variable */
    int screenNum;
    context.connection = xcb_connect (NULL, &screenNum);

    context.key_symbols = xcb_key_symbols_alloc(context.connection);

    /*
     * TODO(nbm): This is X-wide, so it really isn't a good option in reality.
     * We have to be careful and clean up at the end.  If we crash, auto-repeat
     * is left off.
     */
    {
        uint32_t values[1] = {XCB_AUTO_REPEAT_MODE_OFF};
        xcb_change_keyboard_control(context.connection, XCB_KB_AUTO_REPEAT_MODE, values);
    }

    load_atoms(&context);
    context.setup = xcb_get_setup(context.connection);
    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(context.setup);
    xcb_screen_t *screen = iter.data;
    context.fmt = hhxcb_find_format(&context, 32, 24, 32);

    int monitor_refresh_hz = 60;
    real32 game_update_hz = (monitor_refresh_hz / 2.0f); // Should almost always be an int...
    long target_nanoseconds_per_frame = (1000 * 1000 * 1000) / game_update_hz;


    uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    uint32_t values[2] =
    {
        0x0000ffff, //screen->black_pixel,
        0
            | XCB_EVENT_MASK_POINTER_MOTION
            | XCB_EVENT_MASK_KEY_PRESS
            | XCB_EVENT_MASK_KEY_RELEASE
            ,
    };

#define START_WIDTH 960
#define START_HEIGHT 540

    context.window = xcb_generate_id(context.connection);
	// NOTE: changed to not have a border width, so the min/max/close
	// buttons align on compiz, maybe other window managers
    xcb_create_window(context.connection, XCB_COPY_FROM_PARENT, context.window,
            screen->root, 0, 0, START_WIDTH, START_HEIGHT, 0,
            XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values);

    xcb_icccm_set_wm_name(context.connection, context.window, XCB_ATOM_STRING,
            8, strlen("hello"), "hello");

    load_and_set_cursor(&context);

    xcb_map_window(context.connection, context.window);
    xcb_atom_t protocols[] =
    {
        context.wm_delete_window,
    };
    xcb_icccm_set_wm_protocols(context.connection, context.window,
            context.wm_protocols, 1, protocols);

    xcb_size_hints_t hints = {};
    xcb_icccm_size_hints_set_max_size(&hints, START_WIDTH, START_HEIGHT);
    xcb_icccm_size_hints_set_min_size(&hints, START_WIDTH, START_HEIGHT);
    xcb_icccm_set_wm_size_hints(context.connection, context.window,
            XCB_ICCCM_WM_STATE_NORMAL, &hints);

    hhxcb_offscreen_buffer buffer = {};
    hhxcb_resize_backbuffer(&context, &buffer, START_WIDTH, START_HEIGHT);

    xcb_flush(context.connection);

    hhxcb_sound_output sound_output = {};
    sound_output.samples_per_second = 48000;
    sound_output.bytes_per_sample = sizeof(int16) * 2;
    sound_output.secondary_buffer_size = sound_output.samples_per_second * sound_output.bytes_per_sample;
    hhxcb_init_alsa(&context, &sound_output);

    int16 *sample_buffer = (int16 *)malloc(sound_output.secondary_buffer_size);

    thread_context t = {};

    game_memory m = {};
    m.PermanentStorageSize = 256 * 1024 * 1024;
    m.TransientStorageSize = 256 * 1024 * 1024;
    state.total_size = m.PermanentStorageSize + m.TransientStorageSize;
    state.game_memory_block = calloc(state.total_size, sizeof(uint8));
    m.PermanentStorage = (uint8 *)state.game_memory_block;
    m.TransientStorage =
        (uint8_t *)m.PermanentStorage + m.TransientStorageSize;
#ifdef HANDMADE_INTERNAL
    m.DEBUGPlatformFreeFileMemory = debug_xcb_free_file_memory;
    m.DEBUGPlatformReadEntireFile = debug_xcb_read_entire_file;
    m.DEBUGPlatformWriteEntireFile = debug_xcb_write_entire_file;
#endif

    hhxcb_init_replays(&state);

    bool ending = 0;
    timespec last_counter = {};
    timespec flip_wall_clock = {}; // Actually monotonic clock
    clock_gettime(HHXCB_CLOCK, &last_counter);
    clock_gettime(HHXCB_CLOCK, &flip_wall_clock);

    game_input input[2] = {};
    game_input *new_input = &input[0];
    game_input *old_input = &input[1];

    int64_t next_controller_refresh = 0;

    while(!ending)
    {
        if (last_counter.tv_sec >= next_controller_refresh)
        {
            hhxcb_refresh_controllers(&context);
            next_controller_refresh = last_counter.tv_sec + 1;
        }

        struct stat library_statbuf = {};
        stat(source_game_code_library_path, &library_statbuf);
        if (library_statbuf.st_mtime != game_code.library_mtime)
        {
            hhxcb_unload_game(&game_code);
            hhxcb_load_game(&game_code, source_game_code_library_path);
        }

        new_input->dtForFrame = target_nanoseconds_per_frame / (1024.0 * 1024 * 1024);

        hhxcb_process_events(&context, &state, new_input, old_input);

        if (context.ending_flag)
        {
            break;
        }

		// NOTE: setup game_buffer.Memory upside down and set
		// game_buffer.pitch negative, so the game would fill the
		// backbuffer upside down. XCB doesn't seem to have an
		// option to flip the image.
		
        game_offscreen_buffer game_buffer = {};
        game_buffer.Memory = ((uint8*)buffer.xcb_image->data)+
			(buffer.width*(buffer.height-1)*buffer.bytes_per_pixel);
        game_buffer.Width = buffer.width;
        game_buffer.Height = buffer.height;
        game_buffer.Pitch = -buffer.pitch;

        if (state.recording_index)
        {
            hhxcb_record_input(&state, new_input);
        }
        if (state.playback_index)
        {
            hhxcb_playback_input(&state, new_input);
        }
        if (game_code.UpdateAndRender)
        {
            game_code.UpdateAndRender(&t, &m, new_input, &game_buffer);
            HandleDebugCycleCounter(&m);
        }
	
        game_sound_output_buffer sound_buffer;
        sound_buffer.SamplesPerSecond = sound_output.samples_per_second;
        sound_buffer.SampleCount = sound_output.samples_per_second / 30;
        sound_buffer.Samples = sample_buffer;

        int err, frames;
        snd_pcm_sframes_t delay, avail;
        snd_pcm_avail_delay(context.handle, &avail, &delay);
        if (avail == sound_output.secondary_buffer_size)
        {
            // NOTE(nbm): Full available buffer, starting with ~60ms of silence
            bzero(sample_buffer, sound_buffer.SampleCount * sound_output.bytes_per_sample);
            snd_pcm_writei(context.handle, sample_buffer, sound_buffer.SampleCount);
            snd_pcm_writei(context.handle, sample_buffer, sound_buffer.SampleCount);
            snd_pcm_writei(context.handle, sample_buffer, sound_buffer.SampleCount);
            snd_pcm_writei(context.handle, sample_buffer, sound_buffer.SampleCount);
        }
        else
        {
            uint32 target_available_frames = sound_output.secondary_buffer_size;
            target_available_frames -= (sound_buffer.SampleCount * 1);
            if (avail - target_available_frames < sound_buffer.SampleCount)
            {
                sound_buffer.SampleCount += avail - target_available_frames;
            }
        }
        game_code.GetSoundSamples(&t, &m, &sound_buffer);
        if (sound_buffer.SampleCount > 0) {
            frames = snd_pcm_writei(context.handle, sample_buffer, sound_buffer.SampleCount);

            if (frames < 0)
            {
                frames = snd_pcm_recover(context.handle, frames, 0);
            }
            if (frames < 0) {
                printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
                break;
            }
            if (frames > 0 && frames < sound_buffer.SampleCount)
            {
                printf("Short write (expected %i, wrote %i)\n", sound_buffer.SampleCount, frames);
            }
        }

        xcb_image_put(context.connection, buffer.xcb_pixmap_id,
                buffer.xcb_gcontext_id, buffer.xcb_image, 0, 0, 0);
        xcb_flush(context.connection);
		
        timespec target_counter = {};
        target_counter.tv_sec = last_counter.tv_sec;
        target_counter.tv_nsec = last_counter.tv_nsec + target_nanoseconds_per_frame;
        if (target_counter.tv_nsec > (1000 * 1000 * 1000))
        {
            target_counter.tv_sec++;
            target_counter.tv_nsec %= (1000 * 1000 * 1000);
        }

        timespec work_counter = {};
        clock_gettime(HHXCB_CLOCK, &work_counter);

        bool32 might_need_sleep = 0;
        if (work_counter.tv_sec < target_counter.tv_sec)
        {
            might_need_sleep = 1;
        }
        else if ((work_counter.tv_sec == target_counter.tv_sec) && (work_counter.tv_nsec < target_counter.tv_nsec))
        {
            might_need_sleep = 1;
        }
        if (might_need_sleep) {
            timespec sleep_counter = {};
            sleep_counter.tv_nsec = target_counter.tv_nsec - work_counter.tv_nsec;
            if (sleep_counter.tv_nsec < 0) {
                sleep_counter.tv_nsec += (1000 * 1000 * 1000);
            }
            // To closest ms
            sleep_counter.tv_nsec -= sleep_counter.tv_nsec % (1000 * 1000);
            if (sleep_counter.tv_nsec > 0) {
                timespec remaining_sleep_counter = {};
                nanosleep(&sleep_counter, &remaining_sleep_counter);
            }
            else
            {
                // TODO(nbm): Log missed sleep
            }
        }

        timespec spin_counter = {};
        clock_gettime(HHXCB_CLOCK, &spin_counter);
        while (spin_counter.tv_sec <= target_counter.tv_sec && spin_counter.tv_nsec < target_counter.tv_nsec) {
            clock_gettime(HHXCB_CLOCK, &spin_counter);
        }

        timespec end_counter = {};
        clock_gettime(HHXCB_CLOCK, &end_counter);

        long ns_per_frame = end_counter.tv_nsec - last_counter.tv_nsec;
        if (ns_per_frame < 0)
        {
            ns_per_frame += (1000 * 1000 * 1000) * (end_counter.tv_sec - last_counter.tv_sec);
        }
        last_counter = end_counter;
        real32 ms_per_frame = ns_per_frame / (1000 * 1000.0);

        xcb_copy_area(context.connection, buffer.xcb_pixmap_id, context.window,
                buffer.xcb_gcontext_id, 0,0, 0, 0, buffer.xcb_image->width,
                buffer.xcb_image->height);
        xcb_flush(context.connection);

        game_input *temp_input = new_input;
        new_input = old_input;
        old_input = temp_input;
    }

    snd_pcm_close(context.handle);

    // NOTE(nbm): Since auto-repeat seems to be a X-wide thing, let's be nice
    // and return it to where it was before?
    {
        uint32_t values[1] = {XCB_AUTO_REPEAT_MODE_DEFAULT};
        xcb_change_keyboard_control(context.connection, XCB_KB_AUTO_REPEAT_MODE, values);
    }

    xcb_flush(context.connection);
    xcb_disconnect(context.connection);
}
Ejemplo n.º 12
0
/* Main driver */
int
main (int argc, char **argv)
{
    xcb_connection_t *conn;
    int conn_screen;
    xcb_screen_t *root_screen;
    xcb_drawable_t root_window;
    xcb_connection_t *conn_two;
    int conn_two_screen;
    xcb_screen_t *root_two_screen;
    xcb_drawable_t root_two_window;
    xcb_drawable_t window;

    uint32_t mask;
    uint32_t values[1];

    xcb_void_cookie_t cookie;

    xcb_get_geometry_reply_t *geom_reply;

    xcb_generic_event_t *event;

    image_data_t img_data;
    xcb_image_t *image;
    xcb_pixmap_t pixmap;
    xcb_gcontext_t gc;

    /* Check the first argument to see what display to connect to. If
       empty, then use default display. */
    if (argc > 1) {
      conn = xcb_connect(argv[1], &conn_screen);
    } else {
      conn = xcb_connect(NULL, &conn_screen);
    }
    root_screen = xcb_aux_get_screen(conn, conn_screen);
    root_window = root_screen->root;

    /* Get the geometry of the root window */
    geom_reply = GetWindowGeometry(conn, root_window);
    
    WriteWindowInfo(conn, root_window);
	WriteAllChildrenWindowInfo(conn, root_window);
    img_data = GetWindowImageData(conn, root_window);

	xcb_flush(conn);
    /* Get the image of the root window */
    image = xcb_image_get(conn,
                          root_window,
                          geom_reply->x,
                          geom_reply->y,
                          geom_reply->width,
                          geom_reply->height,
                          (unsigned int) ~0L,
                          XCB_IMAGE_FORMAT_Z_PIXMAP);
    /* Set up the events the window will recognize */
    mask = XCB_CW_EVENT_MASK;
    values[0] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;

    /* Create our new window on the default display. Make it half the size */
    conn_two = xcb_connect(NULL, &conn_two_screen);
    root_two_screen = xcb_aux_get_screen(conn_two, conn_two_screen);
    root_two_window = root_two_screen->root;
    window = xcb_generate_id(conn_two);
    cookie = xcb_create_window_checked(conn_two,
                                       XCB_COPY_FROM_PARENT,
                                       window,
                                       root_two_window,
                                       geom_reply->x,
                                       geom_reply->y,
                                       geom_reply->width / 2,
                                       geom_reply->height / 2,
                                       geom_reply->border_width,
                                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
                                       root_two_screen->root_visual,
                                       mask,
                                       values);
    if (RequestCheck(conn_two, cookie, "Falied to create new window")) {
        exit(1);
    }

    WriteWindowInfo(conn_two, window);
    /* Map the window and flush the connection so it draws to the screen */
    xcb_map_window(conn_two, window);
    xcb_flush(conn_two);
    WriteWindowInfo(conn_two, window);

    /* Create the pixmap and associate it with our new window. */
    pixmap = xcb_generate_id(conn_two);
    cookie = xcb_create_pixmap(conn_two,
                               geom_reply->depth,
                               pixmap,
                               window,
                               geom_reply->width,
                               geom_reply->height);
    if (RequestCheck(conn_two, cookie, "Failed to create pixmap")) {
        exit(1);
    }

    /* Put the root_window image into the pixmap. Note that a gc is
     * created, but I believe it is ignored. */
    gc = xcb_generate_id(conn_two);
    xcb_create_gc(conn_two, gc, window, 0, 0);
    cookie = xcb_image_put(conn_two,
                           pixmap,
                           gc,
                           image,
                           0,
                           0,
                           0);
    if (RequestCheck(conn_two, cookie, "Failed to put image into pixmap")) {
        exit(1);
    }

    /* Copy the pixmap into the new window */
    cookie = xcb_copy_area(conn_two,
                           pixmap,
                           window,
                           gc,
                           0,
                           0,
                           0,
                           0,
                           geom_reply->width / 2,
                           geom_reply->height / 2);
    if (RequestCheck(conn_two, cookie, "Failed to put image into pixmap")) {
        exit(1);
    }
                           
    xcb_flush(conn_two);
    WriteWindowInfo(conn_two, window);

    /* Enter infinte loop so the window stays open */
    while (1) {
    }

    /* Never get here, but if we could, would still want to clean up memory */
    free(geom_reply);
    xcb_disconnect(conn);
    xcb_disconnect(conn_two);

    return 0;
}