diff options
| author | Mikhail Burakov <mburakov@mailbox.org> | 2023-04-02 12:09:20 +0200 | 
|---|---|---|
| committer | Mikhail Burakov <mburakov@mailbox.org> | 2023-04-07 13:47:39 +0200 | 
| commit | eecbacdc1ab1b29fee71f3a689e01cabe12b3730 (patch) | |
| tree | 0b6c924678a31ed2f46061f7767a99bb40b57737 | |
| parent | 972e03b4a09b790d9ed9c8102cc897a75c9bb751 (diff) | |
Major rewrite of window to support input events
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | main.c | 22 | ||||
| -rw-r--r-- | window.c | 513 | ||||
| -rw-r--r-- | window.h | 10 | 
4 files changed, 365 insertions, 182 deletions
| @@ -2,4 +2,6 @@  .clang-format  compile_commands.json  compile_flags.txt +linux-dmabuf-unstable-v1.h  receiver +xdg-shell.h @@ -31,11 +31,31 @@  static volatile sig_atomic_t g_signal;  static void OnSignal(int status) { g_signal = status; } +static void OnWindowClose(void* user) { +  (void)user; +  g_signal = SIGINT; +} + +static void OnWindowKey(void* user, unsigned key, bool pressed) { +  // TODO +} + +static void WindowDtor(struct Window** window) { +  if (!*window) return; +  WindowDestroy(*window); +  *window = NULL; +} +  int main(int argc, char* argv[]) {    (void)argc;    (void)argv; -  struct AUTO(Window)* window = WindowCreate(); +  static const struct WindowEventHandlers window_event_handlers = { +      .OnClose = OnWindowClose, +      .OnKey = OnWindowKey, +  }; +  struct Window __attribute__((cleanup(WindowDtor)))* window = +      WindowCreate(&window_event_handlers, NULL);    if (!window) {      LOG("Failed to create window");      return EXIT_FAILURE; @@ -18,7 +18,6 @@  #include "window.h"  #include <errno.h> -#include <signal.h>  #include <stddef.h>  #include <stdio.h>  #include <stdlib.h> @@ -30,108 +29,236 @@  #include "util.h"  #include "xdg-shell.h" +// TODO(mburakov): This would look like shit until Wayland guys finally fix +// https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 +  struct Window { +  const struct WindowEventHandlers* event_handlers; +  void* user; +    struct wl_display* wl_display;    struct wl_surface* wl_surface; +  struct wl_pointer* wl_pointer; +  struct wl_keyboard* wl_keyboard;    struct xdg_wm_base* xdg_wm_base;    struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1; +    struct xdg_surface* xdg_surface;    struct xdg_toplevel* xdg_toplevel;    struct wl_buffer** wl_buffers;  }; -static void wl_registryDestroy(struct wl_registry** wl_registry) { -  if (!wl_registry || !*wl_registry) return; -  wl_registry_destroy(*wl_registry); -  *wl_registry = NULL; -} - -static void wl_compositorDestroy(struct wl_compositor** wl_compositor) { -  if (!wl_compositor || !*wl_compositor) return; -  wl_compositor_destroy(*wl_compositor); -  *wl_compositor = NULL; -} - -static void xdg_wm_baseDestroy(struct xdg_wm_base** xdg_wm_base) { -  if (!xdg_wm_base || !*xdg_wm_base) return; -  xdg_wm_base_destroy(*xdg_wm_base); -  *xdg_wm_base = NULL; -} - -static void zwp_linux_buffer_params_v1Destroy( -    struct zwp_linux_buffer_params_v1** zwp_linux_buffer_params_v1) { -  if (!zwp_linux_buffer_params_v1 || !*zwp_linux_buffer_params_v1) return; -  zwp_linux_buffer_params_v1_destroy(*zwp_linux_buffer_params_v1); -  *zwp_linux_buffer_params_v1 = NULL; -} - -static void wl_bufferDestroy(struct wl_buffer** wl_buffer) { -  if (!wl_buffer || !*wl_buffer) return; -  wl_buffer_destroy(*wl_buffer); -  *wl_buffer = NULL; -} - -static void OnWmBasePing(void* data, struct xdg_wm_base* xdg_wm_base, -                         uint32_t serial) { -  (void)data; -  xdg_wm_base_pong(xdg_wm_base, serial); -} - -static void OnRegistryGlobal(void* data, struct wl_registry* registry, -                             uint32_t name, const char* interface, -                             uint32_t version) { +static void OnWlRegistryGlobal(void* data, struct wl_registry* wl_registry, +                               uint32_t name, const char* interface, +                               uint32_t version) {    struct Window* window = data;    if (!strcmp(interface, wl_compositor_interface.name)) { -    struct AUTO(wl_compositor)* compositor = -        wl_registry_bind(registry, name, &wl_compositor_interface, version); +    struct wl_compositor* compositor = +        wl_registry_bind(wl_registry, name, &wl_compositor_interface, version);      if (!compositor) { -      LOG("Failed to bind wayland compositor (%s)", strerror(errno)); +      LOG("Failed to bind wl_compositor (%s)", strerror(errno));        return;      }      window->wl_surface = wl_compositor_create_surface(compositor); -    if (!window->wl_surface) { -      LOG("Failed to create wayland surface (%s)", strerror(errno)); +    if (!window->wl_surface) +      LOG("Failed to create wl_surface (%s)", strerror(errno)); +    wl_compositor_destroy(compositor); + +  } else if (!strcmp(interface, wl_seat_interface.name)) { +    struct wl_seat* wl_seat = +        wl_registry_bind(wl_registry, name, &wl_seat_interface, version); +    if (!wl_seat) { +      LOG("Failed to bind wl_seat (%s)", strerror(errno));        return;      } +    window->wl_pointer = wl_seat_get_pointer(wl_seat); +    if (!window->wl_pointer) +      LOG("Failed to get wl_pointer (%s)", strerror(errno)); +    window->wl_keyboard = wl_seat_get_keyboard(wl_seat); +    if (!window->wl_keyboard) +      LOG("Failed to get wl_keyboard (%s)", strerror(errno)); +    wl_seat_destroy(wl_seat); +    } else if (!strcmp(interface, xdg_wm_base_interface.name)) { -    struct AUTO(xdg_wm_base)* xdg_wm_base = -        wl_registry_bind(registry, name, &xdg_wm_base_interface, version); -    if (!xdg_wm_base) { -      LOG("Failed to bind wayland xdg_wm_base (%s)", strerror(errno)); -      return; -    } -    static const struct xdg_wm_base_listener wm_base_listener = { -        .ping = OnWmBasePing, -    }; -    if (xdg_wm_base_add_listener(xdg_wm_base, &wm_base_listener, NULL)) { -      LOG("Failed to add wayland wm base listener (%s)", strerror(errno)); -      return; -    } -    window->xdg_wm_base = RELEASE(xdg_wm_base); +    window->xdg_wm_base = +        wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, version); +    if (!window->xdg_wm_base) +      LOG("Failed to bind xdg_wm_base (%s)", strerror(errno)); +    } else if (!strcmp(interface, zwp_linux_dmabuf_v1_interface.name)) {      window->zwp_linux_dmabuf_v1 = wl_registry_bind( -        registry, name, &zwp_linux_dmabuf_v1_interface, version); +        wl_registry, name, &zwp_linux_dmabuf_v1_interface, version);      if (!window->zwp_linux_dmabuf_v1) -      LOG("Failed to bind wayland zwp_linux_dmabuf_v1 (%s)", strerror(errno)); +      LOG("Failed to bind zwp_linux_dmabuf_v1 (%s)", strerror(errno));    }  } -static void OnRegistryGlobalRemove(void* data, struct wl_registry* registry, -                                   uint32_t name) { +static void OnWlRegistryGlobalRemove(void* data, struct wl_registry* registry, +                                     uint32_t name) {    (void)data;    (void)registry;    (void)name;  } -static void OnSurfaceConfigure(void* data, struct xdg_surface* xdg_surface, -                               uint32_t serial) { +static void OnWlPointerEnter(void* data, struct wl_pointer* wl_pointer, +                             uint32_t serial, struct wl_surface* surface, +                             wl_fixed_t surface_x, wl_fixed_t surface_y) { +  (void)data; +  (void)wl_pointer; +  (void)serial; +  (void)surface; +  (void)surface_x; +  (void)surface_y; +} + +static void OnWlPointerLeave(void* data, struct wl_pointer* wl_pointer, +                             uint32_t serial, struct wl_surface* surface) { +  (void)data; +  (void)wl_pointer; +  (void)serial; +  (void)surface; +} + +static void OnWlPointerMotion(void* data, struct wl_pointer* wl_pointer, +                              uint32_t time, wl_fixed_t surface_x, +                              wl_fixed_t surface_y) { +  (void)data; +  (void)wl_pointer; +  (void)time; +  (void)surface_x; +  (void)surface_y; +} + +static void OnWlPointerButton(void* data, struct wl_pointer* wl_pointer, +                              uint32_t serial, uint32_t time, uint32_t button, +                              uint32_t state) { +  (void)data; +  (void)wl_pointer; +  (void)serial; +  (void)time; +  (void)button; +  (void)state; +} + +static void OnWlPointerAxis(void* data, struct wl_pointer* wl_pointer, +                            uint32_t time, uint32_t axis, wl_fixed_t value) { +  (void)data; +  (void)wl_pointer; +  (void)time; +  (void)axis; +  (void)value; +} + +static void OnWlPointerFrame(void* data, struct wl_pointer* wl_pointer) { +  (void)data; +  (void)wl_pointer; +} + +static void OnWlPointerAxisSource(void* data, struct wl_pointer* wl_pointer, +                                  uint32_t axis_source) { +  (void)data; +  (void)wl_pointer; +  (void)axis_source; +} + +static void OnWlPointerAxisStop(void* data, struct wl_pointer* wl_pointer, +                                uint32_t time, uint32_t axis) { +  (void)data; +  (void)wl_pointer; +  (void)time; +  (void)axis; +} + +static void OnWlPointerAxisDiscrete(void* data, struct wl_pointer* wl_pointer, +                                    uint32_t axis, int32_t discrete) { +  (void)data; +  (void)wl_pointer; +  (void)axis; +  (void)discrete; +} + +static void OnWlPointerAxisValue120(void* data, struct wl_pointer* wl_pointer, +                                    uint32_t axis, int32_t value120) { +  (void)data; +  (void)wl_pointer; +  (void)axis; +  (void)value120; +} + +static void OnWlKeyboardKeymap(void* data, struct wl_keyboard* wl_keyboard, +                               uint32_t format, int32_t fd, uint32_t size) { +  (void)data; +  (void)wl_keyboard; +  (void)format; +  (void)fd; +  (void)size; +} + +static void OnWlKeyboardEnter(void* data, struct wl_keyboard* wl_keyboard, +                              uint32_t serial, struct wl_surface* surface, +                              struct wl_array* keys) { +  (void)data; +  (void)wl_keyboard; +  (void)serial; +  (void)surface; +  (void)keys; +} + +static void OnWlKeyboardLeave(void* data, struct wl_keyboard* wl_keyboard, +                              uint32_t serial, struct wl_surface* surface) { +  (void)data; +  (void)wl_keyboard; +  (void)serial; +  (void)surface; +} + +static void OnWlKeyboardKey(void* data, struct wl_keyboard* wl_keyboard, +                            uint32_t serial, uint32_t time, uint32_t key, +                            uint32_t state) { +  (void)wl_keyboard; +  (void)serial; +  (void)time; +  struct Window* window = data; +  window->event_handlers->OnKey(window->user, key, !!state); +} + +static void OnWlKeyboardModifiers(void* data, struct wl_keyboard* wl_keyboard, +                                  uint32_t serial, uint32_t mods_depressed, +                                  uint32_t mods_latched, uint32_t mods_locked, +                                  uint32_t group) { +  (void)data; +  (void)wl_keyboard; +  (void)serial; +  (void)mods_depressed; +  (void)mods_latched; +  (void)mods_locked; +  (void)group; +} + +static void OnWlKeyboardRepeatInfo(void* data, struct wl_keyboard* wl_keyboard, +                                   int32_t rate, int32_t delay) { +  (void)data; +  (void)wl_keyboard; +  (void)rate; +  (void)delay; +} + +static void OnXdgWmBasePing(void* data, struct xdg_wm_base* xdg_wm_base, +                            uint32_t serial) { +  (void)data; +  xdg_wm_base_pong(xdg_wm_base, serial); +} + +static void OnXdgSurfaceConfigure(void* data, struct xdg_surface* xdg_surface, +                                  uint32_t serial) {    (void)data;    xdg_surface_ack_configure(xdg_surface, serial);  } -static void OnToplevelConfigure(void* data, struct xdg_toplevel* xdg_toplevel, -                                int32_t width, int32_t height, -                                struct wl_array* states) { +static void OnXdgToplevelConfigure(void* data, +                                   struct xdg_toplevel* xdg_toplevel, +                                   int32_t width, int32_t height, +                                   struct wl_array* states) {    (void)data;    (void)xdg_toplevel;    (void)width; @@ -139,180 +266,209 @@ static void OnToplevelConfigure(void* data, struct xdg_toplevel* xdg_toplevel,    (void)states;  } -static void OnToplevelClose(void* data, struct xdg_toplevel* xdg_toplevel) { -  (void)data; +static void OnXdgToplevelClose(void* data, struct xdg_toplevel* xdg_toplevel) {    (void)xdg_toplevel; -  raise(SIGINT); +  struct Window* window = data; +  window->event_handlers->OnClose(window->user);  } -static void OnToplevelConfigureBounds(void* data, -                                      struct xdg_toplevel* xdg_toplevel, -                                      int32_t width, int32_t height) { +static void OnXdgToplevelConfigureBounds(void* data, +                                         struct xdg_toplevel* xdg_toplevel, +                                         int32_t width, int32_t height) {    (void)data;    (void)xdg_toplevel;    (void)width;    (void)height;  } -static void OnToplevelWmCapabilities(void* data, -                                     struct xdg_toplevel* xdg_toplevel, -                                     struct wl_array* capabilities) { +static void OnXdgToplevelWmCapabilities(void* data, +                                        struct xdg_toplevel* xdg_toplevel, +                                        struct wl_array* capabilities) {    (void)data;    (void)xdg_toplevel;    (void)capabilities;  } - -struct Window* WindowCreate(void) { -  struct AUTO(Window)* window = calloc(1, sizeof(struct Window)); +struct Window* WindowCreate(const struct WindowEventHandlers* event_handlers, +                            void* user) { +  struct Window* window = malloc(sizeof(struct Window));    if (!window) {      LOG("Failed to allocate window (%s)", strerror(errno));      return NULL;    } +  *window = (struct Window){ +      .event_handlers = event_handlers, +      .user = user, +  };    window->wl_display = wl_display_connect(NULL);    if (!window->wl_display) { -    LOG("Failed to connect wayland display (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to connect wl_display (%s)", strerror(errno)); +    goto rollback_window;    } -  struct AUTO(wl_registry)* wl_registry = -      wl_display_get_registry(window->wl_display); +  struct wl_registry* wl_registry = wl_display_get_registry(window->wl_display);    if (!wl_registry) { -    LOG("Failed to get wayland registry (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to get wl_registry (%s)", strerror(errno)); +    goto rollback_wl_display;    }    static const struct wl_registry_listener wl_registry_listener = { -      .global = OnRegistryGlobal, -      .global_remove = OnRegistryGlobalRemove, +      .global = OnWlRegistryGlobal, +      .global_remove = OnWlRegistryGlobalRemove,    };    if (wl_registry_add_listener(wl_registry, &wl_registry_listener, window)) { -    LOG("Failed to set wayland registry listener (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to add wl_registry listener (%s)", strerror(errno)); +    goto rollback_wl_registry;    }    if (wl_display_roundtrip(window->wl_display) == -1) { -    LOG("Failed to roundtrip wayland display (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to roundtrip wl_display (%s)", strerror(errno)); +    goto rollback_wl_registry;    } - -  if (!window->wl_surface || !window->xdg_wm_base || -      !window->zwp_linux_dmabuf_v1) { +  if (!window->wl_surface || !window->wl_pointer || !window->wl_keyboard || +      !window->xdg_wm_base || !window->zwp_linux_dmabuf_v1) {      LOG("Some wayland objects are missing"); -    return NULL; +    goto rollback_globals; +  } + +  static const struct wl_pointer_listener wl_pointer_listener = { +      .enter = OnWlPointerEnter, +      .leave = OnWlPointerLeave, +      .motion = OnWlPointerMotion, +      .button = OnWlPointerButton, +      .axis = OnWlPointerAxis, +      .frame = OnWlPointerFrame, +      .axis_source = OnWlPointerAxisSource, +      .axis_stop = OnWlPointerAxisStop, +      .axis_discrete = OnWlPointerAxisDiscrete, +      .axis_value120 = OnWlPointerAxisValue120, +  }; +  if (wl_pointer_add_listener(window->wl_pointer, &wl_pointer_listener, +                              window)) { +    LOG("Failed to add wl_pointer listener (%s)", strerror(errno)); +    goto rollback_globals; +  } +  static const struct wl_keyboard_listener wl_keyboard_listener = { +      .keymap = OnWlKeyboardKeymap, +      .enter = OnWlKeyboardEnter, +      .leave = OnWlKeyboardLeave, +      .key = OnWlKeyboardKey, +      .modifiers = OnWlKeyboardModifiers, +      .repeat_info = OnWlKeyboardRepeatInfo, +  }; +  if (wl_keyboard_add_listener(window->wl_keyboard, &wl_keyboard_listener, +                               window)) { +    LOG("Failed to add wl_keyboard listener (%s)", strerror(errno)); +    goto rollback_globals; +  } +  static const struct xdg_wm_base_listener xdg_wm_base_listener = { +      .ping = OnXdgWmBasePing, +  }; +  if (xdg_wm_base_add_listener(window->xdg_wm_base, &xdg_wm_base_listener, +                               NULL)) { +    LOG("Failed to add xdg_wm_base listener (%s)", strerror(errno)); +    goto rollback_globals;    } +    window->xdg_surface =        xdg_wm_base_get_xdg_surface(window->xdg_wm_base, window->wl_surface);    if (!window->xdg_surface) { -    LOG("Failed to get wayland surface (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to get xdg_surface (%s)", strerror(errno)); +    goto rollback_globals;    }    static const struct xdg_surface_listener xdg_surface_listener = { -      .configure = OnSurfaceConfigure, +      .configure = OnXdgSurfaceConfigure,    };    if (xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener,                                 NULL)) { -    LOG("Failed to add wayland surface listener (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to add xdg_surface listener (%s)", strerror(errno)); +    goto rollback_xdg_surface;    } +    window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);    if (!window->xdg_toplevel) { -    LOG("Failed to get wayland toplevel (%s)", strerror(errno)); -    return NULL; +    LOG("Failed to get xdg_toplevel (%s)", strerror(errno)); +    goto rollback_xdg_surface;    }    static const struct xdg_toplevel_listener xdg_toplevel_listener = { -      .configure = OnToplevelConfigure, -      .close = OnToplevelClose, -      .configure_bounds = OnToplevelConfigureBounds, -      .wm_capabilities = OnToplevelWmCapabilities, +      .configure = OnXdgToplevelConfigure, +      .close = OnXdgToplevelClose, +      .configure_bounds = OnXdgToplevelConfigureBounds, +      .wm_capabilities = OnXdgToplevelWmCapabilities,    };    if (xdg_toplevel_add_listener(window->xdg_toplevel, &xdg_toplevel_listener, -                                NULL)) { -    LOG("Failed to add wayland toplevel listener (%s)", strerror(errno)); -    return NULL; +                                window)) { +    LOG("Failed to add xdg_toplevel listener (%s)", strerror(errno)); +    goto rollback_xdg_toplevel;    }    xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);    wl_surface_commit(window->wl_surface); -  return RELEASE(window); +  if (wl_display_roundtrip(window->wl_display) == -1) { +    LOG("Failed to roundtrip wl_display (%s)", strerror(errno)); +    goto rollback_xdg_toplevel; +  } +  wl_registry_destroy(wl_registry); +  return window; + +rollback_xdg_toplevel: +  xdg_toplevel_destroy(window->xdg_toplevel); +rollback_xdg_surface: +  xdg_surface_destroy(window->xdg_surface); +rollback_globals: +  if (window->zwp_linux_dmabuf_v1) +    zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1); +  if (window->xdg_wm_base) xdg_wm_base_destroy(window->xdg_wm_base); +  if (window->wl_keyboard) wl_keyboard_release(window->wl_keyboard); +  if (window->wl_pointer) wl_pointer_release(window->wl_pointer); +  if (window->wl_surface) wl_surface_destroy(window->wl_surface); +rollback_wl_registry: +  wl_registry_destroy(wl_registry); +rollback_wl_display: +  wl_display_disconnect(window->wl_display); +rollback_window: +  free(window); +  return NULL;  }  int WindowGetEventsFd(const struct Window* window) {    int events_fd = wl_display_get_fd(window->wl_display); -  if (events_fd == -1) -    LOG("Failed to get wayland display fd (%s)", strerror(errno)); +  if (events_fd == -1) LOG("Failed to get wl_display fd (%s)", strerror(errno));    return events_fd;  }  bool WindowProcessEvents(const struct Window* window) { -  if (wl_display_dispatch(window->wl_display) == -1) { -    LOG("Failed to dispatch wayland display (%s)", strerror(errno)); -    return false; -  } -  return true; -} - -static void OnZwpLinuxBufferParamsCreated( -    void* data, struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -    struct wl_buffer* buffer) { -  (void)zwp_linux_buffer_params_v1; -  struct wl_buffer** wl_buffer = data; -  *wl_buffer = buffer; -} - -static void OnZwpLinuxBufferParamsFailed( -    void* data, struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1) { -  (void)data; -  (void)zwp_linux_buffer_params_v1; +  bool result = wl_display_dispatch(window->wl_display) != -1; +  if (!result) LOG("Failed to dispatch wl_display (%s)", strerror(errno)); +  return result;  }  static void DestroyBuffers(struct Window* window) {    if (!window->wl_buffers) return;    for (size_t i = 0; window->wl_buffers[i]; i++)      wl_buffer_destroy(window->wl_buffers[i]); -  free(RELEASE(window->wl_buffers)); +  free(window->wl_buffers); +  window->wl_buffers = NULL;  }  static struct wl_buffer* CreateBuffer(struct Window* window,                                        const struct Frame* frame) { -  struct AUTO(zwp_linux_buffer_params_v1)* zwp_linux_buffer_params_v1 = +  struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1 =        zwp_linux_dmabuf_v1_create_params(window->zwp_linux_dmabuf_v1);    if (!zwp_linux_buffer_params_v1) { -    LOG("Failed to create wayland dmabuf params (%s)", strerror(errno)); +    LOG("Failed to create zwp_linux_buffer_params_v1 (%s)", strerror(errno));      return NULL;    } - -  struct AUTO(wl_buffer)* wl_buffer = NULL; -  static const struct zwp_linux_buffer_params_v1_listener -      zwp_linux_buffer_params_v1_listener = { -          .created = OnZwpLinuxBufferParamsCreated, -          .failed = OnZwpLinuxBufferParamsFailed, -      }; -  if (zwp_linux_buffer_params_v1_add_listener( -          zwp_linux_buffer_params_v1, &zwp_linux_buffer_params_v1_listener, -          &wl_buffer)) { -    LOG("Failed to add buffer wayland dmabuf params listener (%s)", -        strerror(errno)); -    return NULL; -  } - -  for (size_t i = 0; i < frame->nplanes; i++) { +  for (uint32_t i = 0; i < frame->nplanes; i++) {      zwp_linux_buffer_params_v1_add( -        zwp_linux_buffer_params_v1, frame->planes[i].dmabuf_fd, (uint32_t)i, +        zwp_linux_buffer_params_v1, frame->planes[i].dmabuf_fd, i,          frame->planes[i].offset, frame->planes[i].pitch,          frame->planes[i].modifier >> 32,          frame->planes[i].modifier & UINT32_MAX);    } -  zwp_linux_buffer_params_v1_create(zwp_linux_buffer_params_v1, -                                    (int)frame->width, (int)frame->height, -                                    frame->fourcc, 0); -  if (wl_display_roundtrip(window->wl_display) == -1) { -    LOG("Failed to roundtrip wayland display (%s)", strerror(errno)); -    return NULL; -  } -  if (!wl_buffer) { -    LOG("Failed to create wl_buffer"); -    return NULL; -  } - -  return RELEASE(wl_buffer); +  struct wl_buffer* wl_buffer = zwp_linux_buffer_params_v1_create_immed( +      zwp_linux_buffer_params_v1, (int)frame->width, (int)frame->height, +      frame->fourcc, 0); +  zwp_linux_buffer_params_v1_destroy(zwp_linux_buffer_params_v1); +  if (!wl_buffer) LOG("Failed to create wl_buffer (%s)", strerror(errno)); +  return wl_buffer;  }  bool WindowAssignFrames(struct Window* window, size_t nframes, @@ -339,20 +495,19 @@ bool WindowShowFrame(struct Window* window, size_t index) {    wl_surface_damage(window->wl_surface, 0, 0, INT32_MAX, INT32_MAX);    wl_surface_commit(window->wl_surface);    bool result = wl_display_roundtrip(window->wl_display) != -1; -  if (!result) LOG("Failed to roundtrip wayland display (%s)", strerror(errno)); +  if (!result) LOG("Failed to roundtrip wl_display (%s)", strerror(errno));    return result;  } -void WindowDestroy(struct Window** window) { -  if (!window || !*window) return; -  DestroyBuffers(*window); -  if ((*window)->xdg_toplevel) xdg_toplevel_destroy((*window)->xdg_toplevel); -  if ((*window)->xdg_surface) xdg_surface_destroy((*window)->xdg_surface); -  if ((*window)->zwp_linux_dmabuf_v1) -    zwp_linux_dmabuf_v1_destroy((*window)->zwp_linux_dmabuf_v1); -  if ((*window)->xdg_wm_base) xdg_wm_base_destroy((*window)->xdg_wm_base); -  if ((*window)->wl_surface) wl_surface_destroy((*window)->wl_surface); -  if ((*window)->wl_display) wl_display_disconnect((*window)->wl_display); -  free(*window); -  *window = NULL; +void WindowDestroy(struct Window* window) { +  DestroyBuffers(window); +  xdg_toplevel_destroy(window->xdg_toplevel); +  xdg_surface_destroy(window->xdg_surface); +  zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1); +  xdg_wm_base_destroy(window->xdg_wm_base); +  wl_keyboard_release(window->wl_keyboard); +  wl_pointer_release(window->wl_pointer); +  wl_surface_destroy(window->wl_surface); +  wl_display_disconnect(window->wl_display); +  free(window);  } @@ -24,12 +24,18 @@  struct Window;  struct Frame; -struct Window* WindowCreate(void); +struct WindowEventHandlers { +  void (*OnClose)(void* user); +  void (*OnKey)(void* user, unsigned key, bool pressed); +}; + +struct Window* WindowCreate( +    const struct WindowEventHandlers* window_event_handlers, void* user);  int WindowGetEventsFd(const struct Window* window);  bool WindowProcessEvents(const struct Window* window);  bool WindowAssignFrames(struct Window* window, size_t nframes,                          const struct Frame* frames);  bool WindowShowFrame(struct Window* window, size_t index); -void WindowDestroy(struct Window** window); +void WindowDestroy(struct Window* window);  #endif  // RECEIVER_WINDOW_H_ | 
