namespace Pasteboard {

const struct wl_data_offer_listener g_dataOfferListener = {
    // offer
    [] (void* data, struct wl_data_offer* offer, const char* type)
    {
        auto& dataDeviceData = *static_cast<PasteboardWayland::DataDeviceData*>(data);
        assert(offer == dataDeviceData.data_offer);
        dataDeviceData.dataTypes.push_back(type);
    },
};

const struct wl_data_device_listener g_dataDeviceListener = {
    // data_offer
    [] (void* data, struct wl_data_device*, struct wl_data_offer* offer)
    {
        auto& dataDeviceData = *static_cast<PasteboardWayland::DataDeviceData*>(data);

        dataDeviceData.dataTypes.clear();
        if (dataDeviceData.data_offer)
            wl_data_offer_destroy(dataDeviceData.data_offer);
        dataDeviceData.data_offer = offer;
        wl_data_offer_add_listener(offer, &g_dataOfferListener, data);
    },
    // enter
    [] (void*, struct wl_data_device*, uint32_t, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer*) {},
    // leave
    [] (void*, struct wl_data_device*) {},
    // motion
    [] (void*, struct wl_data_device*, uint32_t, wl_fixed_t, wl_fixed_t) {},
    // drop
    [] (void*, struct wl_data_device*) {},
    // selection
    [] (void*, struct wl_data_device*, wl_data_offer*) {},
};

PasteboardWayland::PasteboardWayland()
{
    ViewBackend::WaylandDisplay& display = ViewBackend::WaylandDisplay::singleton();

    if (!display.interfaces().data_device_manager)
        return;

    m_dataDevice = wl_data_device_manager_get_data_device(display.interfaces().data_device_manager, display.interfaces().seat);
    wl_data_device_add_listener(m_dataDevice, &g_dataDeviceListener, &m_dataDeviceData);
}

PasteboardWayland::~PasteboardWayland()
{
    if (m_dataDeviceData.data_offer)
        wl_data_offer_destroy(m_dataDeviceData.data_offer);
    m_dataDeviceData.dataTypes.clear();

    wl_data_device_destroy(m_dataDevice);
}

std::vector<std::string> PasteboardWayland::getTypes()
{
    std::vector<std::string> types;
    for (auto dataType: m_dataDeviceData.dataTypes)
        types.push_back(dataType);
    return types;
}

std::string PasteboardWayland::getString(const std::string pasteboardType)
{
    if (!std::any_of(m_dataDeviceData.dataTypes.cbegin(), m_dataDeviceData.dataTypes.cend(),
                     [pasteboardType](std::string str){ return str == pasteboardType;}))
        return std::string();

    int pipefd[2];
    // FIXME: Should probably handle this error somehow.
    if (pipe2(pipefd, O_CLOEXEC) == -1)
        return std::string();
    wl_data_offer_receive(m_dataDeviceData.data_offer, pasteboardType.c_str(), pipefd[1]);
    close(pipefd[1]);

    wl_display_roundtrip(ViewBackend::WaylandDisplay::singleton().display());

    char buf[1024];
    std::string readString;
    ssize_t length;
    do {
        length = read(pipefd[0], buf, 1024);
        readString.append(buf, length);
    } while (length > 0);
    close(pipefd[0]);

    return readString;
}

const struct wl_data_source_listener g_dataSourceListener = {
    // target
    [] (void*, struct wl_data_source*, const char*) {},
    // send
    [] (void* data, struct wl_data_source* source, const char* mime_type, int32_t fd)
    {
        auto& dataSourceData = *static_cast<PasteboardWayland::DataSourceData*>(data);
        assert(dataSourceData.data_source == source);
        assert(!dataSourceData.dataMap.count(mime_type));

        if (strncmp(mime_type, "text/", 5) == 0) {
            std::string stringToSend = dataSourceData.dataMap[mime_type];
            const char* p = stringToSend.data();
            ssize_t length = stringToSend.size();
            ssize_t written = 0;
            while (length > 0 && written != -1) {
                written = write(fd, p, length);
                p += written;
                length -= written;
            }
            close(fd);
            wl_display_roundtrip(ViewBackend::WaylandDisplay::singleton().display());
        } else
            return; // Eventually assert if we don't have a handler for a mimetype we are offering.
    },
    // cancelled
    [] (void* data, struct wl_data_source* source)
    {
        auto& dataSourceData = *static_cast<PasteboardWayland::DataSourceData*>(data);
        assert(dataSourceData.data_source == source);
        wl_data_source_destroy(source);
        dataSourceData.data_source = nullptr;
        dataSourceData.dataMap.clear();
    }
};

void PasteboardWayland::write(std::map<std::string, std::string>&& dataMap)
{
    if (m_dataSourceData.data_source)
        wl_data_source_destroy(m_dataSourceData.data_source);

    m_dataSourceData.dataMap = dataMap;

    ViewBackend::WaylandDisplay& display = ViewBackend::WaylandDisplay::singleton();
    m_dataSourceData.data_source = wl_data_device_manager_create_data_source(display.interfaces().data_device_manager);

    for (auto dataPair : m_dataSourceData.dataMap)
        wl_data_source_offer(m_dataSourceData.data_source, dataPair.first.c_str());

    wl_data_source_add_listener(m_dataSourceData.data_source, &g_dataSourceListener, &m_dataSourceData);
    wl_data_device_set_selection(m_dataDevice, m_dataSourceData.data_source, display.singleton().serial());
}

void PasteboardWayland::write(std::string&& pasteboardType, std::string&& stringToWrite)
{
    std::map<std::string, std::string> dataMap;
    dataMap[pasteboardType] = stringToWrite;
    write(std::move(dataMap));
}

} // namespace Pasteboard
static struct display *
create_display(void)
{
	struct display *display;

	display = malloc(sizeof *display);
	if (display == NULL) {
		fprintf(stderr, "out of memory\n");
		exit(1);
	}
	display->display = wl_display_connect(NULL);
	assert(display->display);

	display->formats = 0;
	display->registry = wl_display_get_registry(display->display);
	wl_registry_add_listener(display->registry,
				 &registry_listener, display);
	wl_display_roundtrip(display->display);
	if (display->shm == NULL) {
		fprintf(stderr, "No wl_shm global\n");
		exit(1);
	}

	wl_display_roundtrip(display->display);

	/*
	 * Why do we need two roundtrips here?
	 *
	 * wl_display_get_registry() sends a request to the server, to which
	 * the server replies by emitting the wl_registry.global events.
	 * The first wl_display_roundtrip() sends wl_display.sync. The server
	 * first processes the wl_display.get_registry which includes sending
	 * the global events, and then processes the sync. Therefore when the
	 * sync (roundtrip) returns, we are guaranteed to have received and
	 * processed all the global events.
	 *
	 * While we are inside the first wl_display_roundtrip(), incoming
	 * events are dispatched, which causes registry_handle_global() to
	 * be called for each global. One of these globals is wl_shm.
	 * registry_handle_global() sends wl_registry.bind request for the
	 * wl_shm global. However, wl_registry.bind request is sent after
	 * the first wl_display.sync, so the reply to the sync comes before
	 * the initial events of the wl_shm object.
	 *
	 * The initial events that get sent as a reply to binding to wl_shm
	 * include wl_shm.format. These tell us which pixel formats are
	 * supported, and we need them before we can create buffers. They
	 * don't change at runtime, so we receive them as part of init.
	 *
	 * When the reply to the first sync comes, the server may or may not
	 * have sent the initial wl_shm events. Therefore we need the second
	 * wl_display_roundtrip() call here.
	 *
	 * The server processes the wl_registry.bind for wl_shm first, and
	 * the second wl_display.sync next. During our second call to
	 * wl_display_roundtrip() the initial wl_shm events are received and
	 * processed. Finally, when the reply to the second wl_display.sync
	 * arrives, it guarantees we have processed all wl_shm initial events.
	 *
	 * This sequence contains two examples on how wl_display_roundtrip()
	 * can be used to guarantee, that all reply events to a request
	 * have been received and processed. This is a general Wayland
	 * technique.
	 */

	if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
		fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
		exit(1);
	}

	return display;
}
Exemple #3
0
	int Roundtrip(){
		return wl_display_roundtrip(cobj);
	}
Exemple #4
0
static int Open(vlc_object_t *obj)
{
    demux_t *demux = (demux_t *)obj;
    if (demux->out == NULL)
        return VLC_EGENERIC;

    demux_sys_t *sys = malloc(sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    /* Connect to the display server */
    char *dpy_name = var_InheritString(demux, "wl-display");
    sys->display = wl_display_connect(dpy_name);
    free(dpy_name);

    if (sys->display == NULL)
    {
        free(sys);
        return VLC_EGENERIC;
    }

    sys->output = NULL;
    sys->shm = NULL;
    sys->screenshooter = NULL;
    sys->es = NULL;
    sys->pagemask = sysconf(_SC_PAGE_SIZE) - 1;
    sys->rate = var_InheritFloat(demux, "screen-fps");
    sys->x = var_InheritInteger(demux, "screen-left");
    sys->y = var_InheritInteger(demux, "screen-top");
    sys->w = var_InheritInteger(demux, "screen-width");
    sys->h = var_InheritInteger(demux, "screen-height");

    if (1000.f * sys->rate <= 0x1.p-30)
        goto error;

    demux->p_sys = sys;

    /* Find the interesting singleton(s) */
    struct wl_registry *registry = wl_display_get_registry(sys->display);
    if (registry == NULL)
        goto error;

    wl_registry_add_listener(registry, &registry_cbs, demux);
    wl_display_roundtrip(sys->display);
    wl_registry_destroy(registry);

    if (sys->output == NULL || sys->shm == NULL || sys->screenshooter == NULL)
    {
        msg_Err(demux, "screenshooter extension not supported");
        goto error;
    }

    wl_output_add_listener(sys->output, &output_cbs, demux);
    screenshooter_add_listener(sys->screenshooter, &screenshooter_cbs,
                               &sys->done);
    wl_display_roundtrip(sys->display);

    if (DisplayError(demux, sys->display))
        goto error;

    /* Initializes demux */
    sys->start = vlc_tick_now();

    if (vlc_clone(&sys->thread, Thread, demux, VLC_THREAD_PRIORITY_INPUT))
        goto error;

    demux->pf_demux = NULL;
    demux->pf_control = Control;
    return VLC_SUCCESS;

error:
    if (sys->screenshooter != NULL)
        screenshooter_destroy(sys->screenshooter);
    if (sys->shm != NULL)
        wl_shm_destroy(sys->shm);
    if (sys->output != NULL)
        wl_output_destroy(sys->output);
    wl_display_disconnect(sys->display);
    free(sys);
    return VLC_EGENERIC;
}
Exemple #5
0
static void *gfx_ctx_wl_init(void *video_driver)
{
#ifdef HAVE_OPENGL
   static const EGLint egl_attribs_gl[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
      EGL_NONE,
   };
#endif

#ifdef HAVE_OPENGLES
#ifdef HAVE_OPENGLES2
   static const EGLint egl_attribs_gles[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE,
   };
#endif

#ifdef HAVE_OPENGLES3
#ifdef EGL_KHR_create_context
   static const EGLint egl_attribs_gles3[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
      EGL_NONE,
   };
#endif
#endif

#endif

#ifdef HAVE_EGL
   static const EGLint egl_attribs_vg[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
      EGL_NONE,
   };

   EGLint major = 0, minor = 0;
   EGLint n;
   const EGLint *attrib_ptr = NULL;
#endif
   gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)
      calloc(1, sizeof(gfx_ctx_wayland_data_t));

   if (!wl)
      return NULL;

   (void)video_driver;

#ifdef HAVE_EGL
   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
#ifdef HAVE_OPENGL
         attrib_ptr = egl_attribs_gl;
#endif
         break;
      case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_OPENGLES
#ifdef HAVE_OPENGLES3
#ifdef EGL_KHR_create_context
         if (g_egl_major >= 3)
            attrib_ptr = egl_attribs_gles3;
         else
#endif
#endif
#ifdef HAVE_OPENGLES2
            attrib_ptr = egl_attribs_gles;
#endif
#endif
         break;
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_VG
         attrib_ptr = egl_attribs_vg;
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }
#endif

   frontend_driver_destroy_signal_handler_state();

   wl->dpy = wl_display_connect(NULL);
   wl->buffer_scale = 1;

   if (!wl->dpy)
   {
      RARCH_ERR("Failed to connect to Wayland server.\n");
      goto error;
   }

   frontend_driver_install_signal_handler();

   wl->registry = wl_display_get_registry(wl->dpy);
   wl_registry_add_listener(wl->registry, &registry_listener, wl);
   wl_display_roundtrip(wl->dpy);

   if (!wl->compositor)
   {
      RARCH_ERR("Failed to create compositor.\n");
      goto error;
   }

   if (!wl->shell)
   {
      RARCH_ERR("Failed to create shell.\n");
      goto error;
   }

   wl->fd = wl_display_get_fd(wl->dpy);

   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL
         if (!egl_init_context(&wl->egl,
                  (EGLNativeDisplayType)wl->dpy,
                  &major, &minor, &n, attrib_ptr))
         {
            egl_report_error();
            goto error;
         }

         if (n == 0 || !egl_has_config(&wl->egl))
            goto error;
#endif
         break;
      case GFX_CTX_VULKAN_API:
#ifdef HAVE_VULKAN
         if (!vulkan_context_init(&wl->vk, VULKAN_WSI_WAYLAND))
            goto error;
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   return wl;

error:
   gfx_ctx_wl_destroy_resources(wl);

   if (wl)
      free(wl);

   return NULL;
}
Exemple #6
0
static bool gfx_ctx_wl_set_video_mode(void *data,
      unsigned width, unsigned height,
      bool fullscreen)
{
#ifdef HAVE_EGL
   EGLint egl_attribs[16];
   EGLint *attr              = egl_fill_attribs(
         (gfx_ctx_wayland_data_t*)data, egl_attribs);
#endif
   gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;

   wl->width        = width  ? width  : DEFAULT_WINDOWED_WIDTH;
   wl->height       = height ? height : DEFAULT_WINDOWED_HEIGHT;

   wl->surface    = wl_compositor_create_surface(wl->compositor);
   wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);

   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL
         wl->win        = wl_egl_window_create(wl->surface, wl->width, wl->height);
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }
   wl->shell_surf = wl_shell_get_shell_surface(wl->shell, wl->surface);

   wl_shell_surface_add_listener(wl->shell_surf, &shell_surface_listener, wl);
   wl_shell_surface_set_toplevel(wl->shell_surf);
   wl_shell_surface_set_class(wl->shell_surf, "RetroArch");
   wl_shell_surface_set_title(wl->shell_surf, "RetroArch");

   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL

         if (!egl_create_context(&wl->egl, (attr != egl_attribs) ? egl_attribs : NULL))
         {
            egl_report_error();
            goto error;
         }

         if (!egl_create_surface(&wl->egl, (EGLNativeWindowType)wl->win))
            goto error;
         egl_set_swap_interval(&wl->egl, wl->egl.interval);
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   if (fullscreen)
      wl_shell_surface_set_fullscreen(wl->shell_surf,
            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);

   flush_wayland_fd(wl);

   switch (wl_api)
   {
      case GFX_CTX_VULKAN_API:
         wl_display_roundtrip(wl->dpy);

#ifdef HAVE_VULKAN
         if (!vulkan_surface_create(&wl->vk, VULKAN_WSI_WAYLAND,
                  wl->dpy, wl->surface, 
                  wl->width, wl->height, wl->swap_interval))
            goto error;
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   return true;

error:
   gfx_ctx_wl_destroy(data);
   return false;
}
Exemple #7
0
static int
create_dmabuf_buffer(struct display *display, struct buffer *buffer,
		     int width, int height)
{
	struct zwp_linux_buffer_params_v1 *params;
	uint64_t modifier;
	uint32_t flags;

	if (!drm_connect(buffer)) {
		fprintf(stderr, "drm_connect failed\n");
		goto error;
	}

	buffer->width = width;
	buffer->height = height;
	buffer->bpp = 32; /* hardcoded XRGB8888 format */

	if (!alloc_bo(buffer)) {
		fprintf(stderr, "alloc_bo failed\n");
		goto error1;
	}

	if (!map_bo(buffer)) {
		fprintf(stderr, "map_bo failed\n");
		goto error2;
	}
	fill_content(buffer);
	unmap_bo(buffer);

	if (drm_intel_bo_gem_export_to_prime(buffer->bo, &buffer->dmabuf_fd) != 0) {
		fprintf(stderr, "drm_intel_bo_gem_export_to_prime failed\n");
		goto error2;
	}
	if (buffer->dmabuf_fd < 0) {
		fprintf(stderr, "error: dmabuf_fd < 0\n");
		goto error2;
	}

	/* We now have a dmabuf! It should contain 2x2 tiles (i.e. each tile
	 * is 256x256) of misc colours, and be mappable, either as ARGB8888, or
	 * XRGB8888. */
	modifier = 0;
	flags = 0;

	params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
	zwp_linux_buffer_params_v1_add(params,
				       buffer->dmabuf_fd,
				       0, /* plane_idx */
				       0, /* offset */
				       buffer->stride,
				       modifier >> 32,
				       modifier & 0xffffffff);
	zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
	zwp_linux_buffer_params_v1_create(params,
					  buffer->width,
					  buffer->height,
					  DRM_FORMAT_XRGB8888,
					  flags);

	/* params is destroyed by the event handlers */

	wl_display_roundtrip(display->display);
	if (buffer->buffer == NULL) {
		goto error2;
	}

	return 0;

error2:
	free_bo(buffer);
error1:
	drm_shutdown(buffer);
error:
	return -1;
}
	xdl_int XdevLWindowWayland::init() {

		XdevLWindowImpl::init();

		wl_display_roundtrip(display);

		if(m_compositor == nullptr) {
			XDEVL_MODULE_ERROR("Wayland compositor object not received.\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Received Wayland compositor object proxy\n");
		}

		if(m_shell == nullptr) {
			XDEVL_MODULE_ERROR("Wayland shell object not received.\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Received Wayland shell object proxy\n");
		}

		if(m_sharedMemory == nullptr) {
			XDEVL_MODULE_ERROR("Wayland shared memory object not received.\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Received Wayland shared memory object proxy\n");
		}
		//
		// Now we create the surface we can see on the screen.
		//
		m_surface = wl_compositor_create_surface(m_compositor);
		if(m_surface == nullptr) {
			XDEVL_MODULE_ERROR("Can't create Wayland surface\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Created surface\n");
		}
		wl_surface_set_user_data(m_surface, this);

		m_shellSurface = wl_shell_get_shell_surface(m_shell, m_surface);
		if(m_shellSurface == nullptr) {
			XDEVL_MODULE_ERROR("Can't create Wayland shell surface\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Created shell surface\n");
		}
		wl_shell_surface_add_listener(m_shellSurface, &shell_surface_listener, this);

		// Bring the surface to the front.
		wl_shell_surface_set_toplevel(m_shellSurface);


//		m_frameCallback = wl_surface_frame(m_surface);
//		wl_callback_add_listener(m_frameCallback, &frame_listener, this);

		createOpaqueRegion(m_attribute.position.x, m_attribute.position.y, m_attribute.size.width, m_attribute.size.height);

		xdl_int ret = initializeEGL();
		if(ret == ERR_ERROR) {
			XDEVL_MODULE_ERROR("Initializing EGL failed.\n");
			return ERR_ERROR;
		}

		m_egl.m_eglWindow = wl_egl_window_create(m_surface, getWidth(), getHeight());
		if(m_egl.m_eglWindow == EGL_NO_SURFACE) {
			XDEVL_MODULE_ERROR("Can't create egl window\n");
			return ERR_ERROR;
		} else {
			XDEVL_MODULE_SUCCESS("Created egl window\n");
		}

		m_egl.m_eglSurface = eglCreateWindowSurface(m_egl.m_eglDisplay, m_egl.m_eglConfig, m_egl.m_eglWindow, nullptr);

		if(!eglMakeCurrent(m_egl.m_eglDisplay, m_egl.m_eglSurface, m_egl.m_eglSurface, m_egl.m_eglContext)) {
			XDEVL_MODULE_ERROR("eglMakeCurrent failed\n");
		}
		glClearColor((1.0f/255.0)*m_backgroundColor[0], (1.0f/255.0)*m_backgroundColor[1], (1.0f/255.0)*m_backgroundColor[2], (1.0f/255.0)*m_backgroundColor[3]);
		glClear(GL_COLOR_BUFFER_BIT);
		glFlush();

		if(!eglSwapBuffers(m_egl.m_eglDisplay, m_egl.m_eglSurface)) {
			XDEVL_MODULE_ERROR("eglSwapBuffers failed\n");
		}

		wl_display_flush(display);

		return ERR_OK;
	}
EGLBoolean
dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
{
   struct dri2_egl_display *dri2_dpy;
   const __DRIconfig *config;
   uint32_t id, types;
   int i;
   static const unsigned int argb_masks[4] =
      { 0xff0000, 0xff00, 0xff, 0xff000000 };
   static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };

   drv->API.CreateWindowSurface = dri2_create_window_surface;
   drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
   drv->API.DestroySurface = dri2_destroy_surface;
   drv->API.SwapBuffers = dri2_swap_buffers;
   drv->API.CreateImageKHR = dri2_wayland_create_image_khr;
   drv->API.Terminate = dri2_terminate;

   dri2_dpy = malloc(sizeof *dri2_dpy);
   if (!dri2_dpy)
      return _eglError(EGL_BAD_ALLOC, "eglInitialize");

   memset(dri2_dpy, 0, sizeof *dri2_dpy);

   disp->DriverData = (void *) dri2_dpy;
   if (disp->PlatformDisplay == NULL) {
      dri2_dpy->wl_dpy = wl_display_connect(NULL);
      if (dri2_dpy->wl_dpy == NULL)
         goto cleanup_dpy;
      dri2_dpy->own_device = 1;
   } else {
      dri2_dpy->wl_dpy = disp->PlatformDisplay;
   }

   id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1);
   if (id == 0)
      wl_display_roundtrip(dri2_dpy->wl_dpy);
   id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1);
   if (id == 0)
      goto cleanup_dpy;
   dri2_dpy->wl_drm = wl_display_bind(dri2_dpy->wl_dpy, id, &wl_drm_interface);
   if (!dri2_dpy->wl_drm)
      goto cleanup_dpy;
   wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
   wl_display_roundtrip(dri2_dpy->wl_dpy);
   if (dri2_dpy->fd == -1)
      goto cleanup_drm;

   wl_display_roundtrip(dri2_dpy->wl_dpy);
   if (!dri2_dpy->authenticated)
      goto cleanup_fd;

   dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
   if (dri2_dpy->driver_name == NULL) {
      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
      goto cleanup_fd;
   }

   if (!dri2_load_driver(disp))
      goto cleanup_driver_name;

   dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
   dri2_dpy->dri2_loader_extension.base.version = 3;
   dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
   dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
   dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
      dri2_get_buffers_with_format;
      
   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
   dri2_dpy->extensions[1] = &image_lookup_extension.base;
   dri2_dpy->extensions[2] = &use_invalidate.base;
   dri2_dpy->extensions[3] = NULL;

   if (!dri2_create_screen(disp))
      goto cleanup_driver;

   types = EGL_WINDOW_BIT | EGL_PIXMAP_BIT;
   if (dri2_dpy->formats & HAS_PREMUL_ARGB32)
      types |= EGL_VG_ALPHA_FORMAT_PRE_BIT;

   for (i = 0; dri2_dpy->driver_configs[i]; i++) {
      config = dri2_dpy->driver_configs[i];
      if (dri2_dpy->formats & HAS_XRGB32)
	 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks);
      if (dri2_dpy->formats & (HAS_ARGB32 | HAS_PREMUL_ARGB32))
	 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks);
   }

   disp->Extensions.KHR_image_pixmap = EGL_TRUE;

   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
   dri2_dpy->authenticate = dri2_wayland_authenticate;

   /* we're supporting EGL 1.4 */
   disp->VersionMajor = 1;
   disp->VersionMinor = 4;

   return EGL_TRUE;

 cleanup_driver:
   dlclose(dri2_dpy->driver);
 cleanup_driver_name:
   free(dri2_dpy->driver_name);
 cleanup_fd:
   close(dri2_dpy->fd);
 cleanup_drm:
   free(dri2_dpy->device_name);
   wl_drm_destroy(dri2_dpy->wl_drm);
 cleanup_dpy:
   free(dri2_dpy);
   
   return EGL_FALSE;
}
Exemple #10
0
/* Initialize a native display for use with WSEGL */
static WSEGLError wseglInitializeDisplay
    (NativeDisplayType nativeDisplay, WSEGLDisplayHandle *display,
     const WSEGLCaps **caps, WSEGLConfig **configs)
{
    struct wl_egl_display *egldisplay = wl_egl_display_create((struct wl_display *) nativeDisplay);

    if (wseglFetchContext(egldisplay) != 1)
    {
       wl_egl_display_destroy(egldisplay);
       return WSEGL_OUT_OF_MEMORY;
    }

    /* If it is a framebuffer */
    if (egldisplay->display == NULL)
    {
       int fd;
       WSEGLPixelFormat format;
       
       /* Open the framebuffer and fetch its properties */
       fd = open("/dev/fb0", O_RDWR, 0);
       if (fd < 0) {
          perror("/dev/fb0");
          wseglReleaseContext(egldisplay);
          wl_egl_display_destroy(egldisplay);
          return WSEGL_CANNOT_INITIALISE;
       }
       if (ioctl(fd, FBIOGET_VSCREENINFO, &egldisplay->var) < 0) {
          perror("FBIOGET_VSCREENINFO");
          wseglReleaseContext(egldisplay);
          wl_egl_display_destroy(egldisplay);
          close(fd);
          return WSEGL_CANNOT_INITIALISE; 
       }
       if (ioctl(fd, FBIOGET_FSCREENINFO, &egldisplay->fix) < 0) {
          perror("FBIOGET_FSCREENINFO");
          wseglReleaseContext(egldisplay);
          wl_egl_display_destroy(egldisplay);
          close(fd);
          return WSEGL_CANNOT_INITIALISE; 
       }
       format = getwseglPixelFormat(egldisplay);

       egldisplay->wseglDisplayConfigs[0].ePixelFormat = format;
       egldisplay->wseglDisplayConfigs[1].ePixelFormat = format;
    }
    else
    {
      uint32_t id;
      id = wl_display_get_global(egldisplay->display, "wl_drm", 1);
      if (id == 0)
        wl_display_roundtrip(egldisplay->display);
      id = wl_display_get_global(egldisplay->display, "wl_drm", 1);
      if (id == 0)
        return WSEGL_CANNOT_INITIALISE; 

      egldisplay->drm = wl_display_bind(egldisplay->display, id, &wl_drm_interface);
      if (!egldisplay->drm)
         return WSEGL_CANNOT_INITIALISE;
      wl_drm_add_listener(egldisplay->drm, &drm_listener, egldisplay);
      wl_display_roundtrip(egldisplay->display);

    }

    *display = (WSEGLDisplayHandle)egldisplay;
    *caps = wseglDisplayCaps;
    *configs = egldisplay->wseglDisplayConfigs;
    return WSEGL_SUCCESS;
}
Exemple #11
0
int _glfwPlatformInit(void)
{
    _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
    if (!_glfw.wl.cursor.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libwayland-cursor");
        return GLFW_FALSE;
    }

    _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
    _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
    _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
    _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");

    _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
    if (!_glfw.wl.egl.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libwayland-egl");
        return GLFW_FALSE;
    }

    _glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");
    _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");
    _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");

    _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");
    if (!_glfw.wl.xkb.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libxkbcommon");
        return GLFW_FALSE;
    }

    _glfw.wl.xkb.context_new = (PFN_xkb_context_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");
    _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");
    _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");
    _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");
    _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");
    _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");
    _glfw.wl.xkb.state_new = (PFN_xkb_state_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");
    _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");
    _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");
    _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");
    _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");

#ifdef HAVE_XKBCOMMON_COMPOSE_H
    _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");
    _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");
    _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");
    _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");
    _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");
    _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
    _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
#endif

    _glfw.wl.display = wl_display_connect(NULL);
    if (!_glfw.wl.display)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to connect to display");
        return GLFW_FALSE;
    }

    _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
    wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);

    createKeyTables();

    _glfw.wl.xkb.context = xkb_context_new(0);
    if (!_glfw.wl.xkb.context)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to initialize xkb context");
        return GLFW_FALSE;
    }

    // Sync so we got all registry objects
    wl_display_roundtrip(_glfw.wl.display);

    // Sync so we got all initial output events
    wl_display_roundtrip(_glfw.wl.display);

    if (!_glfwInitJoysticksLinux())
        return GLFW_FALSE;

    _glfwInitTimerPOSIX();

    _glfw.wl.timerfd = -1;
    if (_glfw.wl.seatVersion >= 4)
        _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);

    if (_glfw.wl.pointer && _glfw.wl.shm)
    {
        _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
        if (!_glfw.wl.cursorTheme)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "Wayland: Unable to load default cursor theme");
            return GLFW_FALSE;
        }
        _glfw.wl.cursorSurface =
            wl_compositor_create_surface(_glfw.wl.compositor);
    }

    return GLFW_TRUE;
}
Exemple #12
0
void Display::roundtrip() const
{
	ASSERT(wl_display_roundtrip(*this) >= 0);
}
Exemple #13
0
static void *gfx_ctx_wl_init(void *video_driver)
{
   static const EGLint egl_attribs_gl[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
      EGL_NONE,
   };

   static const EGLint egl_attribs_gles[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE,
   };

#ifdef EGL_KHR_create_context
   static const EGLint egl_attribs_gles3[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
      EGL_NONE,
   };
#endif

   static const EGLint egl_attribs_vg[] = {
      WL_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
      EGL_NONE,
   };

   EGLint major = 0, minor = 0;
   EGLint n;
   const EGLint *attrib_ptr;
   gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)
      calloc(1, sizeof(gfx_ctx_wayland_data_t));

   (void)video_driver;

   if (!wl)
      return NULL;

   switch (wl->egl.api)
   {
      case GFX_CTX_OPENGL_API:
         attrib_ptr = egl_attribs_gl;
         break;
      case GFX_CTX_OPENGL_ES_API:
#ifdef EGL_KHR_create_context
         if (g_egl_major >= 3)
            attrib_ptr = egl_attribs_gles3;
         else
#endif
            attrib_ptr = egl_attribs_gles;
         break;
      case GFX_CTX_OPENVG_API:
         attrib_ptr = egl_attribs_vg;
         break;
      default:
         attrib_ptr = NULL;
   }

   g_egl_quit = 0;

   wl->dpy = wl_display_connect(NULL);
   if (!wl->dpy)
   {
      RARCH_ERR("Failed to connect to Wayland server.\n");
      goto error;
   }

   wl->registry = wl_display_get_registry(wl->dpy);
   wl_registry_add_listener(wl->registry, &registry_listener, wl);
   wl_display_dispatch(wl->dpy);
   wl_display_roundtrip(wl->dpy);

   if (!wl->compositor)
   {
      RARCH_ERR("Failed to create compositor.\n");
      goto error;
   }

   if (!wl->shell)
   {
      RARCH_ERR("Failed to create shell.\n");
      goto error;
   }

   wl->fd = wl_display_get_fd(wl->dpy);

   if (!egl_init_context(wl, (EGLNativeDisplayType)wl->dpy,
            &major, &minor, &n, attrib_ptr))
   {
      egl_report_error();
      goto error;
   }

   if (n == 0 || !egl_has_config(wl))
      goto error;

   return wl;

error:
   gfx_ctx_wl_destroy_resources(wl);

   if (wl)
      free(wl);

   return NULL;
}
Exemple #14
0
static void vertical_blank(void *pointer)
{
	struct wayland *wayland = pointer;

	wl_display_roundtrip(wayland->display);

	struct timespec tv;
	int32_t nsec_diff;
	clock_gettime(CLOCK_MONOTONIC, &tv);
	if (tv_prev.tv_sec == 0 && tv_prev.tv_nsec == 0) {
		nsec_diff = 0;
		tv_prev = tv;
	}
	else {
		nsec_diff = nano_elapsed(&tv_prev, &tv);
		tv_prev = tv;

		// assert(sec_diff == 0);

		cairo_surface_t *cairo_surface =
			cairo_image_surface_create_for_data(
				(unsigned char *)wayland->back_data,
				CAIRO_FORMAT_ARGB32,
				256 * SCALE, 240 * SCALE, 256 * SCALE * 4);
		cairo_t *cairo = cairo_create(cairo_surface);
		char buffer[200];
		double fps = 1000000000.0 / ((double) nsec_diff);
		sprintf(buffer, "FPS %.1f", fps);
		cairo_set_source_rgba(cairo, 255, 255, 255, 0.8);
		cairo_select_font_face(cairo, "Cousine",
			CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
		cairo_set_font_size(cairo, 12 * SCALE);
		cairo_move_to(cairo, 2 * SCALE, 236 * SCALE);
		cairo_show_text(cairo, buffer);
		cairo_destroy(cairo);
		cairo_surface_destroy(cairo_surface);
		// ++frame_count;
	}

	swap_buffers(wayland);

	wayland->frame_callback = wl_surface_frame(wayland->surface);
	wl_callback_add_listener(wayland->frame_callback,
	                         &frame_callback_listener, wayland);

	wl_surface_damage(wayland->surface, 0, 0,
	                  wayland->width, wayland->height);
	wl_surface_attach(wayland->surface, wayland->front_buffer, 0, 0);
	wl_surface_commit(wayland->surface);

	wl_display_flush(wayland->display);

	const int32_t NSEC_PER_60FPS_TICK = 16666666;
	if (nsec_diff != 0) {
		struct timespec req = {
			.tv_sec = 0,
			.tv_nsec = NSEC_PER_60FPS_TICK - nsec_diff,
		};
		struct timespec rem;
		nanosleep(&req, &rem);
	}
}

static uint8_t joypad1_read(void *pointer)
{
	struct wayland *wayland = pointer;

	wl_display_roundtrip(wayland->display);

	uint8_t state = wayland->joypad1_state;
	wayland->joypad1_state = wayland->joypad1_press;

	return state;
}

uint8_t nes_emulator_ppu_backend_wayland_init(
	struct nes_emulator_ppu_backend **ppu_backend)
{
	if (ppu_backend == NULL) {
		return EXIT_CODE_ARG_ERROR_BIT;
	}
	*ppu_backend = NULL;

	struct nes_emulator_ppu_backend *b =
		malloc(sizeof(struct nes_emulator_ppu_backend));
	if (b == NULL) {
		return EXIT_CODE_OS_ERROR_BIT;
	}

	struct wayland *w = malloc(sizeof(struct wayland));
	if (w == NULL) {
		free(b);
		return EXIT_CODE_OS_ERROR_BIT;
	}
	w->joypad1_state = 0;
	w->joypad1_press = 0;

	uint8_t exit_code = init_wayland(w);
	if (exit_code != 0) {
		free(w);
		free(b);
		return exit_code;
	}

	b->pointer = w;
	b->render_pixel = render_pixel;
	b->vertical_blank = vertical_blank;
	b->joypad1_read = joypad1_read;
	*ppu_backend = b;
	return 0;
}

uint8_t nes_emulator_ppu_backend_wayland_fini(
	struct nes_emulator_ppu_backend **ppu_backend)
{
	uint8_t exit_code = 0;
	struct wayland *wayland = (struct wayland *) (*ppu_backend)->pointer;
	exit_code |= fini_wayland(wayland);
	free(wayland);
	free(*ppu_backend);
	*ppu_backend = NULL;
	return exit_code;
}
Exemple #15
0
int _glfwPlatformInit(void)
{
    const char *cursorTheme;
    const char *cursorSizeStr;
    char *cursorSizeEnd;
    long cursorSizeLong;
    int cursorSize;

    _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
    if (!_glfw.wl.cursor.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libwayland-cursor");
        return GLFW_FALSE;
    }

    _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
    _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
    _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
    _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
        _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");

    _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
    if (!_glfw.wl.egl.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libwayland-egl");
        return GLFW_FALSE;
    }

    _glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");
    _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");
    _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
        _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");

    _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");
    if (!_glfw.wl.xkb.handle)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to open libxkbcommon");
        return GLFW_FALSE;
    }

    _glfw.wl.xkb.context_new = (PFN_xkb_context_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");
    _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");
    _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");
    _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");
    _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");
    _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");
    _glfw.wl.xkb.state_new = (PFN_xkb_state_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");
    _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");
    _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");
    _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");
    _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");

#ifdef HAVE_XKBCOMMON_COMPOSE_H
    _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");
    _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");
    _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");
    _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");
    _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");
    _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
    _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
        _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
#endif

    _glfw.wl.display = wl_display_connect(NULL);
    if (!_glfw.wl.display)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to connect to display");
        return GLFW_FALSE;
    }

    _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
    wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);

    createKeyTables();

    _glfw.wl.xkb.context = xkb_context_new(0);
    if (!_glfw.wl.xkb.context)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to initialize xkb context");
        return GLFW_FALSE;
    }

    // Sync so we got all registry objects
    wl_display_roundtrip(_glfw.wl.display);

    // Sync so we got all initial output events
    wl_display_roundtrip(_glfw.wl.display);

#ifdef __linux__
    if (!_glfwInitJoysticksLinux())
        return GLFW_FALSE;
#endif

    _glfwInitTimerPOSIX();

    _glfw.wl.timerfd = -1;
    if (_glfw.wl.seatVersion >= 4)
        _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);

    if (_glfw.wl.pointer && _glfw.wl.shm)
    {
        cursorTheme = getenv("XCURSOR_THEME");
        cursorSizeStr = getenv("XCURSOR_SIZE");
        cursorSize = 32;
        if (cursorSizeStr)
        {
            errno = 0;
            cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);
            if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)
                cursorSize = (int)cursorSizeLong;
        }
        _glfw.wl.cursorTheme =
            wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);
        if (!_glfw.wl.cursorTheme)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "Wayland: Unable to load default cursor theme");
            return GLFW_FALSE;
        }
        // If this happens to be NULL, we just fallback to the scale=1 version.
        _glfw.wl.cursorThemeHiDPI =
            wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm);
        _glfw.wl.cursorSurface =
            wl_compositor_create_surface(_glfw.wl.compositor);
        _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
    }

    if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)
    {
        _glfw.wl.dataDevice =
            wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
                                                   _glfw.wl.seat);
        wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
        _glfw.wl.clipboardString = malloc(4096);
        if (!_glfw.wl.clipboardString)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "Wayland: Unable to allocate clipboard memory");
            return GLFW_FALSE;
        }
        _glfw.wl.clipboardSize = 4096;
    }

    return GLFW_TRUE;
}