-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
common: Extracts XCB WSI from vulkan-triangle into a separate file fo…
…r reuse
- Loading branch information
Showing
2 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma once | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
typedef void (* WsiExposeEvent) (void); | ||
|
||
bool wsi_init (const char* win_title, | ||
uint32_t width, | ||
uint32_t height, | ||
WsiExposeEvent expose_event); | ||
|
||
void wsi_get_connection_and_window (const void** conn, | ||
const void** win); | ||
|
||
void wsi_toggle_fullscreen (void); | ||
|
||
bool wsi_wait_for_events (void); | ||
|
||
void wsi_window_show (void); | ||
|
||
void wsi_finish (void); |