mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-10-02 16:23:57 +08:00
Add support for X11 primary selection (#6132)
X11 has a so-called primary selection, which you can use by marking text and middle-clicking elsewhere to copy the marked text.
There are 3 new API functions in `SDL_clipboard.h`, which work exactly like their clipboard equivalents.
## Test Instructions
* Run the tests (just a copy of the clipboard tests): `$ ./test/testautomation --filter Clipboard`
* Build and run this small application:
<details>
```C
#include <SDL.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void print_error(const char *where)
{
const char *errstr = SDL_GetError();
if (errstr == NULL || errstr[0] == '\0')
return;
fprintf(stderr, "SDL Error after '%s': %s\n", where, errstr);
SDL_ClearError();
}
int main()
{
char text_buf[256];
srand(time(NULL));
SDL_Init(SDL_INIT_VIDEO);
print_error("SDL_INIT()");
SDL_Window *window = SDL_CreateWindow("Primary Selection Test", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 400, 400, SDL_WINDOW_SHOWN);
print_error("SDL_CreateWindow()");
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
print_error("SDL_CreateRenderer()");
bool quit = false;
unsigned int do_render = 0;
while (!quit) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
print_error("SDL_PollEvent()");
switch (event.type) {
case SDL_QUIT: {
quit = true;
break;
} case SDL_KEYDOWN: {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
quit = true;
break;
case SDLK_c:
snprintf(text_buf, sizeof(text_buf), "foo%d", rand());
SDL_SetClipboardText(text_buf);
print_error("SDL_SetClipboardText()");
printf("clipboard: set_to=\"%s\"\n", text_buf);
break;
case SDLK_v: {
printf("clipboard: has=%d, ", SDL_HasClipboardText());
print_error("SDL_HasClipboardText()");
char *text = SDL_GetClipboardText();
print_error("SDL_GetClipboardText()");
printf("text=\"%s\"\n", text);
SDL_free(text);
break;
} case SDLK_d:
snprintf(text_buf, sizeof(text_buf), "bar%d", rand());
SDL_SetPrimarySelectionText(text_buf);
print_error("SDL_SetPrimarySelectionText()");
printf("primselec: set_to=\"%s\"\n", text_buf);
break;
case SDLK_f: {
printf("primselec: has=%d, ", SDL_HasPrimarySelectionText());
print_error("SDL_HasPrimarySelectionText()");
char *text = SDL_GetPrimarySelectionText();
print_error("SDL_GetPrimarySelectionText()");
printf("text=\"%s\"\n", text);
SDL_free(text);
break;
} default:
break;
}
break;
} default: {
break;
}}
}
// create less noise with WAYLAND_DEBUG=1
if (do_render == 0) {
SDL_RenderPresent(renderer);
print_error("SDL_RenderPresent()");
}
do_render += 1;
usleep(12000);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
print_error("quit");
return 0;
}
```
</details>
* Use c,v,d,f to get and set the clipboard and primary selection.
* Mark text and middle-click also in other applications.
* For wayland under x:
* `$ mutter --wayland --no-x11 --nested`
* `$ XDG_SESSION_TYPE=wayland SDL_VIDEODRIVER=wayland ./<path_to_test_appl_binary>`
This commit is contained in:
@@ -82,6 +82,52 @@ extern DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_HasClipboardText(void);
|
||||
|
||||
/**
|
||||
* Put UTF-8 text into the primary selection.
|
||||
*
|
||||
* \param text the text to store in the primary selection
|
||||
* \returns 0 on success or a negative error code on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \since This function is available since SDL 2.25.0.
|
||||
*
|
||||
* \sa SDL_GetPrimarySelectionText
|
||||
* \sa SDL_HasPrimarySelectionText
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_SetPrimarySelectionText(const char *text);
|
||||
|
||||
/**
|
||||
* Get UTF-8 text from the primary selection, which must be freed with SDL_free().
|
||||
*
|
||||
* This functions returns empty string if there was not enough memory left for
|
||||
* a copy of the primary selection's content.
|
||||
*
|
||||
* \returns the primary selection text on success or an empty string on failure;
|
||||
* call SDL_GetError() for more information. Caller must call SDL_free()
|
||||
* on the returned pointer when done with it (even if there was an
|
||||
* error).
|
||||
*
|
||||
* \since This function is available since SDL 2.25.0.
|
||||
*
|
||||
* \sa SDL_HasPrimarySelectionText
|
||||
* \sa SDL_SetPrimarySelectionText
|
||||
*/
|
||||
extern DECLSPEC char * SDLCALL SDL_GetPrimarySelectionText(void);
|
||||
|
||||
/**
|
||||
* Query whether the primary selection exists and contains a non-empty text
|
||||
* string.
|
||||
*
|
||||
* \returns SDL_TRUE if the primary selection has text, or SDL_FALSE if it does
|
||||
* not.
|
||||
*
|
||||
* \since This function is available since SDL 2.25.0.
|
||||
*
|
||||
* \sa SDL_GetPrimarySelectionText
|
||||
* \sa SDL_SetPrimarySelectionText
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_HasPrimarySelectionText(void);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -143,7 +143,7 @@ typedef enum
|
||||
SDL_MULTIGESTURE,
|
||||
|
||||
/* Clipboard events */
|
||||
SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
|
||||
SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard or primary selection changed */
|
||||
|
||||
/* Drag and drop events */
|
||||
SDL_DROPFILE = 0x1000, /**< The system requests a file open */
|
||||
|
||||
@@ -860,3 +860,6 @@
|
||||
++'_SDL_crc16'.'SDL2.dll'.'SDL_crc16'
|
||||
++'_SDL_GetWindowSizeInPixels'.'SDL2.dll'.'SDL_GetWindowSizeInPixels'
|
||||
++'_SDL_GetJoystickGUIDInfo'.'SDL2.dll'.'SDL_GetJoystickGUIDInfo'
|
||||
++'_SDL_SetPrimarySelectionText'.'SDL2.dll'.'SDL_SetPrimarySelectionText'
|
||||
++'_SDL_GetPrimarySelectionText'.'SDL2.dll'.'SDL_GetPrimarySelectionText'
|
||||
++'_SDL_HasPrimarySelectionText'.'SDL2.dll'.'SDL_HasPrimarySelectionText'
|
||||
|
||||
@@ -886,3 +886,6 @@
|
||||
#define SDL_crc16 SDL_crc16_REAL
|
||||
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
|
||||
#define SDL_GetJoystickGUIDInfo SDL_GetJoystickGUIDInfo_REAL
|
||||
#define SDL_SetPrimarySelectionText SDL_SetPrimarySelectionText_REAL
|
||||
#define SDL_GetPrimarySelectionText SDL_GetPrimarySelectionText_REAL
|
||||
#define SDL_HasPrimarySelectionText SDL_HasPrimarySelectionText_REAL
|
||||
|
||||
@@ -969,3 +969,6 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_ResetHint,(const char *a),(a),return)
|
||||
SDL_DYNAPI_PROC(Uint16,SDL_crc16,(Uint16 a, const void *b, size_t c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),)
|
||||
SDL_DYNAPI_PROC(void,SDL_GetJoystickGUIDInfo,(SDL_JoystickGUID a, Uint16 *b, Uint16 *c, Uint16 *d, Uint16 *e),(a,b,c,d,e),)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetPrimarySelectionText,(const char *a),(a),return)
|
||||
SDL_DYNAPI_PROC(char*,SDL_GetPrimarySelectionText,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_HasPrimarySelectionText,(void),(),return)
|
||||
|
||||
@@ -45,6 +45,27 @@ SDL_SetClipboardText(const char *text)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SetPrimarySelectionText(const char *text)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_SetError("Video subsystem must be initialized to set primary selection text");
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
text = "";
|
||||
}
|
||||
if (_this->SetPrimarySelectionText) {
|
||||
return _this->SetPrimarySelectionText(_this, text);
|
||||
} else {
|
||||
SDL_free(_this->primary_selection_text);
|
||||
_this->primary_selection_text = SDL_strdup(text);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
SDL_GetClipboardText(void)
|
||||
{
|
||||
@@ -66,6 +87,27 @@ SDL_GetClipboardText(void)
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
SDL_GetPrimarySelectionText(void)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
SDL_SetError("Video subsystem must be initialized to get primary selection text");
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
if (_this->GetPrimarySelectionText) {
|
||||
return _this->GetPrimarySelectionText(_this);
|
||||
} else {
|
||||
const char *text = _this->primary_selection_text;
|
||||
if (!text) {
|
||||
text = "";
|
||||
}
|
||||
return SDL_strdup(text);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_HasClipboardText(void)
|
||||
{
|
||||
@@ -87,4 +129,26 @@ SDL_HasClipboardText(void)
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_HasPrimarySelectionText(void)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
SDL_SetError("Video subsystem must be initialized to check primary selection text");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (_this->HasPrimarySelectionText) {
|
||||
return _this->HasPrimarySelectionText(_this);
|
||||
} else {
|
||||
if (_this->primary_selection_text && _this->primary_selection_text[0] != '\0') {
|
||||
return SDL_TRUE;
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -328,6 +328,9 @@ struct SDL_VideoDevice
|
||||
int (*SetClipboardText) (_THIS, const char *text);
|
||||
char * (*GetClipboardText) (_THIS);
|
||||
SDL_bool (*HasClipboardText) (_THIS);
|
||||
int (*SetPrimarySelectionText) (_THIS, const char *text);
|
||||
char * (*GetPrimarySelectionText) (_THIS);
|
||||
SDL_bool (*HasPrimarySelectionText) (_THIS);
|
||||
|
||||
/* MessageBox */
|
||||
int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
||||
@@ -353,6 +356,7 @@ struct SDL_VideoDevice
|
||||
Uint8 window_magic;
|
||||
Uint32 next_object_id;
|
||||
char *clipboard_text;
|
||||
char *primary_selection_text;
|
||||
SDL_bool setting_display_mode;
|
||||
Uint32 quirk_flags;
|
||||
|
||||
@@ -422,11 +426,11 @@ struct SDL_VideoDevice
|
||||
/* Data private to this driver */
|
||||
void *driverdata;
|
||||
struct SDL_GLDriverData *gl_data;
|
||||
|
||||
|
||||
#if SDL_VIDEO_OPENGL_EGL
|
||||
struct SDL_EGL_VideoData *egl_data;
|
||||
#endif
|
||||
|
||||
|
||||
#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
|
||||
struct SDL_PrivateGLESData *gles_data;
|
||||
#endif
|
||||
|
||||
@@ -58,6 +58,39 @@ Wayland_SetClipboardText(_THIS, const char *text)
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
Wayland_SetPrimarySelectionText(_THIS, const char *text)
|
||||
{
|
||||
SDL_VideoData *video_data = NULL;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
||||
|
||||
int status = 0;
|
||||
|
||||
if (_this == NULL || _this->driverdata == NULL) {
|
||||
status = SDL_SetError("Video driver uninitialized");
|
||||
} else {
|
||||
video_data = _this->driverdata;
|
||||
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
|
||||
primary_selection_device = video_data->input->primary_selection_device;
|
||||
if (text[0] != '\0') {
|
||||
SDL_WaylandPrimarySelectionSource* source = Wayland_primary_selection_source_create(_this);
|
||||
Wayland_primary_selection_source_add_data(source, TEXT_MIME, text,
|
||||
SDL_strlen(text));
|
||||
|
||||
status = Wayland_primary_selection_device_set_selection(primary_selection_device,
|
||||
source);
|
||||
if (status != 0) {
|
||||
Wayland_primary_selection_source_destroy(source);
|
||||
}
|
||||
} else {
|
||||
status = Wayland_primary_selection_device_clear_selection(primary_selection_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
char *
|
||||
Wayland_GetClipboardText(_THIS)
|
||||
{
|
||||
@@ -65,8 +98,6 @@ Wayland_GetClipboardText(_THIS)
|
||||
SDL_WaylandDataDevice *data_device = NULL;
|
||||
|
||||
char *text = NULL;
|
||||
|
||||
void *buffer = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
if (_this == NULL || _this->driverdata == NULL) {
|
||||
@@ -75,19 +106,50 @@ Wayland_GetClipboardText(_THIS)
|
||||
video_data = _this->driverdata;
|
||||
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
||||
data_device = video_data->input->data_device;
|
||||
if (data_device->selection_offer != NULL) {
|
||||
buffer = Wayland_data_offer_receive(data_device->selection_offer,
|
||||
/* Prefer own selection, if not canceled */
|
||||
if (Wayland_data_source_has_mime(
|
||||
data_device->selection_source, TEXT_MIME)) {
|
||||
text = Wayland_data_source_get_data(data_device->selection_source,
|
||||
&length, TEXT_MIME, SDL_TRUE);
|
||||
if (length > 0) {
|
||||
text = (char*) buffer;
|
||||
}
|
||||
} else if (Wayland_data_offer_has_mime(
|
||||
data_device->selection_offer, TEXT_MIME)) {
|
||||
text = Wayland_data_offer_receive(data_device->selection_offer,
|
||||
&length, TEXT_MIME, SDL_TRUE);
|
||||
}
|
||||
if (length == 0 && data_device->selection_source != NULL) {
|
||||
buffer = Wayland_data_source_get_data(data_device->selection_source,
|
||||
&length, TEXT_MIME, SDL_TRUE);
|
||||
if (length > 0) {
|
||||
text = (char*) buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (text == NULL) {
|
||||
text = SDL_strdup("");
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
char *
|
||||
Wayland_GetPrimarySelectionText(_THIS)
|
||||
{
|
||||
SDL_VideoData *video_data = NULL;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
||||
|
||||
char *text = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
if (_this == NULL || _this->driverdata == NULL) {
|
||||
SDL_SetError("Video driver uninitialized");
|
||||
} else {
|
||||
video_data = _this->driverdata;
|
||||
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
|
||||
primary_selection_device = video_data->input->primary_selection_device;
|
||||
/* Prefer own selection, if not canceled */
|
||||
if (Wayland_primary_selection_source_has_mime(
|
||||
primary_selection_device->selection_source, TEXT_MIME)) {
|
||||
text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source,
|
||||
&length, TEXT_MIME, SDL_TRUE);
|
||||
} else if (Wayland_primary_selection_offer_has_mime(
|
||||
primary_selection_device->selection_offer, TEXT_MIME)) {
|
||||
text = Wayland_primary_selection_offer_receive(primary_selection_device->selection_offer,
|
||||
&length, TEXT_MIME, SDL_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,13 +174,32 @@ Wayland_HasClipboardText(_THIS)
|
||||
video_data = _this->driverdata;
|
||||
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
||||
data_device = video_data->input->data_device;
|
||||
if (Wayland_data_offer_has_mime(
|
||||
data_device->selection_offer, TEXT_MIME)) {
|
||||
result = SDL_TRUE;
|
||||
} else if (Wayland_data_source_has_mime(
|
||||
data_device->selection_source, TEXT_MIME)) {
|
||||
result = SDL_TRUE;
|
||||
}
|
||||
result = result ||
|
||||
Wayland_data_source_has_mime(data_device->selection_source, TEXT_MIME) ||
|
||||
Wayland_data_offer_has_mime(data_device->selection_offer, TEXT_MIME);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
Wayland_HasPrimarySelectionText(_THIS)
|
||||
{
|
||||
SDL_VideoData *video_data = NULL;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
||||
|
||||
SDL_bool result = SDL_FALSE;
|
||||
if (_this == NULL || _this->driverdata == NULL) {
|
||||
SDL_SetError("Video driver uninitialized");
|
||||
} else {
|
||||
video_data = _this->driverdata;
|
||||
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
|
||||
primary_selection_device = video_data->input->primary_selection_device;
|
||||
result = result ||
|
||||
Wayland_primary_selection_source_has_mime(
|
||||
primary_selection_device->selection_source, TEXT_MIME) ||
|
||||
Wayland_primary_selection_offer_has_mime(
|
||||
primary_selection_device->selection_offer, TEXT_MIME);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
extern int Wayland_SetClipboardText(_THIS, const char *text);
|
||||
extern char *Wayland_GetClipboardText(_THIS);
|
||||
extern SDL_bool Wayland_HasClipboardText(_THIS);
|
||||
extern int Wayland_SetPrimarySelectionText(_THIS, const char *text);
|
||||
extern char *Wayland_GetPrimarySelectionText(_THIS);
|
||||
extern SDL_bool Wayland_HasPrimarySelectionText(_THIS);
|
||||
|
||||
#endif /* SDL_waylandclipboard_h_ */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,12 +43,24 @@ typedef struct {
|
||||
void *data_device;
|
||||
} SDL_WaylandDataSource;
|
||||
|
||||
typedef struct {
|
||||
struct zwp_primary_selection_source_v1 *source;
|
||||
struct wl_list mimes;
|
||||
void *primary_selection_device;
|
||||
} SDL_WaylandPrimarySelectionSource;
|
||||
|
||||
typedef struct {
|
||||
struct wl_data_offer *offer;
|
||||
struct wl_list mimes;
|
||||
void *data_device;
|
||||
} SDL_WaylandDataOffer;
|
||||
|
||||
typedef struct {
|
||||
struct zwp_primary_selection_offer_v1 *offer;
|
||||
struct wl_list mimes;
|
||||
void *primary_selection_device;
|
||||
} SDL_WaylandPrimarySelectionOffer;
|
||||
|
||||
typedef struct {
|
||||
struct wl_data_device *data_device;
|
||||
SDL_VideoData *video_data;
|
||||
@@ -58,46 +70,83 @@ typedef struct {
|
||||
SDL_WaylandDataOffer *drag_offer;
|
||||
SDL_WaylandDataOffer *selection_offer;
|
||||
|
||||
/* Clipboard */
|
||||
/* Clipboard and Primary Selection */
|
||||
uint32_t selection_serial;
|
||||
SDL_WaylandDataSource *selection_source;
|
||||
} SDL_WaylandDataDevice;
|
||||
|
||||
typedef struct {
|
||||
struct zwp_primary_selection_device_v1 *primary_selection_device;
|
||||
SDL_VideoData *video_data;
|
||||
|
||||
uint32_t selection_serial;
|
||||
SDL_WaylandPrimarySelectionSource *selection_source;
|
||||
SDL_WaylandPrimarySelectionOffer *selection_offer;
|
||||
} SDL_WaylandPrimarySelectionDevice;
|
||||
|
||||
extern const char* Wayland_convert_mime_type(const char *mime_type);
|
||||
|
||||
/* Wayland Data Source - (Sending) */
|
||||
/* Wayland Data Source / Primary Selection Source - (Sending) */
|
||||
extern SDL_WaylandDataSource* Wayland_data_source_create(_THIS);
|
||||
extern ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source,
|
||||
extern SDL_WaylandPrimarySelectionSource* Wayland_primary_selection_source_create(_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 int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
|
||||
const char *mime_type,
|
||||
const void *buffer,
|
||||
const char *mime_type,
|
||||
const void *buffer,
|
||||
size_t length);
|
||||
extern int Wayland_primary_selection_source_add_data(SDL_WaylandPrimarySelectionSource *source,
|
||||
const char *mime_type,
|
||||
const void *buffer,
|
||||
size_t length);
|
||||
extern SDL_bool Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
|
||||
const char *mime_type);
|
||||
extern SDL_bool Wayland_primary_selection_source_has_mime(SDL_WaylandPrimarySelectionSource *source,
|
||||
const char *mime_type);
|
||||
extern void* Wayland_data_source_get_data(SDL_WaylandDataSource *source,
|
||||
size_t *length,
|
||||
const char *mime_type,
|
||||
SDL_bool null_terminate);
|
||||
extern void* Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
|
||||
size_t *length,
|
||||
const char *mime_type,
|
||||
SDL_bool null_terminate);
|
||||
extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source);
|
||||
extern void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source);
|
||||
|
||||
/* Wayland Data Offer - (Receiving) */
|
||||
/* Wayland Data / Primary Selection Offer - (Receiving) */
|
||||
extern void* Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
|
||||
size_t *length,
|
||||
const char *mime_type,
|
||||
SDL_bool null_terminate);
|
||||
extern void* Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
size_t *length,
|
||||
const char *mime_type,
|
||||
SDL_bool null_terminate);
|
||||
extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type);
|
||||
extern SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type);
|
||||
extern int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||
const char *mime_type);
|
||||
extern int Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||
const char *mime_type);
|
||||
extern void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer);
|
||||
extern void Wayland_primary_selection_offer_destroy(SDL_WaylandPrimarySelectionOffer *offer);
|
||||
|
||||
/* Clipboard */
|
||||
/* Clipboard / Primary Selection */
|
||||
extern int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device);
|
||||
extern int Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *device);
|
||||
extern int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
|
||||
SDL_WaylandDataSource *source);
|
||||
extern int Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *device,
|
||||
SDL_WaylandPrimarySelectionSource *source);
|
||||
extern int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
|
||||
uint32_t serial);
|
||||
extern int Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *device,
|
||||
uint32_t serial);
|
||||
#endif /* SDL_waylanddatamanager_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,6 +85,7 @@ struct SDL_WaylandInput {
|
||||
struct wl_touch *touch;
|
||||
struct wl_keyboard *keyboard;
|
||||
SDL_WaylandDataDevice *data_device;
|
||||
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
|
||||
SDL_WaylandTextInput *text_input;
|
||||
struct zwp_relative_pointer_v1 *relative_pointer;
|
||||
SDL_WindowData *pointer_focus;
|
||||
@@ -137,6 +138,7 @@ extern void Wayland_SendWakeupEvent(_THIS, SDL_Window *window);
|
||||
extern int Wayland_WaitEventTimeout(_THIS, int timeout);
|
||||
|
||||
extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||
extern void Wayland_add_primary_selection_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||
extern void Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||
|
||||
extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
#include "tablet-unstable-v2-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "primary-selection-unstable-v1-client-protocol.h"
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
#include <libdecor.h>
|
||||
@@ -265,6 +267,9 @@ Wayland_CreateDevice(void)
|
||||
device->SetClipboardText = Wayland_SetClipboardText;
|
||||
device->GetClipboardText = Wayland_GetClipboardText;
|
||||
device->HasClipboardText = Wayland_HasClipboardText;
|
||||
device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText;
|
||||
device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText;
|
||||
device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText;
|
||||
device->StartTextInput = Wayland_StartTextInput;
|
||||
device->StopTextInput = Wayland_StopTextInput;
|
||||
device->SetTextInputRect = Wayland_SetTextInputRect;
|
||||
@@ -868,6 +873,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
||||
Wayland_add_text_input_manager(d, id, version);
|
||||
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
|
||||
Wayland_add_data_device_manager(d, id, version);
|
||||
} else if (SDL_strcmp(interface, "zwp_primary_selection_device_manager_v1") == 0) {
|
||||
Wayland_add_primary_selection_device_manager(d, id, version);
|
||||
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
|
||||
d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);
|
||||
} else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) {
|
||||
@@ -908,7 +915,7 @@ static const struct wl_registry_listener registry_listener = {
|
||||
display_handle_global,
|
||||
display_remove_global
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
static SDL_bool should_use_libdecor(SDL_VideoData *data, SDL_bool ignore_xdg)
|
||||
{
|
||||
@@ -1107,6 +1114,10 @@ Wayland_VideoQuit(_THIS)
|
||||
wp_viewporter_destroy(data->viewporter);
|
||||
}
|
||||
|
||||
if (data->primary_selection_device_manager) {
|
||||
zwp_primary_selection_device_manager_v1_destroy(data->primary_selection_device_manager);
|
||||
}
|
||||
|
||||
if (data->compositor)
|
||||
wl_compositor_destroy(data->compositor);
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct {
|
||||
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||
struct wl_data_device_manager *data_device_manager;
|
||||
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
|
||||
struct zxdg_decoration_manager_v1 *decoration_manager;
|
||||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
|
||||
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
|
||||
|
||||
@@ -52,11 +52,11 @@ GetWindow(_THIS)
|
||||
return data->clipboard_window;
|
||||
}
|
||||
|
||||
|
||||
/* We use our own cut-buffer for intermediate storage instead of
|
||||
XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */
|
||||
/* We use our own cut-buffer for intermediate storage instead of
|
||||
XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */
|
||||
Atom
|
||||
X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type)
|
||||
X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type,
|
||||
Atom selection_type)
|
||||
{
|
||||
switch (mime_type) {
|
||||
case SDL_X11_CLIPBOARD_MIME_TYPE_STRING:
|
||||
@@ -65,7 +65,9 @@ X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType
|
||||
case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8:
|
||||
#endif
|
||||
case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT:
|
||||
return X11_XInternAtom(display, "SDL_CUTBUFFER", False);
|
||||
return X11_XInternAtom(display, selection_type == XA_PRIMARY ?
|
||||
"SDL_CUTBUFFER_PRIMARY_SELECTION" : "SDL_CUTBUFFER",
|
||||
False);
|
||||
default:
|
||||
SDL_SetError("Can't find mime_type.");
|
||||
return XA_STRING;
|
||||
@@ -118,13 +120,11 @@ X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11Clipboa
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
X11_SetClipboardText(_THIS, const char *text)
|
||||
static int
|
||||
SetSelectionText(_THIS, const char *text, Atom selection_type)
|
||||
{
|
||||
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
||||
Window window;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
|
||||
|
||||
/* Get the SDL window that will own the selection */
|
||||
window = GetWindow(_this);
|
||||
@@ -134,22 +134,19 @@ X11_SetClipboardText(_THIS, const char *text)
|
||||
|
||||
/* Save the selection on the root window */
|
||||
X11_XChangeProperty(display, DefaultRootWindow(display),
|
||||
X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), 8, PropModeReplace,
|
||||
X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING, selection_type),
|
||||
X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), 8, PropModeReplace,
|
||||
(const unsigned char *)text, SDL_strlen(text));
|
||||
|
||||
if (XA_CLIPBOARD != None &&
|
||||
X11_XGetSelectionOwner(display, XA_CLIPBOARD) != window) {
|
||||
X11_XSetSelectionOwner(display, XA_CLIPBOARD, window, CurrentTime);
|
||||
if (X11_XGetSelectionOwner(display, selection_type) != window) {
|
||||
X11_XSetSelectionOwner(display, selection_type, window, CurrentTime);
|
||||
}
|
||||
|
||||
if (X11_XGetSelectionOwner(display, XA_PRIMARY) != window) {
|
||||
X11_XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
X11_GetClipboardText(_THIS)
|
||||
static char *
|
||||
GetSlectionText(_THIS, Atom selection_type)
|
||||
{
|
||||
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
|
||||
Display *display = videodata->display;
|
||||
@@ -165,18 +162,13 @@ X11_GetClipboardText(_THIS)
|
||||
char *text;
|
||||
Uint32 waitStart;
|
||||
Uint32 waitElapsed;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
SDL_SetError("Couldn't access X clipboard");
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
text = NULL;
|
||||
|
||||
/* Get the window that holds the selection */
|
||||
window = GetWindow(_this);
|
||||
format = X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING);
|
||||
owner = X11_XGetSelectionOwner(display, XA_CLIPBOARD);
|
||||
owner = X11_XGetSelectionOwner(display, selection_type);
|
||||
if (owner == None) {
|
||||
/* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/
|
||||
owner = DefaultRootWindow(display);
|
||||
@@ -184,12 +176,12 @@ X11_GetClipboardText(_THIS)
|
||||
format = XA_STRING;
|
||||
} else if (owner == window) {
|
||||
owner = DefaultRootWindow(display);
|
||||
selection = X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING);
|
||||
selection = X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING, selection_type);
|
||||
} else {
|
||||
/* Request that the selection owner copy the data to our window */
|
||||
owner = window;
|
||||
selection = X11_XInternAtom(display, "SDL_SELECTION", False);
|
||||
X11_XConvertSelection(display, XA_CLIPBOARD, format, selection, owner,
|
||||
X11_XConvertSelection(display, selection_type, format, selection, owner,
|
||||
CurrentTime);
|
||||
|
||||
/* When using synergy on Linux and when data has been put in the clipboard
|
||||
@@ -200,13 +192,13 @@ X11_GetClipboardText(_THIS)
|
||||
while (videodata->selection_waiting) {
|
||||
SDL_PumpEvents();
|
||||
waitElapsed = SDL_GetTicks() - waitStart;
|
||||
/* Wait one second for a clipboard response. */
|
||||
/* Wait one second for a selection response. */
|
||||
if (waitElapsed > 1000) {
|
||||
videodata->selection_waiting = SDL_FALSE;
|
||||
SDL_SetError("Clipboard timeout");
|
||||
/* We need to set the clipboard text so that next time we won't
|
||||
SDL_SetError("Selection timeout");
|
||||
/* We need to set the selection text so that next time we won't
|
||||
timeout, otherwise we will hang on every call to this function. */
|
||||
X11_SetClipboardText(_this, "");
|
||||
SetSelectionText(_this, "", selection_type);
|
||||
return SDL_strdup("");
|
||||
}
|
||||
}
|
||||
@@ -232,6 +224,41 @@ X11_GetClipboardText(_THIS)
|
||||
return text;
|
||||
}
|
||||
|
||||
int
|
||||
X11_SetClipboardText(_THIS, const char *text)
|
||||
{
|
||||
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
return SDL_SetError("Couldn't access X clipboard");
|
||||
}
|
||||
return SetSelectionText(_this, text, XA_CLIPBOARD);
|
||||
}
|
||||
|
||||
int
|
||||
X11_SetPrimarySelectionText(_THIS, const char *text)
|
||||
{
|
||||
return SetSelectionText(_this, text, XA_PRIMARY);
|
||||
}
|
||||
|
||||
char *
|
||||
X11_GetClipboardText(_THIS)
|
||||
{
|
||||
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
SDL_SetError("Couldn't access X clipboard");
|
||||
return SDL_strdup("");
|
||||
}
|
||||
return GetSlectionText(_this, XA_CLIPBOARD);
|
||||
}
|
||||
|
||||
char *
|
||||
X11_GetPrimarySelectionText(_THIS)
|
||||
{
|
||||
return GetSlectionText(_this, XA_PRIMARY);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
X11_HasClipboardText(_THIS)
|
||||
{
|
||||
@@ -244,6 +271,18 @@ X11_HasClipboardText(_THIS)
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
X11_HasPrimarySelectionText(_THIS)
|
||||
{
|
||||
SDL_bool result = SDL_FALSE;
|
||||
char *text = X11_GetPrimarySelectionText(_this);
|
||||
if (text) {
|
||||
result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_free(text);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -36,7 +36,10 @@ enum ESDLX11ClipboardMimeType {
|
||||
extern int X11_SetClipboardText(_THIS, const char *text);
|
||||
extern char *X11_GetClipboardText(_THIS);
|
||||
extern SDL_bool X11_HasClipboardText(_THIS);
|
||||
extern Atom X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||
extern int X11_SetPrimarySelectionText(_THIS, const char *text);
|
||||
extern char *X11_GetPrimarySelectionText(_THIS);
|
||||
extern SDL_bool X11_HasPrimarySelectionText(_THIS);
|
||||
extern Atom X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type, Atom selection_type);
|
||||
extern Atom X11_GetSDLCutBufferClipboardExternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||
extern Atom X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||
|
||||
|
||||
@@ -620,7 +620,7 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
|
||||
int seln_format, mime_formats;
|
||||
unsigned long nbytes;
|
||||
unsigned long overflow;
|
||||
unsigned char *seln_data;
|
||||
unsigned char *seln_data;
|
||||
Atom supportedFormats[SDL_X11_CLIPBOARD_MIME_TYPE_MAX+1];
|
||||
Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
|
||||
|
||||
@@ -640,11 +640,11 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
|
||||
/* !!! FIXME: We were probably storing this on the root window
|
||||
because an SDL window might go away...? but we don't have to do
|
||||
this now (or ever, really). */
|
||||
|
||||
|
||||
if (req->target == XA_TARGETS) {
|
||||
supportedFormats[0] = XA_TARGETS;
|
||||
mime_formats = 1;
|
||||
for (i = 0; i < SDL_X11_CLIPBOARD_MIME_TYPE_MAX; ++i)
|
||||
for (i = 0; i < SDL_X11_CLIPBOARD_MIME_TYPE_MAX; ++i)
|
||||
supportedFormats[mime_formats++] = X11_GetSDLCutBufferClipboardExternalFormat(display, i);
|
||||
X11_XChangeProperty(display, req->requestor, req->property,
|
||||
XA_ATOM, 32, PropModeReplace,
|
||||
@@ -657,7 +657,7 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
|
||||
if (X11_GetSDLCutBufferClipboardExternalFormat(display, i) != req->target)
|
||||
continue;
|
||||
if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
|
||||
X11_GetSDLCutBufferClipboardType(display, i), 0, INT_MAX/4, False, X11_GetSDLCutBufferClipboardInternalFormat(display, i),
|
||||
X11_GetSDLCutBufferClipboardType(display, i, req->selection), 0, INT_MAX/4, False, X11_GetSDLCutBufferClipboardInternalFormat(display, i),
|
||||
&sevent.xselection.target, &seln_format, &nbytes,
|
||||
&overflow, &seln_data) == Success) {
|
||||
if (seln_format != None) {
|
||||
@@ -946,7 +946,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
|
||||
if (xevent->xcrossing.mode != NotifyGrab &&
|
||||
xevent->xcrossing.mode != NotifyUngrab &&
|
||||
xevent->xcrossing.detail != NotifyInferior) {
|
||||
|
||||
|
||||
/* In order for interaction with the window decorations and menu to work properly
|
||||
on Mutter, we need to ungrab the keyboard when the the mouse leaves. */
|
||||
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN)) {
|
||||
@@ -1158,7 +1158,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
|
||||
&xevent->xconfigure.x, &xevent->xconfigure.y,
|
||||
&ChildReturn);
|
||||
}
|
||||
|
||||
|
||||
if (xevent->xconfigure.x != data->last_xconfigure.x ||
|
||||
xevent->xconfigure.y != data->last_xconfigure.y) {
|
||||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
|
||||
|
||||
@@ -301,6 +301,9 @@ X11_CreateDevice(void)
|
||||
device->SetClipboardText = X11_SetClipboardText;
|
||||
device->GetClipboardText = X11_GetClipboardText;
|
||||
device->HasClipboardText = X11_HasClipboardText;
|
||||
device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
|
||||
device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
|
||||
device->HasPrimarySelectionText = X11_HasPrimarySelectionText;
|
||||
device->StartTextInput = X11_StartTextInput;
|
||||
device->StopTextInput = X11_StopTextInput;
|
||||
device->SetTextInputRect = X11_SetTextInputRect;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user