diff options
Diffstat (limited to 'src/window.c')
-rw-r--r-- | src/window.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..0d5bac8 --- /dev/null +++ b/src/window.c @@ -0,0 +1,177 @@ +#include <vlkn.h> +#include "window.h" +#include "utils.h" +#include <vulkan/vulkan_wayland.h> +#include <stdlib.h> +#include <string.h> + +static void global(void *data, struct wl_registry *reg, + uint32_t name, const char *interface, uint32_t version) { + struct vlkn_window *win = data; + if (strcmp(wl_compositor_interface.name, interface) == 0) { + win->comp = wl_registry_bind(reg, name, &wl_compositor_interface, version); + } else if (strcmp(xdg_wm_base_interface.name, interface) == 0) { + win->xdg_base = wl_registry_bind(reg, name, &xdg_wm_base_interface, version); + } else if (strcmp(zxdg_decoration_manager_v1_interface.name, interface) == 0) { + win->deco_manager = wl_registry_bind(reg, name, + &zxdg_decoration_manager_v1_interface, version); + } +} + +static void global_remove(void *data, struct wl_registry *reg, uint32_t name) { + (void) data; (void) reg; (void) name; + abort(); +} + +static struct wl_registry_listener reg_list = { + .global = global, + .global_remove = global_remove +}; + +static void ping(void *data, struct xdg_wm_base *base, uint32_t serial) { + (void) data; + xdg_wm_base_pong(base, serial); +} + +static struct xdg_wm_base_listener xdg_list = { + .ping = ping +}; + +void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { + (void) data; + xdg_surface_ack_configure(xdg_surface, serial); +} + +static struct xdg_surface_listener xdg_surface_list = { + .configure = xdg_surface_configure, +}; + +void toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, + int32_t width, int32_t height, struct wl_array *states) { + (void) xdg_toplevel; (void) states; + struct vlkn_window *win = data; + win->resize = true; + win->width = width != 0 ? width : 1920; + win->height = height != 0 ? height : 1080; + if (win->on_resize) + win->on_resize(win->data); + + dbglogf("%dx%d\n", win->width, win->height); +} + +void toplevel_close(void *data, struct xdg_toplevel *toplevel) { + (void) toplevel; + struct vlkn_window *win = data; + win->should_close = true; +} + +void configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) { + (void) data; (void) xdg_toplevel; (void) width; (void) height; +} + +void wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities) { + (void) data; (void) xdg_toplevel; (void) capabilities; +} + +static struct xdg_toplevel_listener toplevel_listener = { + .configure = toplevel_configure, + .close = toplevel_close, + .configure_bounds = configure_bounds, + .wm_capabilities = wm_capabilities +}; + +struct vlkn_window *vlkn_window_init(const char *title) { + struct vlkn_window *win = calloc(1, sizeof(*win)); + if (!win) + return NULL; + + win->title = title; + win->should_close = false; + + win->dpy = wl_display_connect(NULL); + if (!win->dpy) + goto err; + + win->reg = wl_display_get_registry(win->dpy); + if (!win->reg) + goto err; + + wl_registry_add_listener(win->reg, ®_list, win); + wl_display_roundtrip(win->dpy); + + if (!win->comp || !win->dpy || !win->deco_manager || !win->xdg_base) + goto err; + + xdg_wm_base_add_listener(win->xdg_base, &xdg_list, win); + + win->surface = wl_compositor_create_surface(win->comp); + if (!win->surface) + goto err; + + win->xdg_surface = xdg_wm_base_get_xdg_surface(win->xdg_base, win->surface); + xdg_surface_add_listener(win->xdg_surface, &xdg_surface_list, win); + + win->xdg_toplevel = xdg_surface_get_toplevel(win->xdg_surface); + xdg_toplevel_set_title(win->xdg_toplevel, title); + xdg_toplevel_set_min_size(win->xdg_toplevel, 640, 480); + xdg_toplevel_add_listener(win->xdg_toplevel, &toplevel_listener, win); + + win->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(win->deco_manager, win->xdg_toplevel); + zxdg_toplevel_decoration_v1_set_mode(win->deco, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + wl_surface_commit(win->surface); + while (!win->resize) + wl_display_roundtrip(win->dpy); + win->resize = false; + + return win; + +err: + vlkn_window_destroy(win); + return NULL; +} + +void window_on_resize(struct vlkn_window *win, void (*callback)(void *data), void *data) { + win->on_resize = callback; + win->data = data; +} + +void vlkn_window_destroy(struct vlkn_window *win) { + if (!win) + return; + + if (win->deco) + zxdg_toplevel_decoration_v1_destroy(win->deco); + if (win->deco_manager) + zxdg_decoration_manager_v1_destroy(win->deco_manager); + if (win->xdg_toplevel) + xdg_toplevel_destroy(win->xdg_toplevel); + if (win->xdg_surface) + xdg_surface_destroy(win->xdg_surface); + if (win->xdg_base) + xdg_wm_base_destroy(win->xdg_base); + if (win->comp) + wl_compositor_destroy(win->comp); + if (win->reg) + wl_registry_destroy(win->reg); + if (win->dpy) + wl_display_disconnect(win->dpy); + free(win); +} + +VkSurfaceKHR window_create_vk_surface(VkInstance instance, struct vlkn_window *win) { + if (!win) + return VK_NULL_HANDLE; + + VkWaylandSurfaceCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + .display = win->dpy, + .surface = win->surface + }; + + VkSurfaceKHR surface; + if (!vlkn_check(vkCreateWaylandSurfaceKHR(instance, &create_info, NULL, &surface))) + return VK_NULL_HANDLE; + + return surface; +} |