Merge commit '206dcdedf195fb320913584180edb12c7731e396' as 'external/SDL'
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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"
|
||||
|
||||
|
||||
bool Wayland_SetClipboardData(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_implicit_grab_seat;
|
||||
bool result = false;
|
||||
|
||||
// If no implicit grab is available yet, just attach it to the first available seat.
|
||||
if (!seat && !WAYLAND_wl_list_empty(&video_data->seat_list)) {
|
||||
seat = wl_container_of(video_data->seat_list.next, seat, link);
|
||||
}
|
||||
|
||||
video_data->last_incoming_data_offer_seat = seat;
|
||||
|
||||
if (seat && seat->data_device) {
|
||||
SDL_WaylandDataDevice *data_device = seat->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);
|
||||
|
||||
result = Wayland_data_device_set_selection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types);
|
||||
if (!result) {
|
||||
Wayland_data_source_destroy(source);
|
||||
}
|
||||
} else {
|
||||
result = Wayland_data_device_clear_selection(data_device);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_incoming_data_offer_seat;
|
||||
void *buffer = NULL;
|
||||
|
||||
if (seat && seat->data_device) {
|
||||
SDL_WaylandDataDevice *data_device = seat->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, true);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_incoming_data_offer_seat;
|
||||
bool result = false;
|
||||
|
||||
if (seat && seat->data_device) {
|
||||
SDL_WaylandDataDevice *data_device = seat->data_device;
|
||||
if (data_device->selection_source) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_implicit_grab_seat;
|
||||
bool result;
|
||||
|
||||
// If no implicit grab is available yet, just attach it to the first available seat.
|
||||
if (!seat && !WAYLAND_wl_list_empty(&video_data->seat_list)) {
|
||||
seat = wl_container_of(video_data->seat_list.next, seat, link);
|
||||
}
|
||||
|
||||
video_data->last_incoming_primary_selection_seat = seat;
|
||||
|
||||
if (seat && seat->primary_selection_device) {
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->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));
|
||||
|
||||
result = Wayland_primary_selection_device_set_selection(primary_selection_device,
|
||||
source,
|
||||
text_mime_types,
|
||||
SDL_arraysize(text_mime_types));
|
||||
if (!result) {
|
||||
Wayland_primary_selection_source_destroy(source);
|
||||
}
|
||||
} else {
|
||||
result = Wayland_primary_selection_device_clear_selection(primary_selection_device);
|
||||
}
|
||||
} else {
|
||||
result = SDL_SetError("Primary selection not supported");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_incoming_primary_selection_seat;
|
||||
char *text = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
if (seat && seat->primary_selection_device) {
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->primary_selection_device;
|
||||
if (primary_selection_device->selection_source) {
|
||||
text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, TEXT_MIME, &length);
|
||||
} else {
|
||||
for (size_t i = 0; i < SDL_arraysize(text_mime_types); i++) {
|
||||
if (Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, text_mime_types[i])) {
|
||||
text = Wayland_primary_selection_offer_receive(primary_selection_device->selection_offer, text_mime_types[i], &length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
text = SDL_strdup("");
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_WaylandSeat *seat = video_data->last_incoming_primary_selection_seat;
|
||||
bool result = false;
|
||||
|
||||
if (seat && seat->primary_selection_device) {
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->primary_selection_device;
|
||||
if (primary_selection_device->selection_source) {
|
||||
result = true;
|
||||
} else {
|
||||
size_t mime_count = 0;
|
||||
const char **mime_types = Wayland_GetTextMimeTypes(_this, &mime_count);
|
||||
for (size_t i = 0; i < mime_count; i++) {
|
||||
if (Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, mime_types[i])) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 bool Wayland_SetClipboardData(SDL_VideoDevice *_this);
|
||||
extern void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
|
||||
extern bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
extern bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
extern bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_waylandclipboard_h_
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandcolor.h"
|
||||
#include "SDL_waylandvideo.h"
|
||||
#include "SDL_waylandwindow.h"
|
||||
#include "color-management-v1-client-protocol.h"
|
||||
#include "../../events/SDL_windowevents_c.h"
|
||||
|
||||
typedef struct Wayland_ColorInfoState
|
||||
{
|
||||
struct wp_image_description_v1 *wp_image_description;
|
||||
struct wp_image_description_info_v1 *wp_image_description_info;
|
||||
struct wl_event_queue *queue;
|
||||
|
||||
union
|
||||
{
|
||||
SDL_WindowData *window_data;
|
||||
SDL_DisplayData *display_data;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WAYLAND_COLOR_OBJECT_TYPE_WINDOW,
|
||||
WAYLAND_COLOR_OBJECT_TYPE_DISPLAY
|
||||
} object_type;
|
||||
|
||||
SDL_HDROutputProperties HDR;
|
||||
|
||||
// The ICC fd is only valid if the size is non-zero.
|
||||
int icc_fd;
|
||||
Uint32 icc_size;
|
||||
|
||||
bool deferred_event_processing;
|
||||
} Wayland_ColorInfoState;
|
||||
|
||||
static void Wayland_CancelColorInfoRequest(Wayland_ColorInfoState *state)
|
||||
{
|
||||
if (state) {
|
||||
if (state->wp_image_description_info) {
|
||||
wp_image_description_info_v1_destroy(state->wp_image_description_info);
|
||||
state->wp_image_description_info = NULL;
|
||||
}
|
||||
if (state->wp_image_description) {
|
||||
wp_image_description_v1_destroy(state->wp_image_description);
|
||||
state->wp_image_description = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_FreeColorInfoState(Wayland_ColorInfoState *state)
|
||||
{
|
||||
if (state) {
|
||||
Wayland_CancelColorInfoRequest(state);
|
||||
if (state->queue) {
|
||||
WAYLAND_wl_event_queue_destroy(state->queue);
|
||||
}
|
||||
|
||||
switch (state->object_type) {
|
||||
case WAYLAND_COLOR_OBJECT_TYPE_WINDOW:
|
||||
state->window_data->color_info_state = NULL;
|
||||
break;
|
||||
case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY:
|
||||
state->display_data->color_info_state = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_free(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void image_description_info_handle_done(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1)
|
||||
{
|
||||
Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data;
|
||||
Wayland_CancelColorInfoRequest(state);
|
||||
|
||||
switch (state->object_type) {
|
||||
case WAYLAND_COLOR_OBJECT_TYPE_WINDOW:
|
||||
{
|
||||
SDL_SetWindowHDRProperties(state->window_data->sdlwindow, &state->HDR, true);
|
||||
if (state->icc_size) {
|
||||
state->window_data->icc_fd = state->icc_fd;
|
||||
state->window_data->icc_size = state->icc_size;
|
||||
SDL_SendWindowEvent(state->window_data->sdlwindow, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0);
|
||||
}
|
||||
} break;
|
||||
case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY:
|
||||
{
|
||||
SDL_copyp(&state->display_data->HDR, &state->HDR);
|
||||
|
||||
if (state->display_data->display) {
|
||||
SDL_VideoDisplay *disp = SDL_GetVideoDisplay(state->display_data->display);
|
||||
if (disp) {
|
||||
SDL_SetDisplayHDRProperties(disp, &state->HDR);
|
||||
}
|
||||
} else {
|
||||
SDL_copyp(&state->display_data->placeholder.HDR, &state->HDR);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static void image_description_info_handle_icc_file(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
int32_t icc, uint32_t icc_size)
|
||||
{
|
||||
Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data;
|
||||
|
||||
state->icc_fd = icc;
|
||||
state->icc_size = icc_size;
|
||||
}
|
||||
|
||||
static void image_description_info_handle_primaries(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
int32_t r_x, int32_t r_y,
|
||||
int32_t g_x, int32_t g_y,
|
||||
int32_t b_x, int32_t b_y,
|
||||
int32_t w_x, int32_t w_y)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_primaries_named(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t primaries)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_tf_power(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t eexp)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_tf_named(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t tf)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_luminances(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t min_lum,
|
||||
uint32_t max_lum,
|
||||
uint32_t reference_lum)
|
||||
{
|
||||
Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data;
|
||||
state->HDR.HDR_headroom = (float)max_lum / (float)reference_lum;
|
||||
}
|
||||
|
||||
static void image_description_info_handle_target_primaries(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
int32_t r_x, int32_t r_y,
|
||||
int32_t g_x, int32_t g_y,
|
||||
int32_t b_x, int32_t b_y,
|
||||
int32_t w_x, int32_t w_y)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_target_luminance(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t min_lum,
|
||||
uint32_t max_lum)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_target_max_cll(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t max_cll)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static void image_description_info_handle_target_max_fall(void *data,
|
||||
struct wp_image_description_info_v1 *wp_image_description_info_v1,
|
||||
uint32_t max_fall)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static const struct wp_image_description_info_v1_listener image_description_info_listener = {
|
||||
image_description_info_handle_done,
|
||||
image_description_info_handle_icc_file,
|
||||
image_description_info_handle_primaries,
|
||||
image_description_info_handle_primaries_named,
|
||||
image_description_info_handle_tf_power,
|
||||
image_description_info_handle_tf_named,
|
||||
image_description_info_handle_luminances,
|
||||
image_description_info_handle_target_primaries,
|
||||
image_description_info_handle_target_luminance,
|
||||
image_description_info_handle_target_max_cll,
|
||||
image_description_info_handle_target_max_fall
|
||||
};
|
||||
|
||||
static void PumpColorspaceEvents(Wayland_ColorInfoState *state)
|
||||
{
|
||||
SDL_VideoData *vid = SDL_GetVideoDevice()->internal;
|
||||
|
||||
// Run the image description sequence to completion in its own queue.
|
||||
while (state->wp_image_description) {
|
||||
WAYLAND_wl_display_dispatch_queue(vid->display, state->queue);
|
||||
}
|
||||
|
||||
Wayland_FreeColorInfoState(state);
|
||||
}
|
||||
|
||||
static void image_description_handle_failed(void *data,
|
||||
struct wp_image_description_v1 *wp_image_description_v1,
|
||||
uint32_t cause,
|
||||
const char *msg)
|
||||
{
|
||||
Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data;
|
||||
Wayland_CancelColorInfoRequest(state);
|
||||
|
||||
if (state->deferred_event_processing) {
|
||||
Wayland_FreeColorInfoState(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void image_description_handle_ready2(void *data,
|
||||
struct wp_image_description_v1 *wp_image_description_v1,
|
||||
uint32_t identity_hi, uint32_t identity_lo)
|
||||
{
|
||||
Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data;
|
||||
|
||||
/* If event processing was deferred, then the image description is on the default queue.
|
||||
* Otherwise, it will inherit the queue from the image description object.
|
||||
*/
|
||||
if (state->deferred_event_processing) {
|
||||
SDL_VideoData *vid = SDL_GetVideoDevice()->internal;
|
||||
state->queue = Wayland_DisplayCreateQueue(vid->display, "SDL Color Management Queue");
|
||||
|
||||
struct wl_proxy *image_desc_wrapper = WAYLAND_wl_proxy_create_wrapper(state->wp_image_description);
|
||||
WAYLAND_wl_proxy_set_queue(image_desc_wrapper, state->queue);
|
||||
state->wp_image_description_info = wp_image_description_v1_get_information((struct wp_image_description_v1 *)image_desc_wrapper);
|
||||
WAYLAND_wl_proxy_wrapper_destroy(image_desc_wrapper);
|
||||
} else {
|
||||
state->wp_image_description_info = wp_image_description_v1_get_information(state->wp_image_description);
|
||||
}
|
||||
wp_image_description_info_v1_add_listener(state->wp_image_description_info, &image_description_info_listener, data);
|
||||
|
||||
if (state->deferred_event_processing) {
|
||||
PumpColorspaceEvents(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void image_description_handle_ready(void *data,
|
||||
struct wp_image_description_v1 *wp_image_description_v1,
|
||||
uint32_t identity)
|
||||
{
|
||||
image_description_handle_ready2(data, wp_image_description_v1, 0, identity);
|
||||
}
|
||||
|
||||
static const struct wp_image_description_v1_listener image_description_listener = {
|
||||
image_description_handle_failed,
|
||||
image_description_handle_ready,
|
||||
image_description_handle_ready2
|
||||
};
|
||||
|
||||
void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing)
|
||||
{
|
||||
// Cancel any pending request, as it is out-of-date.
|
||||
Wayland_FreeColorInfoState(window_data->color_info_state);
|
||||
Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState));
|
||||
|
||||
if (state) {
|
||||
window_data->color_info_state = state;
|
||||
state->window_data = window_data;
|
||||
state->object_type = WAYLAND_COLOR_OBJECT_TYPE_WINDOW;
|
||||
state->deferred_event_processing = defer_event_processing;
|
||||
|
||||
if (!defer_event_processing) {
|
||||
state->queue = Wayland_DisplayCreateQueue(window_data->waylandData->display, "SDL Color Management Queue");
|
||||
|
||||
struct wl_proxy *surface_feedback_wrapper = WAYLAND_wl_proxy_create_wrapper(window_data->wp_color_management_surface_feedback);
|
||||
WAYLAND_wl_proxy_set_queue(surface_feedback_wrapper, state->queue);
|
||||
state->wp_image_description = wp_color_management_surface_feedback_v1_get_preferred((struct wp_color_management_surface_feedback_v1 *)surface_feedback_wrapper);
|
||||
WAYLAND_wl_proxy_wrapper_destroy(surface_feedback_wrapper);
|
||||
} else {
|
||||
state->wp_image_description = wp_color_management_surface_feedback_v1_get_preferred(window_data->wp_color_management_surface_feedback);
|
||||
}
|
||||
wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state);
|
||||
|
||||
if (!defer_event_processing) {
|
||||
PumpColorspaceEvents(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing)
|
||||
{
|
||||
// Cancel any pending request, as it is out-of-date.
|
||||
Wayland_FreeColorInfoState(display_data->color_info_state);
|
||||
Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState));
|
||||
|
||||
if (state) {
|
||||
display_data->color_info_state = state;
|
||||
state->display_data = display_data;
|
||||
state->object_type = WAYLAND_COLOR_OBJECT_TYPE_DISPLAY;
|
||||
state->deferred_event_processing = defer_event_processing;
|
||||
|
||||
if (!defer_event_processing) {
|
||||
state->queue = Wayland_DisplayCreateQueue(display_data->videodata->display, "SDL Color Management Queue");
|
||||
|
||||
struct wl_proxy *output_feedback_wrapper = WAYLAND_wl_proxy_create_wrapper(display_data->wp_color_management_output);
|
||||
WAYLAND_wl_proxy_set_queue(output_feedback_wrapper, state->queue);
|
||||
state->wp_image_description = wp_color_management_output_v1_get_image_description((struct wp_color_management_output_v1 *)output_feedback_wrapper);
|
||||
WAYLAND_wl_proxy_wrapper_destroy(output_feedback_wrapper);
|
||||
} else {
|
||||
state->wp_image_description = wp_color_management_output_v1_get_image_description(display_data->wp_color_management_output);
|
||||
}
|
||||
wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state);
|
||||
|
||||
if (!defer_event_processing) {
|
||||
PumpColorspaceEvents(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandcolor_h_
|
||||
#define SDL_waylandcolor_h_
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
struct Wayland_ColorInfoState;
|
||||
|
||||
extern void Wayland_FreeColorInfoState(struct Wayland_ColorInfoState *state);
|
||||
extern void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing);
|
||||
extern void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing);
|
||||
|
||||
#endif // SDL_waylandcolor_h_
|
||||
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandevents_c.h"
|
||||
#include "SDL_waylanddatamanager.h"
|
||||
#include "primary-selection-unstable-v1-client-protocol.h"
|
||||
|
||||
/* This is arbitrary, but reading while polling should block for less than a frame, to
|
||||
* prevent hanging while pumping events.
|
||||
*
|
||||
* When querying the clipboard data directly, a larger value is needed to avoid timing
|
||||
* out if the source needs to process or transfer a large amount of data.
|
||||
*/
|
||||
#define DEFAULT_PIPE_TIMEOUT_NS SDL_MS_TO_NS(14)
|
||||
#define EXTENDED_PIPE_TIMEOUT_NS SDL_MS_TO_NS(5000)
|
||||
|
||||
/* sigtimedwait() is an optional part of POSIX.1-2001, and OpenBSD doesn't implement it.
|
||||
* Based on https://comp.unix.programmer.narkive.com/rEDH0sPT/sigtimedwait-implementation
|
||||
*/
|
||||
#ifndef HAVE_SIGTIMEDWAIT
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
static int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout)
|
||||
{
|
||||
struct timespec elapsed = { 0 }, rem = { 0 };
|
||||
sigset_t pending;
|
||||
|
||||
do {
|
||||
// Check the pending signals, and call sigwait if there is at least one of interest in the set.
|
||||
sigpending(&pending);
|
||||
for (int signo = 1; signo < NSIG; ++signo) {
|
||||
if (sigismember(set, signo) && sigismember(&pending, signo)) {
|
||||
if (!sigwait(set, &signo)) {
|
||||
if (info) {
|
||||
SDL_zerop(info);
|
||||
info->si_signo = signo;
|
||||
}
|
||||
return signo;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout->tv_sec || timeout->tv_nsec) {
|
||||
long ns = 20000000L; // 2/100ths of a second
|
||||
nanosleep(&(struct timespec){ 0, ns }, &rem);
|
||||
ns -= rem.tv_nsec;
|
||||
elapsed.tv_sec += (elapsed.tv_nsec + ns) / 1000000000L;
|
||||
elapsed.tv_nsec = (elapsed.tv_nsec + ns) % 1000000000L;
|
||||
}
|
||||
} while (elapsed.tv_sec < timeout->tv_sec || (elapsed.tv_sec == timeout->tv_sec && elapsed.tv_nsec < timeout->tv_nsec));
|
||||
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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, DEFAULT_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, NULL, &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, Sint64 timeout_ns)
|
||||
{
|
||||
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, 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) {
|
||||
output_buffer = SDL_malloc(new_buffer_length);
|
||||
} else {
|
||||
output_buffer = SDL_realloc(*buffer, new_buffer_length);
|
||||
}
|
||||
|
||||
if (!output_buffer) {
|
||||
bytes_read = -1;
|
||||
} 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 bool mime_data_list_add(struct wl_list *list,
|
||||
const char *mime_type,
|
||||
const void *buffer, size_t length)
|
||||
{
|
||||
bool result = true;
|
||||
size_t mime_type_length = 0;
|
||||
SDL_MimeDataList *mime_data = NULL;
|
||||
void *internal_buffer = NULL;
|
||||
|
||||
if (buffer) {
|
||||
internal_buffer = SDL_malloc(length);
|
||||
if (!internal_buffer) {
|
||||
return false;
|
||||
}
|
||||
SDL_memcpy(internal_buffer, buffer, length);
|
||||
}
|
||||
|
||||
mime_data = mime_data_list_find(list, mime_type);
|
||||
|
||||
if (!mime_data) {
|
||||
mime_data = SDL_calloc(1, sizeof(*mime_data));
|
||||
if (!mime_data) {
|
||||
result = false;
|
||||
} 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) {
|
||||
result = false;
|
||||
} else {
|
||||
SDL_memcpy(mime_data->mime_type, mime_type, mime_type_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mime_data && buffer && length > 0) {
|
||||
SDL_free(mime_data->data);
|
||||
mime_data->data = internal_buffer;
|
||||
mime_data->length = length;
|
||||
} else {
|
||||
SDL_free(internal_buffer);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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) {
|
||||
SDL_free(mime_data->data);
|
||||
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) {
|
||||
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 (SDL_strcmp(mime_type, SDL_DATA_ORIGIN_MIME) == 0) {
|
||||
data = source->data_device->id_str;
|
||||
length = SDL_strlen(source->data_device->id_str);
|
||||
} else 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, const size_t *len)
|
||||
{
|
||||
void *clone = NULL;
|
||||
if (*len > 0 && buffer) {
|
||||
clone = SDL_malloc((*len)+sizeof(Uint32));
|
||||
if (clone) {
|
||||
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) {
|
||||
SDL_SetError("Invalid data 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_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) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void offer_source_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
|
||||
{
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_WaylandDataOffer *offer = data;
|
||||
char *id = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
wl_callback_destroy(offer->callback);
|
||||
offer->callback = NULL;
|
||||
|
||||
while (read_pipe(offer->read_fd, (void **)&id, &length, DEFAULT_PIPE_TIMEOUT_NS) > 0) {
|
||||
}
|
||||
close(offer->read_fd);
|
||||
offer->read_fd = -1;
|
||||
|
||||
if (id) {
|
||||
const bool source_is_external = SDL_strncmp(offer->data_device->id_str, id, length) != 0;
|
||||
SDL_free(id);
|
||||
if (source_is_external) {
|
||||
Wayland_data_offer_notify_from_mimes(offer, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct wl_callback_listener offer_source_listener = {
|
||||
offer_source_done_handler
|
||||
};
|
||||
|
||||
static void Wayland_data_offer_check_source(SDL_WaylandDataOffer *offer, const char *mime_type)
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = NULL;
|
||||
int pipefd[2];
|
||||
|
||||
if (!offer) {
|
||||
SDL_SetError("Invalid data offer");
|
||||
return;
|
||||
}
|
||||
data_device = offer->data_device;
|
||||
if (!data_device) {
|
||||
SDL_SetError("Data device not initialized");
|
||||
} else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) {
|
||||
SDL_SetError("Could not read pipe");
|
||||
} else {
|
||||
if (offer->callback) {
|
||||
wl_callback_destroy(offer->callback);
|
||||
}
|
||||
if (offer->read_fd >= 0) {
|
||||
close(offer->read_fd);
|
||||
}
|
||||
|
||||
offer->read_fd = pipefd[0];
|
||||
|
||||
wl_data_offer_receive(offer->offer, mime_type, pipefd[1]);
|
||||
close(pipefd[1]);
|
||||
|
||||
offer->callback = wl_display_sync(offer->data_device->seat->display->display);
|
||||
wl_callback_add_listener(offer->callback, &offer_source_listener, offer);
|
||||
|
||||
WAYLAND_wl_display_flush(data_device->seat->display->display);
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_data_offer_notify_from_mimes(SDL_WaylandDataOffer *offer, bool check_origin)
|
||||
{
|
||||
int nformats = 0;
|
||||
char **new_mime_types = NULL;
|
||||
if (offer) {
|
||||
size_t alloc_size = 0;
|
||||
|
||||
// Do a first pass to compute allocation size.
|
||||
SDL_MimeDataList *item = NULL;
|
||||
wl_list_for_each(item, &offer->mimes, link) {
|
||||
// If origin metadata is found, queue a check and wait for confirmation that this offer isn't recursive.
|
||||
if (check_origin && SDL_strcmp(item->mime_type, SDL_DATA_ORIGIN_MIME) == 0) {
|
||||
Wayland_data_offer_check_source(offer, item->mime_type);
|
||||
return;
|
||||
}
|
||||
|
||||
++nformats;
|
||||
alloc_size += SDL_strlen(item->mime_type) + 1;
|
||||
}
|
||||
|
||||
alloc_size += (nformats + 1) * sizeof(char *);
|
||||
|
||||
new_mime_types = SDL_AllocateTemporaryMemory(alloc_size);
|
||||
if (!new_mime_types) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_INPUT, "unable to allocate new_mime_types");
|
||||
return;
|
||||
}
|
||||
|
||||
// Second pass to fill.
|
||||
char *strPtr = (char *)(new_mime_types + nformats + 1);
|
||||
item = NULL;
|
||||
int i = 0;
|
||||
wl_list_for_each(item, &offer->mimes, link) {
|
||||
new_mime_types[i] = strPtr;
|
||||
strPtr = stpcpy(strPtr, item->mime_type) + 1;
|
||||
i++;
|
||||
}
|
||||
new_mime_types[nformats] = NULL;
|
||||
}
|
||||
|
||||
SDL_SendClipboardUpdate(false, new_mime_types, nformats);
|
||||
}
|
||||
|
||||
void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout)
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = NULL;
|
||||
const Sint64 timeout = extended_timeout ? EXTENDED_PIPE_TIMEOUT_NS : DEFAULT_PIPE_TIMEOUT_NS;
|
||||
|
||||
int pipefd[2];
|
||||
void *buffer = NULL;
|
||||
*length = 0;
|
||||
|
||||
if (!offer) {
|
||||
SDL_SetError("Invalid data offer");
|
||||
return NULL;
|
||||
}
|
||||
data_device = offer->data_device;
|
||||
if (!data_device) {
|
||||
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]);
|
||||
close(pipefd[1]);
|
||||
|
||||
WAYLAND_wl_display_flush(data_device->seat->display->display);
|
||||
|
||||
while (read_pipe(pipefd[0], &buffer, length, timeout) > 0) {
|
||||
}
|
||||
close(pipefd[0]);
|
||||
}
|
||||
SDL_LogTrace(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Wayland_data_offer_receive for '%s', buffer (%zu) at %p",
|
||||
mime_type, *length, buffer);
|
||||
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) {
|
||||
SDL_SetError("Invalid data offer");
|
||||
return NULL;
|
||||
}
|
||||
primary_selection_device = offer->primary_selection_device;
|
||||
if (!primary_selection_device) {
|
||||
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]);
|
||||
close(pipefd[1]);
|
||||
|
||||
WAYLAND_wl_display_flush(primary_selection_device->seat->display->display);
|
||||
|
||||
while (read_pipe(pipefd[0], &buffer, length, EXTENDED_PIPE_TIMEOUT_NS) > 0) {
|
||||
}
|
||||
close(pipefd[0]);
|
||||
}
|
||||
SDL_LogTrace(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Wayland_primary_selection_offer_receive for '%s', buffer (%zu) at %p",
|
||||
mime_type, *length, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type)
|
||||
{
|
||||
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
|
||||
}
|
||||
|
||||
bool Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type)
|
||||
{
|
||||
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
|
||||
}
|
||||
|
||||
bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (offer) {
|
||||
found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (offer) {
|
||||
found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
|
||||
{
|
||||
if (offer) {
|
||||
if (offer->callback) {
|
||||
wl_callback_destroy(offer->callback);
|
||||
}
|
||||
if (offer->read_fd >= 0) {
|
||||
close(offer->read_fd);
|
||||
}
|
||||
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) {
|
||||
zwp_primary_selection_offer_v1_destroy(offer->offer);
|
||||
mime_data_list_free(&offer->mimes);
|
||||
SDL_free(offer);
|
||||
}
|
||||
}
|
||||
|
||||
bool Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (!data_device || !data_device->data_device) {
|
||||
result = SDL_SetError("Invalid Data Device");
|
||||
} else if (data_device->selection_source) {
|
||||
wl_data_device_set_selection(data_device->data_device, NULL, data_device->seat->last_implicit_grab_serial);
|
||||
Wayland_data_source_destroy(data_device->selection_source);
|
||||
data_device->selection_source = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (!primary_selection_device || !primary_selection_device->primary_selection_device) {
|
||||
result = SDL_SetError("Invalid Primary Selection Device");
|
||||
} else if (primary_selection_device->selection_source) {
|
||||
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
|
||||
NULL, primary_selection_device->seat->last_implicit_grab_serial);
|
||||
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
|
||||
primary_selection_device->selection_source = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
|
||||
SDL_WaylandDataSource *source,
|
||||
const char **mime_types,
|
||||
size_t mime_count)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (!data_device) {
|
||||
result = SDL_SetError("Invalid Data Device");
|
||||
} else if (!source) {
|
||||
result = 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);
|
||||
}
|
||||
|
||||
// Advertise the data origin MIME
|
||||
wl_data_source_offer(source->source, SDL_DATA_ORIGIN_MIME);
|
||||
|
||||
if (index == 0) {
|
||||
Wayland_data_device_clear_selection(data_device);
|
||||
result = 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) {
|
||||
Wayland_data_source_destroy(data_device->selection_source);
|
||||
}
|
||||
data_device->selection_source = source;
|
||||
source->data_device = data_device;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
|
||||
SDL_WaylandPrimarySelectionSource *source,
|
||||
const char **mime_types,
|
||||
size_t mime_count)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (!primary_selection_device) {
|
||||
result = SDL_SetError("Invalid Primary Selection Device");
|
||||
} else if (!source) {
|
||||
result = 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);
|
||||
result = 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) {
|
||||
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
|
||||
}
|
||||
primary_selection_device->selection_source = source;
|
||||
source->primary_selection_device = primary_selection_device;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device, uint32_t serial)
|
||||
{
|
||||
if (data_device) {
|
||||
data_device->selection_serial = serial;
|
||||
|
||||
// If there was no serial and there is a pending selection set it now.
|
||||
if (data_device->selection_serial == 0 && data_device->selection_source) {
|
||||
wl_data_device_set_selection(data_device->data_device,
|
||||
data_device->selection_source->source,
|
||||
data_device->selection_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (primary_selection_device) {
|
||||
primary_selection_device->selection_serial = serial;
|
||||
|
||||
// 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) {
|
||||
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
|
||||
primary_selection_device->selection_source->source,
|
||||
primary_selection_device->selection_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandevents_c.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"
|
||||
#define FILE_PORTAL_MIME "application/vnd.portal.filetransfer"
|
||||
#define SDL_DATA_ORIGIN_MIME "application/x-sdl3-source-id"
|
||||
|
||||
typedef struct SDL_WaylandDataDevice SDL_WaylandDataDevice;
|
||||
typedef struct SDL_WaylandPrimarySelectionDevice SDL_WaylandPrimarySelectionDevice;
|
||||
|
||||
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;
|
||||
SDL_WaylandDataDevice *data_device;
|
||||
SDL_ClipboardDataCallback callback;
|
||||
SDL_WaylandUserdata userdata;
|
||||
} SDL_WaylandDataSource;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct zwp_primary_selection_source_v1 *source;
|
||||
SDL_WaylandDataDevice *data_device;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
|
||||
SDL_ClipboardDataCallback callback;
|
||||
SDL_WaylandUserdata userdata;
|
||||
} SDL_WaylandPrimarySelectionSource;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_data_offer *offer;
|
||||
struct wl_list mimes;
|
||||
SDL_WaylandDataDevice *data_device;
|
||||
|
||||
// Callback data for queued receive.
|
||||
struct wl_callback *callback;
|
||||
int read_fd;
|
||||
} SDL_WaylandDataOffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct zwp_primary_selection_offer_v1 *offer;
|
||||
struct wl_list mimes;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
|
||||
} SDL_WaylandPrimarySelectionOffer;
|
||||
|
||||
struct SDL_WaylandDataDevice
|
||||
{
|
||||
struct wl_data_device *data_device;
|
||||
struct SDL_WaylandSeat *seat;
|
||||
char *id_str;
|
||||
|
||||
// Drag and Drop
|
||||
uint32_t drag_serial;
|
||||
SDL_WaylandDataOffer *drag_offer;
|
||||
SDL_WaylandDataOffer *selection_offer;
|
||||
const char *mime_type;
|
||||
bool has_mime_file, has_mime_text;
|
||||
SDL_Window *dnd_window;
|
||||
|
||||
// Clipboard and Primary Selection
|
||||
uint32_t selection_serial;
|
||||
SDL_WaylandDataSource *selection_source;
|
||||
};
|
||||
|
||||
struct SDL_WaylandPrimarySelectionDevice
|
||||
{
|
||||
struct zwp_primary_selection_device_v1 *primary_selection_device;
|
||||
struct SDL_WaylandSeat *seat;
|
||||
|
||||
uint32_t selection_serial;
|
||||
SDL_WaylandPrimarySelectionSource *selection_source;
|
||||
SDL_WaylandPrimarySelectionOffer *selection_offer;
|
||||
};
|
||||
|
||||
// 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,
|
||||
bool extended_timeout);
|
||||
extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type,
|
||||
size_t *length);
|
||||
extern bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type);
|
||||
extern void Wayland_data_offer_notify_from_mimes(SDL_WaylandDataOffer *offer,
|
||||
bool check_origin);
|
||||
extern bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type);
|
||||
extern bool Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type);
|
||||
extern bool 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 bool Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device);
|
||||
extern bool Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *device);
|
||||
extern bool Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
|
||||
SDL_WaylandDataSource *source,
|
||||
const char **mime_types,
|
||||
size_t mime_count);
|
||||
extern bool Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *device,
|
||||
SDL_WaylandPrimarySelectionSource *source,
|
||||
const char **mime_types,
|
||||
size_t mime_count);
|
||||
extern void Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
|
||||
uint32_t serial);
|
||||
extern void Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *device,
|
||||
uint32_t serial);
|
||||
#endif // SDL_waylanddatamanager_h_
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland",
|
||||
"Support for Wayland video",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
|
||||
)
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland",
|
||||
"Support for Wayland video",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
|
||||
)
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland",
|
||||
"Support for Wayland video",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
|
||||
)
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland",
|
||||
"Support for Wayland video",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
|
||||
)
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland",
|
||||
"Support for Wayland video",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
|
||||
)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_SharedObject *lib;
|
||||
const char *libname;
|
||||
const char *hint;
|
||||
bool hint_default;
|
||||
} waylanddynlib;
|
||||
|
||||
static waylanddynlib waylandlibs[] = {
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC, NULL, false },
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL, NULL, false },
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR, NULL, false },
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON, NULL, false },
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR, SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, true },
|
||||
#endif
|
||||
{ NULL, NULL, NULL, false }
|
||||
};
|
||||
|
||||
static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, bool required)
|
||||
{
|
||||
void *fn = NULL;
|
||||
waylanddynlib *dynlib;
|
||||
for (dynlib = waylandlibs; dynlib->libname; dynlib++) {
|
||||
if (dynlib->lib) {
|
||||
fn = SDL_LoadFunction(dynlib->lib, fnname);
|
||||
if (fn) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_DYNAMIC_WAYLAND
|
||||
if (fn) {
|
||||
SDL_Log("WAYLAND: Found '%s' in %s (%p)", fnname, dynlib->libname, fn);
|
||||
} else {
|
||||
SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!", fnname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fn && 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;
|
||||
#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;
|
||||
#include "SDL_waylandsym.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
|
||||
for (i = 0; i < SDL_arraysize(waylandlibs); i++) {
|
||||
if (waylandlibs[i].lib) {
|
||||
SDL_UnloadObject(waylandlibs[i].lib);
|
||||
waylandlibs[i].lib = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns non-zero if all needed symbols were loaded.
|
||||
bool SDL_WAYLAND_LoadSymbols(void)
|
||||
{
|
||||
bool result = true; // 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_arraysize(waylandlibs); i++) {
|
||||
if (waylandlibs[i].libname) {
|
||||
if (waylandlibs[i].hint &&
|
||||
!SDL_GetHintBoolean(waylandlibs[i].hint, waylandlibs[i].hint_default)) {
|
||||
continue;
|
||||
}
|
||||
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, true);
|
||||
#define SDL_WAYLAND_SYM_OPT(rc, fn, params) WAYLAND_##fn = (SDL_DYNWAYLANDFN_##fn)WAYLAND_GetSym(#fn, thismod, false);
|
||||
#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();
|
||||
result = false;
|
||||
}
|
||||
|
||||
#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;
|
||||
#include "SDL_waylandsym.h"
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 "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))
|
||||
|
||||
#define SDL_XKBCOMMON_CHECK_VERSION(x, y, z) \
|
||||
(SDL_XKBCOMMON_VERSION_MAJOR > x || \
|
||||
(SDL_XKBCOMMON_VERSION_MAJOR == x && SDL_XKBCOMMON_VERSION_MINOR > y) || \
|
||||
(SDL_XKBCOMMON_VERSION_MAJOR == x && SDL_XKBCOMMON_VERSION_MINOR == y && SDL_XKBCOMMON_VERSION_PATCH >= z))
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
#define SDL_LIBDECOR_CHECK_VERSION(x, y, z) \
|
||||
(SDL_LIBDECOR_VERSION_MAJOR > x || \
|
||||
(SDL_LIBDECOR_VERSION_MAJOR == x && SDL_LIBDECOR_VERSION_MINOR > y) || \
|
||||
(SDL_LIBDECOR_VERSION_MAJOR == x && SDL_LIBDECOR_VERSION_MINOR == y && SDL_LIBDECOR_VERSION_PATCH >= z))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern bool SDL_WAYLAND_LoadSymbols(void);
|
||||
extern 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)
|
||||
|
||||
/*
|
||||
* 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_show_window_menu (*WAYLAND_libdecor_frame_show_window_menu)
|
||||
#define libdecor_frame_get_wm_capabilities (*WAYLAND_libdecor_frame_get_wm_capabilities)
|
||||
#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_
|
||||
+3983
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_keymap_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../events/SDL_pen_c.h"
|
||||
|
||||
#include "SDL_waylandvideo.h"
|
||||
#include "SDL_waylandwindow.h"
|
||||
#include "SDL_waylanddatamanager.h"
|
||||
|
||||
enum SDL_WaylandAxisEvent
|
||||
{
|
||||
SDL_WAYLAND_AXIS_EVENT_CONTINUOUS = 0,
|
||||
SDL_WAYLAND_AXIS_EVENT_DISCRETE,
|
||||
SDL_WAYLAND_AXIS_EVENT_VALUE120
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Sint32 repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
|
||||
Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
|
||||
Uint32 keyboard_id; // ID of the source keyboard.
|
||||
bool is_initialized;
|
||||
|
||||
bool is_key_down;
|
||||
Uint32 key;
|
||||
Uint32 wl_press_time_ms; // Key press time as reported by the Wayland API in milliseconds
|
||||
Uint64 base_time_ns; // Key press time as reported by the Wayland API in nanoseconds
|
||||
Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
|
||||
Uint64 next_repeat_ns; // Next repeat event in nanoseconds
|
||||
Uint32 scancode;
|
||||
char text[8];
|
||||
} SDL_WaylandKeyboardRepeat;
|
||||
|
||||
typedef struct SDL_WaylandCursorState
|
||||
{
|
||||
SDL_CursorData *current_cursor;
|
||||
struct wp_cursor_shape_device_v1 *cursor_shape;
|
||||
struct wl_surface *surface;
|
||||
struct wp_viewport *viewport;
|
||||
|
||||
double scale;
|
||||
|
||||
// Pointer to the internal data for system cursors.
|
||||
void *system_cursor_handle;
|
||||
|
||||
// The cursor animation thread lock must be held when modifying this.
|
||||
struct wl_callback *frame_callback;
|
||||
|
||||
Uint64 last_frame_callback_time_ms;
|
||||
Uint32 current_frame_time_ms;
|
||||
|
||||
// 0 or greater if a buffer is attached, -1 if in the reset state.
|
||||
int current_frame;
|
||||
|
||||
SDL_HitTestResult hit_test_result;
|
||||
} SDL_WaylandCursorState;
|
||||
|
||||
typedef struct SDL_WaylandPenTool // a stylus, etc, on a tablet.
|
||||
{
|
||||
SDL_PenID instance_id;
|
||||
SDL_PenInfo info;
|
||||
SDL_WindowData *focus;
|
||||
struct zwp_tablet_tool_v2 *wltool;
|
||||
Uint32 proximity_serial;
|
||||
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
float axes[SDL_PEN_AXIS_COUNT];
|
||||
Uint32 axes_set;
|
||||
|
||||
enum
|
||||
{
|
||||
WAYLAND_TABLET_TOOL_BUTTON_NONE = 0,
|
||||
WAYLAND_TABLET_TOOL_BUTTON_DOWN,
|
||||
WAYLAND_TABLET_TOOL_BUTTON_UP
|
||||
} buttons[3];
|
||||
|
||||
enum
|
||||
{
|
||||
WAYLAND_TABLET_TOOL_STATE_NONE = 0,
|
||||
WAYLAND_TABLET_TOOL_STATE_DOWN,
|
||||
WAYLAND_TABLET_TOOL_STATE_UP
|
||||
} tool_state;
|
||||
|
||||
bool in_proximity;
|
||||
|
||||
bool have_motion;
|
||||
bool have_proximity;
|
||||
} frame;
|
||||
|
||||
SDL_WaylandCursorState cursor_state;
|
||||
struct wl_list link;
|
||||
} SDL_WaylandPenTool;
|
||||
|
||||
typedef struct SDL_WaylandSeat
|
||||
{
|
||||
SDL_VideoData *display;
|
||||
struct wl_seat *wl_seat;
|
||||
SDL_WaylandDataDevice *data_device;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
|
||||
char *name;
|
||||
struct wl_list link;
|
||||
|
||||
Uint32 last_implicit_grab_serial; // The serial of the last implicit grab event for window activation and selection data.
|
||||
Uint32 registry_id; // The ID of the Wayland seat object,
|
||||
|
||||
struct
|
||||
{
|
||||
struct wl_keyboard *wl_keyboard;
|
||||
struct zwp_input_timestamps_v1 *timestamps;
|
||||
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
|
||||
SDL_WindowData *focus;
|
||||
SDL_Keymap **sdl_keymap;
|
||||
char *current_locale;
|
||||
|
||||
SDL_WaylandKeyboardRepeat repeat;
|
||||
Uint64 highres_timestamp_ns;
|
||||
|
||||
// Current SDL modifier flags
|
||||
SDL_Keymod pressed_modifiers;
|
||||
SDL_Keymod locked_modifiers;
|
||||
|
||||
SDL_KeyboardID sdl_id;
|
||||
bool is_virtual;
|
||||
|
||||
struct
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
struct xkb_compose_table *compose_table;
|
||||
struct xkb_compose_state *compose_state;
|
||||
|
||||
// Current keyboard layout (aka 'group')
|
||||
xkb_layout_index_t num_layouts;
|
||||
xkb_layout_index_t current_layout;
|
||||
|
||||
// Modifier bitshift values
|
||||
xkb_mod_mask_t shift_mask;
|
||||
xkb_mod_mask_t ctrl_mask;
|
||||
xkb_mod_mask_t alt_mask;
|
||||
xkb_mod_mask_t gui_mask;
|
||||
xkb_mod_mask_t level3_mask;
|
||||
xkb_mod_mask_t level5_mask;
|
||||
xkb_mod_mask_t num_mask;
|
||||
xkb_mod_mask_t caps_mask;
|
||||
|
||||
// Current system modifier flags
|
||||
xkb_mod_mask_t wl_pressed_modifiers;
|
||||
xkb_mod_mask_t wl_latched_modifiers;
|
||||
xkb_mod_mask_t wl_locked_modifiers;
|
||||
} xkb;
|
||||
} keyboard;
|
||||
|
||||
struct
|
||||
{
|
||||
struct wl_pointer *wl_pointer;
|
||||
struct zwp_relative_pointer_v1 *relative_pointer;
|
||||
struct zwp_input_timestamps_v1 *timestamps;
|
||||
struct zwp_locked_pointer_v1 *locked_pointer;
|
||||
struct zwp_confined_pointer_v1 *confined_pointer;
|
||||
struct zwp_pointer_gesture_pinch_v1 *gesture_pinch;
|
||||
|
||||
SDL_WindowData *focus;
|
||||
|
||||
// According to the spec, a seat can only have one active gesture of any type at a time.
|
||||
SDL_WindowData *gesture_focus;
|
||||
|
||||
Uint64 highres_timestamp_ns;
|
||||
Uint32 enter_serial;
|
||||
SDL_MouseButtonFlags buttons_pressed;
|
||||
SDL_Point last_motion;
|
||||
bool is_confined;
|
||||
|
||||
SDL_MouseID sdl_id;
|
||||
|
||||
// Information about axis events on the current frame
|
||||
struct
|
||||
{
|
||||
bool have_absolute;
|
||||
bool have_relative;
|
||||
bool have_axis;
|
||||
|
||||
Uint32 buttons_pressed;
|
||||
Uint32 buttons_released;
|
||||
|
||||
struct
|
||||
{
|
||||
wl_fixed_t sx;
|
||||
wl_fixed_t sy;
|
||||
} absolute;
|
||||
|
||||
struct
|
||||
{
|
||||
wl_fixed_t dx;
|
||||
wl_fixed_t dy;
|
||||
wl_fixed_t dx_unaccel;
|
||||
wl_fixed_t dy_unaccel;
|
||||
} relative;
|
||||
|
||||
struct
|
||||
{
|
||||
enum SDL_WaylandAxisEvent x_axis_type;
|
||||
float x;
|
||||
|
||||
enum SDL_WaylandAxisEvent y_axis_type;
|
||||
float y;
|
||||
|
||||
SDL_MouseWheelDirection direction;
|
||||
} axis;
|
||||
|
||||
struct wl_surface *enter_surface;
|
||||
struct wl_surface *leave_surface;
|
||||
|
||||
// Event timestamp in nanoseconds
|
||||
Uint64 timestamp_ns;
|
||||
} pending_frame;
|
||||
|
||||
SDL_WaylandCursorState cursor_state;
|
||||
} pointer;
|
||||
|
||||
struct
|
||||
{
|
||||
struct wl_touch *wl_touch;
|
||||
struct zwp_input_timestamps_v1 *timestamps;
|
||||
Uint64 highres_timestamp_ns;
|
||||
struct wl_list points;
|
||||
} touch;
|
||||
|
||||
struct
|
||||
{
|
||||
struct zwp_text_input_v3 *zwp_text_input;
|
||||
SDL_Rect text_input_rect;
|
||||
int text_input_cursor;
|
||||
bool enabled;
|
||||
bool has_preedit;
|
||||
} text_input;
|
||||
|
||||
struct
|
||||
{
|
||||
struct zwp_tablet_seat_v2 *wl_tablet_seat;
|
||||
struct wl_list tool_list;
|
||||
} tablet;
|
||||
} SDL_WaylandSeat;
|
||||
|
||||
|
||||
extern Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandSeat *seat, 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_DisplayInitInputTimestampManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitPointerGestureManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
|
||||
|
||||
extern void Wayland_DisplayInitTextInputManager(SDL_VideoData *d, uint32_t id);
|
||||
|
||||
extern void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id);
|
||||
extern void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool shutting_down);
|
||||
|
||||
extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||
extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||
extern void Wayland_DisplayRemoveWindowReferencesFromSeats(SDL_VideoData *display, SDL_WindowData *window);
|
||||
|
||||
/* 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_WaylandSeat *seat, Uint32 serial);
|
||||
|
||||
#endif // SDL_waylandevents_h_
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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"
|
||||
|
||||
bool Wayland_InitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
#ifdef SDL_USE_IME
|
||||
SDL_VideoData *internal = _this->internal;
|
||||
if (!internal->text_input_manager) {
|
||||
SDL_IME_Init();
|
||||
}
|
||||
#endif
|
||||
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wayland_QuitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
#ifdef SDL_USE_IME
|
||||
SDL_VideoData *internal = _this->internal;
|
||||
if (!internal->text_input_manager) {
|
||||
SDL_IME_Quit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wayland_SeatUpdateTextInput(SDL_WaylandSeat *seat)
|
||||
{
|
||||
if (seat->text_input.zwp_text_input) {
|
||||
SDL_WindowData *focus = seat->keyboard.focus;
|
||||
|
||||
if (focus && focus->text_input_props.active) {
|
||||
SDL_Window *window = focus->sdlwindow;
|
||||
|
||||
// Enabling will reset all state, so don't do it redundantly.
|
||||
if (!seat->text_input.enabled) {
|
||||
seat->text_input.enabled = true;
|
||||
zwp_text_input_v3_enable(seat->text_input.zwp_text_input);
|
||||
|
||||
// Now that it's enabled, set the input properties
|
||||
zwp_text_input_v3_set_content_type(seat->text_input.zwp_text_input, focus->text_input_props.hint, focus->text_input_props.purpose);
|
||||
if (!SDL_RectEmpty(&window->text_input_rect)) {
|
||||
const SDL_Rect scaled_rect = {
|
||||
(int)SDL_floor(window->text_input_rect.x / focus->pointer_scale.x),
|
||||
(int)SDL_floor(window->text_input_rect.y / focus->pointer_scale.y),
|
||||
(int)SDL_ceil(window->text_input_rect.w / focus->pointer_scale.x),
|
||||
(int)SDL_ceil(window->text_input_rect.h / focus->pointer_scale.y)
|
||||
};
|
||||
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / focus->pointer_scale.x);
|
||||
|
||||
SDL_copyp(&seat->text_input.text_input_rect, &scaled_rect);
|
||||
seat->text_input.text_input_cursor = scaled_cursor;
|
||||
|
||||
// Clamp the x value so it doesn't run too far past the end of the text input area.
|
||||
zwp_text_input_v3_set_cursor_rectangle(seat->text_input.zwp_text_input,
|
||||
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
|
||||
scaled_rect.y,
|
||||
1,
|
||||
scaled_rect.h);
|
||||
}
|
||||
zwp_text_input_v3_commit(seat->text_input.zwp_text_input);
|
||||
|
||||
if (seat->keyboard.xkb.compose_state) {
|
||||
// Reset compose state so composite and dead keys don't carry over
|
||||
WAYLAND_xkb_compose_state_reset(seat->keyboard.xkb.compose_state);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seat->text_input.enabled) {
|
||||
seat->text_input.enabled = false;
|
||||
SDL_zero(seat->text_input.text_input_rect);
|
||||
seat->text_input.text_input_cursor = 0;
|
||||
zwp_text_input_v3_disable(seat->text_input.zwp_text_input);
|
||||
zwp_text_input_v3_commit(seat->text_input.zwp_text_input);
|
||||
}
|
||||
|
||||
if (seat->keyboard.xkb.compose_state) {
|
||||
// Reset compose state so composite and dead keys don't carry over
|
||||
WAYLAND_xkb_compose_state_reset(seat->keyboard.xkb.compose_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
SDL_VideoData *display = _this->internal;
|
||||
|
||||
if (display->text_input_manager) {
|
||||
SDL_WindowData *wind = window->internal;
|
||||
wind->text_input_props.hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
|
||||
|
||||
switch (SDL_GetTextInputType(props)) {
|
||||
default:
|
||||
case SDL_TEXTINPUT_TYPE_TEXT:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD;
|
||||
wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD;
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN;
|
||||
wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
|
||||
wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN;
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (SDL_GetTextInputCapitalization(props)) {
|
||||
default:
|
||||
case SDL_CAPITALIZE_NONE:
|
||||
break;
|
||||
case SDL_CAPITALIZE_LETTERS:
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
|
||||
break;
|
||||
case SDL_CAPITALIZE_WORDS:
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE;
|
||||
break;
|
||||
case SDL_CAPITALIZE_SENTENCES:
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SDL_GetTextInputAutocorrect(props)) {
|
||||
wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK);
|
||||
}
|
||||
if (SDL_GetTextInputMultiline(props)) {
|
||||
wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE;
|
||||
}
|
||||
|
||||
wind->text_input_props.active = true;
|
||||
|
||||
SDL_WaylandSeat *seat;
|
||||
wl_list_for_each (seat, &display->seat_list, link) {
|
||||
if (seat->keyboard.focus == wind) {
|
||||
Wayland_SeatUpdateTextInput(seat);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return SDL_SetError("wayland: cannot enable text input; compositor lacks support for the required zwp_text_input_v3 protocol");
|
||||
}
|
||||
|
||||
bool Wayland_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_VideoData *display = _this->internal;
|
||||
|
||||
if (display->text_input_manager) {
|
||||
SDL_WaylandSeat *seat;
|
||||
SDL_WindowData *wind = window->internal;
|
||||
wind->text_input_props.active = false;
|
||||
|
||||
wl_list_for_each (seat, &display->seat_list, link) {
|
||||
if (seat->keyboard.focus == wind) {
|
||||
Wayland_SeatUpdateTextInput(seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SDL_USE_IME
|
||||
else {
|
||||
SDL_IME_Reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_VideoData *internal = _this->internal;
|
||||
if (internal->text_input_manager) {
|
||||
SDL_WaylandSeat *seat;
|
||||
SDL_WindowData *wind = window->internal;
|
||||
|
||||
wl_list_for_each (seat, &internal->seat_list, link) {
|
||||
if (seat->text_input.zwp_text_input && seat->keyboard.focus == wind) {
|
||||
const SDL_Rect scaled_rect = {
|
||||
(int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
|
||||
(int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
|
||||
(int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
|
||||
(int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
|
||||
};
|
||||
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
|
||||
|
||||
if (!SDL_RectsEqual(&scaled_rect, &seat->text_input.text_input_rect) || scaled_cursor != seat->text_input.text_input_cursor) {
|
||||
SDL_copyp(&seat->text_input.text_input_rect, &scaled_rect);
|
||||
seat->text_input.text_input_cursor = scaled_cursor;
|
||||
|
||||
// Clamp the x value so it doesn't run too far past the end of the text input area.
|
||||
zwp_text_input_v3_set_cursor_rectangle(seat->text_input.zwp_text_input,
|
||||
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
|
||||
scaled_rect.y,
|
||||
1,
|
||||
scaled_rect.h);
|
||||
zwp_text_input_v3_commit(seat->text_input.zwp_text_input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SDL_USE_IME
|
||||
else {
|
||||
SDL_IME_UpdateTextInputArea(window);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
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 *internal = _this->internal;
|
||||
SDL_WaylandSeat *seat;
|
||||
bool hastextmanager = (internal->text_input_manager != NULL);
|
||||
bool haskeyboard = false;
|
||||
|
||||
// Check for at least one keyboard object on one seat.
|
||||
wl_list_for_each (seat, &internal->seat_list, link) {
|
||||
if (seat->keyboard.wl_keyboard) {
|
||||
haskeyboard = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !haskeyboard && hastextmanager;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_
|
||||
|
||||
extern bool Wayland_InitKeyboard(SDL_VideoDevice *_this);
|
||||
extern void Wayland_QuitKeyboard(SDL_VideoDevice *_this);
|
||||
extern bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern bool Wayland_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SeatUpdateTextInput(SDL_WaylandSeat *seat);
|
||||
extern bool Wayland_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_waylandkeyboard_h_
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandmessagebox.h"
|
||||
#include "../../dialog/unix/SDL_zenitymessagebox.h"
|
||||
|
||||
bool Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
|
||||
{
|
||||
// Are we trying to connect to or are currently in a Wayland session?
|
||||
if (!SDL_getenv("WAYLAND_DISPLAY")) {
|
||||
const char *session = SDL_getenv("XDG_SESSION_TYPE");
|
||||
if (session && SDL_strcasecmp(session, "wayland") != 0) {
|
||||
return SDL_SetError("Not on a wayland display");
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_Zenity_ShowMessageBox(messageboxdata, buttonID);
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 bool Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND
|
||||
|
||||
#endif // SDL_waylandmessagebox_h_
|
||||
+1632
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandmouse_h_
|
||||
#define SDL_waylandmouse_h_
|
||||
|
||||
extern void Wayland_InitMouse(SDL_VideoData *data);
|
||||
extern void Wayland_FiniMouse(SDL_VideoData *data);
|
||||
extern void Wayland_SeatUpdatePointerCursor(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_SeatSetDefaultCursor(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_SeatResetCursor(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_DisplayUpdatePointerFocusedScale(SDL_WindowData *updated_window);
|
||||
extern void Wayland_TabletToolUpdateCursor(SDL_WaylandPenTool *tool);
|
||||
extern void Wayland_SeatWarpMouse(SDL_WaylandSeat *seat, SDL_WindowData *window, float x, float y);
|
||||
extern void Wayland_CursorStateSetFrameCallback(SDL_WaylandCursorState *state, void *userdata);
|
||||
extern void Wayland_CursorStateDestroyFrameCallback(SDL_WaylandCursorState *state);
|
||||
extern void Wayland_CursorStateRelease(SDL_WaylandCursorState *state);
|
||||
#if 0 // TODO RECONNECT: See waylandvideo.c for more information!
|
||||
extern void Wayland_RecreateCursors(void);
|
||||
#endif // 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
void Wayland_GLES_SetDefaultProfileConfig(SDL_VideoDevice *_this)
|
||||
{
|
||||
#if defined(SDL_PLATFORM_QNXNTO)
|
||||
// QNX defaults to EGL_PLATFORM_SCREEN_QNX unless this is explicitly specified
|
||||
_this->gl_config.egl_platform = EGL_PLATFORM_WAYLAND_EXT;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wayland_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
bool result;
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
result = SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)data->display);
|
||||
|
||||
Wayland_PumpEvents(_this);
|
||||
WAYLAND_wl_display_flush(data->display);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_GLContext Wayland_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_GLContext context;
|
||||
context = SDL_EGL_CreateContext(_this, window->internal->egl_surface);
|
||||
WAYLAND_wl_display_flush(_this->internal->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. :/ */
|
||||
bool 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 true;
|
||||
}
|
||||
|
||||
bool 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 true;
|
||||
}
|
||||
|
||||
bool Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
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->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN &&
|
||||
data->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* By default, we wait for the Wayland frame callback and then issue the pageflip (eglSwapBuffers),
|
||||
* but if we want low latency (double buffer scheme), we issue the pageflip and then wait
|
||||
* immediately for the Wayland frame callback.
|
||||
*/
|
||||
if (data->double_buffer) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Control swap interval ourselves. See comments on Wayland_GLES_SetSwapInterval
|
||||
if (swap_interval != 0 && data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOWN) {
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
struct wl_display *display = videodata->display;
|
||||
// 20hz, so we'll progress even if throttled to zero.
|
||||
const Uint64 max_wait = SDL_GetTicksNS() + (SDL_NS_PER_SECOND / 20);
|
||||
while (SDL_GetAtomicInt(&data->swap_interval_ready) == 0) {
|
||||
Uint64 now;
|
||||
|
||||
WAYLAND_wl_display_flush(display);
|
||||
|
||||
/* wl_display_prepare_read_queue() will return false 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_SetAtomicInt(&data->swap_interval_ready, 0);
|
||||
}
|
||||
|
||||
if (!data->double_buffer) {
|
||||
// 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 true;
|
||||
}
|
||||
|
||||
bool Wayland_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
|
||||
{
|
||||
bool result;
|
||||
|
||||
if (window && context) {
|
||||
result = SDL_EGL_MakeCurrent(_this, window->internal->egl_surface, context);
|
||||
} else {
|
||||
result = SDL_EGL_MakeCurrent(_this, NULL, NULL);
|
||||
}
|
||||
|
||||
WAYLAND_wl_display_flush(_this->internal->display);
|
||||
|
||||
_this->egl_data->eglSwapInterval(_this->egl_data->egl_display, 0); // see comments on Wayland_GLES_SetSwapInterval.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wayland_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context)
|
||||
{
|
||||
bool result = SDL_EGL_DestroyContext(_this, context);
|
||||
WAYLAND_wl_display_flush(_this->internal->display);
|
||||
return result;
|
||||
}
|
||||
|
||||
EGLSurface Wayland_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *windowdata = window->internal;
|
||||
|
||||
return windowdata->egl_surface;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 bool Wayland_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern SDL_GLContext Wayland_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern bool Wayland_GLES_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern bool Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
extern bool Wayland_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
extern void Wayland_GLES_SetDefaultProfileConfig(SDL_VideoDevice *_this);
|
||||
extern SDL_EGLSurface Wayland_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#endif // SDL_waylandopengles_h_
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "SDL_waylandshmbuffer.h"
|
||||
#include "SDL_waylandvideo.h"
|
||||
#include "single-pixel-buffer-v1-client-protocol.h"
|
||||
|
||||
static bool SetTempFileSize(int fd, off_t size)
|
||||
{
|
||||
#ifdef HAVE_POSIX_FALLOCATE
|
||||
sigset_t set, old_set;
|
||||
int ret;
|
||||
|
||||
/* SIGALRM can potentially block a large posix_fallocate() operation
|
||||
* from succeeding, so block it.
|
||||
*/
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGALRM);
|
||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
|
||||
do {
|
||||
ret = posix_fallocate(fd, 0, size);
|
||||
} while (ret == EINTR);
|
||||
|
||||
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||
|
||||
if (ret == 0) {
|
||||
return true;
|
||||
} else if (ret != EINVAL && errno != EOPNOTSUPP) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ftruncate(fd, size) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int CreateTempFD(off_t size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef HAVE_MEMFD_CREATE
|
||||
fd = memfd_create("SDL", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd >= 0) {
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
static const char template[] = "/sdl-shared-XXXXXX";
|
||||
const char *xdg_path;
|
||||
char tmp_path[PATH_MAX];
|
||||
|
||||
xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
|
||||
if (!xdg_path) {
|
||||
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;
|
||||
}
|
||||
|
||||
// Need to manually unlink the temp files, or they can persist after close and fill up the temp storage.
|
||||
unlink(tmp_path);
|
||||
}
|
||||
|
||||
if (!SetTempFileSize(fd, size)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
static struct wl_buffer_listener buffer_listener = {
|
||||
buffer_handle_release
|
||||
};
|
||||
|
||||
struct Wayland_SHMPool
|
||||
{
|
||||
struct wl_shm_pool *shm_pool;
|
||||
void *shm_pool_memory;
|
||||
int shm_pool_size;
|
||||
int offset;
|
||||
};
|
||||
|
||||
Wayland_SHMPool *Wayland_AllocSHMPool(int size)
|
||||
{
|
||||
SDL_VideoDevice *vd = SDL_GetVideoDevice();
|
||||
SDL_VideoData *data = vd->internal;
|
||||
|
||||
if (size <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Wayland_SHMPool *shmPool = SDL_calloc(1, sizeof(Wayland_SHMPool));
|
||||
if (!shmPool) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shmPool->shm_pool_size = (size + 15) & (~15);
|
||||
|
||||
const int shm_fd = CreateTempFD(shmPool->shm_pool_size);
|
||||
if (shm_fd < 0) {
|
||||
SDL_free(shmPool);
|
||||
SDL_SetError("Creating SHM buffer failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shmPool->shm_pool_memory = mmap(NULL, shmPool->shm_pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
if (shmPool->shm_pool_memory == MAP_FAILED) {
|
||||
shmPool->shm_pool_memory = NULL;
|
||||
close(shm_fd);
|
||||
SDL_free(shmPool);
|
||||
SDL_SetError("mmap() failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shmPool->shm_pool = wl_shm_create_pool(data->shm, shm_fd, shmPool->shm_pool_size);
|
||||
close(shm_fd);
|
||||
|
||||
return shmPool;
|
||||
}
|
||||
|
||||
struct wl_buffer *Wayland_AllocBufferFromPool(Wayland_SHMPool *shmPool, int width, int height, void **data)
|
||||
{
|
||||
const Uint32 SHM_FMT = WL_SHM_FORMAT_ARGB8888;
|
||||
|
||||
if (!shmPool || !width || !height || !data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*data = (Uint8 *)shmPool->shm_pool_memory + shmPool->offset;
|
||||
struct wl_buffer *buffer = wl_shm_pool_create_buffer(shmPool->shm_pool, shmPool->offset, width, height, width * 4, SHM_FMT);
|
||||
wl_buffer_add_listener(buffer, &buffer_listener, shmPool);
|
||||
|
||||
shmPool->offset += width * height * 4;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Wayland_ReleaseSHMPool(Wayland_SHMPool *shmPool)
|
||||
{
|
||||
if (shmPool) {
|
||||
wl_shm_pool_destroy(shmPool->shm_pool);
|
||||
munmap(shmPool->shm_pool_memory, shmPool->shm_pool_size);
|
||||
SDL_free(shmPool);
|
||||
}
|
||||
}
|
||||
|
||||
struct wl_buffer *Wayland_CreateSinglePixelBuffer(Uint32 r, Uint32 g, Uint32 b, Uint32 a)
|
||||
{
|
||||
SDL_VideoData *viddata = SDL_GetVideoDevice()->internal;
|
||||
|
||||
// The single-pixel buffer protocol is preferred, as the compositor can choose an optimal format.
|
||||
if (viddata->single_pixel_buffer_manager) {
|
||||
return wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(viddata->single_pixel_buffer_manager, r, g, b, a);
|
||||
} else {
|
||||
Wayland_SHMPool *pool = Wayland_AllocSHMPool(4);
|
||||
if (!pool) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *mem;
|
||||
struct wl_buffer *wl_buffer = Wayland_AllocBufferFromPool(pool, 1, 1, &mem);
|
||||
|
||||
const Uint8 pixel[4] = { r >> 24, g >> 24, b >> 24, a >> 24 };
|
||||
SDL_memcpy(mem, pixel, sizeof(pixel));
|
||||
|
||||
Wayland_ReleaseSHMPool(pool);
|
||||
return wl_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_waylandshmbuffer_h_
|
||||
#define SDL_waylandshmbuffer_h_
|
||||
|
||||
typedef struct Wayland_SHMPool Wayland_SHMPool;
|
||||
|
||||
extern Wayland_SHMPool *Wayland_AllocSHMPool(int size);
|
||||
extern struct wl_buffer *Wayland_AllocBufferFromPool(Wayland_SHMPool *shmPool, int width, int height, void **data);
|
||||
extern void Wayland_ReleaseSHMPool(Wayland_SHMPool *shmPool);
|
||||
|
||||
extern struct wl_buffer *Wayland_CreateSinglePixelBuffer(Uint32 r, Uint32 g, Uint32 b, Uint32 a);
|
||||
|
||||
#endif
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
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 *interface, 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 SDL_WAYLAND_CHECK_VERSION(1, 23, 0) || defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC)
|
||||
SDL_WAYLAND_SYM_OPT(struct wl_event_queue *, wl_display_create_queue_with_name, (struct wl_display *display, const char *name))
|
||||
#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_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_state_reset, (struct xkb_compose_state *) )
|
||||
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(xkb_layout_index_t, xkb_keymap_num_layouts, (struct xkb_keymap *) )
|
||||
SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, const xkb_keysym_t **) )
|
||||
SDL_WAYLAND_SYM(xkb_level_index_t, xkb_keymap_num_levels_for_key, (struct xkb_keymap *, xkb_keycode_t, xkb_layout_index_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))
|
||||
|
||||
#if SDL_XKBCOMMON_CHECK_VERSION(1, 0, 0)
|
||||
SDL_WAYLAND_SYM(size_t, xkb_keymap_key_get_mods_for_level, (struct xkb_keymap *, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, xkb_mod_mask_t *, size_t) )
|
||||
#else
|
||||
// Only needed in the fallback replacement for xkb_keymap_key_get_mods_for_level().
|
||||
SDL_WAYLAND_SYM(xkb_level_index_t, xkb_state_key_get_level, (struct xkb_state *, xkb_keycode_t, xkb_layout_index_t) )
|
||||
#endif
|
||||
|
||||
#if SDL_XKBCOMMON_CHECK_VERSION(1, 10, 0)
|
||||
SDL_WAYLAND_SYM(xkb_mod_mask_t, xkb_keymap_mod_get_mask, (struct xkb_keymap *, const char *))
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR)
|
||||
|
||||
#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || SDL_LIBDECOR_CHECK_VERSION(0, 3, 0)
|
||||
#define SDL_libdecor_constsince03 const
|
||||
#else
|
||||
#define SDL_libdecor_constsince03 /* nothing */
|
||||
#endif
|
||||
|
||||
SDL_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *))
|
||||
SDL_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *,\
|
||||
SDL_libdecor_constsince03 struct libdecor_interface *))
|
||||
SDL_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\
|
||||
struct wl_surface *,\
|
||||
SDL_libdecor_constsince03 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(void, libdecor_frame_show_window_menu, (struct libdecor_frame *, struct wl_seat *, uint32_t, int, int))
|
||||
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) || SDL_LIBDECOR_CHECK_VERSION(0, 2, 0)
|
||||
// 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, (const struct libdecor_frame *,\
|
||||
int *,\
|
||||
int *))
|
||||
SDL_WAYLAND_SYM_OPT(void, libdecor_frame_get_max_content_size, (const struct libdecor_frame *,\
|
||||
int *,\
|
||||
int *))
|
||||
#endif
|
||||
|
||||
#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || SDL_LIBDECOR_CHECK_VERSION(0, 3, 0)
|
||||
SDL_WAYLAND_SYM_OPT(enum libdecor_wm_capabilities, libdecor_frame_get_wm_capabilities, (struct libdecor_frame *))
|
||||
#endif
|
||||
|
||||
#undef SDL_libdecor_constsince03
|
||||
|
||||
#endif
|
||||
|
||||
#undef SDL_WAYLAND_MODULE
|
||||
#undef SDL_WAYLAND_SYM
|
||||
#undef SDL_WAYLAND_SYM_OPT
|
||||
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
+1890
File diff suppressed because it is too large
Load Diff
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_WaylandSeat;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_cursor_theme *theme;
|
||||
int size;
|
||||
} SDL_WaylandCursorTheme;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_list link;
|
||||
char wl_output_name[];
|
||||
} SDL_WaylandConnectorName;
|
||||
|
||||
struct SDL_VideoData
|
||||
{
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_shm *shm;
|
||||
SDL_WaylandCursorTheme *cursor_themes;
|
||||
int num_cursor_themes;
|
||||
struct
|
||||
{
|
||||
struct xdg_wm_base *xdg;
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
struct libdecor *libdecor;
|
||||
#endif
|
||||
} shell;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||
struct wp_pointer_warp_v1 *wp_pointer_warp_v1;
|
||||
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
|
||||
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 zxdg_exporter_v2 *zxdg_exporter_v2;
|
||||
struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1;
|
||||
struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1;
|
||||
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1;
|
||||
struct frog_color_management_factory_v1 *frog_color_management_factory_v1;
|
||||
struct wp_color_manager_v1 *wp_color_manager_v1;
|
||||
struct zwp_tablet_manager_v2 *tablet_manager;
|
||||
struct wl_fixes *wl_fixes;
|
||||
struct zwp_pointer_gestures_v1 *zwp_pointer_gestures;
|
||||
struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager;
|
||||
|
||||
struct xkb_context *xkb_context;
|
||||
|
||||
struct wl_list seat_list;
|
||||
struct SDL_WaylandSeat *last_implicit_grab_seat;
|
||||
struct SDL_WaylandSeat *last_incoming_data_offer_seat;
|
||||
struct SDL_WaylandSeat *last_incoming_primary_selection_seat;
|
||||
|
||||
SDL_DisplayData **output_list;
|
||||
int output_count;
|
||||
int output_max;
|
||||
|
||||
bool initializing;
|
||||
bool display_disconnected;
|
||||
bool display_externally_owned;
|
||||
bool scale_to_display_enabled;
|
||||
};
|
||||
|
||||
struct SDL_DisplayData
|
||||
{
|
||||
SDL_VideoData *videodata;
|
||||
struct wl_output *output;
|
||||
struct zxdg_output_v1 *xdg_output;
|
||||
struct wp_color_management_output_v1 *wp_color_management_output;
|
||||
struct Wayland_ColorInfoState *color_info_state;
|
||||
char *wl_output_name;
|
||||
double scale_factor;
|
||||
Uint32 registry_id;
|
||||
|
||||
struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} logical;
|
||||
|
||||
struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} pixel;
|
||||
|
||||
struct
|
||||
{
|
||||
int width_mm; // Physical width in millimeters.
|
||||
int height_mm; // Physical height in millimeters.
|
||||
} physical;
|
||||
|
||||
int refresh; // Refresh in mHz
|
||||
int transform; // wl_output_transform enum
|
||||
SDL_DisplayOrientation orientation;
|
||||
|
||||
SDL_HDROutputProperties HDR;
|
||||
|
||||
SDL_DisplayID display;
|
||||
SDL_VideoDisplay placeholder;
|
||||
|
||||
int wl_output_done_count;
|
||||
bool has_logical_position;
|
||||
bool has_logical_size;
|
||||
bool geometry_changed;
|
||||
};
|
||||
|
||||
// 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 bool SDL_WAYLAND_own_surface(struct wl_surface *surface);
|
||||
extern bool SDL_WAYLAND_own_output(struct wl_output *output);
|
||||
|
||||
extern SDL_WindowData *Wayland_GetWindowDataForOwnedSurface(struct wl_surface *surface);
|
||||
void Wayland_AddWindowDataToExternalList(SDL_WindowData *data);
|
||||
void Wayland_RemoveWindowDataFromExternalList(SDL_WindowData *data);
|
||||
struct wl_event_queue *Wayland_DisplayCreateQueue(struct wl_display *display, const char *name);
|
||||
|
||||
extern bool Wayland_LoadLibdecor(SDL_VideoData *data, bool ignore_xdg);
|
||||
|
||||
extern bool Wayland_HandleDisplayDisconnected(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_waylandvideo_h_
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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_vulkan_internal.h"
|
||||
|
||||
#include "SDL_waylandvideo.h"
|
||||
#include "SDL_waylandwindow.h"
|
||||
|
||||
#include "SDL_waylandvulkan.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_OPENBSD
|
||||
#define DEFAULT_VULKAN "libvulkan.so"
|
||||
#else
|
||||
#define DEFAULT_VULKAN "libvulkan.so.1"
|
||||
#endif
|
||||
|
||||
SDL_ELF_NOTE_DLOPEN(
|
||||
"wayland-vulkan",
|
||||
"Support for Vulkan on wayland backend",
|
||||
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
DEFAULT_VULKAN
|
||||
)
|
||||
|
||||
bool Wayland_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
VkExtensionProperties *extensions = NULL;
|
||||
Uint32 i, extensionCount = 0;
|
||||
bool hasSurfaceExtension = false;
|
||||
bool hasWaylandSurfaceExtension = false;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
|
||||
if (_this->vulkan_config.loader_handle) {
|
||||
return SDL_SetError("Vulkan already loaded");
|
||||
}
|
||||
|
||||
// Load the Vulkan loader library
|
||||
if (!path) {
|
||||
path = SDL_GetHint(SDL_HINT_VULKAN_LIBRARY);
|
||||
}
|
||||
if (!path) {
|
||||
path = DEFAULT_VULKAN;
|
||||
}
|
||||
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < extensionCount; i++) {
|
||||
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasSurfaceExtension = true;
|
||||
} else if (SDL_strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasWaylandSurfaceExtension = 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 true;
|
||||
|
||||
fail:
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
char const * const *Wayland_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count)
|
||||
{
|
||||
static const char *const extensionsForWayland[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
|
||||
if (count) {
|
||||
*count = SDL_arraysize(extensionsForWayland);
|
||||
}
|
||||
|
||||
return extensionsForWayland;
|
||||
}
|
||||
|
||||
bool Wayland_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface)
|
||||
{
|
||||
SDL_WindowData *windowData = window->internal;
|
||||
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) {
|
||||
return SDL_SetError("Vulkan is not loaded");
|
||||
}
|
||||
|
||||
if (!vkCreateWaylandSurfaceKHR) {
|
||||
return SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
|
||||
" extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
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, allocator, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
return SDL_SetError("vkCreateWaylandSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wayland_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator)
|
||||
{
|
||||
if (_this->vulkan_config.loader_handle) {
|
||||
SDL_Vulkan_DestroySurface_Internal(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
bool Wayland_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
Uint32 queueFamilyIndex)
|
||||
{
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
|
||||
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
|
||||
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR =
|
||||
(PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkGetPhysicalDeviceWaylandPresentationSupportKHR");
|
||||
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return SDL_SetError("Vulkan is not loaded");
|
||||
}
|
||||
|
||||
if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) {
|
||||
return SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
|
||||
return vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice,
|
||||
queueFamilyIndex,
|
||||
_this->internal->display);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 <SDL3/SDL_vulkan.h>
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WAYLAND)
|
||||
|
||||
extern bool Wayland_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern void Wayland_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
extern char const * const *Wayland_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
|
||||
extern bool Wayland_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
extern void Wayland_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator);
|
||||
extern bool Wayland_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
Uint32 queueFamilyIndex);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDL_waylandvulkan_h_
|
||||
+3588
File diff suppressed because it is too large
Load Diff
+283
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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 "SDL_waylandvideo.h"
|
||||
#include "SDL_waylandshmbuffer.h"
|
||||
|
||||
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;
|
||||
} libdecor;
|
||||
#endif
|
||||
struct
|
||||
{
|
||||
struct xdg_surface *surface;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
} toplevel;
|
||||
struct
|
||||
{
|
||||
struct xdg_popup *xdg_popup;
|
||||
struct xdg_positioner *xdg_positioner;
|
||||
} popup;
|
||||
};
|
||||
|
||||
Uint32 serial;
|
||||
} xdg;
|
||||
} shell_surface;
|
||||
enum
|
||||
{
|
||||
WAYLAND_SHELL_SURFACE_TYPE_UNKNOWN = 0,
|
||||
WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL,
|
||||
WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP,
|
||||
WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR,
|
||||
WAYLAND_SHELL_SURFACE_TYPE_CUSTOM
|
||||
} shell_surface_type;
|
||||
enum
|
||||
{
|
||||
WAYLAND_SHELL_SURFACE_STATUS_HIDDEN = 0,
|
||||
WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE,
|
||||
WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME,
|
||||
WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING,
|
||||
WAYLAND_SHELL_SURFACE_STATUS_SHOWN
|
||||
} shell_surface_status;
|
||||
enum
|
||||
{
|
||||
WAYLAND_WM_CAPS_WINDOW_MENU = 0x01,
|
||||
WAYLAND_WM_CAPS_MAXIMIZE = 0x02,
|
||||
WAYLAND_WM_CAPS_FULLSCREEN = 0x04,
|
||||
WAYLAND_WM_CAPS_MINIMIZE = 0x08,
|
||||
|
||||
WAYLAND_WM_CAPS_ALL = WAYLAND_WM_CAPS_WINDOW_MENU |
|
||||
WAYLAND_WM_CAPS_MAXIMIZE |
|
||||
WAYLAND_WM_CAPS_FULLSCREEN |
|
||||
WAYLAND_WM_CAPS_MINIMIZE
|
||||
} wm_caps;
|
||||
enum
|
||||
{
|
||||
WAYLAND_TOPLEVEL_CONSTRAINED_LEFT = 0x01,
|
||||
WAYLAND_TOPLEVEL_CONSTRAINED_RIGHT = 0x02,
|
||||
WAYLAND_TOPLEVEL_CONSTRAINED_TOP = 0x04,
|
||||
WAYLAND_TOPLEVEL_CONSTRAINED_BOTTOM = 0x08
|
||||
} toplevel_constraints;
|
||||
|
||||
struct wl_egl_window *egl_window;
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
EGLSurface egl_surface;
|
||||
#endif
|
||||
struct zxdg_toplevel_decoration_v1 *server_decoration;
|
||||
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
|
||||
struct xdg_activation_token_v1 *activation_token;
|
||||
struct wp_viewport *viewport;
|
||||
struct wp_fractional_scale_v1 *fractional_scale;
|
||||
struct zxdg_exported_v2 *exported;
|
||||
struct xdg_dialog_v1 *xdg_dialog_v1;
|
||||
struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1;
|
||||
struct xdg_toplevel_icon_v1 *xdg_toplevel_icon_v1;
|
||||
struct frog_color_managed_surface *frog_color_managed_surface;
|
||||
struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback;
|
||||
|
||||
struct Wayland_ColorInfoState *color_info_state;
|
||||
|
||||
SDL_AtomicInt swap_interval_ready;
|
||||
|
||||
SDL_DisplayData **outputs;
|
||||
int num_outputs;
|
||||
|
||||
char *app_id;
|
||||
double scale_factor;
|
||||
|
||||
struct wl_buffer **icon_buffers;
|
||||
int icon_buffer_count;
|
||||
|
||||
// Keyboard, pointer, and touch focus refcount.
|
||||
int keyboard_focus_count;
|
||||
int pointer_focus_count;
|
||||
int active_touch_count;
|
||||
|
||||
struct
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
} pointer_scale;
|
||||
|
||||
// The in-flight window size request.
|
||||
struct
|
||||
{
|
||||
// The requested logical window size.
|
||||
int logical_width;
|
||||
int logical_height;
|
||||
|
||||
// The size of the window in pixels, when using screen space scaling.
|
||||
int pixel_width;
|
||||
int pixel_height;
|
||||
} requested;
|
||||
|
||||
// The current size of the window and drawable backing store.
|
||||
struct
|
||||
{
|
||||
// The size of the underlying window.
|
||||
int logical_width;
|
||||
int logical_height;
|
||||
|
||||
// The size of the window backbuffer in pixels.
|
||||
int pixel_width;
|
||||
int pixel_height;
|
||||
|
||||
// The dimensions of the active viewport, in logical units.
|
||||
int viewport_width;
|
||||
int viewport_height;
|
||||
} current;
|
||||
|
||||
// The last compositor requested parameters; used for deduplication of window geometry configuration.
|
||||
struct
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} last_configure;
|
||||
|
||||
// System enforced window size limits.
|
||||
struct
|
||||
{
|
||||
// Minimum allowed logical window size.
|
||||
int min_width;
|
||||
int min_height;
|
||||
} system_limits;
|
||||
|
||||
struct
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} toplevel_bounds;
|
||||
|
||||
struct
|
||||
{
|
||||
struct wl_surface *surface;
|
||||
struct wl_subsurface *subsurface;
|
||||
struct wl_buffer *buffer;
|
||||
struct wp_viewport *viewport;
|
||||
|
||||
int offset_x;
|
||||
int offset_y;
|
||||
|
||||
bool mapped;
|
||||
bool opaque;
|
||||
} mask;
|
||||
|
||||
struct
|
||||
{
|
||||
int hint;
|
||||
int purpose;
|
||||
bool active;
|
||||
} text_input_props;
|
||||
|
||||
SDL_DisplayID last_displayID;
|
||||
int pending_state_deadline_count;
|
||||
Uint64 last_focus_event_time_ns;
|
||||
int icc_fd;
|
||||
Uint32 icc_size;
|
||||
bool floating;
|
||||
bool suspended;
|
||||
bool resizing;
|
||||
bool active;
|
||||
bool pending_config_ack;
|
||||
bool pending_state_commit;
|
||||
bool limits_changed;
|
||||
bool is_fullscreen;
|
||||
bool fullscreen_exclusive;
|
||||
bool drop_fullscreen_requests;
|
||||
bool showing_window;
|
||||
bool fullscreen_was_positioned;
|
||||
bool show_hide_sync_required;
|
||||
bool scale_to_display;
|
||||
bool reparenting_required;
|
||||
bool double_buffer;
|
||||
|
||||
SDL_HitTestResult hit_test_result;
|
||||
|
||||
struct wl_list external_window_list_link;
|
||||
};
|
||||
|
||||
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 SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *_display, SDL_FullscreenOp fullscreen);
|
||||
extern void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern bool Wayland_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, bool bordered);
|
||||
extern void Wayland_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
extern bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
extern bool Wayland_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SetWindowAspectRatio(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 SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent_window);
|
||||
extern bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern bool Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);
|
||||
extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
extern bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
extern float Wayland_GetWindowContentScale(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
|
||||
|
||||
extern bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled);
|
||||
extern bool Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
extern bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_ReconfigureWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_WindowFlags flags);
|
||||
|
||||
extern void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, SDL_DisplayData *display_data);
|
||||
extern void Wayland_UpdateWindowPosition(SDL_Window *window);
|
||||
|
||||
#endif // SDL_waylandwindow_h_
|
||||
Reference in New Issue
Block a user