Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Last active February 11, 2020 10:43
Show Gist options
  • Save lighth7015/488a88ded5233bf528038304c5057081 to your computer and use it in GitHub Desktop.
Save lighth7015/488a88ded5233bf528038304c5057081 to your computer and use it in GitHub Desktop.
FindWindow()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <xcb/xcb.h>
const char hPropName[] = "HWND";
xcb_connection_t *connection;
xcb_screen_t *display;
xcb_atom_t
WindowCloseEvent,
WM;
typedef struct property {
const char* propName;
intptr_t* value;
} property_t, Property;
static void* nullptr = NULL;
static const char* ConnectionErrors[] = {
(const char *) 0, /* Error 0 */
"Unable to connect to the X server or I/O error", /* XCB_CONN_ERROR */
"Unsupported extension used", /* XCB_CONN_CLOSED_EXT_NOTSUPPORTED */
"Out of memory", /* XCB_CONN_CLOSED_MEM_INSUFFICIENT */
"Maximum allowed request length exceeded", /* XCB_CONN_CLOSED_REQ_LEN_EXCEED */
"Failed to parse display string", /* XCB_CONN_CLOSED_PARSE_ERR */
"No such screen on display", /* XCB_CONN_CLOSED_INVALID_SCREEN */
"Error receiving connection FD" /* XCB_CONN_CLOSED_FDPASSING_FAILED */
};
struct Window;
typedef struct HWND {
struct Window *window;
} *HWND, *HMENU;
typedef struct Window {
xcb_drawable_t hWnd;
xcb_gcontext_t context;
const char *caption;
xcb_rectangle_t rect;
uint32_t nChildren;
HWND *children;
} *Window, window_t;
typedef uint32_t DWORD;
typedef unsigned long HINSTANCE;
typedef const char* LPCTSTR;
typedef void* LPVOID;
size_t hexdump(const char *title, const void *buffer, uint32_t size) {
uint32_t offset, written;
puts("");
printf("*%*s %-66s *\n", 8, "", title);
for( offset = 0, written = 0
; offset < size
; offset += 16)
{
const uint8_t *address = (const uint8_t *) buffer + offset;
static char line[84] = { ' ' };
int num_empty = 0,
length = (size - offset > 16) ? 16 : size - offset;
int empty = length == 16 &&
!memcmp(address, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
if ((num_empty = empty? num_empty + 1: 0) < 2) {
uint32_t written = sprintf( line, "%08" PRIx32 " ", offset), index, size;
line[written] = ' ';
for (index = 0; index < length; index++) {
written += sprintf(line + written, "%*s %02x", index == 8, "", address[index]);
line[written] = ' ';
}
size = 51 - 3 * length - (length >= 9);
written += sprintf( line + written, "%*s|", size, "");
for (index = 0; index < length; index++) {
char ch = address[index] >= ' ' && address[index] <= '~'? address[index] : '.';
written += sprintf( line + written, "%c", ch);
}
written += sprintf( line + written, "|");
}
else if (num_empty == 2) {
sprintf( line, "*" );
}
puts(line);
}
puts("");
return written;
}
Property CreateProperty(const char* name) {
Property property = { .propName = name, .value = nullptr };
return property;
}
Property CreatePropertyFrom(const char* name, void* address) {
Property property = CreateProperty(name);
property.value = address;
return property;
}
const char*
XcbQueryServerError( uint32_t* code ) {
*code = xcb_connection_has_error(connection);
return ConnectionErrors[*code];
}
static inline xcb_atom_t
QueryAtom( const char* xcbAtomName ) {
xcb_generic_error_t *response;
xcb_intern_atom_reply_t* xcbResponse;
xcb_intern_atom_cookie_t xcbRequest =
xcb_intern_atom(connection, 1, strlen(xcbAtomName), xcbAtomName );
if (( xcbResponse = xcb_intern_atom_reply( connection, xcbRequest, &response )) == XCB_ATOM_NONE) {
uint32_t status;
const char* message;
if ((message = XcbQueryServerError( &status ))) {
printf("Connection Error %d [%s].\n", status, message );
}
else {
printf("Server replied [%s (%x, %x): No such atom.]\n", xcbAtomName, (uint32_t) xcbResponse, (uint32_t) response);
}
return XCB_ATOM_NONE;
}
return xcbResponse->atom;
}
static inline
bool XcbAtomCreate( Window hWnd,
const char* xcbAtomName,
xcb_atom_t xcbAtomType,
uint8_t xcbAtomBitLen,
uint32_t xcbAtomLength,
void* data)
{
uint32_t status;
const char* message;
if ((message = XcbQueryServerError( &status )) == nullptr) {
xcb_atom_t xcbAtom = QueryAtom( xcbAtomName );
xcb_generic_error_t *response;
if ( xcbAtom == XCB_ATOM_NONE) {
xcb_intern_atom_cookie_t xcbRequest =
xcb_intern_atom(connection, 0, strlen(xcbAtomName), xcbAtomName );
xcb_intern_atom_reply_t* xcbResponse =
xcb_intern_atom_reply( connection, xcbRequest, &response );
xcbAtom = xcbResponse->atom;
}
if (strcmp(xcbAtomName, hPropName) == 0) {
printf("%-16s: HWND address is %" PRIx64 ".\n", __FUNCTION__, (intptr_t) data );
}
xcb_change_property(connection,
XCB_PROP_MODE_REPLACE,
hWnd->hWnd,
xcbAtom,
xcbAtomType,
xcbAtomBitLen,
xcbAtomLength,
data);
return true;
}
else {
printf("Connection Error %d [%s].\n", status, message );
}
return false;
}
bool WindowPropertyGet( xcb_window_t hWnd, xcb_atom_t propertyType, const char* propertyName, intptr_t* value ) {
uint32_t status;
const char *response;
bool successful = false;
xcb_atom_t propName;
if (( response = XcbQueryServerError( &status )) == nullptr
&& (( propName = QueryAtom( propertyName )))) {
xcb_get_property_cookie_t request =
xcb_get_property(connection, 0, hWnd, propName, propertyType, 0, 0 );
xcb_get_property_reply_t* handle = nullptr;
if (( handle = xcb_get_property_reply(connection, request, nullptr))) {
size_t length = 0;
intptr_t* address = (intptr_t *) xcb_get_property_value( handle );
switch (propertyType) {
case XCB_ATOM_STRING: {
if (( length = xcb_get_property_value_length(handle)) > 0) {
void* buffer = *((void **) value) = (intptr_t *) calloc( 1, length );
memcpy( buffer, xcb_get_property_value( handle ), length );
}
else {
printf("%zu, %p\n", length, address);
}
} break;
default:
*((intptr_t **) value) = address;
break;
}
successful = true;
free( handle );
}
else {
printf( "%s\n", response );
}
}
else {
printf("Connection Error %d [%s].\n", status, response );
}
return successful;
}
HWND FindWindow(xcb_window_t hWnd) {
HWND handle = 0;
uint32_t status;
const char *response;
bool successful = false;
xcb_atom_t propName;
if (( response = XcbQueryServerError( &status )) == nullptr
&& (( propName = QueryAtom( hPropName )))) {
uint32_t length = sizeof( intptr_t * ) / sizeof( uint32_t ) + 1;
xcb_get_property_cookie_t request =
xcb_get_property(connection, 0, hWnd, propName, XCB_ATOM_INTEGER, 0, length);
xcb_get_property_reply_t* handle = nullptr;
if (( handle = xcb_get_property_reply(connection, request, nullptr))) {
if (handle->type != XCB_NONE) {
HWND window = (HWND) *((intptr_t *) xcb_get_property_value( handle ));
//free( handle );
//intptr_t ptrAddress = (intptr_t) (HWND) address;
printf("%-16s: HWND[%" PRIx64 "] is at address %lx\n", __FUNCTION__, (intptr_t) hWnd, (intptr_t) window );
//hexdump( "address", address, sizeof( struct HWND ));
}
else {
printf("%-16s: No such window.\n", __FUNCTION__);
}
}
else {
printf( "%s\n", response );
}
}
else {
printf("Connection Error %d [%s].\n", status, response );
}
return handle;
}
static inline bool
XcbAtomCreateFrom( Window hWnd, xcb_atom_t xcbAtomProp,
xcb_atom_t xcbAtomType,
uint8_t xcbAtomBitLen,
uint32_t xcbAtomLength,
void* data )
{
uint32_t status;
const char* message;
if ((message = XcbQueryServerError( &status ))) {
xcb_change_property(connection,
XCB_PROP_MODE_REPLACE,
hWnd->hWnd,
xcbAtomProp,
xcbAtomType,
xcbAtomBitLen,
xcbAtomLength,
data);
return true;
}
else {
printf("Connection Error %d [%s].\n", status, message );
}
return false;
}
__attribute__((constructor))
void DisplayConnect() {
connection = xcb_connect (nullptr, nullptr);
xcb_atom_t atom;
if ((atom = (xcb_atom_t) QueryAtom( "WM_PROTOCOLS" ))) {
WM = atom;
if ((atom = (xcb_atom_t) QueryAtom( "WM_DELETE_WINDOW" ))) {
display = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
WindowCloseEvent = atom;
}
else {
xcb_disconnect (connection);
exit(-1);
}
}
else {
xcb_disconnect (connection);
exit(-1);
}
}
HWND CreateWindow(LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam)
{
Window window = (Window) calloc(1, sizeof(window_t));
Window parent = (Window) nullptr;
if (hWndParent != nullptr) {
parent = hWndParent->window;
}
if (parent != nullptr) {
parent->nChildren ++;
size_t nWinBytes = sizeof(struct Window);
parent->children = reallocarray( parent->children,
nWinBytes,
parent->nChildren);
parent->children[parent->nChildren] = (HWND) window;
}
window->hWnd = xcb_generate_id (connection);
window->context = xcb_generate_id (connection);
window->caption = strdup(lpWindowName);
void* caption = (void *) window->caption;
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
uint32_t values[2] = {display->white_pixel, 0};
xcb_create_gc (connection, window->context, display->root, mask, values);
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
xcb_drawable_t handle =
(parent == nullptr || parent == 0? window: parent)->hWnd;
xcb_rectangle_t position = { .x = x, .y = y, .height = nHeight, .width = nWidth };
window->rect = position;
xcb_create_window( connection, // connection
XCB_COPY_FROM_PARENT, // depth
handle, // window Id
display->root, // parent window
x, y, // x, y
nWidth, nHeight, // width, height
10, // border_width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
display->root_visual, // visual
mask, values ); // masks
xcb_flush (connection);
HWND hWnd = (HWND)
calloc(1, sizeof(struct HWND));
hWnd->window = window;
if (parent == nullptr || parent == 0) {
XcbAtomCreate( window, "WM_PROTOCOLS", XCB_ATOM_ATOM, 32, 1, &WindowCloseEvent );
printf("%-16s: HWND[%" PRIx64 "] is at address %lx\n", __FUNCTION__, (intptr_t) window->hWnd, (intptr_t) hWnd);
printf("%-16s: Creating top-level window.\n", __FUNCTION__);
FindWindow(window->hWnd);
}
else {
hWnd->window = parent;
}
XcbAtomCreate( window, hPropName, XCB_ATOM_INTEGER, 32, __POINTER_WIDTH__ / 32, hWnd );
XcbAtomCreate( window, "WM_NAME", XCB_ATOM_STRING, 8, strlen(window->caption), caption );
return hWnd;
}
bool DestroyWindow(HWND hWnd) {
uint32_t i, result;
const char* message;
Window window = (Window) hWnd,
wChild = nullptr;
if (window->nChildren > 0) {
for ( i = 0
, wChild = ((window_t *) window->children[ i ])
; i < window->nChildren
; i++
, wChild = ((window_t *) window->children[ i ]))
{
if (DestroyWindow((HWND) wChild) == false) {
puts( "Error destroying window." );
exit(1);
}
}
} else {
xcb_destroy_window_checked (connection, window->hWnd);
xcb_flush (connection);
if (( message = XcbQueryServerError( &result ))) {
printf("%-8d Server error: %s\n", result, message );
exit(1);
} else {
printf("Destroying window id %d [%s], Message address is %p, error code is %d.\n",
window->hWnd, window->caption, message, result);
free(window);
return true;
}
}
return false;
}
bool ShowWindow(HWND hWnd, bool nCmdShow) {
xcb_generic_error_t *response = nullptr;
Window window = (Window) hWnd->window;
xcb_void_cookie_t (*method)(xcb_connection_t *conn, xcb_window_t window) =
nCmdShow? xcb_map_window_checked: xcb_unmap_window_checked;
const char* stubText = nCmdShow? "xcb_map_window_checked": "xcb_unmap_window_checked";
xcb_void_cookie_t cookie = method(connection, window->hWnd);
if ((response = xcb_request_check(connection, cookie))) {
printf("%s(%s): Invalid hWnd id=(%d). Err=%04d\n", __FUNCTION__, stubText, window->hWnd, response->error_code);
}
else {
printf("%-16s: Method (%s) dispatched.\n", __FUNCTION__, stubText);
return true;
}
return false;
}
int main () {
/* Open the connection to the X server */
HWND window = CreateWindow(
nullptr,
"My Window Title",
0,
0, 0,
350, 350,
0,
0,
0,
0);
HWND control = CreateWindow(
nullptr,
"Child window",
0,
0, 0,
75, 75,
window,
0,
0,
0);
/* Map the window on the screen and flush*/
ShowWindow(window, true);
/* draw primitives */
int running = 1;
xcb_flush (connection);
for ( xcb_generic_event_t *event = xcb_wait_for_event (connection)
; running && event != nullptr
; event = xcb_wait_for_event (connection))
{
switch (event->response_type & ~0x80) {
/*
* flush the request
*/
case XCB_EXPOSE:
xcb_flush (connection);
break;
case XCB_CLIENT_MESSAGE: {
xcb_client_message_event_t client =
*(xcb_client_message_event_t *) event;
if( client.data.data32[0] == WindowCloseEvent) {
HWND window = 0;
if (( window = FindWindow( client.window ))) {
printf("Source is HWND %lx\n", (intptr_t) window);
//DestroyWindow(window);
}
}
} break;
default:
/* Unknown event type, ignore it */
break;
}
free (event);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment