mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-04-13 05:43:18 -07:00
So that they can be used for e.g. Wayland or macOS support. Or Windows, if we're so inclined.
240 lines
7.8 KiB
C
240 lines
7.8 KiB
C
/*
|
|
* Copyright 2016 Józef Kucia for CodeWeavers
|
|
* Copyright 2016 Henri Verbeet for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
struct demo_window_xcb
|
|
{
|
|
struct demo_window w;
|
|
|
|
xcb_window_t window;
|
|
};
|
|
|
|
static xcb_screen_t *demo_xcb_get_screen(xcb_connection_t *c, int idx)
|
|
{
|
|
xcb_screen_iterator_t iter;
|
|
|
|
iter = xcb_setup_roots_iterator(xcb_get_setup(c));
|
|
for (; iter.rem; xcb_screen_next(&iter), --idx)
|
|
{
|
|
if (!idx)
|
|
return iter.data;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static xcb_atom_t demo_xcb_get_atom(xcb_connection_t *c, const char *name)
|
|
{
|
|
xcb_intern_atom_cookie_t cookie;
|
|
xcb_intern_atom_reply_t *reply;
|
|
xcb_atom_t atom = XCB_NONE;
|
|
|
|
cookie = xcb_intern_atom(c, 0, strlen(name), name);
|
|
if ((reply = xcb_intern_atom_reply(c, cookie, NULL)))
|
|
{
|
|
atom = reply->atom;
|
|
free(reply);
|
|
}
|
|
|
|
return atom;
|
|
}
|
|
|
|
static struct demo_window_xcb *demo_xcb_find_xcb_window(struct demo *demo, xcb_window_t window)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < demo->window_count; ++i)
|
|
{
|
|
struct demo_window_xcb *window_xcb = CONTAINING_RECORD(demo->windows[i], struct demo_window_xcb, w);
|
|
|
|
if (window_xcb->window == window)
|
|
return window_xcb;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static VkSurfaceKHR demo_window_xcb_create_vk_surface(struct demo_window *window, VkInstance vk_instance)
|
|
{
|
|
struct demo_window_xcb *window_xcb = CONTAINING_RECORD(window, struct demo_window_xcb, w);
|
|
struct VkXcbSurfaceCreateInfoKHR surface_desc;
|
|
VkSurfaceKHR vk_surface;
|
|
|
|
surface_desc.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
|
|
surface_desc.pNext = NULL;
|
|
surface_desc.flags = 0;
|
|
surface_desc.connection = window->demo->xcb.connection;
|
|
surface_desc.window = window_xcb->window;
|
|
if (vkCreateXcbSurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface) < 0)
|
|
return VK_NULL_HANDLE;
|
|
|
|
return vk_surface;
|
|
}
|
|
|
|
static void demo_window_xcb_destroy(struct demo_window *window)
|
|
{
|
|
struct demo_window_xcb *window_xcb = CONTAINING_RECORD(window, struct demo_window_xcb, w);
|
|
struct demo_xcb *xcb = &window->demo->xcb;
|
|
|
|
xcb_destroy_window(xcb->connection, window_xcb->window);
|
|
xcb_flush(xcb->connection);
|
|
demo_window_cleanup(&window_xcb->w);
|
|
free(window_xcb);
|
|
}
|
|
|
|
static struct demo_window *demo_window_xcb_create(struct demo *demo, const char *title,
|
|
unsigned int width, unsigned int height, void *user_data)
|
|
{
|
|
struct demo_window_xcb *window_xcb;
|
|
struct demo_xcb *xcb = &demo->xcb;
|
|
xcb_size_hints_t hints;
|
|
xcb_screen_t *screen;
|
|
|
|
static const uint32_t window_events = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
|
|
|
|
if (!(screen = demo_xcb_get_screen(xcb->connection, xcb->screen)))
|
|
return NULL;
|
|
|
|
if (!(window_xcb = malloc(sizeof(*window_xcb))))
|
|
return NULL;
|
|
|
|
if (!demo_window_init(&window_xcb->w, demo, user_data))
|
|
{
|
|
free(window_xcb);
|
|
return NULL;
|
|
}
|
|
|
|
window_xcb->window = xcb_generate_id(xcb->connection);
|
|
xcb_create_window(xcb->connection, XCB_COPY_FROM_PARENT, window_xcb->window, screen->root, 0, 0,
|
|
width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
|
|
XCB_CW_EVENT_MASK, &window_events);
|
|
xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, window_xcb->window, XCB_ATOM_WM_NAME,
|
|
XCB_ATOM_STRING, 8, strlen(title), title);
|
|
xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, window_xcb->window, xcb->wm_protocols_atom,
|
|
XCB_ATOM_ATOM, 32, 1, &xcb->wm_delete_window_atom);
|
|
hints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE;
|
|
hints.min_width = width;
|
|
hints.min_height = height;
|
|
hints.max_width = width;
|
|
hints.max_height = height;
|
|
xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, window_xcb->window, XCB_ATOM_WM_NORMAL_HINTS,
|
|
XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
|
|
|
|
xcb_map_window(xcb->connection, window_xcb->window);
|
|
|
|
xcb_flush(xcb->connection);
|
|
|
|
return &window_xcb->w;
|
|
}
|
|
|
|
static void demo_xcb_get_dpi(struct demo *demo, double *dpi_x, double *dpi_y)
|
|
{
|
|
struct demo_xcb *xcb = &demo->xcb;
|
|
xcb_screen_t *screen;
|
|
|
|
if (!(screen = demo_xcb_get_screen(xcb->connection, xcb->screen)))
|
|
{
|
|
*dpi_x = *dpi_y = 96.0;
|
|
return;
|
|
}
|
|
|
|
*dpi_x = screen->width_in_pixels * 25.4 / screen->width_in_millimeters;
|
|
*dpi_y = screen->height_in_pixels * 25.4 / screen->height_in_millimeters;
|
|
}
|
|
|
|
static void demo_xcb_process_events(struct demo *demo)
|
|
{
|
|
const struct xcb_client_message_event_t *client_message;
|
|
struct xcb_key_press_event_t *key_press;
|
|
struct demo_window_xcb *window_xcb;
|
|
struct demo_xcb *xcb = &demo->xcb;
|
|
xcb_generic_event_t *event;
|
|
xcb_keysym_t sym;
|
|
|
|
xcb_flush(xcb->connection);
|
|
|
|
while (demo->window_count)
|
|
{
|
|
if (!demo->idle_func)
|
|
{
|
|
if (!(event = xcb_wait_for_event(xcb->connection)))
|
|
break;
|
|
}
|
|
else if (!(event = xcb_poll_for_event(xcb->connection)))
|
|
{
|
|
demo->idle_func(demo, demo->user_data);
|
|
continue;
|
|
}
|
|
|
|
switch (XCB_EVENT_RESPONSE_TYPE(event))
|
|
{
|
|
case XCB_EXPOSE:
|
|
if ((window_xcb = demo_xcb_find_xcb_window(demo, ((struct xcb_expose_event_t *)event)->window))
|
|
&& window_xcb->w.expose_func)
|
|
window_xcb->w.expose_func(&window_xcb->w, window_xcb->w.user_data);
|
|
break;
|
|
|
|
case XCB_KEY_PRESS:
|
|
key_press = (struct xcb_key_press_event_t *)event;
|
|
if (!(window_xcb = demo_xcb_find_xcb_window(demo, key_press->event)) || !window_xcb->w.key_press_func)
|
|
break;
|
|
sym = xcb_key_press_lookup_keysym(xcb->xcb_keysyms, key_press, 0);
|
|
window_xcb->w.key_press_func(&window_xcb->w, sym, window_xcb->w.user_data);
|
|
break;
|
|
|
|
case XCB_CLIENT_MESSAGE:
|
|
client_message = (xcb_client_message_event_t *)event;
|
|
if (client_message->type == xcb->wm_protocols_atom
|
|
&& client_message->data.data32[0] == xcb->wm_delete_window_atom
|
|
&& (window_xcb = demo_xcb_find_xcb_window(demo, client_message->window)))
|
|
demo_window_xcb_destroy(&window_xcb->w);
|
|
break;
|
|
}
|
|
|
|
free(event);
|
|
}
|
|
}
|
|
|
|
static void demo_xcb_cleanup(struct demo *demo)
|
|
{
|
|
struct demo_xcb *xcb = &demo->xcb;
|
|
|
|
xcb_key_symbols_free(xcb->xcb_keysyms);
|
|
xcb_disconnect(xcb->connection);
|
|
}
|
|
|
|
static bool demo_xcb_init(struct demo_xcb *xcb)
|
|
{
|
|
if (!(xcb->connection = xcb_connect(NULL, &xcb->screen)))
|
|
return false;
|
|
if (xcb_connection_has_error(xcb->connection) > 0)
|
|
goto fail;
|
|
if ((xcb->wm_delete_window_atom = demo_xcb_get_atom(xcb->connection, "WM_DELETE_WINDOW")) == XCB_NONE)
|
|
goto fail;
|
|
if ((xcb->wm_protocols_atom = demo_xcb_get_atom(xcb->connection, "WM_PROTOCOLS")) == XCB_NONE)
|
|
goto fail;
|
|
if (!(xcb->xcb_keysyms = xcb_key_symbols_alloc(xcb->connection)))
|
|
goto fail;
|
|
|
|
return true;
|
|
|
|
fail:
|
|
xcb_disconnect(xcb->connection);
|
|
return false;
|
|
}
|