mirror of
https://github.com/elima/gpu-playground.git
synced 2025-06-06 23:46:17 +00:00
212 lines
6.0 KiB
C
212 lines
6.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <xcb/xcb.h>
|
|
#include "wsi.h"
|
|
|
|
static struct {
|
|
xcb_connection_t* conn;
|
|
xcb_screen_t* screen;
|
|
xcb_window_t win;
|
|
xcb_intern_atom_reply_t* atom_wm_delete_window;
|
|
WsiExposeEvent expose_event;
|
|
} xcb_data = { 0, };
|
|
|
|
static bool
|
|
wsi_handle_event_xcb (xcb_generic_event_t* event)
|
|
{
|
|
while (event != NULL) {
|
|
uint8_t event_code = event->response_type & 0x7f;
|
|
|
|
switch (event_code) {
|
|
case XCB_EXPOSE:
|
|
if (xcb_data.expose_event != NULL)
|
|
xcb_data.expose_event ();
|
|
break;
|
|
|
|
case XCB_CLIENT_MESSAGE:
|
|
if ((* (xcb_client_message_event_t*) event).data.data32[0] ==
|
|
(* xcb_data.atom_wm_delete_window).atom) {
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case XCB_KEY_RELEASE: {
|
|
const xcb_key_release_event_t* key =
|
|
(const xcb_key_release_event_t*) event;
|
|
switch (key->detail) {
|
|
case 0x9:
|
|
/* ESC key */
|
|
return false;
|
|
break;
|
|
|
|
case 0x29:
|
|
/* F key */
|
|
wsi_toggle_fullscreen ();
|
|
break;
|
|
|
|
default:
|
|
printf ("key pressed: %x\n", key->detail);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
free (event);
|
|
event = xcb_poll_for_event (xcb_data.conn);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
wsi_toggle_fullscreen (void)
|
|
{
|
|
static bool fullscreen_mode = false;
|
|
|
|
fullscreen_mode = ! fullscreen_mode;
|
|
|
|
xcb_intern_atom_cookie_t cookie =
|
|
xcb_intern_atom (xcb_data.conn, 0, 13, "_NET_WM_STATE");
|
|
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply (xcb_data.conn,
|
|
cookie,
|
|
0);
|
|
xcb_atom_t atom1 = reply->atom;
|
|
free (reply);
|
|
|
|
cookie = xcb_intern_atom (xcb_data.conn, 0, 24, "_NET_WM_STATE_FULLSCREEN");
|
|
reply = xcb_intern_atom_reply (xcb_data.conn, cookie, 0);
|
|
xcb_atom_t atom2 = reply->atom;
|
|
free (reply);
|
|
|
|
xcb_client_message_event_t msg = {0};
|
|
msg.response_type = XCB_CLIENT_MESSAGE;
|
|
msg.window = xcb_data.win;
|
|
msg.format = 32;
|
|
msg.type = atom1;
|
|
memset (msg.data.data32, 0, 5 * sizeof (uint32_t));
|
|
msg.data.data32[0] = fullscreen_mode ? 1 : 0;
|
|
msg.data.data32[1] = atom2;
|
|
|
|
xcb_send_event (xcb_data.conn,
|
|
true,
|
|
xcb_data.screen->root,
|
|
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
|
(const char *) &msg);
|
|
xcb_flush (xcb_data.conn);
|
|
}
|
|
|
|
bool
|
|
wsi_init (const char* win_title,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
WsiExposeEvent expose_event)
|
|
{
|
|
/* connection to the X server */
|
|
xcb_data.conn = xcb_connect (NULL, NULL);
|
|
if (xcb_data.conn == NULL) {
|
|
printf ("XCB: Error: Failed to connect to X server\n");
|
|
return false;
|
|
}
|
|
printf ("XCB: Connected to the X server\n");
|
|
|
|
/* Get the first screen */
|
|
const xcb_setup_t* xcb_setup = xcb_get_setup (xcb_data.conn);
|
|
xcb_screen_iterator_t iter = xcb_setup_roots_iterator (xcb_setup);
|
|
xcb_data.screen = iter.data;
|
|
|
|
/* Create the window */
|
|
xcb_data.win = xcb_generate_id (xcb_data.conn);
|
|
|
|
uint32_t value_mask, value_list[32];
|
|
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
|
value_list[0] = xcb_data.screen->black_pixel;
|
|
value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
|
|
|
|
xcb_create_window (xcb_data.conn, /* Connection */
|
|
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
|
|
xcb_data.win, /* window Id */
|
|
xcb_data.screen->root, /* parent window */
|
|
0, 0, /* x, y */
|
|
width, height, /* width, height */
|
|
0, /* border_width */
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
|
|
xcb_data.screen->root_visual, /* visual */
|
|
value_mask, value_list); /* masks, not used yet */
|
|
|
|
xcb_intern_atom_cookie_t cookie =
|
|
xcb_intern_atom (xcb_data.conn, 1, 12, "WM_PROTOCOLS");
|
|
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply (xcb_data.conn,
|
|
cookie,
|
|
0);
|
|
|
|
xcb_intern_atom_cookie_t cookie1 =
|
|
xcb_intern_atom (xcb_data.conn, 0, 16, "WM_DELETE_WINDOW");
|
|
xcb_data.atom_wm_delete_window = xcb_intern_atom_reply (xcb_data.conn,
|
|
cookie1,
|
|
0);
|
|
|
|
xcb_change_property (xcb_data.conn,
|
|
XCB_PROP_MODE_REPLACE,
|
|
xcb_data.win,
|
|
(*reply).atom,
|
|
4, 32, 1,
|
|
&(*xcb_data.atom_wm_delete_window).atom);
|
|
|
|
free (reply);
|
|
|
|
/* Make sure commands are sent before we pause so that the window gets
|
|
* shown.
|
|
*/
|
|
xcb_flush (xcb_data.conn);
|
|
|
|
xcb_data.expose_event = expose_event;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
wsi_get_connection_and_window (const void** conn, const void** win)
|
|
{
|
|
if (conn != NULL)
|
|
*conn = (const void*) xcb_data.conn;
|
|
|
|
if (win != NULL)
|
|
*win = (const void*) &xcb_data.win;
|
|
}
|
|
|
|
bool
|
|
wsi_wait_for_events (void)
|
|
{
|
|
xcb_generic_event_t* event;
|
|
|
|
event = xcb_wait_for_event (xcb_data.conn);
|
|
return wsi_handle_event_xcb (event);
|
|
}
|
|
|
|
void
|
|
wsi_window_show (void)
|
|
{
|
|
xcb_map_window (xcb_data.conn, xcb_data.win);
|
|
}
|
|
|
|
void
|
|
wsi_finish (void)
|
|
{
|
|
if (xcb_data.conn == NULL)
|
|
return;
|
|
|
|
/* Unmap the window from the screen */
|
|
xcb_unmap_window (xcb_data.conn, xcb_data.win);
|
|
|
|
free (xcb_data.atom_wm_delete_window);
|
|
|
|
/* disconnect from the X server */
|
|
xcb_disconnect (xcb_data.conn);
|
|
}
|