<NME> compositor.c
<BEF> #include <assert.h>
#include <chck/overflow/overflow.h>
#include "internal.h"
#include "macros.h"
#include "visibility.h"
#include "compositor.h"
#include "output.h"
#include "view.h"
#include "session/fd.h"
#include "resources/resources.h"
#include "resources/types/region.h"
#include "resources/types/surface.h"

static void
wl_cb_subsurface_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y)
{
   (void)client;
   struct wlc_surface *surface;
   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))
      return;

   surface->pending.subsurface_position = (struct wlc_point){x, y};
}

static void
restack_subsurface_relative_to(wlc_resource surface, wlc_resource sibling, int32_t offset)
{

   size_t surface_idx = (size_t)~0, target_idx = (size_t)~0;

   struct wlc_surface *surface_ptr;
   if (!(surface_ptr = convert_from_wlc_resource(surface, "surface")))
      return;

   struct wlc_surface *parent = convert_from_wlc_resource(surface_ptr->parent, "surface");
   wlc_resource *sub;
   chck_iter_pool_for_each(&parent->subsurface_list, sub) {
      if (*sub == surface)
         surface_idx = _I - 1;

      if (*sub == sibling)
         target_idx = _I - 1;
   }

   if (surface_idx == (size_t)~0 || target_idx == (size_t)~0)
      return;

   if (surface_idx < target_idx)
      --target_idx;

   chck_iter_pool_remove(&parent->subsurface_list, surface_idx);
   chck_iter_pool_insert(&parent->subsurface_list, target_idx + offset, &surface);
}

static void
wl_cb_subsurface_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)
{
   (void)client, (void)resource, (void)sibling_resource;

   wlc_resource surface_res = (wlc_resource)wl_resource_get_user_data(resource);
   wlc_resource sibling_res = (wlc_resource)wl_resource_get_user_data(sibling_resource);

   restack_subsurface_relative_to(surface_res, sibling_res, 0);
}

static void
wl_cb_subsurface_place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)
{
   (void)client, (void)resource, (void)sibling_resource;

   wlc_resource surface_res = (wlc_resource)wl_resource_get_user_data(resource);
   wlc_resource sibling_res = (wlc_resource)wl_resource_get_user_data(sibling_resource);

   restack_subsurface_relative_to(surface_res, sibling_res, 1);
}

static void
recursive_set_subsurface_parent_sync_state(struct wlc_surface *surface, bool state)
{
   if (!surface || surface->synchronized)
      return;

   surface->parent_synchronized = state;

   wlc_resource *r;
   chck_iter_pool_for_each(&surface->subsurface_list, r)
      recursive_set_subsurface_parent_sync_state(convert_from_wlc_resource(*r, "surface"), state);
}

static void
wl_cb_subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
{
   (void)client;

   struct wlc_surface *surface;
   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))
      return;

   if (surface) {
      surface->synchronized = true;
      recursive_set_subsurface_parent_sync_state(surface, true);
   }
}

static void
wl_cb_subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
{
   (void)client;

   struct wlc_surface *surface;
   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))
      return;

   if (surface) {
      surface->synchronized = false;
      recursive_set_subsurface_parent_sync_state(surface, false);

      struct wlc_surface *parent = convert_from_wlc_resource(surface->parent, "surface");

      if (parent && !parent->synchronized && !parent->parent_synchronized)
         wlc_surface_commit(surface);
   }
}

static const struct wl_subsurface_interface wl_subsurface_implementation = {
   .destroy = wlc_cb_resource_destructor,
   .set_position = wl_cb_subsurface_set_position,
   .place_above = wl_cb_subsurface_place_above,
   .place_below = wl_cb_subsurface_place_below,
   .set_sync = wl_cb_subsurface_set_sync,
   .set_desync = wl_cb_subsurface_set_desync
};

static void
wl_cb_subcompositor_get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource)
{
   struct wlc_compositor *compositor;
   if (!(compositor = wl_resource_get_user_data(resource)))
      return;

   wlc_resource surface = wlc_resource_from_wl_resource(surface_resource);
   wlc_resource parent = wlc_resource_from_wl_resource(parent_resource);

   if (surface == parent) {
      wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "wl_surface@%d cannot be its own parent", wl_resource_get_id(surface_resource));
      return;
   }

   wlc_resource r;
   if (!(r = wlc_resource_create(&compositor->subsurfaces, client, &wl_subsurface_interface, wl_resource_get_version(resource), 1, id)))
      return;

   wlc_resource_implement(r, &wl_subsurface_implementation, (void*)surface);
   wlc_surface_set_parent(convert_from_wlc_resource(surface, "surface"), convert_from_wlc_resource(parent, "surface"));
}

static void
wl_cb_subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
{
   (void)client;
   wl_resource_destroy(resource);
}

static const struct wl_subcompositor_interface wl_subcompositor_implementation = {
   .destroy = wl_cb_subcompositor_destroy,
   .get_subsurface = wl_cb_subcompositor_get_subsurface
};

static void
wl_subcompositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
   struct wl_resource *resource;
   if (!(resource = wl_resource_create_checked(client, &wl_subcompositor_interface, version, 1, id)))
      return;

   wl_resource_set_implementation(resource, &wl_subcompositor_implementation, data, NULL);
}

static void
wl_cb_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
{
   struct wlc_compositor *compositor;
   if (!(compositor = wl_resource_get_user_data(resource)))
      return;

   wlc_resource r;
   if (!(r = wlc_resource_create(&compositor->surfaces, client, &wl_surface_interface, wl_resource_get_version(resource), 3, id)))
      return;

   wlc_resource_implement(r, wlc_surface_implementation(), compositor);

   struct wlc_surface_event ev = { .surface = convert_from_wlc_resource(r, "surface"), .type = WLC_SURFACE_EVENT_CREATED };
   wl_signal_emit(&wlc_system_signals()->surface, &ev);
}

static void
wl_cb_region_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
{
   struct wlc_compositor *compositor;
   if (!(compositor = wl_resource_get_user_data(resource)))
      return;

   wlc_resource r;
   if (!(r = wlc_resource_create(&compositor->regions, client, &wl_region_interface, wl_resource_get_version(resource), 3, id)))
      return;

   wlc_resource_implement(r, wlc_region_implementation(), wl_resource_get_user_data(resource));
}

static const struct wl_compositor_interface wl_compositor_implementation = {
   .create_surface = wl_cb_surface_create,
   .create_region = wl_cb_region_create
};

static void
wl_compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
   struct wl_resource *r;
   if (!(r = wl_resource_create_checked(client, &wl_compositor_interface, version, 3, id)))
      return;

   wl_resource_set_implementation(r, &wl_compositor_implementation, data, NULL);
}

static void
cb_idle_vt_switch(void *data)
{
   struct wlc_compositor *compositor = data;
   wlc_fd_activate_vt(compositor->state.vt);
   compositor->state.vt = 0;
   wl_event_source_remove(compositor->state.idle);
   compositor->state.idle = NULL;
}

static void
activate_tty(struct wlc_compositor *compositor)
{
   if (compositor->state.tty != ACTIVATING)
      return;

   compositor->state.tty = IDLE;
   wlc_fd_activate();
}

static void
deactivate_tty(struct wlc_compositor *compositor)
{
   if (compositor->state.tty != DEACTIVATING)
      return;

   // check that all outputs are surfaceless
   struct wlc_output *o;
   chck_pool_for_each(&compositor->outputs.pool, o) {
      if (o->bsurface.display)
         return;
   }

   compositor->state.tty = IDLE;

   if (compositor->state.vt != 0) {
      compositor->state.idle = wl_event_loop_add_idle(wlc_event_loop(), cb_idle_vt_switch, compositor);
   } else {
      wlc_fd_deactivate();
   }
}

static void
respond_tty_activate(struct wlc_compositor *compositor)
{
   if (compositor->state.tty == ACTIVATING) {
      activate_tty(compositor);
   } else if (compositor->state.tty == DEACTIVATING) {
      deactivate_tty(compositor);
   }
}

static void
activate_event(struct wl_listener *listener, void *data)
{
   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.activate));

   struct wlc_activate_event *ev = data;
   if (!ev->active) {
      compositor->state.tty = DEACTIVATING;
      compositor->state.vt = ev->vt;
      chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_set_backend_surface, NULL);
      deactivate_tty(compositor);
   } else {
      compositor->state.tty = ACTIVATING;
      compositor->state.vt = 0;
      activate_tty(compositor);
      wlc_backend_update_outputs(&compositor->backend, &compositor->outputs.pool);
      chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_set_sleep_ptr, false);
   }
}

static void
terminate_event(struct wl_listener *listener, void *data)
{
   (void)data;
   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.terminate));
   wlc_compositor_terminate(compositor);
}

static void
xwayland_event(struct wl_listener *listener, void *data)
{
   bool activated = *(bool*)data;

   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.xwayland));

   if (activated) {
      wlc_xwm(&compositor->xwm, &compositor->seat);
   } else {
      wlc_xwm_release(&compositor->xwm);
   }

   if (!compositor->state.ready) {
      WLC_INTERFACE_EMIT(compositor.ready);
      compositor->state.ready = true;
   }
}

static void
attach_surface_to_view_or_create(struct wlc_compositor *compositor, struct wlc_surface *surface, enum wlc_surface_role type, wlc_resource role)
{
   assert(compositor && surface && type < WLC_SURFACE_ROLE_LAST);

   struct wlc_view *view;
   if (!(view = wlc_compositor_view_for_surface(compositor, surface)))
      return;

   // views without role are ok.
   if (!role)
      return;

   wlc_resource *res[WLC_SURFACE_ROLE_LAST] = {
      &view->shell_surface,
      &view->xdg_surface,
      &view->xdg_toplevel,
      &view->custom_surface,
   };

   const char *name[WLC_SURFACE_ROLE_LAST] = {
      "shell-surface",
      "xdg-surface",
      "xdg-toplevel",
      "custom-surface",
   };

   *res[type] = role;

   if (type != WLC_CUSTOM_SURFACE)
      wl_resource_set_user_data(wl_resource_from_wlc_resource(role, name[type]), (void*)convert_to_wlc_handle(view));
}

static void
attach_popup_to_view_or_create(struct wlc_compositor *compositor, struct wlc_surface *surface, struct wlc_surface *parent, wlc_resource role)
{
   assert(compositor && surface && parent);

   struct wlc_view *view;
   if (!(view = wlc_compositor_view_for_surface(compositor, surface)))
      return;

   view->xdg_popup = role;
   wlc_view_set_parent_ptr(view, convert_from_wlc_handle(parent->view, "view"));
   wlc_view_set_type_ptr(view, WLC_BIT_POPUP, true);
   wl_resource_set_user_data(wl_resource_from_wlc_resource(role, "xdg-popup"), (void*)convert_to_wlc_handle(view));
}

static void
surface_event(struct wl_listener *listener, void *data)
{
   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.surface));

   struct wlc_surface_event *ev = data;
   switch (ev->type) {
      case WLC_SURFACE_EVENT_REQUEST_VIEW_ATTACH:
         attach_surface_to_view_or_create(compositor, ev->surface, ev->attach.type, ev->attach.role);
         break;

      case WLC_SURFACE_EVENT_REQUEST_VIEW_POPUP:
         attach_popup_to_view_or_create(compositor, ev->surface, ev->popup.parent, ev->popup.role);
         break;

      case WLC_SURFACE_EVENT_DESTROYED:
      {
         struct wlc_view *v;
         chck_pool_for_each(&compositor->views.pool, v) {
            if (v->parent == ev->surface->view)
               wlc_view_set_parent_ptr(v, NULL);
         }

         struct wlc_surface *s;
         chck_pool_for_each(&compositor->surfaces.pool, s) {
            if (s->parent == convert_to_wlc_resource(ev->surface))
   if (!(compositor->backend = wlc_backend_init(compositor)))
      goto fail;

   if (!(compositor->context = wlc_context_init(compositor->backend)))
      goto fail;

   if (!(compositor->render = wlc_render_init(compositor->context)))
}

static struct wlc_output*
get_surfaceless_output(struct wlc_compositor *compositor)
{
   struct wlc_output *o;
   chck_pool_for_each(&compositor->outputs.pool, o) {
      if (!o->bsurface.display)
         return o;
   }
   return NULL;
}

static void
active_output(struct wlc_compositor *compositor, struct wlc_output *output)
{
   assert(compositor);

   wlc_dlog(WLC_DBG_FOCUS, "focus output %" PRIuWLC " %" PRIuWLC, compositor->active.output, convert_to_wlc_handle(output));

   if (compositor->active.output == convert_to_wlc_handle(output))
      return;

   if (compositor->active.output)
      WLC_INTERFACE_EMIT(output.focus, compositor->active.output, false);

   wlc_output_schedule_repaint(convert_from_wlc_handle(compositor->active.output, "output"));
   compositor->active.output = convert_to_wlc_handle(output);

   if (compositor->active.output) {
      WLC_INTERFACE_EMIT(output.focus, compositor->active.output, true);
      wlc_output_schedule_repaint(output);
   }
}

static void
add_output(struct wlc_compositor *compositor, struct wlc_backend_surface *bsurface, struct wlc_output_information *info)
{
   assert(compositor && bsurface && info);

   struct wlc_output *output;
   if (!(output = get_surfaceless_output(compositor)))
      output = wlc_handle_create(&compositor->outputs);

   if (!output) {
      wlc_backend_surface_release(bsurface);
      return;
   }

   wlc_output_set_information(output, info);

   if (WLC_INTERFACE_EMIT_EXCEPT(output.created, false, convert_to_wlc_handle(output))) {
      wlc_output_terminate(output);
      return;
   }

   output->state.created = true;

   wlc_output_set_backend_surface(output, bsurface);

   if (!compositor->active.output)
      active_output(compositor, output);

   wlc_output_schedule_repaint(output);
   wlc_log(WLC_LOG_INFO, "Added output (%" PRIuWLC ")", convert_to_wlc_handle(output));
}

static void
remove_output(struct wlc_compositor *compositor, struct wlc_output *output)
{
   assert(compositor && output);

   struct wlc_output *o, *alive = NULL;
   chck_pool_for_each(&compositor->outputs.pool, o) {
      if (!o->bsurface.display || o == output)
         continue;

      alive = o;
      break;
   }

   if (compositor->active.output == convert_to_wlc_handle(output)) {
      compositor->active.output = 0; // make sure we don't redraw
      active_output(compositor, alive);
   }

   WLC_INTERFACE_EMIT(output.destroyed, convert_to_wlc_handle(output));
   wlc_output_set_backend_surface(output, NULL);

   wlc_log(WLC_LOG_INFO, "Removed output (%" PRIuWLC ")", convert_to_wlc_handle(output));

   if (compositor->state.terminating && !alive)
      wlc_compositor_terminate(compositor);
}

static void
output_event(struct wl_listener *listener, void *data)
{
   struct wlc_output_event *ev = data;

   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.output));

   switch (ev->type) {
      case WLC_OUTPUT_EVENT_ADD:
         add_output(compositor, ev->add.bsurface, ev->add.info);
         break;

      case WLC_OUTPUT_EVENT_ACTIVE:
         active_output(compositor, ev->active.output);
         break;

      case WLC_OUTPUT_EVENT_REMOVE:
         remove_output(compositor, ev->remove.output);
         break;

      case WLC_OUTPUT_EVENT_UPDATE:
         wlc_backend_update_outputs(&compositor->backend, &compositor->outputs.pool);
         break;

      case WLC_OUTPUT_EVENT_SURFACE:
         respond_tty_activate(compositor);
         break;
   }
}

static void
focus_event(struct wl_listener *listener, void *data)
{
   struct wlc_compositor *compositor;
   except(compositor = wl_container_of(listener, compositor, listener.focus));

   struct wlc_focus_event *ev = data;
   switch (ev->type) {
      case WLC_FOCUS_EVENT_OUTPUT:
         active_output(compositor, ev->output);
         break;

      default: break;
   }
}

struct wlc_view*
wlc_compositor_view_for_surface(struct wlc_compositor *compositor, struct wlc_surface *surface)
{
   struct wlc_view *view;
   if (!(view = convert_from_wlc_handle(surface->view, "view")) && !(view = wlc_handle_create(&compositor->views)))
      return NULL;

   wlc_surface_attach_to_output(surface, convert_from_wlc_handle(compositor->active.output, "output"), wlc_surface_get_buffer(surface));
   wlc_surface_attach_to_view(surface, view);
   return view;
}

// XXX: We do not currently expose compositor to public API.
//      So we use static variable here for some public api functions.
//
//      Never use this variable anywhere else.
static struct wlc_compositor *_g_compositor;

WLC_API const wlc_handle*
wlc_get_outputs(size_t *out_memb)
{
   assert(_g_compositor);

   if (out_memb)
      *out_memb = 0;

   // Allocate linear array which we then return
   free(_g_compositor->tmp.outputs);
   if (!(_g_compositor->tmp.outputs = chck_malloc_mul_of(_g_compositor->outputs.pool.items.count, sizeof(wlc_handle))))
      return NULL;

   {
      size_t i = 0;
      struct wlc_output *o;
      chck_pool_for_each(&_g_compositor->outputs.pool, o)
         _g_compositor->tmp.outputs[i++] = convert_to_wlc_handle(o);
   }

   if (out_memb)
      *out_memb = _g_compositor->outputs.pool.items.count;

   return _g_compositor->tmp.outputs;
}

WLC_API WLC_PURE wlc_handle
wlc_get_focused_output(void)
{
   assert(_g_compositor);
   return _g_compositor->active.output;
}

WLC_API WLC_PURE struct xkb_state*
wlc_keyboard_get_xkb_state(void)
{
   assert(_g_compositor);
   return _g_compositor->seat.keyboard.state.xkb;
}

WLC_API WLC_PURE struct xkb_keymap*
wlc_keyboard_get_xkb_keymap(void)
{
   assert(_g_compositor);
   return _g_compositor->seat.keymap.keymap;
}

WLC_API const uint32_t*
wlc_keyboard_get_current_keys(size_t *out_memb)
{
   assert(_g_compositor);
   return chck_iter_pool_to_c_array(&_g_compositor->seat.keyboard.keys, out_memb);
}

WLC_API uint32_t
wlc_keyboard_get_keysym_for_key(uint32_t key, const struct wlc_modifiers *modifiers)
{
   assert(_g_compositor);
   return wlc_keyboard_get_keysym_for_key_ptr(&_g_compositor->seat.keyboard, key, modifiers);
}

WLC_API uint32_t
wlc_keyboard_get_utf32_for_key(uint32_t key, const struct wlc_modifiers *modifiers)
{
   assert(_g_compositor);
   return wlc_keyboard_get_utf32_for_key_ptr(&_g_compositor->seat.keyboard, key, modifiers);
}

WLC_API void
wlc_pointer_get_position_v2(double *out_x, double *out_y)
{
   assert(_g_compositor && out_x && out_y);
   *out_x = _g_compositor->seat.pointer.pos.x;
   *out_y = _g_compositor->seat.pointer.pos.y;
}

WLC_API void
wlc_pointer_get_position(struct wlc_point *out_position)
{
   assert(_g_compositor && out_position);
   out_position->x = _g_compositor->seat.pointer.pos.x;
   out_position->y = _g_compositor->seat.pointer.pos.y;
}

WLC_API void
wlc_pointer_set_position_v2(double x, double y)
{
   assert(_g_compositor);
   _g_compositor->seat.pointer.pos.x = x;
   _g_compositor->seat.pointer.pos.y = y;
}

WLC_API void
wlc_pointer_set_position(const struct wlc_point *position)
{
   assert(_g_compositor && position);
   _g_compositor->seat.pointer.pos.x = position->x;
   _g_compositor->seat.pointer.pos.y = position->y;
}

void
wlc_compositor_terminate(struct wlc_compositor *compositor)
{
   if (!compositor || !_g_compositor)
      return;

   if (!compositor->state.terminating) {
      wlc_log(WLC_LOG_INFO, "Terminating compositor...");
      compositor->state.terminating = true;

      WLC_INTERFACE_EMIT(compositor.terminate);

      if (compositor->outputs.pool.items.count > 0) {
         chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_terminate);
         return;
      }
   }

   wlc_log(WLC_LOG_INFO, "Compositor terminated...");
   wl_signal_emit(&wlc_system_signals()->compositor, NULL);
}

bool
wlc_compositor_is_good(struct wlc_compositor *compositor)
{
   assert(compositor);

   struct wlc_output *o;
   chck_pool_for_each(&compositor->outputs.pool, o) {
      if (o->context.context)
         return true;
   }

   // There were no outputs or all outputs failed context creation
   // wlc.c does this check and will return false in init
   // XXX: Skip this check when we request headless mode
   return false;
}

void
wlc_compositor_release(struct wlc_compositor *compositor)
{
   if (!compositor || !_g_compositor)
      return;

   wl_list_remove(&compositor->listener.activate.link);
   wl_list_remove(&compositor->listener.terminate.link);
   wl_list_remove(&compositor->listener.xwayland.link);
   wl_list_remove(&compositor->listener.surface.link);
   wl_list_remove(&compositor->listener.output.link);
   wl_list_remove(&compositor->listener.focus.link);

   wlc_backend_release(&compositor->backend);
   wlc_shell_release(&compositor->shell);
   wlc_xdg_shell_release(&compositor->xdg_shell);
   wlc_custom_shell_release(&compositor->custom_shell);
   wlc_seat_release(&compositor->seat);

   if (compositor->wl.subcompositor)
      wl_global_destroy(compositor->wl.subcompositor);

   if (compositor->wl.compositor)
      wl_global_destroy(compositor->wl.compositor);

   free(_g_compositor->tmp.outputs);
   wlc_source_release(&compositor->outputs);
   wlc_source_release(&compositor->views);
   wlc_source_release(&compositor->surfaces);
   wlc_source_release(&compositor->subsurfaces);
   wlc_source_release(&compositor->regions);

   memset(compositor, 0, sizeof(struct wlc_compositor));
   _g_compositor = NULL;
}

bool
wlc_compositor(struct wlc_compositor *compositor)
{
   assert(wlc_display() && wlc_event_loop() && !_g_compositor);
   memset(compositor, 0, sizeof(struct wlc_compositor));

   if (!wlc_display() || !wlc_event_loop() || _g_compositor) {
      wlc_log(WLC_LOG_ERROR, "wlc_compositor called before wlc_init()");
      abort();
   }

   _g_compositor = compositor;

   compositor->listener.activate.notify = activate_event;
   compositor->listener.terminate.notify = terminate_event;
   compositor->listener.xwayland.notify = xwayland_event;
   compositor->listener.surface.notify = surface_event;
   compositor->listener.output.notify = output_event;
   compositor->listener.focus.notify = focus_event;
   wl_signal_add(&wlc_system_signals()->activate, &compositor->listener.activate);
   wl_signal_add(&wlc_system_signals()->terminate, &compositor->listener.terminate);
   wl_signal_add(&wlc_system_signals()->xwayland, &compositor->listener.xwayland);
   wl_signal_add(&wlc_system_signals()->surface, &compositor->listener.surface);
   wl_signal_add(&wlc_system_signals()->output, &compositor->listener.output);
   wl_signal_add(&wlc_system_signals()->focus, &compositor->listener.focus);

   if (!wlc_source(&compositor->outputs, "output", wlc_output, wlc_output_release, 4, sizeof(struct wlc_output)) ||
       !wlc_source(&compositor->views, "view", wlc_view, wlc_view_release, 32, sizeof(struct wlc_view)) ||
       !wlc_source(&compositor->surfaces, "surface", wlc_surface, wlc_surface_release, 32, sizeof(struct wlc_surface)) ||
       !wlc_source(&compositor->subsurfaces, "subsurface", NULL, NULL, 32, sizeof(struct wlc_resource)) ||
       !wlc_source(&compositor->regions, "region", NULL, wlc_region_release, 32, sizeof(struct wlc_region)))
      goto fail;

   if (!(compositor->wl.compositor = wl_global_create(wlc_display(), &wl_compositor_interface, 3, compositor, wl_compositor_bind)))
      goto compositor_interface_fail;

   if (!(compositor->wl.subcompositor = wl_global_create(wlc_display(), &wl_subcompositor_interface, 1, compositor, wl_subcompositor_bind)))
      goto subcompositor_interface_fail;

   if (!wlc_seat(&compositor->seat) ||
       !wlc_shell(&compositor->shell) ||
       !wlc_xdg_shell(&compositor->xdg_shell) ||
       !wlc_custom_shell(&compositor->custom_shell) ||
       !wlc_backend(&compositor->backend))
      goto fail;

   return true;

compositor_interface_fail:
   wlc_log(WLC_LOG_WARN, "Failed to bind compositor interface");
   goto fail;
subcompositor_interface_fail:
   wlc_log(WLC_LOG_WARN, "Failed to bind subcompositor interface");
   goto fail;
fail:
   wlc_compositor_release(compositor);
   return false;
}

<MSG> Basic EGL support.

TODO: Need to use the damaged swap extension.
And fallback to other heuristics when it's not available for flicker
free updates.

<DFF> @@ -402,7 +402,7 @@ wlc_compositor_new(void)
    if (!(compositor->backend = wlc_backend_init(compositor)))
       goto fail;
 
-   if (!(compositor->context = wlc_context_init(compositor->backend)))
+   if (!(compositor->context = wlc_context_init(compositor, compositor->backend)))
       goto fail;
 
    if (!(compositor->render = wlc_render_init(compositor->context)))

{'commit': 'diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c\nindex 71f3891..5a81cf0 100644\n--- a/src/compositor/compositor.c\n+++ b/src/compositor/compositor.c\n@@ -402,7 +402,7 @@ wlc_compositor_new(void)\n    if (!(compositor->backend = wlc_backend_init(compositor)))\n       goto fail;\n \n-   if (!(compositor->context = wlc_context_init(compositor->backend)))\n+   if (!(compositor->context = wlc_context_init(compositor, compositor->backend)))\n       goto fail;\n \n    if (!(compositor->render = wlc_render_init(compositor->context)))\ndiff --git a/src/compositor/surface.h b/src/compositor/surface.h\nindex 546af8f..6b81a45 100644\n--- a/src/compositor/surface.h\n+++ b/src/compositor/surface.h\n@@ -31,7 +31,13 @@ struct wlc_surface {\n     * "Texture" as we use OpenGL terminology, but can be id to anything.\n     * Managed by the renderer.\n     */\n-   uint32_t texture;\n+   uint32_t textures[3];\n+\n+   /**\n+    * Images, contains hw surfaces that can be anything (For example EGL KHR Images in EGL/gles2 renderer).\n+    * Managed by the renderer.\n+    */\n+   void *images[3];\n \n    int32_t width, height;\n    bool created;\ndiff --git a/src/context/context.c b/src/context/context.c\nindex edb4c63..e43dd2e 100644\n--- a/src/context/context.c\n+++ b/src/context/context.c\n@@ -16,20 +16,20 @@ wlc_context_terminate(struct wlc_context *context)\n }\n \n struct wlc_context*\n-wlc_context_init(struct wlc_backend *backend)\n+wlc_context_init(struct wlc_compositor *compositor, struct wlc_backend *backend)\n {\n    struct wlc_context *context;\n \n    if (!(context = calloc(1, sizeof(struct wlc_context))))\n       goto out_of_memory;\n \n-   bool (*init[])(struct wlc_backend*, struct wlc_context*) = {\n+   bool (*init[])(struct wlc_compositor*, struct wlc_backend*, struct wlc_context*) = {\n       wlc_egl_init,\n       NULL\n    };\n \n    for (int i = 0; init[i]; ++i)\n-      if (init[i](backend, context))\n+      if (init[i](compositor, backend, context))\n          return context;\n \n    fprintf(stderr, "-!- Could not initialize any context\\n");\ndiff --git a/src/context/context.h b/src/context/context.h\nindex 02d5b94..e4eb06e 100644\n--- a/src/context/context.h\n+++ b/src/context/context.h\n@@ -2,6 +2,7 @@\n #define _WLC_CONTEXT_H_\n \n struct wlc_backend;\n+struct wlc_compositor;\n \n struct wlc_context {\n    void (*terminate)(void);\n@@ -12,6 +13,6 @@ struct wlc_context {\n };\n \n void wlc_context_terminate(struct wlc_context *context);\n-struct wlc_context* wlc_context_init(struct wlc_backend *backend);\n+struct wlc_context* wlc_context_init(struct wlc_compositor *compositor, struct wlc_backend *backend);\n \n #endif /* _WLC_CONTEXT_H_ */\ndiff --git a/src/context/egl.c b/src/context/egl.c\nindex 695cc51..5aac8e8 100644\n--- a/src/context/egl.c\n+++ b/src/context/egl.c\n@@ -1,6 +1,7 @@\n #include "egl.h"\n #include "context.h"\n \n+#include "compositor/compositor.h"\n #include "backend/backend.h"\n \n #include <stdio.h>\n@@ -10,9 +11,13 @@\n #include <assert.h>\n \n #include <EGL/egl.h>\n+#include <EGL/eglext.h>\n+\n+#include <wayland-server.h>\n \n static struct {\n    struct wlc_backend *backend;\n+   struct wl_display *wl_display;\n \n    EGLDisplay display;\n    EGLContext context;\n@@ -37,6 +42,14 @@ static struct {\n       EGLBoolean (*eglDestroySurface)(EGLDisplay, EGLSurface);\n       EGLBoolean (*eglMakeCurrent)(EGLDisplay, EGLSurface, EGLSurface, EGLContext);\n       EGLBoolean (*eglSwapBuffers)(EGLDisplay, EGLSurface);\n+      EGLBoolean (*eglSwapInterval)(EGLDisplay, EGLint);\n+\n+      // Needed for EGL hw surfaces\n+      PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;\n+      PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;\n+      PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL;\n+      PFNEGLUNBINDWAYLANDDISPLAYWL eglUnbindWaylandDisplayWL;\n+      PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;\n    } api;\n } egl;\n \n@@ -78,6 +91,15 @@ egl_load(void)\n       goto function_pointer_exception;\n    if (!load(eglSwapBuffers))\n       goto function_pointer_exception;\n+   if (!load(eglSwapInterval))\n+      goto function_pointer_exception;\n+\n+   // EGL surfaces won\'t work without these\n+   load(eglCreateImageKHR);\n+   load(eglDestroyImageKHR);\n+   load(eglBindWaylandDisplayWL);\n+   load(eglUnbindWaylandDisplayWL);\n+   load(eglQueryWaylandBufferWL);\n \n #undef load\n \n@@ -181,6 +203,9 @@ terminate(void)\n       if (egl.context)\n          egl.api.eglDestroyContext(egl.display, egl.context);\n \n+      if (egl.api.eglUnbindWaylandDisplayWL && egl.wl_display)\n+         egl.api.eglUnbindWaylandDisplayWL(egl.display, egl.wl_display);\n+\n       egl.api.eglTerminate(egl.display);\n    }\n \n@@ -190,8 +215,32 @@ terminate(void)\n    memset(&egl, 0, sizeof(egl));\n }\n \n+EGLBoolean\n+wlc_egl_query_buffer(struct wl_resource *buffer, EGLint attribute, EGLint *value)\n+{\n+   if (egl.api.eglQueryWaylandBufferWL)\n+      return egl.api.eglQueryWaylandBufferWL(egl.display, buffer, attribute, value);\n+   return EGL_FALSE;\n+}\n+\n+EGLImageKHR\n+wlc_egl_create_image(EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)\n+{\n+   if (egl.api.eglCreateImageKHR)\n+      return egl.api.eglCreateImageKHR(egl.display, egl.context, target, buffer, attrib_list);\n+   return NULL;\n+}\n+\n+EGLBoolean\n+wlc_egl_destroy_image(EGLImageKHR image)\n+{\n+   if (egl.api.eglDestroyImageKHR)\n+      return egl.api.eglDestroyImageKHR(egl.display, image);\n+   return EGL_FALSE;\n+}\n+\n bool\n-wlc_egl_init(struct wlc_backend *backend, struct wlc_context *out_context)\n+wlc_egl_init(struct wlc_compositor *compositor, struct wlc_backend *backend, struct wlc_context *out_context)\n {\n    if (!egl_load())\n       goto fail;\n@@ -224,6 +273,14 @@ wlc_egl_init(struct wlc_backend *backend, struct wlc_context *out_context)\n    if (!egl.api.eglBindAPI(EGL_OPENGL_ES_API))\n       goto egl_fail;\n \n+   const char *str;\n+   str = egl.api.eglQueryString(egl.display, EGL_VERSION);\n+   fprintf(stdout, "EGL version: %s\\n", str ? str : "(null)");\n+   str = egl.api.eglQueryString(egl.display, EGL_VENDOR);\n+   fprintf(stdout, "EGL vendor: %s\\n", str ? str : "(null)");\n+   str = egl.api.eglQueryString(egl.display, EGL_CLIENT_APIS);\n+   fprintf(stdout, "EGL client APIs: %s\\n", str ? str : "(null)");\n+\n    egl.extensions = egl.api.eglQueryString(egl.display, EGL_EXTENSIONS);\n \n    EGLint n;\n@@ -239,6 +296,13 @@ wlc_egl_init(struct wlc_backend *backend, struct wlc_context *out_context)\n    if (!egl.api.eglMakeCurrent(egl.display, egl.surface, egl.surface, egl.context))\n       goto egl_fail;\n \n+   if (egl.api.eglBindWaylandDisplayWL && egl.api.eglBindWaylandDisplayWL(egl.display, compositor->display))\n+      egl.wl_display = compositor->display;\n+\n+   egl.api.eglSwapInterval(egl.display, 1);\n+\n+   wl_display_add_shm_format(compositor->display, WL_SHM_FORMAT_RGB565);\n+\n    egl.has_current = true;\n \n    out_context->terminate = terminate;\ndiff --git a/src/context/egl.h b/src/context/egl.h\nindex 5dd0e4e..6d79040 100644\n--- a/src/context/egl.h\n+++ b/src/context/egl.h\n@@ -3,9 +3,17 @@\n \n #include <stdbool.h>\n \n+#include <EGL/egl.h>\n+#include <EGL/eglext.h>\n+\n+struct wlc_compositor;\n struct wlc_context;\n struct wlc_backend;\n+struct wl_resource;\n \n-bool wlc_egl_init(struct wlc_backend *backend, struct wlc_context *out_context);\n+EGLBoolean wlc_egl_query_buffer(struct wl_resource *buffer, EGLint attribute, EGLint *value);\n+EGLImageKHR wlc_egl_create_image(EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);\n+EGLBoolean wlc_egl_destroy_image(EGLImageKHR image);\n+bool wlc_egl_init(struct wlc_compositor *compositor, struct wlc_backend *backend, struct wlc_context *out_context);\n \n #endif /* _WLC_EGL_H_ */\ndiff --git a/src/render/gles2.c b/src/render/gles2.c\nindex c5b98cb..dfb1026 100644\n--- a/src/render/gles2.c\n+++ b/src/render/gles2.c\n@@ -1,6 +1,7 @@\n #include "gles2.h"\n #include "render.h"\n \n+#include "context/egl.h"\n #include "context/context.h"\n #include "compositor/view.h"\n #include "compositor/surface.h"\n@@ -65,9 +66,12 @@ static struct {\n       void (*glGenTextures)(GLsizei, GLuint*);\n       void (*glDeleteTextures)(GLsizei, GLuint*);\n       void (*glBindTexture)(GLenum, GLuint);\n+      void (*glActiveTexture)(GLenum);\n       void (*glTexParameteri)(GLenum, GLenum, GLenum);\n       void (*glPixelStorei)(GLenum, GLint);\n       void (*glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);\n+\n+      PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;\n    } api;\n } gl;\n \n@@ -135,6 +139,8 @@ gles2_load(void)\n       goto function_pointer_exception;\n    if (!(load(glBindTexture)))\n       goto function_pointer_exception;\n+   if (!(load(glActiveTexture)))\n+      goto function_pointer_exception;\n    if (!(load(glTexParameteri)))\n       goto function_pointer_exception;\n    if (!(load(glPixelStorei)))\n@@ -142,6 +148,9 @@ gles2_load(void)\n    if (!(load(glTexImage2D)))\n       goto function_pointer_exception;\n \n+   // Needed for EGL hw surfaces\n+   load(glEGLImageTargetTexture2DOES);\n+\n #undef load\n \n    return true;\n@@ -174,6 +183,48 @@ has_extension(const char *extension)\n }\n #endif\n \n+static void\n+surface_gen_textures(struct wlc_surface *surface, const int num_textures)\n+{\n+   for (int i = 0; i < num_textures; ++i) {\n+      if (surface->textures[i])\n+         continue;\n+\n+      gl.api.glGenTextures(1, &surface->textures[i]);\n+      gl.api.glBindTexture(GL_TEXTURE_2D, surface->textures[i]);\n+      gl.api.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n+      gl.api.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n+   }\n+}\n+\n+static void\n+surface_flush_textures(struct wlc_surface *surface)\n+{\n+   for (int i = 0; i < 3; ++i) {\n+      if (surface->textures[i])\n+         gl.api.glDeleteTextures(1, &surface->textures[i]);\n+   }\n+\n+   memset(surface->textures, 0, sizeof(surface->textures));\n+}\n+\n+static void\n+surface_flush_images(struct wlc_surface *surface)\n+{\n+   for (int i = 0; i < 3; ++i) {\n+      if (surface->images[i])\n+         wlc_egl_destroy_image(surface->images[i]);\n+   }\n+\n+   memset(surface->images, 0, sizeof(surface->images));\n+}\n+\n+static void\n+surface_destroy(struct wlc_surface *surface)\n+{\n+   surface_flush_textures(surface);\n+}\n+\n static void\n shm_attach(struct wlc_surface *surface, struct wlc_buffer *buffer, struct wl_shm_buffer *shm_buffer)\n {\n@@ -207,15 +258,8 @@ shm_attach(struct wlc_surface *surface, struct wlc_buffer *buffer, struct wl_shm\n          return;\n    }\n \n-   if (!surface->texture) {\n-      gl.api.glGenTextures(1, &surface->texture);\n-      gl.api.glBindTexture(GL_TEXTURE_2D, surface->texture);\n-      gl.api.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n-      gl.api.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n-   } else {\n-      gl.api.glBindTexture(GL_TEXTURE_2D, surface->texture);\n-   }\n-\n+   surface_gen_textures(surface, 1);\n+   gl.api.glBindTexture(GL_TEXTURE_2D, surface->textures[0]);\n    gl.api.glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);\n    gl.api.glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);\n    gl.api.glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);\n@@ -226,31 +270,84 @@ shm_attach(struct wlc_surface *surface, struct wlc_buffer *buffer, struct wl_shm\n    wl_resource_queue_event(buffer->resource, WL_BUFFER_RELEASE);\n }\n \n+static void\n+egl_attach(struct wlc_surface *surface, struct wlc_buffer *buffer, uint32_t format)\n+{\n+   buffer->legacy_buffer = (struct wlc_buffer*)buffer->resource;\n+   wlc_egl_query_buffer(buffer->legacy_buffer, EGL_WIDTH, &buffer->width);\n+   wlc_egl_query_buffer(buffer->legacy_buffer, EGL_HEIGHT, &buffer->height);\n+   wlc_egl_query_buffer(buffer->legacy_buffer, EGL_WAYLAND_Y_INVERTED_WL, (EGLint*)&buffer->y_inverted);\n+\n+   int num_planes;\n+   GLenum target = GL_TEXTURE_2D;\n+   switch (format) {\n+      case EGL_TEXTURE_RGB:\n+      case EGL_TEXTURE_RGBA:\n+      default:\n+         num_planes = 1;\n+         // gs->shader = &gr->texture_shader_rgba;\n+         break;\n+      case 0x31DA:\n+         num_planes = 1;\n+         // gs->target = GL_TEXTURE_EXTERNAL_OES;\n+         // gs->shader = &gr->texture_shader_egl_external;\n+         break;\n+      case EGL_TEXTURE_Y_UV_WL:\n+         num_planes = 2;\n+         // gs->shader = &gr->texture_shader_y_uv;\n+         break;\n+      case EGL_TEXTURE_Y_U_V_WL:\n+         num_planes = 3;\n+         // gs->shader = &gr->texture_shader_y_u_v;\n+         break;\n+      case EGL_TEXTURE_Y_XUXV_WL:\n+         num_planes = 2;\n+         // gs->shader = &gr->texture_shader_y_xuxv;\n+         break;\n+   }\n+\n+   if (num_planes > 3) {\n+      fprintf(stderr, "planes > 3 in egl surfaces not supported, nor should be possible\\n");\n+      return;\n+   }\n+\n+   surface_flush_images(surface);\n+   surface_gen_textures(surface, num_planes);\n+\n+   for (int i = 0; i < num_planes; ++i) {\n+      EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, i, EGL_NONE };\n+      if (!(surface->images[i] = wlc_egl_create_image(EGL_WAYLAND_BUFFER_WL, buffer->legacy_buffer, attribs)))\n+         continue;\n+\n+      gl.api.glActiveTexture(GL_TEXTURE0 + i);\n+      gl.api.glBindTexture(target, surface->textures[i]);\n+      gl.api.glEGLImageTargetTexture2DOES(target, surface->images[i]);\n+   }\n+\n+   wl_resource_queue_event(buffer->resource, WL_BUFFER_RELEASE);\n+}\n+\n static void\n surface_attach(struct wlc_surface *surface, struct wlc_buffer *buffer)\n {\n    if (!buffer) {\n-      /* TODO: cleanup */\n+      surface_flush_images(surface);\n+      surface_flush_textures(surface);\n       return;\n    }\n \n+   int format;\n    struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(buffer->resource);\n    if (shm_buffer) {\n       shm_attach(surface, buffer, shm_buffer);\n-   } else if (1) {\n-      /* EGL buffer */\n+   } else if (gl.api.glEGLImageTargetTexture2DOES && wlc_egl_query_buffer((void*)buffer->resource, EGL_TEXTURE_FORMAT, &format)) {\n+      egl_attach(surface, buffer, format);\n    } else {\n       /* unknown buffer */\n+      puts("unknown buffer");\n    }\n }\n \n-static void\n-surface_destroy(struct wlc_surface *surface)\n-{\n-   if (surface->texture)\n-      gl.api.glDeleteTextures(1, &surface->texture);\n-}\n-\n static void\n view_render(struct wlc_view *view)\n {\n@@ -274,7 +371,14 @@ view_render(struct wlc_view *view)\n    };\n \n    gl.api.glUniform1f(gl.uniforms[UNIFORM_ALPHA], (view->state & WLC_BIT_ACTIVATED ? 1.0f : 0.5f));\n-   gl.api.glBindTexture(GL_TEXTURE_2D, view->surface->texture);\n+\n+   for (int i = 0; i < 3; ++i) {\n+      if (!view->surface->textures[i])\n+         break;\n+\n+      gl.api.glActiveTexture(GL_TEXTURE0 + i);\n+      gl.api.glBindTexture(GL_TEXTURE_2D, view->surface->textures[i]);\n+   }\n \n    if (view->surface->width != b.w || view->surface->height != b.h) {\n       gl.api.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n', 'commit_subject': 'Basic EGL support.', 'repo_name': 'Cloudef/wlc', 'committer': {'name': 'Jari Vetoniemi', 'email': 'a17f2b1885dfaf9e67dbc84d19e588692d50291e@gmail.com', 'time_sec': '1412283460', 'tz_offset': '180', 'date': {'seconds': '1412283460'}}, 'commit_tree': '8391dc199470972a6b0366acc7bbbafaadd83a3f', 'commit_message': "Basic EGL support.\n\nTODO: Need to use the damaged swap extension.\nAnd fallback to other heuristics when it's not available for flicker\nfree updates.\n", 'language_name': 'C', 'license': 'mit', 'hunks': '@@ -402,7 +402,7 @@ wlc_compositor_new(void)\n    if (!(compositor->backend = wlc_backend_init(compositor)))\n       goto fail;\n \n-   if (!(compositor->context = wlc_context_init(compositor->backend)))\n+   if (!(compositor->context = wlc_context_init(compositor, compositor->backend)))\n       goto fail;\n \n    if (!(compositor->render = wlc_render_init(compositor->context)))\n', 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/src/compositor/compositor.c', 'tgt_file': 'b/src/compositor/compositor.c', 'file_extension': '.c', 'before_file': '#include <assert.h>\n#include <chck/overflow/overflow.h>\n#include "internal.h"\n#include "macros.h"\n#include "visibility.h"\n#include "compositor.h"\n#include "output.h"\n#include "view.h"\n#include "session/fd.h"\n#include "resources/resources.h"\n#include "resources/types/region.h"\n#include "resources/types/surface.h"\n\nstatic void\nwl_cb_subsurface_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y)\n{\n   (void)client;\n   struct wlc_surface *surface;\n   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))\n      return;\n\n   surface->pending.subsurface_position = (struct wlc_point){x, y};\n}\n\nstatic void\nrestack_subsurface_relative_to(wlc_resource surface, wlc_resource sibling, int32_t offset)\n{\n\n   size_t surface_idx = (size_t)~0, target_idx = (size_t)~0;\n\n   struct wlc_surface *surface_ptr;\n   if (!(surface_ptr = convert_from_wlc_resource(surface, "surface")))\n      return;\n\n   struct wlc_surface *parent = convert_from_wlc_resource(surface_ptr->parent, "surface");\n   wlc_resource *sub;\n   chck_iter_pool_for_each(&parent->subsurface_list, sub) {\n      if (*sub == surface)\n         surface_idx = _I - 1;\n\n      if (*sub == sibling)\n         target_idx = _I - 1;\n   }\n\n   if (surface_idx == (size_t)~0 || target_idx == (size_t)~0)\n      return;\n\n   if (surface_idx < target_idx)\n      --target_idx;\n\n   chck_iter_pool_remove(&parent->subsurface_list, surface_idx);\n   chck_iter_pool_insert(&parent->subsurface_list, target_idx + offset, &surface);\n}\n\nstatic void\nwl_cb_subsurface_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)\n{\n   (void)client, (void)resource, (void)sibling_resource;\n\n   wlc_resource surface_res = (wlc_resource)wl_resource_get_user_data(resource);\n   wlc_resource sibling_res = (wlc_resource)wl_resource_get_user_data(sibling_resource);\n\n   restack_subsurface_relative_to(surface_res, sibling_res, 0);\n}\n\nstatic void\nwl_cb_subsurface_place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)\n{\n   (void)client, (void)resource, (void)sibling_resource;\n\n   wlc_resource surface_res = (wlc_resource)wl_resource_get_user_data(resource);\n   wlc_resource sibling_res = (wlc_resource)wl_resource_get_user_data(sibling_resource);\n\n   restack_subsurface_relative_to(surface_res, sibling_res, 1);\n}\n\nstatic void\nrecursive_set_subsurface_parent_sync_state(struct wlc_surface *surface, bool state)\n{\n   if (!surface || surface->synchronized)\n      return;\n\n   surface->parent_synchronized = state;\n\n   wlc_resource *r;\n   chck_iter_pool_for_each(&surface->subsurface_list, r)\n      recursive_set_subsurface_parent_sync_state(convert_from_wlc_resource(*r, "surface"), state);\n}\n\nstatic void\nwl_cb_subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)\n{\n   (void)client;\n\n   struct wlc_surface *surface;\n   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))\n      return;\n\n   if (surface) {\n      surface->synchronized = true;\n      recursive_set_subsurface_parent_sync_state(surface, true);\n   }\n}\n\nstatic void\nwl_cb_subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)\n{\n   (void)client;\n\n   struct wlc_surface *surface;\n   if (!(surface = convert_from_wlc_resource((wlc_resource)wl_resource_get_user_data(resource), "surface")))\n      return;\n\n   if (surface) {\n      surface->synchronized = false;\n      recursive_set_subsurface_parent_sync_state(surface, false);\n\n      struct wlc_surface *parent = convert_from_wlc_resource(surface->parent, "surface");\n\n      if (parent && !parent->synchronized && !parent->parent_synchronized)\n         wlc_surface_commit(surface);\n   }\n}\n\nstatic const struct wl_subsurface_interface wl_subsurface_implementation = {\n   .destroy = wlc_cb_resource_destructor,\n   .set_position = wl_cb_subsurface_set_position,\n   .place_above = wl_cb_subsurface_place_above,\n   .place_below = wl_cb_subsurface_place_below,\n   .set_sync = wl_cb_subsurface_set_sync,\n   .set_desync = wl_cb_subsurface_set_desync\n};\n\nstatic void\nwl_cb_subcompositor_get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource)\n{\n   struct wlc_compositor *compositor;\n   if (!(compositor = wl_resource_get_user_data(resource)))\n      return;\n\n   wlc_resource surface = wlc_resource_from_wl_resource(surface_resource);\n   wlc_resource parent = wlc_resource_from_wl_resource(parent_resource);\n\n   if (surface == parent) {\n      wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "wl_surface@%d cannot be its own parent", wl_resource_get_id(surface_resource));\n      return;\n   }\n\n   wlc_resource r;\n   if (!(r = wlc_resource_create(&compositor->subsurfaces, client, &wl_subsurface_interface, wl_resource_get_version(resource), 1, id)))\n      return;\n\n   wlc_resource_implement(r, &wl_subsurface_implementation, (void*)surface);\n   wlc_surface_set_parent(convert_from_wlc_resource(surface, "surface"), convert_from_wlc_resource(parent, "surface"));\n}\n\nstatic void\nwl_cb_subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)\n{\n   (void)client;\n   wl_resource_destroy(resource);\n}\n\nstatic const struct wl_subcompositor_interface wl_subcompositor_implementation = {\n   .destroy = wl_cb_subcompositor_destroy,\n   .get_subsurface = wl_cb_subcompositor_get_subsurface\n};\n\nstatic void\nwl_subcompositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)\n{\n   struct wl_resource *resource;\n   if (!(resource = wl_resource_create_checked(client, &wl_subcompositor_interface, version, 1, id)))\n      return;\n\n   wl_resource_set_implementation(resource, &wl_subcompositor_implementation, data, NULL);\n}\n\nstatic void\nwl_cb_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)\n{\n   struct wlc_compositor *compositor;\n   if (!(compositor = wl_resource_get_user_data(resource)))\n      return;\n\n   wlc_resource r;\n   if (!(r = wlc_resource_create(&compositor->surfaces, client, &wl_surface_interface, wl_resource_get_version(resource), 3, id)))\n      return;\n\n   wlc_resource_implement(r, wlc_surface_implementation(), compositor);\n\n   struct wlc_surface_event ev = { .surface = convert_from_wlc_resource(r, "surface"), .type = WLC_SURFACE_EVENT_CREATED };\n   wl_signal_emit(&wlc_system_signals()->surface, &ev);\n}\n\nstatic void\nwl_cb_region_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)\n{\n   struct wlc_compositor *compositor;\n   if (!(compositor = wl_resource_get_user_data(resource)))\n      return;\n\n   wlc_resource r;\n   if (!(r = wlc_resource_create(&compositor->regions, client, &wl_region_interface, wl_resource_get_version(resource), 3, id)))\n      return;\n\n   wlc_resource_implement(r, wlc_region_implementation(), wl_resource_get_user_data(resource));\n}\n\nstatic const struct wl_compositor_interface wl_compositor_implementation = {\n   .create_surface = wl_cb_surface_create,\n   .create_region = wl_cb_region_create\n};\n\nstatic void\nwl_compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)\n{\n   struct wl_resource *r;\n   if (!(r = wl_resource_create_checked(client, &wl_compositor_interface, version, 3, id)))\n      return;\n\n   wl_resource_set_implementation(r, &wl_compositor_implementation, data, NULL);\n}\n\nstatic void\ncb_idle_vt_switch(void *data)\n{\n   struct wlc_compositor *compositor = data;\n   wlc_fd_activate_vt(compositor->state.vt);\n   compositor->state.vt = 0;\n   wl_event_source_remove(compositor->state.idle);\n   compositor->state.idle = NULL;\n}\n\nstatic void\nactivate_tty(struct wlc_compositor *compositor)\n{\n   if (compositor->state.tty != ACTIVATING)\n      return;\n\n   compositor->state.tty = IDLE;\n   wlc_fd_activate();\n}\n\nstatic void\ndeactivate_tty(struct wlc_compositor *compositor)\n{\n   if (compositor->state.tty != DEACTIVATING)\n      return;\n\n   // check that all outputs are surfaceless\n   struct wlc_output *o;\n   chck_pool_for_each(&compositor->outputs.pool, o) {\n      if (o->bsurface.display)\n         return;\n   }\n\n   compositor->state.tty = IDLE;\n\n   if (compositor->state.vt != 0) {\n      compositor->state.idle = wl_event_loop_add_idle(wlc_event_loop(), cb_idle_vt_switch, compositor);\n   } else {\n      wlc_fd_deactivate();\n   }\n}\n\nstatic void\nrespond_tty_activate(struct wlc_compositor *compositor)\n{\n   if (compositor->state.tty == ACTIVATING) {\n      activate_tty(compositor);\n   } else if (compositor->state.tty == DEACTIVATING) {\n      deactivate_tty(compositor);\n   }\n}\n\nstatic void\nactivate_event(struct wl_listener *listener, void *data)\n{\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.activate));\n\n   struct wlc_activate_event *ev = data;\n   if (!ev->active) {\n      compositor->state.tty = DEACTIVATING;\n      compositor->state.vt = ev->vt;\n      chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_set_backend_surface, NULL);\n      deactivate_tty(compositor);\n   } else {\n      compositor->state.tty = ACTIVATING;\n      compositor->state.vt = 0;\n      activate_tty(compositor);\n      wlc_backend_update_outputs(&compositor->backend, &compositor->outputs.pool);\n      chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_set_sleep_ptr, false);\n   }\n}\n\nstatic void\nterminate_event(struct wl_listener *listener, void *data)\n{\n   (void)data;\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.terminate));\n   wlc_compositor_terminate(compositor);\n}\n\nstatic void\nxwayland_event(struct wl_listener *listener, void *data)\n{\n   bool activated = *(bool*)data;\n\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.xwayland));\n\n   if (activated) {\n      wlc_xwm(&compositor->xwm, &compositor->seat);\n   } else {\n      wlc_xwm_release(&compositor->xwm);\n   }\n\n   if (!compositor->state.ready) {\n      WLC_INTERFACE_EMIT(compositor.ready);\n      compositor->state.ready = true;\n   }\n}\n\nstatic void\nattach_surface_to_view_or_create(struct wlc_compositor *compositor, struct wlc_surface *surface, enum wlc_surface_role type, wlc_resource role)\n{\n   assert(compositor && surface && type < WLC_SURFACE_ROLE_LAST);\n\n   struct wlc_view *view;\n   if (!(view = wlc_compositor_view_for_surface(compositor, surface)))\n      return;\n\n   // views without role are ok.\n   if (!role)\n      return;\n\n   wlc_resource *res[WLC_SURFACE_ROLE_LAST] = {\n      &view->shell_surface,\n      &view->xdg_surface,\n      &view->xdg_toplevel,\n      &view->custom_surface,\n   };\n\n   const char *name[WLC_SURFACE_ROLE_LAST] = {\n      "shell-surface",\n      "xdg-surface",\n      "xdg-toplevel",\n      "custom-surface",\n   };\n\n   *res[type] = role;\n\n   if (type != WLC_CUSTOM_SURFACE)\n      wl_resource_set_user_data(wl_resource_from_wlc_resource(role, name[type]), (void*)convert_to_wlc_handle(view));\n}\n\nstatic void\nattach_popup_to_view_or_create(struct wlc_compositor *compositor, struct wlc_surface *surface, struct wlc_surface *parent, wlc_resource role)\n{\n   assert(compositor && surface && parent);\n\n   struct wlc_view *view;\n   if (!(view = wlc_compositor_view_for_surface(compositor, surface)))\n      return;\n\n   view->xdg_popup = role;\n   wlc_view_set_parent_ptr(view, convert_from_wlc_handle(parent->view, "view"));\n   wlc_view_set_type_ptr(view, WLC_BIT_POPUP, true);\n   wl_resource_set_user_data(wl_resource_from_wlc_resource(role, "xdg-popup"), (void*)convert_to_wlc_handle(view));\n}\n\nstatic void\nsurface_event(struct wl_listener *listener, void *data)\n{\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.surface));\n\n   struct wlc_surface_event *ev = data;\n   switch (ev->type) {\n      case WLC_SURFACE_EVENT_REQUEST_VIEW_ATTACH:\n         attach_surface_to_view_or_create(compositor, ev->surface, ev->attach.type, ev->attach.role);\n         break;\n\n      case WLC_SURFACE_EVENT_REQUEST_VIEW_POPUP:\n         attach_popup_to_view_or_create(compositor, ev->surface, ev->popup.parent, ev->popup.role);\n         break;\n\n      case WLC_SURFACE_EVENT_DESTROYED:\n      {\n         struct wlc_view *v;\n         chck_pool_for_each(&compositor->views.pool, v) {\n            if (v->parent == ev->surface->view)\n               wlc_view_set_parent_ptr(v, NULL);\n         }\n\n         struct wlc_surface *s;\n         chck_pool_for_each(&compositor->surfaces.pool, s) {\n            if (s->parent == convert_to_wlc_resource(ev->surface))\n   if (!(compositor->backend = wlc_backend_init(compositor)))\n      goto fail;\n\n   if (!(compositor->context = wlc_context_init(compositor->backend)))\n      goto fail;\n\n   if (!(compositor->render = wlc_render_init(compositor->context)))\n}\n\nstatic struct wlc_output*\nget_surfaceless_output(struct wlc_compositor *compositor)\n{\n   struct wlc_output *o;\n   chck_pool_for_each(&compositor->outputs.pool, o) {\n      if (!o->bsurface.display)\n         return o;\n   }\n   return NULL;\n}\n\nstatic void\nactive_output(struct wlc_compositor *compositor, struct wlc_output *output)\n{\n   assert(compositor);\n\n   wlc_dlog(WLC_DBG_FOCUS, "focus output %" PRIuWLC " %" PRIuWLC, compositor->active.output, convert_to_wlc_handle(output));\n\n   if (compositor->active.output == convert_to_wlc_handle(output))\n      return;\n\n   if (compositor->active.output)\n      WLC_INTERFACE_EMIT(output.focus, compositor->active.output, false);\n\n   wlc_output_schedule_repaint(convert_from_wlc_handle(compositor->active.output, "output"));\n   compositor->active.output = convert_to_wlc_handle(output);\n\n   if (compositor->active.output) {\n      WLC_INTERFACE_EMIT(output.focus, compositor->active.output, true);\n      wlc_output_schedule_repaint(output);\n   }\n}\n\nstatic void\nadd_output(struct wlc_compositor *compositor, struct wlc_backend_surface *bsurface, struct wlc_output_information *info)\n{\n   assert(compositor && bsurface && info);\n\n   struct wlc_output *output;\n   if (!(output = get_surfaceless_output(compositor)))\n      output = wlc_handle_create(&compositor->outputs);\n\n   if (!output) {\n      wlc_backend_surface_release(bsurface);\n      return;\n   }\n\n   wlc_output_set_information(output, info);\n\n   if (WLC_INTERFACE_EMIT_EXCEPT(output.created, false, convert_to_wlc_handle(output))) {\n      wlc_output_terminate(output);\n      return;\n   }\n\n   output->state.created = true;\n\n   wlc_output_set_backend_surface(output, bsurface);\n\n   if (!compositor->active.output)\n      active_output(compositor, output);\n\n   wlc_output_schedule_repaint(output);\n   wlc_log(WLC_LOG_INFO, "Added output (%" PRIuWLC ")", convert_to_wlc_handle(output));\n}\n\nstatic void\nremove_output(struct wlc_compositor *compositor, struct wlc_output *output)\n{\n   assert(compositor && output);\n\n   struct wlc_output *o, *alive = NULL;\n   chck_pool_for_each(&compositor->outputs.pool, o) {\n      if (!o->bsurface.display || o == output)\n         continue;\n\n      alive = o;\n      break;\n   }\n\n   if (compositor->active.output == convert_to_wlc_handle(output)) {\n      compositor->active.output = 0; // make sure we don\'t redraw\n      active_output(compositor, alive);\n   }\n\n   WLC_INTERFACE_EMIT(output.destroyed, convert_to_wlc_handle(output));\n   wlc_output_set_backend_surface(output, NULL);\n\n   wlc_log(WLC_LOG_INFO, "Removed output (%" PRIuWLC ")", convert_to_wlc_handle(output));\n\n   if (compositor->state.terminating && !alive)\n      wlc_compositor_terminate(compositor);\n}\n\nstatic void\noutput_event(struct wl_listener *listener, void *data)\n{\n   struct wlc_output_event *ev = data;\n\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.output));\n\n   switch (ev->type) {\n      case WLC_OUTPUT_EVENT_ADD:\n         add_output(compositor, ev->add.bsurface, ev->add.info);\n         break;\n\n      case WLC_OUTPUT_EVENT_ACTIVE:\n         active_output(compositor, ev->active.output);\n         break;\n\n      case WLC_OUTPUT_EVENT_REMOVE:\n         remove_output(compositor, ev->remove.output);\n         break;\n\n      case WLC_OUTPUT_EVENT_UPDATE:\n         wlc_backend_update_outputs(&compositor->backend, &compositor->outputs.pool);\n         break;\n\n      case WLC_OUTPUT_EVENT_SURFACE:\n         respond_tty_activate(compositor);\n         break;\n   }\n}\n\nstatic void\nfocus_event(struct wl_listener *listener, void *data)\n{\n   struct wlc_compositor *compositor;\n   except(compositor = wl_container_of(listener, compositor, listener.focus));\n\n   struct wlc_focus_event *ev = data;\n   switch (ev->type) {\n      case WLC_FOCUS_EVENT_OUTPUT:\n         active_output(compositor, ev->output);\n         break;\n\n      default: break;\n   }\n}\n\nstruct wlc_view*\nwlc_compositor_view_for_surface(struct wlc_compositor *compositor, struct wlc_surface *surface)\n{\n   struct wlc_view *view;\n   if (!(view = convert_from_wlc_handle(surface->view, "view")) && !(view = wlc_handle_create(&compositor->views)))\n      return NULL;\n\n   wlc_surface_attach_to_output(surface, convert_from_wlc_handle(compositor->active.output, "output"), wlc_surface_get_buffer(surface));\n   wlc_surface_attach_to_view(surface, view);\n   return view;\n}\n\n// XXX: We do not currently expose compositor to public API.\n//      So we use static variable here for some public api functions.\n//\n//      Never use this variable anywhere else.\nstatic struct wlc_compositor *_g_compositor;\n\nWLC_API const wlc_handle*\nwlc_get_outputs(size_t *out_memb)\n{\n   assert(_g_compositor);\n\n   if (out_memb)\n      *out_memb = 0;\n\n   // Allocate linear array which we then return\n   free(_g_compositor->tmp.outputs);\n   if (!(_g_compositor->tmp.outputs = chck_malloc_mul_of(_g_compositor->outputs.pool.items.count, sizeof(wlc_handle))))\n      return NULL;\n\n   {\n      size_t i = 0;\n      struct wlc_output *o;\n      chck_pool_for_each(&_g_compositor->outputs.pool, o)\n         _g_compositor->tmp.outputs[i++] = convert_to_wlc_handle(o);\n   }\n\n   if (out_memb)\n      *out_memb = _g_compositor->outputs.pool.items.count;\n\n   return _g_compositor->tmp.outputs;\n}\n\nWLC_API WLC_PURE wlc_handle\nwlc_get_focused_output(void)\n{\n   assert(_g_compositor);\n   return _g_compositor->active.output;\n}\n\nWLC_API WLC_PURE struct xkb_state*\nwlc_keyboard_get_xkb_state(void)\n{\n   assert(_g_compositor);\n   return _g_compositor->seat.keyboard.state.xkb;\n}\n\nWLC_API WLC_PURE struct xkb_keymap*\nwlc_keyboard_get_xkb_keymap(void)\n{\n   assert(_g_compositor);\n   return _g_compositor->seat.keymap.keymap;\n}\n\nWLC_API const uint32_t*\nwlc_keyboard_get_current_keys(size_t *out_memb)\n{\n   assert(_g_compositor);\n   return chck_iter_pool_to_c_array(&_g_compositor->seat.keyboard.keys, out_memb);\n}\n\nWLC_API uint32_t\nwlc_keyboard_get_keysym_for_key(uint32_t key, const struct wlc_modifiers *modifiers)\n{\n   assert(_g_compositor);\n   return wlc_keyboard_get_keysym_for_key_ptr(&_g_compositor->seat.keyboard, key, modifiers);\n}\n\nWLC_API uint32_t\nwlc_keyboard_get_utf32_for_key(uint32_t key, const struct wlc_modifiers *modifiers)\n{\n   assert(_g_compositor);\n   return wlc_keyboard_get_utf32_for_key_ptr(&_g_compositor->seat.keyboard, key, modifiers);\n}\n\nWLC_API void\nwlc_pointer_get_position_v2(double *out_x, double *out_y)\n{\n   assert(_g_compositor && out_x && out_y);\n   *out_x = _g_compositor->seat.pointer.pos.x;\n   *out_y = _g_compositor->seat.pointer.pos.y;\n}\n\nWLC_API void\nwlc_pointer_get_position(struct wlc_point *out_position)\n{\n   assert(_g_compositor && out_position);\n   out_position->x = _g_compositor->seat.pointer.pos.x;\n   out_position->y = _g_compositor->seat.pointer.pos.y;\n}\n\nWLC_API void\nwlc_pointer_set_position_v2(double x, double y)\n{\n   assert(_g_compositor);\n   _g_compositor->seat.pointer.pos.x = x;\n   _g_compositor->seat.pointer.pos.y = y;\n}\n\nWLC_API void\nwlc_pointer_set_position(const struct wlc_point *position)\n{\n   assert(_g_compositor && position);\n   _g_compositor->seat.pointer.pos.x = position->x;\n   _g_compositor->seat.pointer.pos.y = position->y;\n}\n\nvoid\nwlc_compositor_terminate(struct wlc_compositor *compositor)\n{\n   if (!compositor || !_g_compositor)\n      return;\n\n   if (!compositor->state.terminating) {\n      wlc_log(WLC_LOG_INFO, "Terminating compositor...");\n      compositor->state.terminating = true;\n\n      WLC_INTERFACE_EMIT(compositor.terminate);\n\n      if (compositor->outputs.pool.items.count > 0) {\n         chck_pool_for_each_call(&compositor->outputs.pool, wlc_output_terminate);\n         return;\n      }\n   }\n\n   wlc_log(WLC_LOG_INFO, "Compositor terminated...");\n   wl_signal_emit(&wlc_system_signals()->compositor, NULL);\n}\n\nbool\nwlc_compositor_is_good(struct wlc_compositor *compositor)\n{\n   assert(compositor);\n\n   struct wlc_output *o;\n   chck_pool_for_each(&compositor->outputs.pool, o) {\n      if (o->context.context)\n         return true;\n   }\n\n   // There were no outputs or all outputs failed context creation\n   // wlc.c does this check and will return false in init\n   // XXX: Skip this check when we request headless mode\n   return false;\n}\n\nvoid\nwlc_compositor_release(struct wlc_compositor *compositor)\n{\n   if (!compositor || !_g_compositor)\n      return;\n\n   wl_list_remove(&compositor->listener.activate.link);\n   wl_list_remove(&compositor->listener.terminate.link);\n   wl_list_remove(&compositor->listener.xwayland.link);\n   wl_list_remove(&compositor->listener.surface.link);\n   wl_list_remove(&compositor->listener.output.link);\n   wl_list_remove(&compositor->listener.focus.link);\n\n   wlc_backend_release(&compositor->backend);\n   wlc_shell_release(&compositor->shell);\n   wlc_xdg_shell_release(&compositor->xdg_shell);\n   wlc_custom_shell_release(&compositor->custom_shell);\n   wlc_seat_release(&compositor->seat);\n\n   if (compositor->wl.subcompositor)\n      wl_global_destroy(compositor->wl.subcompositor);\n\n   if (compositor->wl.compositor)\n      wl_global_destroy(compositor->wl.compositor);\n\n   free(_g_compositor->tmp.outputs);\n   wlc_source_release(&compositor->outputs);\n   wlc_source_release(&compositor->views);\n   wlc_source_release(&compositor->surfaces);\n   wlc_source_release(&compositor->subsurfaces);\n   wlc_source_release(&compositor->regions);\n\n   memset(compositor, 0, sizeof(struct wlc_compositor));\n   _g_compositor = NULL;\n}\n\nbool\nwlc_compositor(struct wlc_compositor *compositor)\n{\n   assert(wlc_display() && wlc_event_loop() && !_g_compositor);\n   memset(compositor, 0, sizeof(struct wlc_compositor));\n\n   if (!wlc_display() || !wlc_event_loop() || _g_compositor) {\n      wlc_log(WLC_LOG_ERROR, "wlc_compositor called before wlc_init()");\n      abort();\n   }\n\n   _g_compositor = compositor;\n\n   compositor->listener.activate.notify = activate_event;\n   compositor->listener.terminate.notify = terminate_event;\n   compositor->listener.xwayland.notify = xwayland_event;\n   compositor->listener.surface.notify = surface_event;\n   compositor->listener.output.notify = output_event;\n   compositor->listener.focus.notify = focus_event;\n   wl_signal_add(&wlc_system_signals()->activate, &compositor->listener.activate);\n   wl_signal_add(&wlc_system_signals()->terminate, &compositor->listener.terminate);\n   wl_signal_add(&wlc_system_signals()->xwayland, &compositor->listener.xwayland);\n   wl_signal_add(&wlc_system_signals()->surface, &compositor->listener.surface);\n   wl_signal_add(&wlc_system_signals()->output, &compositor->listener.output);\n   wl_signal_add(&wlc_system_signals()->focus, &compositor->listener.focus);\n\n   if (!wlc_source(&compositor->outputs, "output", wlc_output, wlc_output_release, 4, sizeof(struct wlc_output)) ||\n       !wlc_source(&compositor->views, "view", wlc_view, wlc_view_release, 32, sizeof(struct wlc_view)) ||\n       !wlc_source(&compositor->surfaces, "surface", wlc_surface, wlc_surface_release, 32, sizeof(struct wlc_surface)) ||\n       !wlc_source(&compositor->subsurfaces, "subsurface", NULL, NULL, 32, sizeof(struct wlc_resource)) ||\n       !wlc_source(&compositor->regions, "region", NULL, wlc_region_release, 32, sizeof(struct wlc_region)))\n      goto fail;\n\n   if (!(compositor->wl.compositor = wl_global_create(wlc_display(), &wl_compositor_interface, 3, compositor, wl_compositor_bind)))\n      goto compositor_interface_fail;\n\n   if (!(compositor->wl.subcompositor = wl_global_create(wlc_display(), &wl_subcompositor_interface, 1, compositor, wl_subcompositor_bind)))\n      goto subcompositor_interface_fail;\n\n   if (!wlc_seat(&compositor->seat) ||\n       !wlc_shell(&compositor->shell) ||\n       !wlc_xdg_shell(&compositor->xdg_shell) ||\n       !wlc_custom_shell(&compositor->custom_shell) ||\n       !wlc_backend(&compositor->backend))\n      goto fail;\n\n   return true;\n\ncompositor_interface_fail:\n   wlc_log(WLC_LOG_WARN, "Failed to bind compositor interface");\n   goto fail;\nsubcompositor_interface_fail:\n   wlc_log(WLC_LOG_WARN, "Failed to bind subcompositor interface");\n   goto fail;\nfail:\n   wlc_compositor_release(compositor);\n   return false;\n}\n', 'message': "Basic EGL support.\n\nTODO: Need to use the damaged swap extension.\nAnd fallback to other heuristics when it's not available for flicker\nfree updates.\n", 'author_name': 'Jari Vetoniemi', 'lang': 'c'}