Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

View File

@ -0,0 +1,173 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylandclipboard.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_events_c.h"
int Wayland_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL;
int status = 0;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
if (_this->clipboard_callback && _this->clipboard_mime_types) {
SDL_WaylandDataSource *source = Wayland_data_source_create(_this);
Wayland_data_source_set_callback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence);
status = Wayland_data_device_set_selection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types);
if (status != 0) {
Wayland_data_source_destroy(source);
}
} else {
status = Wayland_data_device_clear_selection(data_device);
}
}
return status;
}
void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL;
void *buffer = NULL;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
if (data_device->selection_source) {
buffer = SDL_GetInternalClipboardData(_this, mime_type, length);
} else if (Wayland_data_offer_has_mime(data_device->selection_offer, mime_type)) {
buffer = Wayland_data_offer_receive(data_device->selection_offer, mime_type, length);
}
}
return buffer;
}
SDL_bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL;
SDL_bool result = SDL_FALSE;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
if (data_device->selection_source != NULL) {
result = SDL_HasInternalClipboardData(_this, mime_type);
} else {
result = Wayland_data_offer_has_mime(data_device->selection_offer, mime_type);
}
}
return result;
}
static const char *text_mime_types[] = {
TEXT_MIME,
"text/plain",
"TEXT",
"UTF8_STRING",
"STRING"
};
const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{
*num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
}
int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
int status = 0;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (text[0] != '\0') {
SDL_WaylandPrimarySelectionSource *source = Wayland_primary_selection_source_create(_this);
Wayland_primary_selection_source_set_callback(source, SDL_ClipboardTextCallback, SDL_strdup(text));
status = Wayland_primary_selection_device_set_selection(primary_selection_device,
source,
text_mime_types,
SDL_arraysize(text_mime_types));
if (status != 0) {
Wayland_primary_selection_source_destroy(source);
}
} else {
status = Wayland_primary_selection_device_clear_selection(primary_selection_device);
}
}
return status;
}
char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
char *text = NULL;
size_t length = 0;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (primary_selection_device->selection_source != NULL) {
text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, TEXT_MIME, &length);
} else if (Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, TEXT_MIME)) {
text = Wayland_primary_selection_offer_receive(primary_selection_device->selection_offer, TEXT_MIME, &length);
}
}
if (text == NULL) {
text = SDL_strdup("");
}
return text;
}
SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
SDL_bool result = SDL_FALSE;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (primary_selection_device->selection_source != NULL) {
result = SDL_TRUE;
} else {
result = Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, TEXT_MIME);
}
}
return result;
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandclipboard_h_
#define SDL_waylandclipboard_h_
extern const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types);
extern int Wayland_SetClipboardData(SDL_VideoDevice *_this);
extern void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
extern SDL_bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
extern int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
extern char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this);
extern SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this);
#endif /* SDL_waylandclipboard_h_ */

View File

@ -0,0 +1,627 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <signal.h>
#include "../../core/unix/SDL_poll.h"
#include "../../events/SDL_events_c.h"
#include "../SDL_clipboard_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylanddatamanager.h"
#include "primary-selection-unstable-v1-client-protocol.h"
/* FIXME: This is arbitrary, but we want this to be less than a frame because
* any longer can potentially spin an infinite loop of PumpEvents (!)
*/
#define PIPE_TIMEOUT_NS SDL_MS_TO_NS(14)
static ssize_t write_pipe(int fd, const void *buffer, size_t total_length, size_t *pos)
{
int ready = 0;
ssize_t bytes_written = 0;
ssize_t length = total_length - *pos;
sigset_t sig_set;
sigset_t old_sig_set;
struct timespec zerotime = { 0 };
ready = SDL_IOReady(fd, SDL_IOR_WRITE, PIPE_TIMEOUT_NS);
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGPIPE);
#ifdef SDL_THREADS_DISABLED
sigprocmask(SIG_BLOCK, &sig_set, &old_sig_set);
#else
pthread_sigmask(SIG_BLOCK, &sig_set, &old_sig_set);
#endif
if (ready == 0) {
bytes_written = SDL_SetError("Pipe timeout");
} else if (ready < 0) {
bytes_written = SDL_SetError("Pipe select error");
} else {
if (length > 0) {
bytes_written = write(fd, (Uint8 *)buffer + *pos, SDL_min(length, PIPE_BUF));
}
if (bytes_written > 0) {
*pos += bytes_written;
}
}
sigtimedwait(&sig_set, 0, &zerotime);
#ifdef SDL_THREADS_DISABLED
sigprocmask(SIG_SETMASK, &old_sig_set, NULL);
#else
pthread_sigmask(SIG_SETMASK, &old_sig_set, NULL);
#endif
return bytes_written;
}
static ssize_t read_pipe(int fd, void **buffer, size_t *total_length)
{
int ready = 0;
void *output_buffer = NULL;
char temp[PIPE_BUF];
size_t new_buffer_length = 0;
ssize_t bytes_read = 0;
size_t pos = 0;
ready = SDL_IOReady(fd, SDL_IOR_READ, PIPE_TIMEOUT_NS);
if (ready == 0) {
bytes_read = SDL_SetError("Pipe timeout");
} else if (ready < 0) {
bytes_read = SDL_SetError("Pipe select error");
} else {
bytes_read = read(fd, temp, sizeof(temp));
}
if (bytes_read > 0) {
pos = *total_length;
*total_length += bytes_read;
new_buffer_length = *total_length + sizeof(Uint32);
if (*buffer == NULL) {
output_buffer = SDL_malloc(new_buffer_length);
} else {
output_buffer = SDL_realloc(*buffer, new_buffer_length);
}
if (output_buffer == NULL) {
bytes_read = SDL_OutOfMemory();
} else {
SDL_memcpy((Uint8 *)output_buffer + pos, temp, bytes_read);
SDL_memset((Uint8 *)output_buffer + (new_buffer_length - sizeof(Uint32)), 0, sizeof(Uint32));
*buffer = output_buffer;
}
}
return bytes_read;
}
static SDL_MimeDataList *mime_data_list_find(struct wl_list *list,
const char *mime_type)
{
SDL_MimeDataList *found = NULL;
SDL_MimeDataList *mime_list = NULL;
wl_list_for_each (mime_list, list, link) {
if (SDL_strcmp(mime_list->mime_type, mime_type) == 0) {
found = mime_list;
break;
}
}
return found;
}
static int mime_data_list_add(struct wl_list *list,
const char *mime_type,
const void *buffer, size_t length)
{
int status = 0;
size_t mime_type_length = 0;
SDL_MimeDataList *mime_data = NULL;
void *internal_buffer = NULL;
if (buffer != NULL) {
internal_buffer = SDL_malloc(length);
if (internal_buffer == NULL) {
return SDL_OutOfMemory();
}
SDL_memcpy(internal_buffer, buffer, length);
}
mime_data = mime_data_list_find(list, mime_type);
if (mime_data == NULL) {
mime_data = SDL_calloc(1, sizeof(*mime_data));
if (mime_data == NULL) {
status = SDL_OutOfMemory();
} else {
WAYLAND_wl_list_insert(list, &(mime_data->link));
mime_type_length = SDL_strlen(mime_type) + 1;
mime_data->mime_type = SDL_malloc(mime_type_length);
if (mime_data->mime_type == NULL) {
status = SDL_OutOfMemory();
} else {
SDL_memcpy(mime_data->mime_type, mime_type, mime_type_length);
}
}
}
if (mime_data != NULL && buffer != NULL && length > 0) {
if (mime_data->data != NULL) {
SDL_free(mime_data->data);
}
mime_data->data = internal_buffer;
mime_data->length = length;
} else {
SDL_free(internal_buffer);
}
return status;
}
static void mime_data_list_free(struct wl_list *list)
{
SDL_MimeDataList *mime_data = NULL;
SDL_MimeDataList *next = NULL;
wl_list_for_each_safe(mime_data, next, list, link)
{
if (mime_data->data != NULL) {
SDL_free(mime_data->data);
}
if (mime_data->mime_type != NULL) {
SDL_free(mime_data->mime_type);
}
SDL_free(mime_data);
}
}
static size_t Wayland_send_data(const void *data, size_t length, int fd)
{
size_t result = 0;
if (length > 0 && data != NULL) {
while (write_pipe(fd, data, length, &result) > 0) {
/* Just keep spinning */
}
}
close(fd);
return result;
}
ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime_type, int fd)
{
const void *data = NULL;
size_t length = 0;
if (source->callback) {
data = source->callback(source->userdata.data, mime_type, &length);
}
return Wayland_send_data(data, length, fd);
}
ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource *source, const char *mime_type, int fd)
{
const void *data = NULL;
size_t length = 0;
if (source->callback) {
data = source->callback(source->userdata.data, mime_type, &length);
}
return Wayland_send_data(data, length, fd);
}
void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
SDL_ClipboardDataCallback callback,
void *userdata,
Uint32 sequence)
{
if (source) {
source->callback = callback;
source->userdata.sequence = sequence;
source->userdata.data = userdata;
}
}
void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source,
SDL_ClipboardDataCallback callback,
void *userdata)
{
if (source) {
source->callback = callback;
source->userdata.sequence = 0;
source->userdata.data = userdata;
}
}
static void *Wayland_clone_data_buffer(const void *buffer, size_t *len)
{
void *clone = NULL;
if (*len > 0 && buffer != NULL) {
clone = SDL_malloc((*len)+sizeof(Uint32));
if (clone == NULL) {
SDL_OutOfMemory();
} else {
SDL_memcpy(clone, buffer, *len);
SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32));
}
}
return clone;
}
void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
const char *mime_type, size_t *length)
{
void *buffer = NULL;
const void *internal_buffer;
*length = 0;
if (source == NULL) {
SDL_SetError("Invalid data source");
} else if (source->callback != NULL) {
internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length);
}
return buffer;
}
void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
const char *mime_type, size_t *length)
{
void *buffer = NULL;
const void *internal_buffer;
*length = 0;
if (source == NULL) {
SDL_SetError("Invalid primary selection source");
} else if (source->callback) {
internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length);
}
return buffer;
}
void Wayland_data_source_destroy(SDL_WaylandDataSource *source)
{
if (source != NULL) {
SDL_WaylandDataDevice *data_device = (SDL_WaylandDataDevice *)source->data_device;
if (data_device && (data_device->selection_source == source)) {
data_device->selection_source = NULL;
}
wl_data_source_destroy(source->source);
if (source->userdata.sequence) {
SDL_CancelClipboardData(source->userdata.sequence);
} else {
SDL_free(source->userdata.data);
}
SDL_free(source);
}
}
void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source)
{
if (source != NULL) {
SDL_WaylandPrimarySelectionDevice *primary_selection_device = (SDL_WaylandPrimarySelectionDevice *)source->primary_selection_device;
if (primary_selection_device && (primary_selection_device->selection_source == source)) {
primary_selection_device->selection_source = NULL;
}
zwp_primary_selection_source_v1_destroy(source->source);
if (source->userdata.sequence == 0) {
SDL_free(source->userdata.data);
}
SDL_free(source);
}
}
void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
const char *mime_type, size_t *length)
{
SDL_WaylandDataDevice *data_device = NULL;
int pipefd[2];
void *buffer = NULL;
*length = 0;
if (offer == NULL) {
SDL_SetError("Invalid data offer");
return NULL;
}
data_device = offer->data_device;
if (data_device == NULL) {
SDL_SetError("Data device not initialized");
} else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) {
SDL_SetError("Could not read pipe");
} else {
wl_data_offer_receive(offer->offer, mime_type, pipefd[1]);
/* TODO: Needs pump and flush? */
WAYLAND_wl_display_flush(data_device->video_data->display);
close(pipefd[1]);
while (read_pipe(pipefd[0], &buffer, length) > 0) {
}
close(pipefd[0]);
}
return buffer;
}
void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type, size_t *length)
{
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
int pipefd[2];
void *buffer = NULL;
*length = 0;
if (offer == NULL) {
SDL_SetError("Invalid data offer");
return NULL;
}
primary_selection_device = offer->primary_selection_device;
if (primary_selection_device == NULL) {
SDL_SetError("Primary selection device not initialized");
} else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) {
SDL_SetError("Could not read pipe");
} else {
zwp_primary_selection_offer_v1_receive(offer->offer, mime_type, pipefd[1]);
/* TODO: Needs pump and flush? */
WAYLAND_wl_display_flush(primary_selection_device->video_data->display);
close(pipefd[1]);
while (read_pipe(pipefd[0], &buffer, length) > 0) {
}
close(pipefd[0]);
}
return buffer;
}
int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
const char *mime_type)
{
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
}
int Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type)
{
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
}
SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
const char *mime_type)
{
SDL_bool found = SDL_FALSE;
if (offer != NULL) {
found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
}
return found;
}
SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type)
{
SDL_bool found = SDL_FALSE;
if (offer != NULL) {
found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
}
return found;
}
void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
{
if (offer != NULL) {
wl_data_offer_destroy(offer->offer);
mime_data_list_free(&offer->mimes);
SDL_free(offer);
}
}
void Wayland_primary_selection_offer_destroy(SDL_WaylandPrimarySelectionOffer *offer)
{
if (offer != NULL) {
zwp_primary_selection_offer_v1_destroy(offer->offer);
mime_data_list_free(&offer->mimes);
SDL_free(offer);
}
}
int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
{
int status = 0;
if (data_device == NULL || data_device->data_device == NULL) {
status = SDL_SetError("Invalid Data Device");
} else if (data_device->selection_source != NULL) {
wl_data_device_set_selection(data_device->data_device, NULL, 0);
Wayland_data_source_destroy(data_device->selection_source);
data_device->selection_source = NULL;
}
return status;
}
int Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device)
{
int status = 0;
if (primary_selection_device == NULL || primary_selection_device->primary_selection_device == NULL) {
status = SDL_SetError("Invalid Primary Selection Device");
} else if (primary_selection_device->selection_source != NULL) {
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
NULL, 0);
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
primary_selection_device->selection_source = NULL;
}
return status;
}
int Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
SDL_WaylandDataSource *source,
const char **mime_types,
size_t mime_count)
{
int status = 0;
if (data_device == NULL) {
status = SDL_SetError("Invalid Data Device");
} else if (source == NULL) {
status = SDL_SetError("Invalid source");
} else {
size_t index = 0;
const char *mime_type;
for (index = 0; index < mime_count; ++index) {
mime_type = mime_types[index];
wl_data_source_offer(source->source,
mime_type);
}
if (index == 0) {
Wayland_data_device_clear_selection(data_device);
status = SDL_SetError("No mime data");
} else {
/* Only set if there is a valid serial if not set it later */
if (data_device->selection_serial != 0) {
wl_data_device_set_selection(data_device->data_device,
source->source,
data_device->selection_serial);
}
if (data_device->selection_source != NULL) {
Wayland_data_source_destroy(data_device->selection_source);
}
data_device->selection_source = source;
source->data_device = data_device;
}
}
return status;
}
int Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
SDL_WaylandPrimarySelectionSource *source,
const char **mime_types,
size_t mime_count)
{
int status = 0;
if (primary_selection_device == NULL) {
status = SDL_SetError("Invalid Primary Selection Device");
} else if (source == NULL) {
status = SDL_SetError("Invalid source");
} else {
size_t index = 0;
const char *mime_type = mime_types[index];
for (index = 0; index < mime_count; ++index) {
mime_type = mime_types[index];
zwp_primary_selection_source_v1_offer(source->source, mime_type);
}
if (index == 0) {
Wayland_primary_selection_device_clear_selection(primary_selection_device);
status = SDL_SetError("No mime data");
} else {
/* Only set if there is a valid serial if not set it later */
if (primary_selection_device->selection_serial != 0) {
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
source->source,
primary_selection_device->selection_serial);
}
if (primary_selection_device->selection_source != NULL) {
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
}
primary_selection_device->selection_source = source;
source->primary_selection_device = primary_selection_device;
}
}
return status;
}
int Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
uint32_t serial)
{
int status = -1;
if (data_device != NULL) {
status = 0;
/* If there was no serial and there is a pending selection set it now. */
if (data_device->selection_serial == 0 && data_device->selection_source != NULL) {
wl_data_device_set_selection(data_device->data_device,
data_device->selection_source->source,
data_device->selection_serial);
}
data_device->selection_serial = serial;
}
return status;
}
int Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
uint32_t serial)
{
int status = -1;
if (primary_selection_device != NULL) {
status = 0;
/* If there was no serial and there is a pending selection set it now. */
if (primary_selection_device->selection_serial == 0 && primary_selection_device->selection_source != NULL) {
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
primary_selection_device->selection_source->source,
primary_selection_device->selection_serial);
}
primary_selection_device->selection_serial = serial;
}
return status;
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,160 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylanddatamanager_h_
#define SDL_waylanddatamanager_h_
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#define TEXT_MIME "text/plain;charset=utf-8"
#define FILE_MIME "text/uri-list"
typedef struct
{
char *mime_type;
void *data;
size_t length;
struct wl_list link;
} SDL_MimeDataList;
typedef struct SDL_WaylandUserdata
{
Uint32 sequence;
void *data;
} SDL_WaylandUserdata;
typedef struct
{
struct wl_data_source *source;
void *data_device;
SDL_ClipboardDataCallback callback;
SDL_WaylandUserdata userdata;
} SDL_WaylandDataSource;
typedef struct
{
struct zwp_primary_selection_source_v1 *source;
void *data_device;
void *primary_selection_device;
SDL_ClipboardDataCallback callback;
SDL_WaylandUserdata userdata;
} SDL_WaylandPrimarySelectionSource;
typedef struct
{
struct wl_data_offer *offer;
struct wl_list mimes;
void *data_device;
} SDL_WaylandDataOffer;
typedef struct
{
struct zwp_primary_selection_offer_v1 *offer;
struct wl_list mimes;
void *primary_selection_device;
} SDL_WaylandPrimarySelectionOffer;
typedef struct
{
struct wl_data_device *data_device;
SDL_VideoData *video_data;
/* Drag and Drop */
uint32_t drag_serial;
SDL_WaylandDataOffer *drag_offer;
SDL_WaylandDataOffer *selection_offer;
SDL_Window *dnd_window;
/* Clipboard and Primary Selection */
uint32_t selection_serial;
SDL_WaylandDataSource *selection_source;
} SDL_WaylandDataDevice;
typedef struct
{
struct zwp_primary_selection_device_v1 *primary_selection_device;
SDL_VideoData *video_data;
uint32_t selection_serial;
SDL_WaylandPrimarySelectionSource *selection_source;
SDL_WaylandPrimarySelectionOffer *selection_offer;
} SDL_WaylandPrimarySelectionDevice;
/* Wayland Data Source / Primary Selection Source - (Sending) */
extern SDL_WaylandDataSource *Wayland_data_source_create(SDL_VideoDevice *_this);
extern SDL_WaylandPrimarySelectionSource *Wayland_primary_selection_source_create(SDL_VideoDevice *_this);
extern ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source,
const char *mime_type, int fd);
extern ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource *source,
const char *mime_type, int fd);
extern void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
SDL_ClipboardDataCallback callback,
void *userdata,
Uint32 sequence);
extern void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source,
SDL_ClipboardDataCallback callback,
void *userdata);
extern void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
const char *mime_type,
size_t *length);
extern void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
const char *mime_type,
size_t *length);
extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source);
extern void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source);
/* Wayland Data / Primary Selection Offer - (Receiving) */
extern void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
const char *mime_type,
size_t *length);
extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type,
size_t *length);
extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
const char *mime_type);
extern SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type);
extern int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
const char *mime_type);
extern int Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type);
extern void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer);
extern void Wayland_primary_selection_offer_destroy(SDL_WaylandPrimarySelectionOffer *offer);
/* Clipboard / Primary Selection */
extern int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device);
extern int Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *device);
extern int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
SDL_WaylandDataSource *source,
const char **mime_types,
size_t mime_count);
extern int Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *device,
SDL_WaylandPrimarySelectionSource *source,
const char **mime_types,
size_t mime_count);
extern int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
uint32_t serial);
extern int Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *device,
uint32_t serial);
#endif /* SDL_waylanddatamanager_h_ */

View File

@ -0,0 +1,179 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#define DEBUG_DYNAMIC_WAYLAND 0
#include "SDL_waylanddyn.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
typedef struct
{
void *lib;
const char *libname;
} waylanddynlib;
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR NULL
#endif
static waylanddynlib waylandlibs[] = {
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC },
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL },
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR },
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON },
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR }
};
static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool required)
{
int i;
void *fn = NULL;
for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) {
if (waylandlibs[i].lib != NULL) {
fn = SDL_LoadFunction(waylandlibs[i].lib, fnname);
if (fn != NULL) {
break;
}
}
}
#if DEBUG_DYNAMIC_WAYLAND
if (fn != NULL)
SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, waylandlibs[i].libname, fn);
else
SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!\n", fnname);
#endif
if (fn == NULL && required) {
*pHasModule = 0; /* kill this module. */
}
return fn;
}
#else
#include <wayland-egl.h>
#endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */
/* Define all the function pointers and wrappers... */
#define SDL_WAYLAND_MODULE(modname) int SDL_WAYLAND_HAVE_##modname = 0;
#define SDL_WAYLAND_SYM(rc, fn, params) SDL_DYNWAYLANDFN_##fn WAYLAND_##fn = NULL;
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) SDL_DYNWAYLANDFN_##fn WAYLAND_##fn = NULL;
#define SDL_WAYLAND_INTERFACE(iface) const struct wl_interface *WAYLAND_##iface = NULL;
#include "SDL_waylandsym.h"
static int wayland_load_refcount = 0;
void SDL_WAYLAND_UnloadSymbols(void)
{
/* Don't actually unload if more than one module is using the libs... */
if (wayland_load_refcount > 0) {
if (--wayland_load_refcount == 0) {
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
int i;
#endif
/* set all the function pointers to NULL. */
#define SDL_WAYLAND_MODULE(modname) SDL_WAYLAND_HAVE_##modname = 0;
#define SDL_WAYLAND_SYM(rc, fn, params) WAYLAND_##fn = NULL;
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) WAYLAND_##fn = NULL;
#define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = NULL;
#include "SDL_waylandsym.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) {
if (waylandlibs[i].lib != NULL) {
SDL_UnloadObject(waylandlibs[i].lib);
waylandlibs[i].lib = NULL;
}
}
#endif
}
}
}
/* returns non-zero if all needed symbols were loaded. */
int SDL_WAYLAND_LoadSymbols(void)
{
int rc = 1; /* always succeed if not using Dynamic WAYLAND stuff. */
/* deal with multiple modules (dga, wayland, etc) needing these symbols... */
if (wayland_load_refcount++ == 0) {
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
int i;
int *thismod = NULL;
for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) {
if (waylandlibs[i].libname != NULL) {
waylandlibs[i].lib = SDL_LoadObject(waylandlibs[i].libname);
}
}
#define SDL_WAYLAND_MODULE(modname) SDL_WAYLAND_HAVE_##modname = 1; /* default yes */
#include "SDL_waylandsym.h"
#define SDL_WAYLAND_MODULE(modname) thismod = &SDL_WAYLAND_HAVE_##modname;
#define SDL_WAYLAND_SYM(rc, fn, params) WAYLAND_##fn = (SDL_DYNWAYLANDFN_##fn)WAYLAND_GetSym(#fn, thismod, SDL_TRUE);
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) WAYLAND_##fn = (SDL_DYNWAYLANDFN_##fn)WAYLAND_GetSym(#fn, thismod, SDL_FALSE);
#define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = (struct wl_interface *)WAYLAND_GetSym(#iface, thismod, SDL_TRUE);
#include "SDL_waylandsym.h"
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT &&
SDL_WAYLAND_HAVE_WAYLAND_CURSOR &&
SDL_WAYLAND_HAVE_WAYLAND_EGL &&
SDL_WAYLAND_HAVE_WAYLAND_XKB) {
/* All required symbols loaded, only libdecor is optional. */
SDL_ClearError();
} else {
/* in case something got loaded... */
SDL_WAYLAND_UnloadSymbols();
rc = 0;
}
#else /* no dynamic WAYLAND */
#define SDL_WAYLAND_MODULE(modname) SDL_WAYLAND_HAVE_##modname = 1; /* default yes */
#define SDL_WAYLAND_SYM(rc, fn, params) WAYLAND_##fn = fn;
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) WAYLAND_##fn = fn;
#define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = &iface;
#include "SDL_waylandsym.h"
#endif
}
return rc;
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,187 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_waylanddyn_h_
#define SDL_waylanddyn_h_
#include "SDL_internal.h"
/* We can't include wayland-client.h here
* but we need some structs from it
*/
struct wl_interface;
struct wl_proxy;
struct wl_event_queue;
struct wl_display;
struct wl_surface;
struct wl_shm;
/* We also need some for libdecor */
struct wl_seat;
struct wl_output;
struct libdecor;
struct libdecor_frame;
struct libdecor_state;
struct libdecor_configuration;
struct libdecor_interface;
struct libdecor_frame_interface;
enum libdecor_resize_edge;
enum libdecor_capabilities;
enum libdecor_window_state;
#include <stdint.h>
#include "wayland-cursor.h"
#include "wayland-util.h"
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-compose.h"
/* Must be included before our #defines, see Bugzilla #4957 */
#include "wayland-client-core.h"
#define SDL_WAYLAND_CHECK_VERSION(x, y, z) \
(WAYLAND_VERSION_MAJOR > x || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z))
#ifdef __cplusplus
extern "C" {
#endif
int SDL_WAYLAND_LoadSymbols(void);
void SDL_WAYLAND_UnloadSymbols(void);
#define SDL_WAYLAND_MODULE(modname) extern int SDL_WAYLAND_HAVE_##modname;
#define SDL_WAYLAND_SYM(rc, fn, params) \
typedef rc(*SDL_DYNWAYLANDFN_##fn) params; \
extern SDL_DYNWAYLANDFN_##fn WAYLAND_##fn;
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) \
typedef rc(*SDL_DYNWAYLANDFN_##fn) params; \
extern SDL_DYNWAYLANDFN_##fn WAYLAND_##fn;
#define SDL_WAYLAND_INTERFACE(iface) extern const struct wl_interface *WAYLAND_##iface;
#include "SDL_waylandsym.h"
#ifdef __cplusplus
}
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
#if defined(_WAYLAND_CLIENT_H) || defined(WAYLAND_CLIENT_H)
#error Do not include wayland-client ahead of SDL_waylanddyn.h in dynamic loading mode
#endif
/* wayland-client-protocol.h included from wayland-client.h
* has inline functions that require these to be defined in dynamic loading mode
*/
#define wl_proxy_create (*WAYLAND_wl_proxy_create)
#define wl_proxy_destroy (*WAYLAND_wl_proxy_destroy)
#define wl_proxy_marshal (*WAYLAND_wl_proxy_marshal)
#define wl_proxy_set_user_data (*WAYLAND_wl_proxy_set_user_data)
#define wl_proxy_get_user_data (*WAYLAND_wl_proxy_get_user_data)
#define wl_proxy_get_version (*WAYLAND_wl_proxy_get_version)
#define wl_proxy_add_listener (*WAYLAND_wl_proxy_add_listener)
#define wl_proxy_marshal_constructor (*WAYLAND_wl_proxy_marshal_constructor)
#define wl_proxy_marshal_constructor_versioned (*WAYLAND_wl_proxy_marshal_constructor_versioned)
#define wl_proxy_set_tag (*WAYLAND_wl_proxy_set_tag)
#define wl_proxy_get_tag (*WAYLAND_wl_proxy_get_tag)
#define wl_proxy_marshal_flags (*WAYLAND_wl_proxy_marshal_flags)
#define wl_proxy_marshal_array_flags (*WAYLAND_wl_proxy_marshal_array_flags)
#define wl_display_reconnect (*WAYLAND_wl_display_reconnect)
#define wl_seat_interface (*WAYLAND_wl_seat_interface)
#define wl_surface_interface (*WAYLAND_wl_surface_interface)
#define wl_shm_pool_interface (*WAYLAND_wl_shm_pool_interface)
#define wl_buffer_interface (*WAYLAND_wl_buffer_interface)
#define wl_registry_interface (*WAYLAND_wl_registry_interface)
#define wl_region_interface (*WAYLAND_wl_region_interface)
#define wl_pointer_interface (*WAYLAND_wl_pointer_interface)
#define wl_keyboard_interface (*WAYLAND_wl_keyboard_interface)
#define wl_compositor_interface (*WAYLAND_wl_compositor_interface)
#define wl_output_interface (*WAYLAND_wl_output_interface)
#define wl_shm_interface (*WAYLAND_wl_shm_interface)
#define wl_data_device_interface (*WAYLAND_wl_data_device_interface)
#define wl_data_offer_interface (*WAYLAND_wl_data_offer_interface)
#define wl_data_source_interface (*WAYLAND_wl_data_source_interface)
#define wl_data_device_manager_interface (*WAYLAND_wl_data_device_manager_interface)
/*
* These must be included before libdecor.h, otherwise the libdecor header
* pulls in the system Wayland protocol headers instead of ours.
*/
#include "wayland-client-protocol.h"
#include "wayland-egl.h"
#ifdef HAVE_LIBDECOR_H
/* Must be included before our defines */
#include <libdecor.h>
#define libdecor_unref (*WAYLAND_libdecor_unref)
#define libdecor_new (*WAYLAND_libdecor_new)
#define libdecor_decorate (*WAYLAND_libdecor_decorate)
#define libdecor_frame_unref (*WAYLAND_libdecor_frame_unref)
#define libdecor_frame_set_title (*WAYLAND_libdecor_frame_set_title)
#define libdecor_frame_set_app_id (*WAYLAND_libdecor_frame_set_app_id)
#define libdecor_frame_set_max_content_size (*WAYLAND_libdecor_frame_set_max_content_size)
#define libdecor_frame_get_max_content_size (*WAYLAND_libdecor_frame_get_max_content_size)
#define libdecor_frame_set_min_content_size (*WAYLAND_libdecor_frame_set_min_content_size)
#define libdecor_frame_get_min_content_size (*WAYLAND_libdecor_frame_get_min_content_size)
#define libdecor_frame_resize (*WAYLAND_libdecor_frame_resize)
#define libdecor_frame_move (*WAYLAND_libdecor_frame_move)
#define libdecor_frame_commit (*WAYLAND_libdecor_frame_commit)
#define libdecor_frame_set_minimized (*WAYLAND_libdecor_frame_set_minimized)
#define libdecor_frame_set_maximized (*WAYLAND_libdecor_frame_set_maximized)
#define libdecor_frame_unset_maximized (*WAYLAND_libdecor_frame_unset_maximized)
#define libdecor_frame_set_fullscreen (*WAYLAND_libdecor_frame_set_fullscreen)
#define libdecor_frame_unset_fullscreen (*WAYLAND_libdecor_frame_unset_fullscreen)
#define libdecor_frame_set_capabilities (*WAYLAND_libdecor_frame_set_capabilities)
#define libdecor_frame_unset_capabilities (*WAYLAND_libdecor_frame_unset_capabilities)
#define libdecor_frame_has_capability (*WAYLAND_libdecor_frame_has_capability)
#define libdecor_frame_set_visibility (*WAYLAND_libdecor_frame_set_visibility)
#define libdecor_frame_is_visible (*WAYLAND_libdecor_frame_is_visible)
#define libdecor_frame_is_floating (*WAYLAND_libdecor_frame_is_floating)
#define libdecor_frame_set_parent (*WAYLAND_libdecor_frame_set_parent)
#define libdecor_frame_get_xdg_surface (*WAYLAND_libdecor_frame_get_xdg_surface)
#define libdecor_frame_get_xdg_toplevel (*WAYLAND_libdecor_frame_get_xdg_toplevel)
#define libdecor_frame_translate_coordinate (*WAYLAND_libdecor_frame_translate_coordinate)
#define libdecor_frame_map (*WAYLAND_libdecor_frame_map)
#define libdecor_state_new (*WAYLAND_libdecor_state_new)
#define libdecor_state_free (*WAYLAND_libdecor_state_free)
#define libdecor_configuration_get_content_size (*WAYLAND_libdecor_configuration_get_content_size)
#define libdecor_configuration_get_window_state (*WAYLAND_libdecor_configuration_get_window_state)
#define libdecor_dispatch (*WAYLAND_libdecor_dispatch)
#endif
#else /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */
/*
* These must be included before libdecor.h, otherwise the libdecor header
* pulls in the system Wayland protocol headers instead of ours.
*/
#include "wayland-client-protocol.h"
#include "wayland-egl.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
#endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */
#endif /* SDL_waylanddyn_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandevents_h_
#define SDL_waylandevents_h_
#include "../../events/SDL_mouse_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"
enum SDL_WaylandAxisEvent
{
AXIS_EVENT_CONTINUOUS = 0,
AXIS_EVENT_DISCRETE,
AXIS_EVENT_VALUE120
};
struct SDL_WaylandTabletSeat;
struct SDL_WaylandTabletObjectListNode
{
void *object;
struct SDL_WaylandTabletObjectListNode *next;
};
struct SDL_WaylandTabletInput
{
struct SDL_WaylandInput *sdlWaylandInput;
struct zwp_tablet_seat_v2 *seat;
struct SDL_WaylandTabletObjectListNode *tablets;
struct SDL_WaylandTabletObjectListNode *tools;
struct SDL_WaylandTabletObjectListNode *pads;
SDL_WindowData *tool_focus;
uint32_t tool_prox_serial;
/* Last motion location */
wl_fixed_t sx_w;
wl_fixed_t sy_w;
SDL_bool is_down;
SDL_bool btn_stylus;
SDL_bool btn_stylus2;
SDL_bool btn_stylus3;
};
typedef struct
{
int32_t repeat_rate; /* Repeat rate in range of [1, 1000] character(s) per second */
int32_t repeat_delay_ms; /* Time to first repeat event in milliseconds */
SDL_bool is_initialized;
SDL_bool is_key_down;
uint32_t key;
Uint64 wl_press_time_ns; /* Key press time as reported by the Wayland API */
Uint64 sdl_press_time_ns; /* Key press time expressed in SDL ticks */
Uint64 next_repeat_ns; /* Next repeat event in nanoseconds */
uint32_t scancode;
char text[8];
} SDL_WaylandKeyboardRepeat;
struct SDL_WaylandInput
{
SDL_VideoData *display;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_touch *touch;
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
SDL_WaylandTextInput *text_input;
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_input_timestamps_v1 *keyboard_timestamps;
struct zwp_input_timestamps_v1 *pointer_timestamps;
struct zwp_input_timestamps_v1 *touch_timestamps;
SDL_WindowData *pointer_focus;
SDL_WindowData *keyboard_focus;
uint32_t pointer_enter_serial;
/* High-resolution event timestamps */
Uint64 keyboard_timestamp_ns;
Uint64 pointer_timestamp_ns;
Uint64 touch_timestamp_ns;
/* Last motion location */
wl_fixed_t sx_w;
wl_fixed_t sy_w;
uint32_t buttons_pressed;
/* The serial of the last implicit grab event for window activation and selection data. */
Uint32 last_implicit_grab_serial;
struct
{
struct xkb_keymap *keymap;
struct xkb_state *state;
struct xkb_compose_table *compose_table;
struct xkb_compose_state *compose_state;
/* Keyboard layout "group" */
uint32_t current_group;
/* Modifier bitshift values */
uint32_t idx_shift;
uint32_t idx_ctrl;
uint32_t idx_alt;
uint32_t idx_gui;
uint32_t idx_mode;
uint32_t idx_num;
uint32_t idx_caps;
/* Current system modifier flags */
uint32_t wl_pressed_modifiers;
uint32_t wl_locked_modifiers;
} xkb;
/* information about axis events on current frame */
struct
{
enum SDL_WaylandAxisEvent x_axis_type;
float x;
enum SDL_WaylandAxisEvent y_axis_type;
float y;
/* Event timestamp in nanoseconds */
Uint64 timestamp_ns;
SDL_MouseWheelDirection direction;
} pointer_curr_axis_info;
SDL_WaylandKeyboardRepeat keyboard_repeat;
struct SDL_WaylandTabletInput *tablet;
/* are we forcing relative mouse mode? */
SDL_bool cursor_visible;
SDL_bool relative_mode_override;
SDL_bool warp_emulation_prohibited;
SDL_bool keyboard_is_virtual;
/* Current SDL modifier flags */
SDL_Keymod pressed_modifiers;
SDL_Keymod locked_modifiers;
};
extern Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms);
extern void Wayland_PumpEvents(SDL_VideoDevice *_this);
extern void Wayland_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_add_primary_selection_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_destroy_input(SDL_VideoData *d);
extern void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id);
extern void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d);
extern int Wayland_input_lock_pointer(struct SDL_WaylandInput *input);
extern int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input);
extern int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *window);
extern int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input, SDL_Window *window);
extern void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id);
extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d);
extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input);
extern int Wayland_input_ungrab_keyboard(SDL_Window *window);
extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager *tablet_manager);
extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
extern void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input);
/* The implicit grab serial needs to be updated on:
* - Keyboard key down/up
* - Mouse button down
* - Touch event down
* - Tablet tool down
* - Tablet tool button down/up
*/
extern void Wayland_UpdateImplicitGrabSerial(struct SDL_WaylandInput *input, Uint32 serial);
#endif /* SDL_waylandevents_h_ */

View File

@ -0,0 +1,153 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if SDL_VIDEO_DRIVER_WAYLAND
#include "../SDL_sysvideo.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandevents_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "text-input-unstable-v3-client-protocol.h"
int Wayland_InitKeyboard(SDL_VideoDevice *_this)
{
#ifdef SDL_USE_IME
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager == NULL) {
SDL_IME_Init();
}
#endif
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
return 0;
}
void Wayland_QuitKeyboard(SDL_VideoDevice *_this)
{
#ifdef SDL_USE_IME
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager == NULL) {
SDL_IME_Quit();
}
#endif
}
void Wayland_StartTextInput(SDL_VideoDevice *_this)
{
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
const SDL_Rect *rect = &input->text_input->cursor_rect;
/* Don't re-enable if we're already enabled. */
if (input->text_input->is_enabled) {
return;
}
/* For some reason this has to be done twice, it appears to be a
* bug in mutter? Maybe?
* -flibit
*/
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
zwp_text_input_v3_enable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
/* Now that it's enabled, set the input properties */
zwp_text_input_v3_set_content_type(input->text_input->text_input,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
if (!SDL_RectEmpty(rect)) {
/* This gets reset on enable so we have to cache it */
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
}
zwp_text_input_v3_commit(input->text_input->text_input);
input->text_input->is_enabled = SDL_TRUE;
}
}
}
void Wayland_StopTextInput(SDL_VideoDevice *_this)
{
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
zwp_text_input_v3_disable(input->text_input->text_input);
zwp_text_input_v3_commit(input->text_input->text_input);
input->text_input->is_enabled = SDL_FALSE;
}
}
#ifdef SDL_USE_IME
else {
SDL_IME_Reset();
}
#endif
}
int Wayland_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
{
SDL_VideoData *driverdata = _this->driverdata;
if (driverdata->text_input_manager) {
struct SDL_WaylandInput *input = driverdata->input;
if (input != NULL && input->text_input) {
if (!SDL_RectsEqual(rect, &input->text_input->cursor_rect)) {
SDL_copyp(&input->text_input->cursor_rect, rect);
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
rect->x,
rect->y,
rect->w,
rect->h);
zwp_text_input_v3_commit(input->text_input->text_input);
}
}
}
#ifdef SDL_USE_IME
else {
SDL_IME_UpdateTextRect(rect);
}
#endif
return 0;
}
SDL_bool Wayland_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
{
/* In reality we just want to return true when the screen keyboard is the
* _only_ way to get text input. So, in addition to checking for the text
* input protocol, make sure we don't have any physical keyboards either.
*/
SDL_VideoData *driverdata = _this->driverdata;
SDL_bool haskeyboard = (driverdata->input != NULL) && (driverdata->input->keyboard != NULL);
SDL_bool hastextmanager = (driverdata->text_input_manager != NULL);
return !haskeyboard && hastextmanager;
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandkeyboard_h_
#define SDL_waylandkeyboard_h_
typedef struct SDL_WaylandTextInput
{
struct zwp_text_input_v3 *text_input;
SDL_Rect cursor_rect;
SDL_bool has_preedit;
SDL_bool is_enabled;
} SDL_WaylandTextInput;
extern int Wayland_InitKeyboard(SDL_VideoDevice *_this);
extern void Wayland_QuitKeyboard(SDL_VideoDevice *_this);
extern void Wayland_StartTextInput(SDL_VideoDevice *_this);
extern void Wayland_StopTextInput(SDL_VideoDevice *_this);
extern int Wayland_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);
extern SDL_bool Wayland_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
#endif /* SDL_waylandkeyboard_h_ */

View File

@ -0,0 +1,249 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#include <stdlib.h> /* fgets */
#include <stdio.h> /* FILE, STDOUT_FILENO, fdopen, fclose */
#include <unistd.h> /* pid_t, pipe, fork, close, dup2, execvp, _exit */
#include <sys/wait.h> /* waitpid, WIFEXITED, WEXITSTATUS */
#include <string.h> /* strerr */
#include <errno.h>
#include "SDL_waylandmessagebox.h"
#define ZENITY_VERSION_LEN 32 /* Number of bytes to read from zenity --version (including NUL)*/
#define MAX_BUTTONS 8 /* Maximum number of buttons supported */
static int run_zenity(const char **args, int fd_pipe[2]) {
int status;
pid_t pid1;
pid1 = fork();
if (pid1 == 0) { /* child process */
close(fd_pipe[0]); /* no reading from pipe */
/* write stdout in pipe */
if (dup2(fd_pipe[1], STDOUT_FILENO) == -1) {
_exit(128);
}
/* const casting argv is fine:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html -> rational
*/
execvp("zenity", (char **)args);
_exit(129);
} else if (pid1 < 0) { /* fork() failed */
return SDL_SetError("fork() failed: %s", strerror(errno));
} else { /* parent process */
close(fd_pipe[1]); /* no writing to the pipe */
if (waitpid(pid1, &status, 0) != pid1) {
return SDL_SetError("Waiting on zenity failed: %s", strerror(errno));
}
if (!WIFEXITED(status)) {
return SDL_SetError("zenity failed for some reason");
}
if (WEXITSTATUS(status) >= 128) {
return SDL_SetError("zenity reported error or failed to launch: %d", WEXITSTATUS(status));
}
return 0; /* success! */
}
}
static int get_zenity_version(int *major, int *minor) {
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
const char *argv[] = { "zenity", "--version", NULL };
if (pipe(fd_pipe) != 0) { /* create a pipe */
return SDL_SetError("pipe() failed: %s", strerror(errno));
}
if (run_zenity(argv, fd_pipe) == 0) {
FILE *outputfp = NULL;
char version_str[ZENITY_VERSION_LEN];
char *version_ptr = NULL, *end_ptr = NULL;
int tmp;
outputfp = fdopen(fd_pipe[0], "r");
if (outputfp == NULL) {
close(fd_pipe[0]);
return SDL_SetError("failed to open pipe for reading: %s", strerror(errno));
}
version_ptr = fgets(version_str, ZENITY_VERSION_LEN, outputfp);
(void)fclose(outputfp); /* will close underlying fd */
/* we expect the version string is in the form of MAJOR.MINOR.MICRO
* as described in meson.build. We'll ignore everything after that.
*/
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
if (tmp == 0 && end_ptr == version_ptr) {
return SDL_SetError("failed to get zenity major version number");
}
*major = tmp;
version_ptr = end_ptr + 1; /* skip the dot */
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
if (tmp == 0 && end_ptr == version_ptr) {
return SDL_SetError("failed to get zenity minor version number");
}
*minor = tmp;
return 0; /* success */
}
close(fd_pipe[0]);
close(fd_pipe[1]);
return -1; /* run_zenity should've called SDL_SetError() */
}
int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) {
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
int zenity_major = 0, zenity_minor = 0, output_len = 0;
int argc = 5, i;
const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = {
"zenity", "--question", "--switch", "--no-wrap", "--no-markup"
};
if (messageboxdata->numbuttons > MAX_BUTTONS) {
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
}
/* get zenity version so we know which arg to use */
if (get_zenity_version(&zenity_major, &zenity_minor) != 0) {
return -1; /* get_zenity_version() calls SDL_SetError(), so message is already set */
}
if (pipe(fd_pipe) != 0) { /* create a pipe */
return SDL_SetError("pipe() failed: %s", strerror(errno));
}
/* https://gitlab.gnome.org/GNOME/zenity/-/commit/c686bdb1b45e95acf010efd9ca0c75527fbb4dea
* This commit removed --icon-name without adding a deprecation notice.
* We need to handle it gracefully, otherwise no message box will be shown.
*/
argv[argc++] = zenity_major > 3 || (zenity_major == 3 && zenity_minor >= 90) ? "--icon" : "--icon-name";
switch (messageboxdata->flags) {
case SDL_MESSAGEBOX_ERROR:
argv[argc++] = "dialog-error";
break;
case SDL_MESSAGEBOX_WARNING:
argv[argc++] = "dialog-warning";
break;
case SDL_MESSAGEBOX_INFORMATION:
default:
argv[argc++] = "dialog-information";
break;
}
if (messageboxdata->title && messageboxdata->title[0]) {
argv[argc++] = "--title";
argv[argc++] = messageboxdata->title;
} else {
argv[argc++] = "--title=\"\"";
}
if (messageboxdata->message && messageboxdata->message[0]) {
argv[argc++] = "--text";
argv[argc++] = messageboxdata->message;
} else {
argv[argc++] = "--text=\"\"";
}
for (i = 0; i < messageboxdata->numbuttons; ++i) {
if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) {
int len = SDL_strlen(messageboxdata->buttons[i].text);
if (len > output_len) {
output_len = len;
}
argv[argc++] = "--extra-button";
argv[argc++] = messageboxdata->buttons[i].text;
} else {
argv[argc++] = "--extra-button=\"\"";
}
}
argv[argc] = NULL;
if (run_zenity(argv, fd_pipe) == 0) {
FILE *outputfp = NULL;
char *output = NULL;
char *tmp = NULL;
if (buttonid == NULL) {
/* if we don't need buttonid, we can return immediately */
close(fd_pipe[0]);
return 0; /* success */
}
*buttonid = -1;
output = SDL_malloc(output_len + 1);
if (output == NULL) {
close(fd_pipe[0]);
return SDL_OutOfMemory();
}
output[0] = '\0';
outputfp = fdopen(fd_pipe[0], "r");
if (outputfp == NULL) {
SDL_free(output);
close(fd_pipe[0]);
return SDL_SetError("Couldn't open pipe for reading: %s", strerror(errno));
}
tmp = fgets(output, output_len + 1, outputfp);
(void)fclose(outputfp);
if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) {
SDL_free(output);
return 0; /* User simply closed the dialog */
}
/* It likes to add a newline... */
tmp = SDL_strrchr(output, '\n');
if (tmp != NULL) {
*tmp = '\0';
}
/* Check which button got pressed */
for (i = 0; i < messageboxdata->numbuttons; i += 1) {
if (messageboxdata->buttons[i].text != NULL) {
if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) {
*buttonid = messageboxdata->buttons[i].buttonid;
break;
}
}
}
SDL_free(output);
return 0; /* success! */
}
close(fd_pipe[0]);
close(fd_pipe[1]);
return -1; /* run_zenity() calls SDL_SetError(), so message is already set */
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_waylandmessagebox_h_
#define SDL_waylandmessagebox_h_
#ifdef SDL_VIDEO_DRIVER_WAYLAND
extern int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
#endif /* SDL_waylandmessagebox_h_ */

View File

@ -0,0 +1,797 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include "../SDL_sysvideo.h"
#include "../../events/SDL_mouse_c.h"
#include "SDL_waylandvideo.h"
#include "../SDL_pixels_c.h"
#include "SDL_waylandevents_c.h"
#include "wayland-cursor.h"
#include "SDL_waylandmouse.h"
#include "../../SDL_hints_c.h"
static int Wayland_SetRelativeMouseMode(SDL_bool enabled);
typedef struct
{
struct wl_buffer *buffer;
struct wl_surface *surface;
int hot_x, hot_y;
int w, h;
/* shm_data is non-NULL for custom cursors.
* When shm_data is NULL, system_cursor must be valid
*/
SDL_SystemCursor system_cursor;
void *shm_data;
} Wayland_CursorData;
static int dbus_cursor_size;
static char *dbus_cursor_theme;
static void Wayland_FreeCursorThemes(SDL_VideoData *vdata)
{
for (int i = 0; i < vdata->num_cursor_themes; i += 1) {
WAYLAND_wl_cursor_theme_destroy(vdata->cursor_themes[i].theme);
}
vdata->num_cursor_themes = 0;
SDL_free(vdata->cursor_themes);
vdata->cursor_themes = NULL;
}
#ifdef SDL_USE_LIBDBUS
#include "../../core/linux/SDL_dbus.h"
#define CURSOR_NODE "org.freedesktop.portal.Desktop"
#define CURSOR_PATH "/org/freedesktop/portal/desktop"
#define CURSOR_INTERFACE "org.freedesktop.portal.Settings"
#define CURSOR_NAMESPACE "org.gnome.desktop.interface"
#define CURSOR_SIGNAL_NAME "SettingChanged"
#define CURSOR_SIZE_KEY "cursor-size"
#define CURSOR_THEME_KEY "cursor-theme"
static DBusMessage *Wayland_ReadDBusProperty(SDL_DBusContext *dbus, const char *key)
{
static const char *iface = "org.gnome.desktop.interface";
DBusMessage *reply = NULL;
DBusMessage *msg = dbus->message_new_method_call(CURSOR_NODE,
CURSOR_PATH,
CURSOR_INTERFACE,
"Read"); /* Method */
if (msg) {
if (dbus->message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) {
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, NULL);
}
dbus->message_unref(msg);
}
return reply;
}
static SDL_bool Wayland_ParseDBusReply(SDL_DBusContext *dbus, DBusMessage *reply, int type, void *value)
{
DBusMessageIter iter[3];
dbus->message_iter_init(reply, &iter[0]);
if (dbus->message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) {
return SDL_FALSE;
}
dbus->message_iter_recurse(&iter[0], &iter[1]);
if (dbus->message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) {
return SDL_FALSE;
}
dbus->message_iter_recurse(&iter[1], &iter[2]);
if (dbus->message_iter_get_arg_type(&iter[2]) != type) {
return SDL_FALSE;
}
dbus->message_iter_get_basic(&iter[2], value);
return SDL_TRUE;
}
static DBusHandlerResult Wayland_DBusCursorMessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
SDL_VideoData *vdata = (SDL_VideoData *)data;
if (dbus->message_is_signal(msg, CURSOR_INTERFACE, CURSOR_SIGNAL_NAME)) {
DBusMessageIter signal_iter, variant_iter;
const char *namespace, *key;
dbus->message_iter_init(msg, &signal_iter);
/* Check if the parameters are what we expect */
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) {
goto not_our_signal;
}
dbus->message_iter_get_basic(&signal_iter, &namespace);
if (SDL_strcmp(CURSOR_NAMESPACE, namespace) != 0) {
goto not_our_signal;
}
if (!dbus->message_iter_next(&signal_iter)) {
goto not_our_signal;
}
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) {
goto not_our_signal;
}
dbus->message_iter_get_basic(&signal_iter, &key);
if (SDL_strcmp(CURSOR_SIZE_KEY, key) == 0) {
int new_cursor_size;
if (!dbus->message_iter_next(&signal_iter)) {
goto not_our_signal;
}
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) {
goto not_our_signal;
}
dbus->message_iter_recurse(&signal_iter, &variant_iter);
if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_INT32) {
goto not_our_signal;
}
dbus->message_iter_get_basic(&variant_iter, &new_cursor_size);
if (dbus_cursor_size != new_cursor_size) {
dbus_cursor_size = new_cursor_size;
SDL_SetCursor(NULL); /* Force cursor update */
}
} else if (SDL_strcmp(CURSOR_THEME_KEY, key) == 0) {
const char *new_cursor_theme = NULL;
if (!dbus->message_iter_next(&signal_iter)) {
goto not_our_signal;
}
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) {
goto not_our_signal;
}
dbus->message_iter_recurse(&signal_iter, &variant_iter);
if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
goto not_our_signal;
}
dbus->message_iter_get_basic(&variant_iter, &new_cursor_theme);
if (!dbus_cursor_theme || !new_cursor_theme || SDL_strcmp(dbus_cursor_theme, new_cursor_theme) != 0) {
SDL_free(dbus_cursor_theme);
if (new_cursor_theme) {
dbus_cursor_theme = SDL_strdup(new_cursor_theme);
} else {
dbus_cursor_theme = NULL;
}
/* Purge the current cached themes and force a cursor refresh. */
Wayland_FreeCursorThemes(vdata);
SDL_SetCursor(NULL);
}
} else {
goto not_our_signal;
}
return DBUS_HANDLER_RESULT_HANDLED;
}
not_our_signal:
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void Wayland_DBusInitCursorProperties(SDL_VideoData *vdata)
{
DBusMessage *reply;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
SDL_bool add_filter = SDL_FALSE;
if (dbus == NULL) {
return;
}
if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_SIZE_KEY))) {
if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_INT32, &dbus_cursor_size)) {
add_filter = SDL_TRUE;
}
dbus->message_unref(reply);
}
if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_THEME_KEY))) {
const char *temp = NULL;
if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_STRING, &temp)) {
add_filter = SDL_TRUE;
if (temp) {
dbus_cursor_theme = SDL_strdup(temp);
}
}
dbus->message_unref(reply);
}
/* Only add the filter if at least one of the settings we want is present. */
if (add_filter) {
dbus->bus_add_match(dbus->session_conn,
"type='signal', interface='"CURSOR_INTERFACE"',"
"member='"CURSOR_SIGNAL_NAME"', arg0='"CURSOR_NAMESPACE"'", NULL);
dbus->connection_add_filter(dbus->session_conn, &Wayland_DBusCursorMessageFilter, vdata, NULL);
dbus->connection_flush(dbus->session_conn);
}
}
static void Wayland_DBusFinishCursorProperties()
{
SDL_free(dbus_cursor_theme);
dbus_cursor_theme = NULL;
}
#endif
static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorData *cdata, float *scale)
{
struct wl_cursor_theme *theme = NULL;
struct wl_cursor *cursor;
int size = dbus_cursor_size;
SDL_Window *focus;
SDL_WindowData *focusdata;
int i;
/* Fallback envvar if the DBus properties don't exist */
if (size <= 0) {
const char *xcursor_size = SDL_getenv("XCURSOR_SIZE");
if (xcursor_size) {
size = SDL_atoi(xcursor_size);
}
}
if (size <= 0) {
size = 24;
}
/* First, find the appropriate theme based on the current scale... */
focus = SDL_GetMouse()->focus;
if (focus == NULL) {
/* Nothing to see here, bail. */
return SDL_FALSE;
}
focusdata = focus->driverdata;
/* Cursors use integer scaling. */
*scale = SDL_ceilf(focusdata->windowed_scale_factor);
size *= *scale;
for (i = 0; i < vdata->num_cursor_themes; i += 1) {
if (vdata->cursor_themes[i].size == size) {
theme = vdata->cursor_themes[i].theme;
break;
}
}
if (theme == NULL) {
const char *xcursor_theme = dbus_cursor_theme;
vdata->cursor_themes = SDL_realloc(vdata->cursor_themes,
sizeof(SDL_WaylandCursorTheme) * (vdata->num_cursor_themes + 1));
if (vdata->cursor_themes == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
/* Fallback envvar if the DBus properties don't exist */
if (!xcursor_theme) {
xcursor_theme = SDL_getenv("XCURSOR_THEME");
}
theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, size, vdata->shm);
vdata->cursor_themes[vdata->num_cursor_themes].size = size;
vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme;
}
/* Next, find the cursor from the theme... */
switch (cdata->system_cursor) {
case SDL_SYSTEM_CURSOR_ARROW:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "left_ptr");
break;
case SDL_SYSTEM_CURSOR_IBEAM:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "xterm");
break;
case SDL_SYSTEM_CURSOR_WAIT:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "watch");
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "tcross");
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "watch");
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "top_left_corner");
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "top_right_corner");
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "sb_h_double_arrow");
break;
case SDL_SYSTEM_CURSOR_SIZENS:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "sb_v_double_arrow");
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "fleur");
break;
case SDL_SYSTEM_CURSOR_NO:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "pirate");
break;
case SDL_SYSTEM_CURSOR_HAND:
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "hand2");
break;
default:
SDL_assert(0);
return SDL_FALSE;
}
/* Fallback to the default cursor if the chosen one wasn't found */
if (!cursor) {
cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "left_ptr");
if (!cursor) {
return SDL_FALSE;
}
}
/* ... Set the cursor data, finally. */
cdata->buffer = WAYLAND_wl_cursor_image_get_buffer(cursor->images[0]);
cdata->hot_x = cursor->images[0]->hotspot_x;
cdata->hot_y = cursor->images[0]->hotspot_y;
cdata->w = cursor->images[0]->width;
cdata->h = cursor->images[0]->height;
return SDL_TRUE;
}
static int wayland_create_tmp_file(off_t size)
{
static const char template[] = "/sdl-shared-XXXXXX";
char *xdg_path;
char tmp_path[PATH_MAX];
int fd;
xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
if (xdg_path == NULL) {
return -1;
}
SDL_strlcpy(tmp_path, xdg_path, PATH_MAX);
SDL_strlcat(tmp_path, template, PATH_MAX);
fd = mkostemp(tmp_path, O_CLOEXEC);
if (fd < 0) {
return -1;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
static void mouse_buffer_release(void *data, struct wl_buffer *buffer)
{
}
static const struct wl_buffer_listener mouse_buffer_listener = {
mouse_buffer_release
};
static int create_buffer_from_shm(Wayland_CursorData *d,
int width,
int height,
uint32_t format)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *data = vd->driverdata;
struct wl_shm_pool *shm_pool;
int stride = width * 4;
int size = stride * height;
int shm_fd;
shm_fd = wayland_create_tmp_file(size);
if (shm_fd < 0) {
return SDL_SetError("Creating mouse cursor buffer failed.");
}
d->shm_data = mmap(NULL,
size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shm_fd,
0);
if (d->shm_data == MAP_FAILED) {
d->shm_data = NULL;
close(shm_fd);
return SDL_SetError("mmap() failed.");
}
SDL_assert(d->shm_data != NULL);
shm_pool = wl_shm_create_pool(data->shm, shm_fd, size);
d->buffer = wl_shm_pool_create_buffer(shm_pool,
0,
width,
height,
stride,
format);
wl_buffer_add_listener(d->buffer,
&mouse_buffer_listener,
d);
wl_shm_pool_destroy(shm_pool);
close(shm_fd);
return 0;
}
static SDL_Cursor *Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *wd = vd->driverdata;
Wayland_CursorData *data = SDL_calloc(1, sizeof(Wayland_CursorData));
if (data == NULL) {
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
cursor->driverdata = (void *)data;
/* Allocate shared memory buffer for this cursor */
if (create_buffer_from_shm(data,
surface->w,
surface->h,
WL_SHM_FORMAT_ARGB8888) < 0) {
SDL_free(cursor->driverdata);
SDL_free(cursor);
return NULL;
}
/* Wayland requires premultiplied alpha for its surfaces. */
SDL_PremultiplyAlpha(surface->w, surface->h,
surface->format->format, surface->pixels, surface->pitch,
SDL_PIXELFORMAT_ARGB8888, data->shm_data, surface->w * 4);
data->surface = wl_compositor_create_surface(wd->compositor);
wl_surface_set_user_data(data->surface, NULL);
data->hot_x = hot_x;
data->hot_y = hot_y;
data->w = surface->w;
data->h = surface->h;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *Wayland_CreateSystemCursor(SDL_SystemCursor id)
{
SDL_VideoData *data = SDL_GetVideoDevice()->driverdata;
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
Wayland_CursorData *cdata = SDL_calloc(1, sizeof(Wayland_CursorData));
if (cdata == NULL) {
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
cursor->driverdata = (void *)cdata;
cdata->surface = wl_compositor_create_surface(data->compositor);
wl_surface_set_user_data(cdata->surface, NULL);
/* Note that we can't actually set any other cursor properties, as this
* is output-specific. See wayland_get_system_cursor for the rest!
*/
cdata->system_cursor = id;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *Wayland_CreateDefaultCursor(void)
{
return Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
}
static void Wayland_FreeCursorData(Wayland_CursorData *d)
{
if (d->buffer) {
if (d->shm_data) {
wl_buffer_destroy(d->buffer);
}
d->buffer = NULL;
}
if (d->surface) {
wl_surface_destroy(d->surface);
d->surface = NULL;
}
}
static void Wayland_FreeCursor(SDL_Cursor *cursor)
{
if (cursor == NULL) {
return;
}
/* Probably not a cursor we own */
if (!cursor->driverdata) {
return;
}
Wayland_FreeCursorData((Wayland_CursorData *)cursor->driverdata);
/* Not sure what's meant to happen to shm_data */
SDL_free(cursor->driverdata);
SDL_free(cursor);
}
static int Wayland_ShowCursor(SDL_Cursor *cursor)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *d = vd->driverdata;
struct SDL_WaylandInput *input = d->input;
struct wl_pointer *pointer = d->pointer;
float scale = 1.0f;
if (pointer == NULL) {
return -1;
}
if (cursor) {
Wayland_CursorData *data = cursor->driverdata;
/* TODO: High-DPI custom cursors? -flibit */
if (data->shm_data == NULL) {
if (!wayland_get_system_cursor(d, data, &scale)) {
return -1;
}
}
wl_surface_set_buffer_scale(data->surface, scale);
wl_pointer_set_cursor(pointer,
input->pointer_enter_serial,
data->surface,
data->hot_x / scale,
data->hot_y / scale);
wl_surface_attach(data->surface, data->buffer, 0, 0);
wl_surface_damage(data->surface, 0, 0, data->w, data->h);
wl_surface_commit(data->surface);
input->cursor_visible = SDL_TRUE;
if (input->relative_mode_override) {
Wayland_input_unlock_pointer(input);
input->relative_mode_override = SDL_FALSE;
}
} else {
input->cursor_visible = SDL_FALSE;
wl_pointer_set_cursor(pointer, input->pointer_enter_serial, NULL, 0, 0);
}
return 0;
}
static int Wayland_WarpMouse(SDL_Window *window, float x, float y)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *d = vd->driverdata;
struct SDL_WaylandInput *input = d->input;
if (input->cursor_visible == SDL_TRUE) {
return SDL_Unsupported();
} else if (input->warp_emulation_prohibited) {
return SDL_Unsupported();
} else {
if (!d->relative_mouse_mode) {
Wayland_input_lock_pointer(input);
input->relative_mode_override = SDL_TRUE;
}
}
return 0;
}
static int Wayland_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *data = vd->driverdata;
if (enabled) {
/* Disable mouse warp emulation if it's enabled. */
if (data->input->relative_mode_override) {
data->input->relative_mode_override = SDL_FALSE;
}
/* If the app has used relative mode before, it probably shouldn't
* also be emulating it using repeated mouse warps, so disable
* mouse warp emulation by default.
*/
data->input->warp_emulation_prohibited = SDL_TRUE;
return Wayland_input_lock_pointer(data->input);
} else {
return Wayland_input_unlock_pointer(data->input);
}
}
static void SDLCALL Wayland_EmulateMouseWarpChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)userdata;
input->warp_emulation_prohibited = !SDL_GetStringBoolean(hint, !input->warp_emulation_prohibited);
}
/* Wayland doesn't support getting the true global cursor position, but it can
* be faked well enough for what most applications use it for: querying the
* global cursor coordinates and transforming them to the window-relative
* coordinates manually.
*
* The global position is derived by taking the cursor position relative to the
* toplevel window, and offsetting it by the origin of the output the window is
* currently considered to be on. The cursor position and button state when the
* cursor is outside an application window are unknown, but this gives 'correct'
* coordinates when the window has focus, which is good enough for most
* applications.
*/
static Uint32 SDLCALL Wayland_GetGlobalMouseState(float *x, float *y)
{
SDL_Window *focus = SDL_GetMouseFocus();
Uint32 ret = 0;
if (focus) {
int off_x, off_y;
ret = SDL_GetMouseState(x, y);
SDL_RelativeToGlobalForWindow(focus, focus->x, focus->y, &off_x, &off_y);
*x += off_x;
*y += off_y;
}
return ret;
}
#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */
static void Wayland_RecreateCursor(SDL_Cursor *cursor, SDL_VideoData *vdata)
{
Wayland_CursorData *cdata = (Wayland_CursorData *) cursor->driverdata;
/* Probably not a cursor we own */
if (cdata == NULL) {
return;
}
Wayland_FreeCursorData(cdata);
/* We're not currently freeing this, so... yolo? */
if (cdata->shm_data != NULL) {
void *old_data_pointer = cdata->shm_data;
int stride = cdata->w * 4;
create_buffer_from_shm(cdata, cdata->w, cdata->h, WL_SHM_FORMAT_ARGB8888);
SDL_memcpy(cdata->shm_data, old_data_pointer, stride * cdata->h);
}
cdata->surface = wl_compositor_create_surface(vdata->compositor);
wl_surface_set_user_data(cdata->surface, NULL);
}
void Wayland_RecreateCursors(void)
{
SDL_Cursor *cursor;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_VideoData *vdata = SDL_GetVideoDevice()->driverdata;
if (vdata && vdata->cursor_themes) {
SDL_free(vdata->cursor_themes);
vdata->cursor_themes = NULL;
vdata->num_cursor_themes = 0;
}
if (mouse == NULL) {
return;
}
for (cursor = mouse->cursors; cursor != NULL; cursor = cursor->next) {
Wayland_RecreateCursor(cursor, vdata);
}
if (mouse->def_cursor) {
Wayland_RecreateCursor(mouse->def_cursor, vdata);
}
if (mouse->cur_cursor) {
Wayland_RecreateCursor(mouse->cur_cursor, vdata);
if (mouse->cursor_shown) {
Wayland_ShowCursor(mouse->cur_cursor);
}
}
}
#endif /* 0 */
void Wayland_InitMouse(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_VideoDevice *vd = SDL_GetVideoDevice();
SDL_VideoData *d = vd->driverdata;
struct SDL_WaylandInput *input = d->input;
mouse->CreateCursor = Wayland_CreateCursor;
mouse->CreateSystemCursor = Wayland_CreateSystemCursor;
mouse->ShowCursor = Wayland_ShowCursor;
mouse->FreeCursor = Wayland_FreeCursor;
mouse->WarpMouse = Wayland_WarpMouse;
mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode;
mouse->GetGlobalMouseState = Wayland_GetGlobalMouseState;
input->relative_mode_override = SDL_FALSE;
input->cursor_visible = SDL_TRUE;
#ifdef SDL_USE_LIBDBUS
Wayland_DBusInitCursorProperties(d);
#endif
SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
SDL_AddHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
Wayland_EmulateMouseWarpChanged, input);
}
void Wayland_FiniMouse(SDL_VideoData *data)
{
struct SDL_WaylandInput *input = data->input;
Wayland_FreeCursorThemes(data);
#ifdef SDL_USE_LIBDBUS
Wayland_DBusFinishCursorProperties();
#endif
SDL_DelHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
Wayland_EmulateMouseWarpChanged, input);
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_waylandvideo.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND
extern void Wayland_InitMouse(void);
extern void Wayland_FiniMouse(SDL_VideoData *data);
#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */
extern void Wayland_RecreateCursors(void);
#endif /* 0 */
#endif

View File

@ -0,0 +1,205 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WAYLAND) && defined(SDL_VIDEO_OPENGL_EGL)
#include "../../core/unix/SDL_poll.h"
#include "../SDL_sysvideo.h"
#include "../../events/SDL_windowevents_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandopengles.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandevents_c.h"
#include "xdg-shell-client-protocol.h"
/* EGL implementation of SDL OpenGL ES support */
int Wayland_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
int ret;
SDL_VideoData *data = _this->driverdata;
ret = SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)data->display, _this->gl_config.egl_platform);
Wayland_PumpEvents(_this);
WAYLAND_wl_display_flush(data->display);
return ret;
}
SDL_GLContext Wayland_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_GLContext context;
context = SDL_EGL_CreateContext(_this, window->driverdata->egl_surface);
WAYLAND_wl_display_flush(_this->driverdata->display);
return context;
}
/* Wayland wants to tell you when to provide new frames, and if you have a non-zero
swap interval, Mesa will block until a callback tells it to do so. On some
compositors, they might decide that a minimized window _never_ gets a callback,
which causes apps to hang during swapping forever. So we always set the official
eglSwapInterval to zero to avoid blocking inside EGL, and manage this ourselves.
If a swap blocks for too long waiting on a callback, we just go on, under the
assumption the frame will be wasted, but this is better than freezing the app.
I frown upon platforms that dictate this sort of control inversion (the callback
is intended for _rendering_, not stalling until vsync), but we can work around
this for now. --ryan. */
/* Addendum: several recent APIs demand this sort of control inversion: Emscripten,
libretro, Wayland, probably others...it feels like we're eventually going to have
to give in with a future SDL API revision, since we can bend the other APIs to
this style, but this style is much harder to bend the other way. :/ */
int Wayland_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval)
{
if (!_this->egl_data) {
return SDL_SetError("EGL not initialized");
}
/* technically, this is _all_ adaptive vsync (-1), because we can't
actually wait for the _next_ vsync if you set 1, but things that
request 1 probably won't care _that_ much. I hope. No matter what
you do, though, you never see tearing on Wayland. */
if (interval > 1) {
interval = 1;
} else if (interval < -1) {
interval = -1;
}
/* !!! FIXME: technically, this should be per-context, right? */
_this->egl_data->egl_swapinterval = interval;
_this->egl_data->eglSwapInterval(_this->egl_data->egl_display, 0);
return 0;
}
int Wayland_GLES_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
{
if (!_this->egl_data) {
return SDL_SetError("EGL not initialized");
}
*interval =_this->egl_data->egl_swapinterval;
return 0;
}
int Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
const int swap_interval = _this->egl_data->egl_swapinterval;
/* For windows that we know are hidden, skip swaps entirely, if we don't do
* this compositors will intentionally stall us indefinitely and there's no
* way for an end user to show the window, unlike other situations (i.e.
* the window is minimized, behind another window, etc.).
*
* FIXME: Request EGL_WAYLAND_swap_buffers_with_timeout.
* -flibit
*/
if (data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN &&
data->surface_status != WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME) {
return 0;
}
/* Control swap interval ourselves. See comments on Wayland_GLES_SetSwapInterval */
if (swap_interval != 0 && data->surface_status == WAYLAND_SURFACE_STATUS_SHOWN) {
SDL_VideoData *videodata = _this->driverdata;
struct wl_display *display = videodata->display;
/* 1 sec, so we'll progress even if throttled to zero. */
const Uint64 max_wait = SDL_GetTicksNS() + SDL_NS_PER_SECOND;
while (SDL_AtomicGet(&data->swap_interval_ready) == 0) {
Uint64 now;
WAYLAND_wl_display_flush(display);
/* wl_display_prepare_read_queue() will return -1 if the event queue is not empty.
* If the event queue is empty, it will prepare us for our SDL_IOReady() call. */
if (WAYLAND_wl_display_prepare_read_queue(display, data->gles_swap_frame_event_queue) != 0) {
/* We have some pending events. Check if the frame callback happened. */
WAYLAND_wl_display_dispatch_queue_pending(display, data->gles_swap_frame_event_queue);
continue;
}
/* Beyond this point, we must either call wl_display_cancel_read() or wl_display_read_events() */
now = SDL_GetTicksNS();
if (now >= max_wait) {
/* Timeout expired. Cancel the read. */
WAYLAND_wl_display_cancel_read(display);
break;
}
if (SDL_IOReady(WAYLAND_wl_display_get_fd(display), SDL_IOR_READ, max_wait - now) <= 0) {
/* Error or timeout expired without any events for us. Cancel the read. */
WAYLAND_wl_display_cancel_read(display);
break;
}
/* We have events. Read and dispatch them. */
WAYLAND_wl_display_read_events(display);
WAYLAND_wl_display_dispatch_queue_pending(display, data->gles_swap_frame_event_queue);
}
SDL_AtomicSet(&data->swap_interval_ready, 0);
}
/* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */
if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) {
return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
}
WAYLAND_wl_display_flush(data->waylandData->display);
return 0;
}
int Wayland_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
int ret;
if (window && context) {
ret = SDL_EGL_MakeCurrent(_this, window->driverdata->egl_surface, context);
} else {
ret = SDL_EGL_MakeCurrent(_this, NULL, NULL);
}
WAYLAND_wl_display_flush(_this->driverdata->display);
_this->egl_data->eglSwapInterval(_this->egl_data->egl_display, 0); /* see comments on Wayland_GLES_SetSwapInterval. */
return ret;
}
int Wayland_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
SDL_EGL_DeleteContext(_this, context);
WAYLAND_wl_display_flush(_this->driverdata->display);
return 0;
}
EGLSurface Wayland_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *windowdata = window->driverdata;
return windowdata->egl_surface;
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */

View File

@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandopengles_h_
#define SDL_waylandopengles_h_
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
typedef struct SDL_PrivateGLESData
{
int dummy;
} SDL_PrivateGLESData;
/* OpenGLES functions */
#define Wayland_GLES_GetAttribute SDL_EGL_GetAttribute
#define Wayland_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define Wayland_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
extern int Wayland_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_GLContext Wayland_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int Wayland_GLES_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
extern int Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
extern int Wayland_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
extern SDL_EGLSurface Wayland_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_waylandopengles_h_ */

View File

@ -0,0 +1,238 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* *INDENT-OFF* */ /* clang-format off */
#ifndef SDL_WAYLAND_MODULE
#define SDL_WAYLAND_MODULE(modname)
#endif
#ifndef SDL_WAYLAND_SYM
#define SDL_WAYLAND_SYM(rc,fn,params)
#endif
#ifndef SDL_WAYLAND_SYM_OPT
#define SDL_WAYLAND_SYM_OPT(rc,fn,params)
#endif
#ifndef SDL_WAYLAND_INTERFACE
#define SDL_WAYLAND_INTERFACE(iface)
#endif
#include <stdbool.h>
SDL_WAYLAND_MODULE(WAYLAND_CLIENT)
SDL_WAYLAND_SYM(void, wl_proxy_marshal, (struct wl_proxy *, uint32_t, ...))
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_create, (struct wl_proxy *, const struct wl_interface *))
SDL_WAYLAND_SYM(void, wl_proxy_destroy, (struct wl_proxy *))
SDL_WAYLAND_SYM(int, wl_proxy_add_listener, (struct wl_proxy *, void (**)(void), void *))
SDL_WAYLAND_SYM(void, wl_proxy_set_user_data, (struct wl_proxy *, void *))
SDL_WAYLAND_SYM(void *, wl_proxy_get_user_data, (struct wl_proxy *))
SDL_WAYLAND_SYM(uint32_t, wl_proxy_get_version, (struct wl_proxy *))
SDL_WAYLAND_SYM(uint32_t, wl_proxy_get_id, (struct wl_proxy *))
SDL_WAYLAND_SYM(const char *, wl_proxy_get_class, (struct wl_proxy *))
SDL_WAYLAND_SYM(void, wl_proxy_set_queue, (struct wl_proxy *, struct wl_event_queue *))
SDL_WAYLAND_SYM(void *, wl_proxy_create_wrapper, (void *))
SDL_WAYLAND_SYM(void, wl_proxy_wrapper_destroy, (void *))
SDL_WAYLAND_SYM(struct wl_display *, wl_display_connect, (const char *))
SDL_WAYLAND_SYM(struct wl_display *, wl_display_connect_to_fd, (int))
SDL_WAYLAND_SYM(void, wl_display_disconnect, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_get_fd, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_dispatch, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_dispatch_queue, (struct wl_display *, struct wl_event_queue *))
SDL_WAYLAND_SYM(int, wl_display_dispatch_queue_pending, (struct wl_display *, struct wl_event_queue *))
SDL_WAYLAND_SYM(int, wl_display_dispatch_pending, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_prepare_read, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_prepare_read_queue, (struct wl_display *, struct wl_event_queue *))
SDL_WAYLAND_SYM(int, wl_display_read_events, (struct wl_display *))
SDL_WAYLAND_SYM(void, wl_display_cancel_read, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_get_error, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_flush, (struct wl_display *))
SDL_WAYLAND_SYM(int, wl_display_roundtrip, (struct wl_display *))
SDL_WAYLAND_SYM(struct wl_event_queue *, wl_display_create_queue, (struct wl_display *))
SDL_WAYLAND_SYM(void, wl_event_queue_destroy, (struct wl_event_queue *))
SDL_WAYLAND_SYM(void, wl_log_set_handler_client, (wl_log_func_t))
SDL_WAYLAND_SYM(void, wl_list_init, (struct wl_list *))
SDL_WAYLAND_SYM(void, wl_list_insert, (struct wl_list *, struct wl_list *) )
SDL_WAYLAND_SYM(void, wl_list_remove, (struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_length, (const struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_empty, (const struct wl_list *))
SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *))
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy *, uint32_t opcode, const struct wl_interface *interface, ...))
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...))
SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *))
SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *))
#if SDL_WAYLAND_CHECK_VERSION(1, 20, 0)
/* wayland-scanner 1.20 generates code that will call these, so these are
* non-optional when we are compiling against Wayland 1.20. We don't
* explicitly call them ourselves, though, so if we are only compiling
* against Wayland 1.18, they're unnecessary. */
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interfac, uint32_t version, uint32_t flags, ...))
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args))
#endif
#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */
#if SDL_WAYLAND_CHECK_VERSION(broken, on, purpose)
SDL_WAYLAND_SYM(int, wl_display_reconnect, (struct wl_display*))
#endif
#endif /* 0 */
SDL_WAYLAND_INTERFACE(wl_seat_interface)
SDL_WAYLAND_INTERFACE(wl_surface_interface)
SDL_WAYLAND_INTERFACE(wl_shm_pool_interface)
SDL_WAYLAND_INTERFACE(wl_buffer_interface)
SDL_WAYLAND_INTERFACE(wl_registry_interface)
SDL_WAYLAND_INTERFACE(wl_region_interface)
SDL_WAYLAND_INTERFACE(wl_pointer_interface)
SDL_WAYLAND_INTERFACE(wl_keyboard_interface)
SDL_WAYLAND_INTERFACE(wl_compositor_interface)
SDL_WAYLAND_INTERFACE(wl_output_interface)
SDL_WAYLAND_INTERFACE(wl_shm_interface)
SDL_WAYLAND_INTERFACE(wl_data_device_interface)
SDL_WAYLAND_INTERFACE(wl_data_source_interface)
SDL_WAYLAND_INTERFACE(wl_data_offer_interface)
SDL_WAYLAND_INTERFACE(wl_data_device_manager_interface)
SDL_WAYLAND_MODULE(WAYLAND_EGL)
SDL_WAYLAND_SYM(struct wl_egl_window *, wl_egl_window_create, (struct wl_surface *, int, int))
SDL_WAYLAND_SYM(void, wl_egl_window_destroy, (struct wl_egl_window *))
SDL_WAYLAND_SYM(void, wl_egl_window_resize, (struct wl_egl_window *, int, int, int, int))
SDL_WAYLAND_SYM(void, wl_egl_window_get_attached_size, (struct wl_egl_window *, int *, int *))
SDL_WAYLAND_MODULE(WAYLAND_CURSOR)
SDL_WAYLAND_SYM(struct wl_cursor_theme *, wl_cursor_theme_load, (const char *, int , struct wl_shm *))
SDL_WAYLAND_SYM(void, wl_cursor_theme_destroy, (struct wl_cursor_theme *))
SDL_WAYLAND_SYM(struct wl_cursor *, wl_cursor_theme_get_cursor, (struct wl_cursor_theme *, const char *))
SDL_WAYLAND_SYM(struct wl_buffer *, wl_cursor_image_get_buffer, (struct wl_cursor_image *))
SDL_WAYLAND_SYM(int, wl_cursor_frame, (struct wl_cursor *, uint32_t))
SDL_WAYLAND_MODULE(WAYLAND_XKB)
SDL_WAYLAND_SYM(int, xkb_state_key_get_syms, (struct xkb_state *, xkb_keycode_t, const xkb_keysym_t **))
SDL_WAYLAND_SYM(int, xkb_keysym_to_utf8, (xkb_keysym_t, char *, size_t) )
SDL_WAYLAND_SYM(struct xkb_keymap *, xkb_keymap_new_from_string, (struct xkb_context *, const char *, enum xkb_keymap_format, enum xkb_keymap_compile_flags))
SDL_WAYLAND_SYM(struct xkb_state *, xkb_state_new, (struct xkb_keymap *) )
SDL_WAYLAND_SYM(int, xkb_keymap_key_repeats, (struct xkb_keymap *keymap, xkb_keycode_t key) )
SDL_WAYLAND_SYM(void, xkb_keymap_unref, (struct xkb_keymap *) )
SDL_WAYLAND_SYM(void, xkb_state_unref, (struct xkb_state *) )
SDL_WAYLAND_SYM(void, xkb_context_unref, (struct xkb_context *) )
SDL_WAYLAND_SYM(struct xkb_context *, xkb_context_new, (enum xkb_context_flags flags) )
SDL_WAYLAND_SYM(enum xkb_state_component, xkb_state_update_mask, (struct xkb_state *state,\
xkb_mod_mask_t depressed_mods,\
xkb_mod_mask_t latched_mods,\
xkb_mod_mask_t locked_mods,\
xkb_layout_index_t depressed_layout,\
xkb_layout_index_t latched_layout,\
xkb_layout_index_t locked_layout) )
SDL_WAYLAND_SYM(struct xkb_compose_table *, xkb_compose_table_new_from_locale, (struct xkb_context *,\
const char *locale, enum xkb_compose_compile_flags) )
SDL_WAYLAND_SYM(void, xkb_compose_table_unref, (struct xkb_compose_table *) )
SDL_WAYLAND_SYM(struct xkb_compose_state *, xkb_compose_state_new, (struct xkb_compose_table *, enum xkb_compose_state_flags) )
SDL_WAYLAND_SYM(void, xkb_compose_state_unref, (struct xkb_compose_state *) )
SDL_WAYLAND_SYM(enum xkb_compose_feed_result, xkb_compose_state_feed, (struct xkb_compose_state *, xkb_keysym_t) )
SDL_WAYLAND_SYM(enum xkb_compose_status, xkb_compose_state_get_status, (struct xkb_compose_state *) )
SDL_WAYLAND_SYM(xkb_keysym_t, xkb_compose_state_get_one_sym, (struct xkb_compose_state *) )
SDL_WAYLAND_SYM(void, xkb_keymap_key_for_each, (struct xkb_keymap *, xkb_keymap_key_iter_t, void*) )
SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
xkb_keycode_t,
xkb_layout_index_t,
xkb_layout_index_t,
const xkb_keysym_t **) )
SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *,
const char *) )
SDL_WAYLAND_SYM(const char *, xkb_keymap_layout_get_name, (struct xkb_keymap*, xkb_layout_index_t))
#ifdef HAVE_LIBDECOR_H
SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR)
SDL_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *))
SDL_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *, struct libdecor_interface *))
SDL_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\
struct wl_surface *,\
struct libdecor_frame_interface *,\
void *))
SDL_WAYLAND_SYM(void, libdecor_frame_unref, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_title, (struct libdecor_frame *, const char *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_app_id, (struct libdecor_frame *, const char *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_max_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
SDL_WAYLAND_SYM(void, libdecor_frame_set_min_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
SDL_WAYLAND_SYM(void, libdecor_frame_resize, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t,\
enum libdecor_resize_edge))
SDL_WAYLAND_SYM(void, libdecor_frame_move, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t))
SDL_WAYLAND_SYM(void, libdecor_frame_commit, (struct libdecor_frame *,\
struct libdecor_state *,\
struct libdecor_configuration *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_minimized, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_maximized, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_unset_maximized, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_fullscreen, (struct libdecor_frame *, struct wl_output *))
SDL_WAYLAND_SYM(void, libdecor_frame_unset_fullscreen, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
SDL_WAYLAND_SYM(void, libdecor_frame_unset_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
SDL_WAYLAND_SYM(bool, libdecor_frame_has_capability, (struct libdecor_frame *, \
enum libdecor_capabilities))
SDL_WAYLAND_SYM(void, libdecor_frame_set_visibility, (struct libdecor_frame *, bool))
SDL_WAYLAND_SYM(bool, libdecor_frame_is_visible, (struct libdecor_frame *))
SDL_WAYLAND_SYM(bool, libdecor_frame_is_floating, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_parent, (struct libdecor_frame *,\
struct libdecor_frame *))
SDL_WAYLAND_SYM(struct xdg_surface *, libdecor_frame_get_xdg_surface, (struct libdecor_frame *))
SDL_WAYLAND_SYM(struct xdg_toplevel *, libdecor_frame_get_xdg_toplevel, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_translate_coordinate, (struct libdecor_frame *, int, int, int *, int *))
SDL_WAYLAND_SYM(void, libdecor_frame_map, (struct libdecor_frame *))
SDL_WAYLAND_SYM(struct libdecor_state *, libdecor_state_new, (int, int))
SDL_WAYLAND_SYM(void, libdecor_state_free, (struct libdecor_state *))
SDL_WAYLAND_SYM(bool, libdecor_configuration_get_content_size, (struct libdecor_configuration *,\
struct libdecor_frame *,\
int *,\
int *))
SDL_WAYLAND_SYM(bool, libdecor_configuration_get_window_state, (struct libdecor_configuration *,\
enum libdecor_window_state *))
SDL_WAYLAND_SYM(int, libdecor_dispatch, (struct libdecor *, int))
#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || defined(SDL_HAVE_LIBDECOR_VER_0_1_2)
/* Only found in libdecor 0.1.1 or higher, so failure to load them is not fatal. */
SDL_WAYLAND_SYM_OPT(void, libdecor_frame_get_min_content_size, (struct libdecor_frame *,\
int *,\
int *))
SDL_WAYLAND_SYM_OPT(void, libdecor_frame_get_max_content_size, (struct libdecor_frame *,\
int *,\
int *))
#endif
#endif
#undef SDL_WAYLAND_MODULE
#undef SDL_WAYLAND_SYM
#undef SDL_WAYLAND_SYM_OPT
#undef SDL_WAYLAND_INTERFACE
/* *INDENT-ON* */ /* clang-format on */

View File

@ -0,0 +1,283 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* Contributed by Thomas Perl <thomas.perl@jollamobile.com> */
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
#include "SDL_waylandtouch.h"
#include "SDL_waylandevents_c.h"
#include "../../events/SDL_touch_c.h"
struct SDL_WaylandTouch
{
struct qt_touch_extension *touch_extension;
};
/**
* Qt TouchPointState
* adapted from qtbase/src/corelib/global/qnamespace.h
**/
enum QtWaylandTouchPointState
{
QtWaylandTouchPointPressed = 0x01,
QtWaylandTouchPointMoved = 0x02,
/*
Never sent by the server:
QtWaylandTouchPointStationary = 0x04,
*/
QtWaylandTouchPointReleased = 0x08,
};
static void touch_handle_touch(void *data,
struct qt_touch_extension *qt_touch_extension,
uint32_t time,
uint32_t id,
uint32_t state,
int32_t x,
int32_t y,
int32_t normalized_x,
int32_t normalized_y,
int32_t width,
int32_t height,
uint32_t pressure,
int32_t velocity_x,
int32_t velocity_y,
uint32_t flags,
struct wl_array *rawdata)
{
/**
* Event is assembled in QtWayland in TouchExtensionGlobal::postTouchEvent
* (src/compositor/wayland_wrapper/qwltouch.cpp)
**/
SDL_VideoData *viddata = data;
float FIXED_TO_FLOAT = 1. / 10000.;
float xf = FIXED_TO_FLOAT * normalized_x;
float yf = FIXED_TO_FLOAT * normalized_y;
float PRESSURE_TO_FLOAT = 1. / 255.;
float pressuref = PRESSURE_TO_FLOAT * pressure;
uint32_t touchState = state & 0xFFFF;
/*
Other fields that are sent by the server (qwltouch.cpp),
but not used at the moment can be decoded in this way:
uint32_t sentPointCount = state >> 16;
uint32_t touchFlags = flags & 0xFFFF;
uint32_t capabilities = flags >> 16;
*/
SDL_Window *window = NULL;
SDL_TouchID deviceId = 1;
if (SDL_AddTouch(deviceId, SDL_TOUCH_DEVICE_DIRECT, "qt_touch_extension") < 0) {
SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
}
/* FIXME: This should be the window the given wayland surface is associated
* with, but how do we get the wayland surface? */
window = SDL_GetMouseFocus();
if (window == NULL) {
window = SDL_GetKeyboardFocus();
}
switch (touchState) {
case QtWaylandTouchPointPressed:
case QtWaylandTouchPointReleased:
SDL_SendTouch(Wayland_GetTouchTimestamp(viddata->input, time), deviceId, (SDL_FingerID)id,
window, (touchState == QtWaylandTouchPointPressed) ? SDL_TRUE : SDL_FALSE, xf, yf, pressuref);
break;
case QtWaylandTouchPointMoved:
SDL_SendTouchMotion(Wayland_GetTouchTimestamp(viddata->input, time), deviceId, (SDL_FingerID)id,
window, xf, yf, pressuref);
break;
default:
/* Should not happen */
break;
}
}
static void touch_handle_configure(void *data,
struct qt_touch_extension *qt_touch_extension,
uint32_t flags)
{
}
/* wayland-qt-touch-extension.c BEGINS */
static const struct qt_touch_extension_listener touch_listener = {
touch_handle_touch,
touch_handle_configure,
};
static const struct wl_interface *qt_touch_extension_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static const struct wl_message qt_touch_extension_requests[] = {
{ "dummy", "", qt_touch_extension_types + 0 },
};
static const struct wl_message qt_touch_extension_events[] = {
{ "touch", "uuuiiiiiiuiiua", qt_touch_extension_types + 0 },
{ "configure", "u", qt_touch_extension_types + 0 },
};
const struct wl_interface qt_touch_extension_interface = {
"qt_touch_extension",
1,
1,
qt_touch_extension_requests,
2,
qt_touch_extension_events,
};
/* wayland-qt-touch-extension.c ENDS */
/* wayland-qt-windowmanager.c BEGINS */
static const struct wl_interface *qt_windowmanager_types[] = {
NULL,
NULL,
};
static const struct wl_message qt_windowmanager_requests[] = {
{ "open_url", "us", qt_windowmanager_types + 0 },
};
static const struct wl_message qt_windowmanager_events[] = {
{ "hints", "i", qt_windowmanager_types + 0 },
{ "quit", "", qt_windowmanager_types + 0 },
};
const struct wl_interface qt_windowmanager_interface = {
"qt_windowmanager",
1,
1,
qt_windowmanager_requests,
2,
qt_windowmanager_events,
};
/* wayland-qt-windowmanager.c ENDS */
/* wayland-qt-surface-extension.c BEGINS */
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
extern const struct wl_interface wl_surface_interface;
#endif
static const struct wl_interface *qt_surface_extension_types[] = {
NULL,
NULL,
&qt_extended_surface_interface,
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
/* FIXME: Set this dynamically to (*WAYLAND_wl_surface_interface) ?
* The value comes from auto generated code and does
* not appear to actually be used anywhere
*/
NULL,
#else
&wl_surface_interface,
#endif
};
static const struct wl_message qt_surface_extension_requests[] = {
{ "get_extended_surface", "no", qt_surface_extension_types + 2 },
};
const struct wl_interface qt_surface_extension_interface = {
"qt_surface_extension",
1,
1,
qt_surface_extension_requests,
0,
NULL,
};
static const struct wl_message qt_extended_surface_requests[] = {
{ "update_generic_property", "sa", qt_surface_extension_types + 0 },
{ "set_content_orientation", "i", qt_surface_extension_types + 0 },
{ "set_window_flags", "i", qt_surface_extension_types + 0 },
};
static const struct wl_message qt_extended_surface_events[] = {
{ "onscreen_visibility", "i", qt_surface_extension_types + 0 },
{ "set_generic_property", "sa", qt_surface_extension_types + 0 },
{ "close", "", qt_surface_extension_types + 0 },
};
const struct wl_interface qt_extended_surface_interface = {
"qt_extended_surface",
1,
3,
qt_extended_surface_requests,
3,
qt_extended_surface_events,
};
/* wayland-qt-surface-extension.c ENDS */
void Wayland_touch_create(SDL_VideoData *data, uint32_t id)
{
struct SDL_WaylandTouch *touch;
if (data->touch) {
Wayland_touch_destroy(data);
}
/* !!! FIXME: check for failure, call SDL_OutOfMemory() */
data->touch = SDL_malloc(sizeof(struct SDL_WaylandTouch));
touch = data->touch;
touch->touch_extension = wl_registry_bind(data->registry, id, &qt_touch_extension_interface, 1);
qt_touch_extension_add_listener(touch->touch_extension, &touch_listener, data);
}
void Wayland_touch_destroy(SDL_VideoData *data)
{
if (data->touch) {
struct SDL_WaylandTouch *touch = data->touch;
if (touch->touch_extension) {
qt_touch_extension_destroy(touch->touch_extension);
}
SDL_free(data->touch);
data->touch = NULL;
}
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */

View File

@ -0,0 +1,334 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_waylandtouch_h_
#define SDL_waylandtouch_h_
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
#include "SDL_waylandvideo.h"
#include <stdint.h>
#include <stddef.h>
#include "wayland-util.h"
void Wayland_touch_create(SDL_VideoData *data, uint32_t id);
void Wayland_touch_destroy(SDL_VideoData *data);
struct qt_touch_extension;
/* Autogenerated QT headers */
/*
Support for Wayland with QmlCompositor as Server
================================================
The Wayland video driver has support for some additional features when
using QtWayland's "qmlcompositor" as Wayland server. This is needed for touch
input when running SDL applications under a qmlcompositor Wayland server.
The files following headers have been
generated from the Wayland XML Protocol Definition in QtWayland as follows:
Clone QtWayland from Git:
http://qt.gitorious.org/qt/qtwayland/
Generate headers and glue code:
for extension in touch-extension surface-extension windowmanager; do
wayland-scanner client-header < src/extensions/$extension.xml > wayland-qt-$extension.h
wayland-scanner code < src/extensions/$extension.xml > wayland-qt-$extension.c
done
*/
/* wayland-qt-surface-extension.h */
struct wl_client;
struct wl_resource;
struct qt_surface_extension;
struct qt_extended_surface;
extern const struct wl_interface qt_surface_extension_interface;
extern const struct wl_interface qt_extended_surface_interface;
#define QT_SURFACE_EXTENSION_GET_EXTENDED_SURFACE 0
static inline void qt_surface_extension_set_user_data(struct qt_surface_extension *qt_surface_extension, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *)qt_surface_extension, user_data);
}
static inline void *qt_surface_extension_get_user_data(struct qt_surface_extension *qt_surface_extension)
{
return wl_proxy_get_user_data((struct wl_proxy *)qt_surface_extension);
}
static inline void qt_surface_extension_destroy(struct qt_surface_extension *qt_surface_extension)
{
WAYLAND_wl_proxy_destroy((struct wl_proxy *)qt_surface_extension);
}
static inline struct qt_extended_surface *qt_surface_extension_get_extended_surface(struct qt_surface_extension *qt_surface_extension, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_create((struct wl_proxy *)qt_surface_extension,
&qt_extended_surface_interface);
if (id == NULL)
return NULL;
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_surface_extension,
QT_SURFACE_EXTENSION_GET_EXTENDED_SURFACE, id, surface);
return (struct qt_extended_surface *)id;
}
#ifndef QT_EXTENDED_SURFACE_ORIENTATION_ENUM
#define QT_EXTENDED_SURFACE_ORIENTATION_ENUM
enum qt_extended_surface_orientation
{
QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION = 0,
QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION = 1,
QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION = 2,
QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION = 4,
QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION = 8,
};
#endif /* QT_EXTENDED_SURFACE_ORIENTATION_ENUM */
#ifndef QT_EXTENDED_SURFACE_WINDOWFLAG_ENUM
#define QT_EXTENDED_SURFACE_WINDOWFLAG_ENUM
enum qt_extended_surface_windowflag
{
QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES = 1,
QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP = 2,
};
#endif /* QT_EXTENDED_SURFACE_WINDOWFLAG_ENUM */
struct qt_extended_surface_listener
{
/**
* onscreen_visibility - (none)
* @visible: (none)
*/
void (*onscreen_visibility)(void *data,
struct qt_extended_surface *qt_extended_surface,
int32_t visible);
/**
* set_generic_property - (none)
* @name: (none)
* @value: (none)
*/
void (*set_generic_property)(void *data,
struct qt_extended_surface *qt_extended_surface,
const char *name,
struct wl_array *value);
/**
* close - (none)
*/
void (*close)(void *data,
struct qt_extended_surface *qt_extended_surface);
};
static inline int qt_extended_surface_add_listener(struct qt_extended_surface *qt_extended_surface,
const struct qt_extended_surface_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *)qt_extended_surface,
(void (**)(void))listener, data);
}
#define QT_EXTENDED_SURFACE_UPDATE_GENERIC_PROPERTY 0
#define QT_EXTENDED_SURFACE_SET_CONTENT_ORIENTATION 1
#define QT_EXTENDED_SURFACE_SET_WINDOW_FLAGS 2
static inline void qt_extended_surface_set_user_data(struct qt_extended_surface *qt_extended_surface, void *user_data)
{
WAYLAND_wl_proxy_set_user_data((struct wl_proxy *)qt_extended_surface, user_data);
}
static inline void *qt_extended_surface_get_user_data(struct qt_extended_surface *qt_extended_surface)
{
return WAYLAND_wl_proxy_get_user_data((struct wl_proxy *)qt_extended_surface);
}
static inline void qt_extended_surface_destroy(struct qt_extended_surface *qt_extended_surface)
{
WAYLAND_wl_proxy_destroy((struct wl_proxy *)qt_extended_surface);
}
static inline void qt_extended_surface_update_generic_property(struct qt_extended_surface *qt_extended_surface, const char *name, struct wl_array *value)
{
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_extended_surface,
QT_EXTENDED_SURFACE_UPDATE_GENERIC_PROPERTY, name, value);
}
static inline void qt_extended_surface_set_content_orientation(struct qt_extended_surface *qt_extended_surface, int32_t orientation)
{
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_extended_surface,
QT_EXTENDED_SURFACE_SET_CONTENT_ORIENTATION, orientation);
}
static inline void qt_extended_surface_set_window_flags(struct qt_extended_surface *qt_extended_surface, int32_t flags)
{
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_extended_surface,
QT_EXTENDED_SURFACE_SET_WINDOW_FLAGS, flags);
}
/* wayland-qt-touch-extension.h */
extern const struct wl_interface qt_touch_extension_interface;
#ifndef QT_TOUCH_EXTENSION_FLAGS_ENUM
#define QT_TOUCH_EXTENSION_FLAGS_ENUM
enum qt_touch_extension_flags
{
QT_TOUCH_EXTENSION_FLAGS_MOUSE_FROM_TOUCH = 0x1,
};
#endif /* QT_TOUCH_EXTENSION_FLAGS_ENUM */
struct qt_touch_extension_listener
{
/**
* touch - (none)
* @time: (none)
* @id: (none)
* @state: (none)
* @x: (none)
* @y: (none)
* @normalized_x: (none)
* @normalized_y: (none)
* @width: (none)
* @height: (none)
* @pressure: (none)
* @velocity_x: (none)
* @velocity_y: (none)
* @flags: (none)
* @rawdata: (none)
*/
void (*touch)(void *data,
struct qt_touch_extension *qt_touch_extension,
uint32_t time,
uint32_t id,
uint32_t state,
int32_t x,
int32_t y,
int32_t normalized_x,
int32_t normalized_y,
int32_t width,
int32_t height,
uint32_t pressure,
int32_t velocity_x,
int32_t velocity_y,
uint32_t flags,
struct wl_array *rawdata);
/**
* configure - (none)
* @flags: (none)
*/
void (*configure)(void *data,
struct qt_touch_extension *qt_touch_extension,
uint32_t flags);
};
static inline int qt_touch_extension_add_listener(struct qt_touch_extension *qt_touch_extension,
const struct qt_touch_extension_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *)qt_touch_extension,
(void (**)(void))listener, data);
}
#define QT_TOUCH_EXTENSION_DUMMY 0
static inline void qt_touch_extension_set_user_data(struct qt_touch_extension *qt_touch_extension, void *user_data)
{
WAYLAND_wl_proxy_set_user_data((struct wl_proxy *)qt_touch_extension, user_data);
}
static inline void *qt_touch_extension_get_user_data(struct qt_touch_extension *qt_touch_extension)
{
return WAYLAND_wl_proxy_get_user_data((struct wl_proxy *)qt_touch_extension);
}
static inline void qt_touch_extension_destroy(struct qt_touch_extension *qt_touch_extension)
{
WAYLAND_wl_proxy_destroy((struct wl_proxy *)qt_touch_extension);
}
static inline void qt_touch_extension_dummy(struct qt_touch_extension *qt_touch_extension)
{
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_touch_extension,
QT_TOUCH_EXTENSION_DUMMY);
}
/* wayland-qt-windowmanager.h */
extern const struct wl_interface qt_windowmanager_interface;
struct qt_windowmanager_listener
{
/**
* hints - (none)
* @show_is_fullscreen: (none)
*/
void (*hints)(void *data,
struct qt_windowmanager *qt_windowmanager,
int32_t show_is_fullscreen);
/**
* quit - (none)
*/
void (*quit)(void *data,
struct qt_windowmanager *qt_windowmanager);
};
static inline int qt_windowmanager_add_listener(struct qt_windowmanager *qt_windowmanager,
const struct qt_windowmanager_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *)qt_windowmanager,
(void (**)(void))listener, data);
}
#define QT_WINDOWMANAGER_OPEN_URL 0
static inline void qt_windowmanager_set_user_data(struct qt_windowmanager *qt_windowmanager, void *user_data)
{
WAYLAND_wl_proxy_set_user_data((struct wl_proxy *)qt_windowmanager, user_data);
}
static inline void *qt_windowmanager_get_user_data(struct qt_windowmanager *qt_windowmanager)
{
return WAYLAND_wl_proxy_get_user_data((struct wl_proxy *)qt_windowmanager);
}
static inline void qt_windowmanager_destroy(struct qt_windowmanager *qt_windowmanager)
{
WAYLAND_wl_proxy_destroy((struct wl_proxy *)qt_windowmanager);
}
static inline void qt_windowmanager_open_url(struct qt_windowmanager *qt_windowmanager, uint32_t remaining, const char *url)
{
WAYLAND_wl_proxy_marshal((struct wl_proxy *)qt_windowmanager,
QT_WINDOWMANAGER_OPEN_URL, remaining, url);
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
#endif /* SDL_waylandtouch_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandvideo_h_
#define SDL_waylandvideo_h_
#include <EGL/egl.h>
#include "wayland-util.h"
#include "../SDL_sysvideo.h"
#include "../../core/linux/SDL_dbus.h"
#include "../../core/linux/SDL_ime.h"
struct xkb_context;
struct SDL_WaylandInput;
struct SDL_WaylandTabletManager;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch;
struct qt_surface_extension;
struct qt_windowmanager;
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
typedef struct
{
struct wl_cursor_theme *theme;
int size;
} SDL_WaylandCursorTheme;
struct SDL_VideoData
{
SDL_bool initializing;
struct wl_display *display;
int display_disconnected;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
SDL_WaylandCursorTheme *cursor_themes;
int num_cursor_themes;
struct wl_pointer *pointer;
struct
{
struct xdg_wm_base *xdg;
#ifdef HAVE_LIBDECOR_H
struct libdecor *libdecor;
#endif
} shell;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct zxdg_decoration_manager_v1 *decoration_manager;
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
struct zwp_text_input_manager_v3 *text_input_manager;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
struct xkb_context *xkb_context;
struct SDL_WaylandInput *input;
struct SDL_WaylandTabletManager *tablet_manager;
struct wl_list output_list;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch *touch;
struct qt_surface_extension *surface_extension;
struct qt_windowmanager *windowmanager;
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
int relative_mouse_mode;
};
struct SDL_DisplayData
{
SDL_VideoData *videodata;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t registry_id;
float scale_factor;
int pixel_width, pixel_height;
int x, y, screen_width, screen_height, refresh, transform;
SDL_DisplayOrientation orientation;
int physical_width, physical_height;
SDL_bool has_logical_position, has_logical_size;
SDL_DisplayID display;
SDL_VideoDisplay placeholder;
int wl_output_done_count;
struct wl_list link;
};
/* Needed here to get wl_surface declaration, fixes GitHub#4594 */
#include "SDL_waylanddyn.h"
extern void SDL_WAYLAND_register_surface(struct wl_surface *surface);
extern void SDL_WAYLAND_register_output(struct wl_output *output);
extern SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface);
extern SDL_bool SDL_WAYLAND_own_output(struct wl_output *output);
extern SDL_bool Wayland_LoadLibdecor(SDL_VideoData *data, SDL_bool ignore_xdg);
extern SDL_bool Wayland_VideoReconnect(SDL_VideoDevice *_this);
#endif /* SDL_waylandvideo_h_ */

View File

@ -0,0 +1,175 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WAYLAND)
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandvulkan.h"
#include <SDL3/SDL_syswm.h>
#ifdef __OpenBSD__
#define DEFAULT_VULKAN "libvulkan.so"
#else
#define DEFAULT_VULKAN "libvulkan.so.1"
#endif
int Wayland_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 i, extensionCount = 0;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasWaylandSurfaceExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
/* Load the Vulkan loader library */
if (path == NULL) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_VULKAN;
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return -1;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (extensions == NULL) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasWaylandSurfaceExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasWaylandSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "extension");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void Wayland_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
SDL_bool Wayland_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
static const char *const extensionsForWayland[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
};
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForWayland),
extensionsForWayland);
}
SDL_bool Wayland_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
SDL_WindowData *windowData = window->driverdata;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR =
(PFN_vkCreateWaylandSurfaceKHR)vkGetInstanceProcAddr(
instance,
"vkCreateWaylandSurfaceKHR");
VkWaylandSurfaceCreateInfoKHR createInfo;
VkResult result;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (!vkCreateWaylandSurfaceKHR) {
SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.display = windowData->waylandData->display;
createInfo.surface = windowData->surface;
result = vkCreateWaylandSurfaceKHR(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateWaylandSurfaceKHR failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.h.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandvulkan_h_
#define SDL_waylandvulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WAYLAND)
int Wayland_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void Wayland_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool Wayland_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool Wayland_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_waylandvulkan_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,160 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_waylandwindow_h_
#define SDL_waylandwindow_h_
#include "../SDL_sysvideo.h"
#include "../../events/SDL_touch_c.h"
#include <SDL3/SDL_syswm.h>
#include "SDL_waylandvideo.h"
struct SDL_WaylandInput;
struct SDL_WindowData
{
SDL_Window *sdlwindow;
SDL_VideoData *waylandData;
struct wl_surface *surface;
struct wl_callback *gles_swap_frame_callback;
struct wl_event_queue *gles_swap_frame_event_queue;
struct wl_surface *gles_swap_frame_surface_wrapper;
struct wl_callback *surface_frame_callback;
union
{
#ifdef HAVE_LIBDECOR_H
struct
{
struct libdecor_frame *frame;
SDL_bool initial_configure_seen;
} libdecor;
#endif
struct
{
struct xdg_surface *surface;
union
{
struct xdg_toplevel *toplevel;
struct
{
struct xdg_popup *popup;
struct xdg_positioner *positioner;
} popup;
} roleobj;
SDL_bool initial_configure_seen;
} xdg;
} shell_surface;
enum
{
WAYLAND_SURFACE_UNKNOWN = 0,
WAYLAND_SURFACE_XDG_TOPLEVEL,
WAYLAND_SURFACE_XDG_POPUP,
WAYLAND_SURFACE_LIBDECOR
} shell_surface_type;
enum
{
WAYLAND_SURFACE_STATUS_HIDDEN = 0,
WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE,
WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME,
WAYLAND_SURFACE_STATUS_SHOW_PENDING,
WAYLAND_SURFACE_STATUS_SHOWN
} surface_status;
struct wl_egl_window *egl_window;
struct SDL_WaylandInput *keyboard_device;
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
struct zwp_locked_pointer_v1 *locked_pointer;
struct zwp_confined_pointer_v1 *confined_pointer;
struct zxdg_toplevel_decoration_v1 *server_decoration;
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
struct xdg_activation_token_v1 *activation_token;
struct wp_viewport *draw_viewport;
struct wp_fractional_scale_v1 *fractional_scale;
/* floating dimensions for restoring from maximized and fullscreen */
int floating_width, floating_height;
SDL_AtomicInt swap_interval_ready;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct qt_extended_surface *extended_surface;
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
SDL_DisplayData **outputs;
int num_outputs;
SDL_Window *keyboard_focus;
char *app_id;
float windowed_scale_factor;
float pointer_scale_x;
float pointer_scale_y;
int requested_window_width, requested_window_height;
int drawable_width, drawable_height;
int wl_window_width, wl_window_height;
int system_min_required_width;
int system_min_required_height;
SDL_DisplayID last_displayID;
SDL_bool floating;
SDL_bool suspended;
SDL_bool is_fullscreen;
SDL_bool in_fullscreen_transition;
SDL_bool fullscreen_was_positioned;
};
extern void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window,
SDL_VideoDisplay *_display,
SDL_bool fullscreen);
extern void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void Wayland_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool bordered);
extern void Wayland_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
extern int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);
extern int Wayland_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, SDL_SysWMinfo *info);
extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern int Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
#endif /* SDL_waylandwindow_h_ */