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; }
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); } }
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; }
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; }
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); }
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()); }
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; }
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; }
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); }
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); }
/* 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; }