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>`main
parent
72fe6cc8f1
commit
ac5b9bc4ee
|
@ -82,6 +82,52 @@ extern DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_bool SDLCALL SDL_HasClipboardText(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++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -143,7 +143,7 @@ typedef enum
|
||||||
SDL_MULTIGESTURE,
|
SDL_MULTIGESTURE,
|
||||||
|
|
||||||
/* Clipboard events */
|
/* Clipboard events */
|
||||||
SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
|
SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard or primary selection changed */
|
||||||
|
|
||||||
/* Drag and drop events */
|
/* Drag and drop events */
|
||||||
SDL_DROPFILE = 0x1000, /**< The system requests a file open */
|
SDL_DROPFILE = 0x1000, /**< The system requests a file open */
|
||||||
|
|
|
@ -860,3 +860,6 @@
|
||||||
++'_SDL_crc16'.'SDL2.dll'.'SDL_crc16'
|
++'_SDL_crc16'.'SDL2.dll'.'SDL_crc16'
|
||||||
++'_SDL_GetWindowSizeInPixels'.'SDL2.dll'.'SDL_GetWindowSizeInPixels'
|
++'_SDL_GetWindowSizeInPixels'.'SDL2.dll'.'SDL_GetWindowSizeInPixels'
|
||||||
++'_SDL_GetJoystickGUIDInfo'.'SDL2.dll'.'SDL_GetJoystickGUIDInfo'
|
++'_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_crc16 SDL_crc16_REAL
|
||||||
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
|
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
|
||||||
#define SDL_GetJoystickGUIDInfo SDL_GetJoystickGUIDInfo_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(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_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(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 *
|
char *
|
||||||
SDL_GetClipboardText(void)
|
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_bool
|
||||||
SDL_HasClipboardText(void)
|
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: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -328,6 +328,9 @@ struct SDL_VideoDevice
|
||||||
int (*SetClipboardText) (_THIS, const char *text);
|
int (*SetClipboardText) (_THIS, const char *text);
|
||||||
char * (*GetClipboardText) (_THIS);
|
char * (*GetClipboardText) (_THIS);
|
||||||
SDL_bool (*HasClipboardText) (_THIS);
|
SDL_bool (*HasClipboardText) (_THIS);
|
||||||
|
int (*SetPrimarySelectionText) (_THIS, const char *text);
|
||||||
|
char * (*GetPrimarySelectionText) (_THIS);
|
||||||
|
SDL_bool (*HasPrimarySelectionText) (_THIS);
|
||||||
|
|
||||||
/* MessageBox */
|
/* MessageBox */
|
||||||
int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
||||||
|
@ -353,6 +356,7 @@ struct SDL_VideoDevice
|
||||||
Uint8 window_magic;
|
Uint8 window_magic;
|
||||||
Uint32 next_object_id;
|
Uint32 next_object_id;
|
||||||
char *clipboard_text;
|
char *clipboard_text;
|
||||||
|
char *primary_selection_text;
|
||||||
SDL_bool setting_display_mode;
|
SDL_bool setting_display_mode;
|
||||||
Uint32 quirk_flags;
|
Uint32 quirk_flags;
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,39 @@ Wayland_SetClipboardText(_THIS, const char *text)
|
||||||
return status;
|
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 *
|
char *
|
||||||
Wayland_GetClipboardText(_THIS)
|
Wayland_GetClipboardText(_THIS)
|
||||||
{
|
{
|
||||||
|
@ -65,8 +98,6 @@ Wayland_GetClipboardText(_THIS)
|
||||||
SDL_WaylandDataDevice *data_device = NULL;
|
SDL_WaylandDataDevice *data_device = NULL;
|
||||||
|
|
||||||
char *text = NULL;
|
char *text = NULL;
|
||||||
|
|
||||||
void *buffer = NULL;
|
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
if (_this == NULL || _this->driverdata == NULL) {
|
if (_this == NULL || _this->driverdata == NULL) {
|
||||||
|
@ -75,21 +106,52 @@ Wayland_GetClipboardText(_THIS)
|
||||||
video_data = _this->driverdata;
|
video_data = _this->driverdata;
|
||||||
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
||||||
data_device = video_data->input->data_device;
|
data_device = video_data->input->data_device;
|
||||||
if (data_device->selection_offer != NULL) {
|
/* Prefer own selection, if not canceled */
|
||||||
buffer = Wayland_data_offer_receive(data_device->selection_offer,
|
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);
|
&length, TEXT_MIME, SDL_TRUE);
|
||||||
if (length > 0) {
|
} else if (Wayland_data_offer_has_mime(
|
||||||
text = (char*) buffer;
|
data_device->selection_offer, TEXT_MIME)) {
|
||||||
}
|
text = Wayland_data_offer_receive(data_device->selection_offer,
|
||||||
}
|
|
||||||
if (length == 0 && data_device->selection_source != NULL) {
|
|
||||||
buffer = Wayland_data_source_get_data(data_device->selection_source,
|
|
||||||
&length, TEXT_MIME, SDL_TRUE);
|
&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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text == NULL) {
|
if (text == NULL) {
|
||||||
|
@ -112,14 +174,33 @@ Wayland_HasClipboardText(_THIS)
|
||||||
video_data = _this->driverdata;
|
video_data = _this->driverdata;
|
||||||
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
if (video_data->input != NULL && video_data->input->data_device != NULL) {
|
||||||
data_device = video_data->input->data_device;
|
data_device = video_data->input->data_device;
|
||||||
if (Wayland_data_offer_has_mime(
|
result = result ||
|
||||||
data_device->selection_offer, TEXT_MIME)) {
|
Wayland_data_source_has_mime(data_device->selection_source, TEXT_MIME) ||
|
||||||
result = SDL_TRUE;
|
Wayland_data_offer_has_mime(data_device->selection_offer, TEXT_MIME);
|
||||||
} else if (Wayland_data_source_has_mime(
|
|
||||||
data_device->selection_source, TEXT_MIME)) {
|
|
||||||
result = SDL_TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
extern int Wayland_SetClipboardText(_THIS, const char *text);
|
extern int Wayland_SetClipboardText(_THIS, const char *text);
|
||||||
extern char *Wayland_GetClipboardText(_THIS);
|
extern char *Wayland_GetClipboardText(_THIS);
|
||||||
extern SDL_bool Wayland_HasClipboardText(_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_ */
|
#endif /* SDL_waylandclipboard_h_ */
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,12 @@
|
||||||
|
|
||||||
#include "SDL_waylandvideo.h"
|
#include "SDL_waylandvideo.h"
|
||||||
#include "SDL_waylanddatamanager.h"
|
#include "SDL_waylanddatamanager.h"
|
||||||
|
#include "primary-selection-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
/* FIXME: This is arbitrary, but we want this to be less than a frame because
|
/* FIXME: This is arbitrary, but we want this to be less than a frame because
|
||||||
* any longer can potentially spin an infinite loop of PumpEvents (!)
|
* any longer can potentially spin an infinite loop of PumpEvents (!)
|
||||||
*/
|
*/
|
||||||
#define PIPE_MS_TIMEOUT 10
|
#define PIPE_MS_TIMEOUT 14
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
write_pipe(int fd, const void* buffer, size_t total_length, size_t *pos)
|
write_pipe(int fd, const void* buffer, size_t total_length, size_t *pos)
|
||||||
|
@ -247,17 +248,11 @@ mime_data_list_free(struct wl_list *list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
static ssize_t
|
||||||
Wayland_data_source_send(SDL_WaylandDataSource *source,
|
Wayland_source_send(SDL_MimeDataList *mime_data, const char *mime_type, int fd)
|
||||||
const char *mime_type, int fd)
|
|
||||||
{
|
{
|
||||||
size_t written_bytes = 0;
|
size_t written_bytes = 0;
|
||||||
ssize_t status = 0;
|
ssize_t status = 0;
|
||||||
SDL_MimeDataList *mime_data = NULL;
|
|
||||||
|
|
||||||
mime_type = Wayland_convert_mime_type(mime_type);
|
|
||||||
mime_data = mime_data_list_find(&source->mimes,
|
|
||||||
mime_type);
|
|
||||||
|
|
||||||
if (mime_data == NULL || mime_data->data == NULL) {
|
if (mime_data == NULL || mime_data->data == NULL) {
|
||||||
status = SDL_SetError("Invalid mime type");
|
status = SDL_SetError("Invalid mime type");
|
||||||
|
@ -271,6 +266,32 @@ Wayland_data_source_send(SDL_WaylandDataSource *source,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
Wayland_data_source_send(SDL_WaylandDataSource *source,
|
||||||
|
const char *mime_type, int fd)
|
||||||
|
{
|
||||||
|
SDL_MimeDataList *mime_data = NULL;
|
||||||
|
|
||||||
|
mime_type = Wayland_convert_mime_type(mime_type);
|
||||||
|
mime_data = mime_data_list_find(&source->mimes,
|
||||||
|
mime_type);
|
||||||
|
|
||||||
|
return Wayland_source_send(mime_data, mime_type, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource *source,
|
||||||
|
const char *mime_type, int fd)
|
||||||
|
{
|
||||||
|
SDL_MimeDataList *mime_data = NULL;
|
||||||
|
|
||||||
|
mime_type = Wayland_convert_mime_type(mime_type);
|
||||||
|
mime_data = mime_data_list_find(&source->mimes,
|
||||||
|
mime_type);
|
||||||
|
|
||||||
|
return Wayland_source_send(mime_data, mime_type, fd);
|
||||||
|
}
|
||||||
|
|
||||||
int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
|
int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
|
||||||
const char *mime_type,
|
const char *mime_type,
|
||||||
const void *buffer,
|
const void *buffer,
|
||||||
|
@ -279,6 +300,14 @@ int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
|
||||||
return mime_data_list_add(&source->mimes, mime_type, buffer, length);
|
return mime_data_list_add(&source->mimes, mime_type, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Wayland_primary_selection_source_add_data(SDL_WaylandPrimarySelectionSource *source,
|
||||||
|
const char *mime_type,
|
||||||
|
const void *buffer,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
return mime_data_list_add(&source->mimes, mime_type, buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_bool
|
SDL_bool
|
||||||
Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
|
Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
|
@ -291,19 +320,25 @@ Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
SDL_bool
|
||||||
Wayland_data_source_get_data(SDL_WaylandDataSource *source,
|
Wayland_primary_selection_source_has_mime(SDL_WaylandPrimarySelectionSource *source,
|
||||||
size_t *length, const char* mime_type,
|
const char *mime_type)
|
||||||
|
{
|
||||||
|
SDL_bool found = SDL_FALSE;
|
||||||
|
|
||||||
|
if (source != NULL) {
|
||||||
|
found = mime_data_list_find(&source->mimes, mime_type) != NULL;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
Wayland_source_get_data(SDL_MimeDataList *mime_data,
|
||||||
|
size_t *length,
|
||||||
SDL_bool null_terminate)
|
SDL_bool null_terminate)
|
||||||
{
|
{
|
||||||
SDL_MimeDataList *mime_data = NULL;
|
|
||||||
void *buffer = NULL;
|
void *buffer = NULL;
|
||||||
*length = 0;
|
|
||||||
|
|
||||||
if (source == NULL) {
|
|
||||||
SDL_SetError("Invalid data source");
|
|
||||||
} else {
|
|
||||||
mime_data = mime_data_list_find(&source->mimes, mime_type);
|
|
||||||
if (mime_data != NULL && mime_data->length > 0) {
|
if (mime_data != NULL && mime_data->length > 0) {
|
||||||
size_t buffer_length = mime_data->length;
|
size_t buffer_length = mime_data->length;
|
||||||
|
|
||||||
|
@ -321,6 +356,43 @@ Wayland_data_source_get_data(SDL_WaylandDataSource *source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
Wayland_data_source_get_data(SDL_WaylandDataSource *source,
|
||||||
|
size_t *length, const char* mime_type,
|
||||||
|
SDL_bool null_terminate)
|
||||||
|
{
|
||||||
|
SDL_MimeDataList *mime_data = NULL;
|
||||||
|
void *buffer = NULL;
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
if (source == NULL) {
|
||||||
|
SDL_SetError("Invalid data source");
|
||||||
|
} else {
|
||||||
|
mime_data = mime_data_list_find(&source->mimes, mime_type);
|
||||||
|
buffer = Wayland_source_get_data(mime_data, length, null_terminate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
|
||||||
|
size_t *length, const char* mime_type,
|
||||||
|
SDL_bool null_terminate)
|
||||||
|
{
|
||||||
|
SDL_MimeDataList *mime_data = NULL;
|
||||||
|
void *buffer = NULL;
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
if (source == NULL) {
|
||||||
|
SDL_SetError("Invalid primary selection source");
|
||||||
|
} else {
|
||||||
|
mime_data = mime_data_list_find(&source->mimes, mime_type);
|
||||||
|
buffer = Wayland_source_get_data(mime_data, length, null_terminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -340,6 +412,20 @@ Wayland_data_source_destroy(SDL_WaylandDataSource *source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source)
|
||||||
|
{
|
||||||
|
if (source != NULL) {
|
||||||
|
SDL_WaylandPrimarySelectionDevice *primary_selection_device = (SDL_WaylandPrimarySelectionDevice *) source->primary_selection_device;
|
||||||
|
if (primary_selection_device && (primary_selection_device->selection_source == source)) {
|
||||||
|
primary_selection_device->selection_source = NULL;
|
||||||
|
}
|
||||||
|
zwp_primary_selection_source_v1_destroy(source->source);
|
||||||
|
mime_data_list_free(&source->mimes);
|
||||||
|
SDL_free(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
|
Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
|
||||||
size_t *length, const char* mime_type,
|
size_t *length, const char* mime_type,
|
||||||
|
@ -371,6 +457,37 @@ Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
|
||||||
|
size_t *length, const char* mime_type,
|
||||||
|
SDL_bool null_terminate)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
||||||
|
|
||||||
|
int pipefd[2];
|
||||||
|
void *buffer = NULL;
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
if (offer == NULL) {
|
||||||
|
SDL_SetError("Invalid data offer");
|
||||||
|
} else if ((primary_selection_device = offer->primary_selection_device) == NULL) {
|
||||||
|
SDL_SetError("Primary selection device not initialized");
|
||||||
|
} else if (pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) {
|
||||||
|
SDL_SetError("Could not read pipe");
|
||||||
|
} else {
|
||||||
|
zwp_primary_selection_offer_v1_receive(offer->offer, mime_type, pipefd[1]);
|
||||||
|
|
||||||
|
/* TODO: Needs pump and flush? */
|
||||||
|
WAYLAND_wl_display_flush(primary_selection_device->video_data->display);
|
||||||
|
|
||||||
|
close(pipefd[1]);
|
||||||
|
|
||||||
|
while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0);
|
||||||
|
close(pipefd[0]);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||||
const char* mime_type)
|
const char* mime_type)
|
||||||
|
@ -378,6 +495,12 @@ Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||||
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
|
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||||
|
const char* mime_type)
|
||||||
|
{
|
||||||
|
return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_bool
|
SDL_bool
|
||||||
Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||||
|
@ -391,6 +514,18 @@ Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_bool
|
||||||
|
Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,
|
||||||
|
const char *mime_type)
|
||||||
|
{
|
||||||
|
SDL_bool found = SDL_FALSE;
|
||||||
|
|
||||||
|
if (offer != NULL) {
|
||||||
|
found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
|
Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
|
||||||
{
|
{
|
||||||
|
@ -401,6 +536,16 @@ Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Wayland_primary_selection_offer_destroy(SDL_WaylandPrimarySelectionOffer *offer)
|
||||||
|
{
|
||||||
|
if (offer != NULL) {
|
||||||
|
zwp_primary_selection_offer_v1_destroy(offer->offer);
|
||||||
|
mime_data_list_free(&offer->mimes);
|
||||||
|
SDL_free(offer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
|
Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
|
||||||
{
|
{
|
||||||
|
@ -416,6 +561,22 @@ Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if (primary_selection_device == NULL || primary_selection_device->primary_selection_device == NULL) {
|
||||||
|
status = SDL_SetError("Invalid Primary Selection Device");
|
||||||
|
} else if (primary_selection_device->selection_source != NULL) {
|
||||||
|
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
|
||||||
|
NULL, 0);
|
||||||
|
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
|
||||||
|
primary_selection_device->selection_source = NULL;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
|
Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
|
||||||
SDL_WaylandDataSource *source)
|
SDL_WaylandDataSource *source)
|
||||||
|
@ -468,6 +629,58 @@ Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
|
||||||
|
SDL_WaylandPrimarySelectionSource *source)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
size_t num_offers = 0;
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
if (primary_selection_device == NULL) {
|
||||||
|
status = SDL_SetError("Invalid Primary Selection Device");
|
||||||
|
} else if (source == NULL) {
|
||||||
|
status = SDL_SetError("Invalid source");
|
||||||
|
} else {
|
||||||
|
SDL_MimeDataList *mime_data = NULL;
|
||||||
|
|
||||||
|
wl_list_for_each(mime_data, &(source->mimes), link) {
|
||||||
|
zwp_primary_selection_source_v1_offer(source->source,
|
||||||
|
mime_data->mime_type);
|
||||||
|
|
||||||
|
/* TODO - Improve system for multiple mime types to same data */
|
||||||
|
for (index = 0; index < MIME_LIST_SIZE; ++index) {
|
||||||
|
if (SDL_strcmp(mime_conversion_list[index][1], mime_data->mime_type) == 0) {
|
||||||
|
zwp_primary_selection_source_v1_offer(source->source,
|
||||||
|
mime_conversion_list[index][0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* */
|
||||||
|
|
||||||
|
++num_offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_offers == 0) {
|
||||||
|
Wayland_primary_selection_device_clear_selection(primary_selection_device);
|
||||||
|
status = SDL_SetError("No mime data");
|
||||||
|
} else {
|
||||||
|
/* Only set if there is a valid serial if not set it later */
|
||||||
|
if (primary_selection_device->selection_serial != 0) {
|
||||||
|
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
|
||||||
|
source->source,
|
||||||
|
primary_selection_device->selection_serial);
|
||||||
|
}
|
||||||
|
if (primary_selection_device->selection_source != NULL) {
|
||||||
|
Wayland_primary_selection_source_destroy(primary_selection_device->selection_source);
|
||||||
|
}
|
||||||
|
primary_selection_device->selection_source = source;
|
||||||
|
source->primary_selection_device = primary_selection_device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
|
Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
|
||||||
uint32_t serial)
|
uint32_t serial)
|
||||||
|
@ -481,7 +694,7 @@ Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
|
||||||
&& data_device->selection_source != NULL) {
|
&& data_device->selection_source != NULL) {
|
||||||
wl_data_device_set_selection(data_device->data_device,
|
wl_data_device_set_selection(data_device->data_device,
|
||||||
data_device->selection_source->source,
|
data_device->selection_source->source,
|
||||||
serial);
|
data_device->selection_serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_device->selection_serial = serial;
|
data_device->selection_serial = serial;
|
||||||
|
@ -490,6 +703,28 @@ Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
int status = -1;
|
||||||
|
if (primary_selection_device != NULL) {
|
||||||
|
status = 0;
|
||||||
|
|
||||||
|
/* If there was no serial and there is a pending selection set it now. */
|
||||||
|
if (primary_selection_device->selection_serial == 0
|
||||||
|
&& primary_selection_device->selection_source != NULL) {
|
||||||
|
zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
|
||||||
|
primary_selection_device->selection_source->source,
|
||||||
|
primary_selection_device->selection_serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
primary_selection_device->selection_serial = serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
|
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -43,12 +43,24 @@ typedef struct {
|
||||||
void *data_device;
|
void *data_device;
|
||||||
} SDL_WaylandDataSource;
|
} SDL_WaylandDataSource;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct zwp_primary_selection_source_v1 *source;
|
||||||
|
struct wl_list mimes;
|
||||||
|
void *primary_selection_device;
|
||||||
|
} SDL_WaylandPrimarySelectionSource;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct wl_data_offer *offer;
|
struct wl_data_offer *offer;
|
||||||
struct wl_list mimes;
|
struct wl_list mimes;
|
||||||
void *data_device;
|
void *data_device;
|
||||||
} SDL_WaylandDataOffer;
|
} SDL_WaylandDataOffer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct zwp_primary_selection_offer_v1 *offer;
|
||||||
|
struct wl_list mimes;
|
||||||
|
void *primary_selection_device;
|
||||||
|
} SDL_WaylandPrimarySelectionOffer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct wl_data_device *data_device;
|
struct wl_data_device *data_device;
|
||||||
SDL_VideoData *video_data;
|
SDL_VideoData *video_data;
|
||||||
|
@ -58,46 +70,83 @@ typedef struct {
|
||||||
SDL_WaylandDataOffer *drag_offer;
|
SDL_WaylandDataOffer *drag_offer;
|
||||||
SDL_WaylandDataOffer *selection_offer;
|
SDL_WaylandDataOffer *selection_offer;
|
||||||
|
|
||||||
/* Clipboard */
|
/* Clipboard and Primary Selection */
|
||||||
uint32_t selection_serial;
|
uint32_t selection_serial;
|
||||||
SDL_WaylandDataSource *selection_source;
|
SDL_WaylandDataSource *selection_source;
|
||||||
} SDL_WaylandDataDevice;
|
} 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);
|
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 SDL_WaylandDataSource* Wayland_data_source_create(_THIS);
|
||||||
|
extern SDL_WaylandPrimarySelectionSource* Wayland_primary_selection_source_create(_THIS);
|
||||||
extern ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source,
|
extern ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source,
|
||||||
const char *mime_type, int fd);
|
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,
|
extern int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
|
||||||
const char *mime_type,
|
const char *mime_type,
|
||||||
const void *buffer,
|
const void *buffer,
|
||||||
size_t length);
|
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,
|
extern SDL_bool Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
|
||||||
const char *mime_type);
|
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,
|
extern void* Wayland_data_source_get_data(SDL_WaylandDataSource *source,
|
||||||
size_t *length,
|
size_t *length,
|
||||||
const char *mime_type,
|
const char *mime_type,
|
||||||
SDL_bool null_terminate);
|
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_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,
|
extern void* Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
|
||||||
size_t *length,
|
size_t *length,
|
||||||
const char *mime_type,
|
const char *mime_type,
|
||||||
SDL_bool null_terminate);
|
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,
|
extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
|
||||||
const char *mime_type);
|
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,
|
extern int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
|
||||||
const char *mime_type);
|
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_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_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,
|
extern int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
|
||||||
SDL_WaylandDataSource *source);
|
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,
|
extern int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
|
||||||
uint32_t serial);
|
uint32_t serial);
|
||||||
|
extern int Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *device,
|
||||||
|
uint32_t serial);
|
||||||
#endif /* SDL_waylanddatamanager_h_ */
|
#endif /* SDL_waylanddatamanager_h_ */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||||
#include "text-input-unstable-v3-client-protocol.h"
|
#include "text-input-unstable-v3-client-protocol.h"
|
||||||
#include "tablet-unstable-v2-client-protocol.h"
|
#include "tablet-unstable-v2-client-protocol.h"
|
||||||
|
#include "primary-selection-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBDECOR_H
|
#ifdef HAVE_LIBDECOR_H
|
||||||
#include <libdecor.h>
|
#include <libdecor.h>
|
||||||
|
@ -587,6 +588,7 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
|
||||||
}
|
}
|
||||||
|
|
||||||
Wayland_data_device_set_serial(input->data_device, serial);
|
Wayland_data_device_set_serial(input->data_device, serial);
|
||||||
|
Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
|
||||||
|
|
||||||
SDL_SendMouseButton(window->sdlwindow, 0,
|
SDL_SendMouseButton(window->sdlwindow, 0,
|
||||||
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
||||||
|
@ -1106,6 +1108,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
||||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
if (has_text && !(SDL_GetModState() & KMOD_CTRL)) {
|
if (has_text && !(SDL_GetModState() & KMOD_CTRL)) {
|
||||||
Wayland_data_device_set_serial(input->data_device, serial);
|
Wayland_data_device_set_serial(input->data_device, serial);
|
||||||
|
Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
|
||||||
if (!handled_by_ime) {
|
if (!handled_by_ime) {
|
||||||
SDL_SendKeyboardText(text);
|
SDL_SendKeyboardText(text);
|
||||||
}
|
}
|
||||||
|
@ -1319,6 +1322,25 @@ static const struct wl_data_source_listener data_source_listener = {
|
||||||
data_source_handle_action, // Version 3
|
data_source_handle_action, // Version 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
primary_selection_source_send(void *data, struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1,
|
||||||
|
const char *mime_type, int32_t fd)
|
||||||
|
{
|
||||||
|
Wayland_primary_selection_source_send((SDL_WaylandPrimarySelectionSource *)data,
|
||||||
|
mime_type, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
primary_selection_source_cancelled(void *data, struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1)
|
||||||
|
{
|
||||||
|
Wayland_primary_selection_source_destroy(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = {
|
||||||
|
primary_selection_source_send,
|
||||||
|
primary_selection_source_cancelled,
|
||||||
|
};
|
||||||
|
|
||||||
SDL_WaylandDataSource*
|
SDL_WaylandDataSource*
|
||||||
Wayland_data_source_create(_THIS)
|
Wayland_data_source_create(_THIS)
|
||||||
{
|
{
|
||||||
|
@ -1355,6 +1377,41 @@ Wayland_data_source_create(_THIS)
|
||||||
return data_source;
|
return data_source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_WaylandPrimarySelectionSource*
|
||||||
|
Wayland_primary_selection_source_create(_THIS)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionSource *primary_selection_source = NULL;
|
||||||
|
SDL_VideoData *driver_data = NULL;
|
||||||
|
struct zwp_primary_selection_source_v1 *id = NULL;
|
||||||
|
|
||||||
|
if (_this == NULL || _this->driverdata == NULL) {
|
||||||
|
SDL_SetError("Video driver uninitialized");
|
||||||
|
} else {
|
||||||
|
driver_data = _this->driverdata;
|
||||||
|
|
||||||
|
if (driver_data->primary_selection_device_manager != NULL) {
|
||||||
|
id = zwp_primary_selection_device_manager_v1_create_source(
|
||||||
|
driver_data->primary_selection_device_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == NULL) {
|
||||||
|
SDL_SetError("Wayland unable to create primary selection source");
|
||||||
|
} else {
|
||||||
|
primary_selection_source = SDL_calloc(1, sizeof *primary_selection_source);
|
||||||
|
if (primary_selection_source == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
zwp_primary_selection_source_v1_destroy(id);
|
||||||
|
} else {
|
||||||
|
WAYLAND_wl_list_init(&(primary_selection_source->mimes));
|
||||||
|
primary_selection_source->source = id;
|
||||||
|
zwp_primary_selection_source_v1_add_listener(id, &primary_selection_source_listener,
|
||||||
|
primary_selection_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return primary_selection_source;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
|
data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
|
@ -1381,6 +1438,18 @@ static const struct wl_data_offer_listener data_offer_listener = {
|
||||||
data_offer_handle_actions, // Version 3
|
data_offer_handle_actions, // Version 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
primary_selection_offer_handle_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1,
|
||||||
|
const char *mime_type)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionOffer *offer = data;
|
||||||
|
Wayland_primary_selection_offer_add_mime(offer, mime_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = {
|
||||||
|
primary_selection_offer_handle_offer,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
|
data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
|
||||||
struct wl_data_offer *id)
|
struct wl_data_offer *id)
|
||||||
|
@ -1620,6 +1689,48 @@ static const struct wl_data_device_listener data_device_listener = {
|
||||||
data_device_handle_selection
|
data_device_handle_selection
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
primary_selection_device_handle_offer(void *data, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1,
|
||||||
|
struct zwp_primary_selection_offer_v1 *id)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionOffer *primary_selection_offer = NULL;
|
||||||
|
|
||||||
|
primary_selection_offer = SDL_calloc(1, sizeof *primary_selection_offer);
|
||||||
|
if (primary_selection_offer == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
} else {
|
||||||
|
primary_selection_offer->offer = id;
|
||||||
|
primary_selection_offer->primary_selection_device = data;
|
||||||
|
WAYLAND_wl_list_init(&(primary_selection_offer->mimes));
|
||||||
|
zwp_primary_selection_offer_v1_set_user_data(id, primary_selection_offer);
|
||||||
|
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, primary_selection_offer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
primary_selection_device_handle_selection(void *data, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1,
|
||||||
|
struct zwp_primary_selection_offer_v1 *id)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionDevice *primary_selection_device = data;
|
||||||
|
SDL_WaylandPrimarySelectionOffer *offer = NULL;
|
||||||
|
|
||||||
|
if (id != NULL) {
|
||||||
|
offer = zwp_primary_selection_offer_v1_get_user_data(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (primary_selection_device->selection_offer != offer) {
|
||||||
|
Wayland_primary_selection_offer_destroy(primary_selection_device->selection_offer);
|
||||||
|
primary_selection_device->selection_offer = offer;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SendClipboardUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
|
||||||
|
primary_selection_device_handle_offer,
|
||||||
|
primary_selection_device_handle_selection
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
text_input_enter(void *data,
|
text_input_enter(void *data,
|
||||||
struct zwp_text_input_v3 *zwp_text_input_v3,
|
struct zwp_text_input_v3 *zwp_text_input_v3,
|
||||||
|
@ -1753,6 +1864,32 @@ Wayland_create_data_device(SDL_VideoData *d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
Wayland_create_primary_selection_device(SDL_VideoData *d)
|
||||||
|
{
|
||||||
|
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
||||||
|
|
||||||
|
primary_selection_device = SDL_calloc(1, sizeof *primary_selection_device);
|
||||||
|
if (primary_selection_device == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
primary_selection_device->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
|
||||||
|
d->primary_selection_device_manager, d->input->seat
|
||||||
|
);
|
||||||
|
primary_selection_device->video_data = d;
|
||||||
|
|
||||||
|
if (primary_selection_device->primary_selection_device == NULL) {
|
||||||
|
SDL_free(primary_selection_device);
|
||||||
|
} else {
|
||||||
|
zwp_primary_selection_device_v1_set_user_data(primary_selection_device->primary_selection_device,
|
||||||
|
primary_selection_device);
|
||||||
|
zwp_primary_selection_device_v1_add_listener(primary_selection_device->primary_selection_device,
|
||||||
|
&primary_selection_device_listener, primary_selection_device);
|
||||||
|
d->input->primary_selection_device = primary_selection_device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Wayland_create_text_input(SDL_VideoData *d)
|
Wayland_create_text_input(SDL_VideoData *d)
|
||||||
{
|
{
|
||||||
|
@ -1787,6 +1924,16 @@ Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Wayland_add_primary_selection_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
|
||||||
|
{
|
||||||
|
d->primary_selection_device_manager = wl_registry_bind(d->registry, id, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||||
|
|
||||||
|
if (d->input != NULL) {
|
||||||
|
Wayland_create_primary_selection_device(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
|
Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
|
||||||
{
|
{
|
||||||
|
@ -2173,6 +2320,9 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
|
||||||
if (d->data_device_manager != NULL) {
|
if (d->data_device_manager != NULL) {
|
||||||
Wayland_create_data_device(d);
|
Wayland_create_data_device(d);
|
||||||
}
|
}
|
||||||
|
if (d->primary_selection_device_manager != NULL) {
|
||||||
|
Wayland_create_primary_selection_device(d);
|
||||||
|
}
|
||||||
if (d->text_input_manager != NULL) {
|
if (d->text_input_manager != NULL) {
|
||||||
Wayland_create_text_input(d);
|
Wayland_create_text_input(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ struct SDL_WaylandInput {
|
||||||
struct wl_touch *touch;
|
struct wl_touch *touch;
|
||||||
struct wl_keyboard *keyboard;
|
struct wl_keyboard *keyboard;
|
||||||
SDL_WaylandDataDevice *data_device;
|
SDL_WaylandDataDevice *data_device;
|
||||||
|
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
|
||||||
SDL_WaylandTextInput *text_input;
|
SDL_WaylandTextInput *text_input;
|
||||||
struct zwp_relative_pointer_v1 *relative_pointer;
|
struct zwp_relative_pointer_v1 *relative_pointer;
|
||||||
SDL_WindowData *pointer_focus;
|
SDL_WindowData *pointer_focus;
|
||||||
|
@ -137,6 +138,7 @@ extern void Wayland_SendWakeupEvent(_THIS, SDL_Window *window);
|
||||||
extern int Wayland_WaitEventTimeout(_THIS, int timeout);
|
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_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_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||||
|
|
||||||
extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
|
extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
#include "tablet-unstable-v2-client-protocol.h"
|
#include "tablet-unstable-v2-client-protocol.h"
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
#include "viewporter-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
|
#ifdef HAVE_LIBDECOR_H
|
||||||
#include <libdecor.h>
|
#include <libdecor.h>
|
||||||
|
@ -265,6 +267,9 @@ Wayland_CreateDevice(void)
|
||||||
device->SetClipboardText = Wayland_SetClipboardText;
|
device->SetClipboardText = Wayland_SetClipboardText;
|
||||||
device->GetClipboardText = Wayland_GetClipboardText;
|
device->GetClipboardText = Wayland_GetClipboardText;
|
||||||
device->HasClipboardText = Wayland_HasClipboardText;
|
device->HasClipboardText = Wayland_HasClipboardText;
|
||||||
|
device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText;
|
||||||
|
device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText;
|
||||||
|
device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText;
|
||||||
device->StartTextInput = Wayland_StartTextInput;
|
device->StartTextInput = Wayland_StartTextInput;
|
||||||
device->StopTextInput = Wayland_StopTextInput;
|
device->StopTextInput = Wayland_StopTextInput;
|
||||||
device->SetTextInputRect = Wayland_SetTextInputRect;
|
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);
|
Wayland_add_text_input_manager(d, id, version);
|
||||||
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
|
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
|
||||||
Wayland_add_data_device_manager(d, id, version);
|
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) {
|
} 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);
|
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) {
|
} else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) {
|
||||||
|
@ -1107,6 +1114,10 @@ Wayland_VideoQuit(_THIS)
|
||||||
wp_viewporter_destroy(data->viewporter);
|
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)
|
if (data->compositor)
|
||||||
wl_compositor_destroy(data->compositor);
|
wl_compositor_destroy(data->compositor);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ typedef struct {
|
||||||
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||||||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||||
struct wl_data_device_manager *data_device_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 zxdg_decoration_manager_v1 *decoration_manager;
|
||||||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
|
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
|
||||||
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
|
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
|
||||||
|
|
|
@ -52,11 +52,11 @@ GetWindow(_THIS)
|
||||||
return data->clipboard_window;
|
return data->clipboard_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* We use our own cut-buffer for intermediate storage instead of
|
/* We use our own cut-buffer for intermediate storage instead of
|
||||||
XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */
|
XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */
|
||||||
Atom
|
Atom
|
||||||
X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type)
|
X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type,
|
||||||
|
Atom selection_type)
|
||||||
{
|
{
|
||||||
switch (mime_type) {
|
switch (mime_type) {
|
||||||
case SDL_X11_CLIPBOARD_MIME_TYPE_STRING:
|
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:
|
case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8:
|
||||||
#endif
|
#endif
|
||||||
case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT:
|
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:
|
default:
|
||||||
SDL_SetError("Can't find mime_type.");
|
SDL_SetError("Can't find mime_type.");
|
||||||
return XA_STRING;
|
return XA_STRING;
|
||||||
|
@ -118,13 +120,11 @@ X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11Clipboa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
int
|
SetSelectionText(_THIS, const char *text, Atom selection_type)
|
||||||
X11_SetClipboardText(_THIS, const char *text)
|
|
||||||
{
|
{
|
||||||
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
||||||
Window window;
|
Window window;
|
||||||
Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
|
|
||||||
|
|
||||||
/* Get the SDL window that will own the selection */
|
/* Get the SDL window that will own the selection */
|
||||||
window = GetWindow(_this);
|
window = GetWindow(_this);
|
||||||
|
@ -134,22 +134,19 @@ X11_SetClipboardText(_THIS, const char *text)
|
||||||
|
|
||||||
/* Save the selection on the root window */
|
/* Save the selection on the root window */
|
||||||
X11_XChangeProperty(display, DefaultRootWindow(display),
|
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));
|
(const unsigned char *)text, SDL_strlen(text));
|
||||||
|
|
||||||
if (XA_CLIPBOARD != None &&
|
if (X11_XGetSelectionOwner(display, selection_type) != window) {
|
||||||
X11_XGetSelectionOwner(display, XA_CLIPBOARD) != window) {
|
X11_XSetSelectionOwner(display, selection_type, window, CurrentTime);
|
||||||
X11_XSetSelectionOwner(display, XA_CLIPBOARD, window, CurrentTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (X11_XGetSelectionOwner(display, XA_PRIMARY) != window) {
|
|
||||||
X11_XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static char *
|
||||||
X11_GetClipboardText(_THIS)
|
GetSlectionText(_THIS, Atom selection_type)
|
||||||
{
|
{
|
||||||
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
|
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
|
||||||
Display *display = videodata->display;
|
Display *display = videodata->display;
|
||||||
|
@ -165,18 +162,13 @@ X11_GetClipboardText(_THIS)
|
||||||
char *text;
|
char *text;
|
||||||
Uint32 waitStart;
|
Uint32 waitStart;
|
||||||
Uint32 waitElapsed;
|
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;
|
text = NULL;
|
||||||
|
|
||||||
/* Get the window that holds the selection */
|
/* Get the window that holds the selection */
|
||||||
window = GetWindow(_this);
|
window = GetWindow(_this);
|
||||||
format = X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING);
|
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) {
|
if (owner == None) {
|
||||||
/* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/
|
/* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/
|
||||||
owner = DefaultRootWindow(display);
|
owner = DefaultRootWindow(display);
|
||||||
|
@ -184,12 +176,12 @@ X11_GetClipboardText(_THIS)
|
||||||
format = XA_STRING;
|
format = XA_STRING;
|
||||||
} else if (owner == window) {
|
} else if (owner == window) {
|
||||||
owner = DefaultRootWindow(display);
|
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 {
|
} else {
|
||||||
/* Request that the selection owner copy the data to our window */
|
/* Request that the selection owner copy the data to our window */
|
||||||
owner = window;
|
owner = window;
|
||||||
selection = X11_XInternAtom(display, "SDL_SELECTION", False);
|
selection = X11_XInternAtom(display, "SDL_SELECTION", False);
|
||||||
X11_XConvertSelection(display, XA_CLIPBOARD, format, selection, owner,
|
X11_XConvertSelection(display, selection_type, format, selection, owner,
|
||||||
CurrentTime);
|
CurrentTime);
|
||||||
|
|
||||||
/* When using synergy on Linux and when data has been put in the clipboard
|
/* 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) {
|
while (videodata->selection_waiting) {
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
waitElapsed = SDL_GetTicks() - waitStart;
|
waitElapsed = SDL_GetTicks() - waitStart;
|
||||||
/* Wait one second for a clipboard response. */
|
/* Wait one second for a selection response. */
|
||||||
if (waitElapsed > 1000) {
|
if (waitElapsed > 1000) {
|
||||||
videodata->selection_waiting = SDL_FALSE;
|
videodata->selection_waiting = SDL_FALSE;
|
||||||
SDL_SetError("Clipboard timeout");
|
SDL_SetError("Selection timeout");
|
||||||
/* We need to set the clipboard text so that next time we won't
|
/* 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. */
|
timeout, otherwise we will hang on every call to this function. */
|
||||||
X11_SetClipboardText(_this, "");
|
SetSelectionText(_this, "", selection_type);
|
||||||
return SDL_strdup("");
|
return SDL_strdup("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +224,41 @@ X11_GetClipboardText(_THIS)
|
||||||
return text;
|
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
|
SDL_bool
|
||||||
X11_HasClipboardText(_THIS)
|
X11_HasClipboardText(_THIS)
|
||||||
{
|
{
|
||||||
|
@ -244,6 +271,18 @@ X11_HasClipboardText(_THIS)
|
||||||
return result;
|
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 */
|
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -36,7 +36,10 @@ enum ESDLX11ClipboardMimeType {
|
||||||
extern int X11_SetClipboardText(_THIS, const char *text);
|
extern int X11_SetClipboardText(_THIS, const char *text);
|
||||||
extern char *X11_GetClipboardText(_THIS);
|
extern char *X11_GetClipboardText(_THIS);
|
||||||
extern SDL_bool X11_HasClipboardText(_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_GetSDLCutBufferClipboardExternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||||
extern Atom X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
extern Atom X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||||
|
|
||||||
|
|
|
@ -657,7 +657,7 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
|
||||||
if (X11_GetSDLCutBufferClipboardExternalFormat(display, i) != req->target)
|
if (X11_GetSDLCutBufferClipboardExternalFormat(display, i) != req->target)
|
||||||
continue;
|
continue;
|
||||||
if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
|
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,
|
&sevent.xselection.target, &seln_format, &nbytes,
|
||||||
&overflow, &seln_data) == Success) {
|
&overflow, &seln_data) == Success) {
|
||||||
if (seln_format != None) {
|
if (seln_format != None) {
|
||||||
|
|
|
@ -301,6 +301,9 @@ X11_CreateDevice(void)
|
||||||
device->SetClipboardText = X11_SetClipboardText;
|
device->SetClipboardText = X11_SetClipboardText;
|
||||||
device->GetClipboardText = X11_GetClipboardText;
|
device->GetClipboardText = X11_GetClipboardText;
|
||||||
device->HasClipboardText = X11_HasClipboardText;
|
device->HasClipboardText = X11_HasClipboardText;
|
||||||
|
device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
|
||||||
|
device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
|
||||||
|
device->HasPrimarySelectionText = X11_HasPrimarySelectionText;
|
||||||
device->StartTextInput = X11_StartTextInput;
|
device->StartTextInput = X11_StartTextInput;
|
||||||
device->StopTextInput = X11_StopTextInput;
|
device->StopTextInput = X11_StopTextInput;
|
||||||
device->SetTextInputRect = X11_SetTextInputRect;
|
device->SetTextInputRect = X11_SetTextInputRect;
|
||||||
|
|
|
@ -27,6 +27,21 @@ clipboard_testHasClipboardText(void *arg)
|
||||||
return TEST_COMPLETED;
|
return TEST_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check call to SDL_HasPrimarySelectionText
|
||||||
|
*
|
||||||
|
* \sa
|
||||||
|
* http://wiki.libsdl.org/SDL_HasPrimarySelectionText
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clipboard_testHasPrimarySelectionText(void *arg)
|
||||||
|
{
|
||||||
|
SDL_HasPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_HasPrimarySelectionText succeeded");
|
||||||
|
|
||||||
|
return TEST_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Check call to SDL_GetClipboardText
|
* \brief Check call to SDL_GetClipboardText
|
||||||
*
|
*
|
||||||
|
@ -45,6 +60,24 @@ clipboard_testGetClipboardText(void *arg)
|
||||||
return TEST_COMPLETED;
|
return TEST_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check call to SDL_GetPrimarySelectionText
|
||||||
|
*
|
||||||
|
* \sa
|
||||||
|
* http://wiki.libsdl.org/SDL_GetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clipboard_testGetPrimarySelectionText(void *arg)
|
||||||
|
{
|
||||||
|
char *charResult;
|
||||||
|
charResult = SDL_GetPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_GetPrimarySelectionText succeeded");
|
||||||
|
|
||||||
|
SDL_free(charResult);
|
||||||
|
|
||||||
|
return TEST_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Check call to SDL_SetClipboardText
|
* \brief Check call to SDL_SetClipboardText
|
||||||
* \sa
|
* \sa
|
||||||
|
@ -74,6 +107,35 @@ clipboard_testSetClipboardText(void *arg)
|
||||||
return TEST_COMPLETED;
|
return TEST_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check call to SDL_SetPrimarySelectionText
|
||||||
|
* \sa
|
||||||
|
* http://wiki.libsdl.org/SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clipboard_testSetPrimarySelectionText(void *arg)
|
||||||
|
{
|
||||||
|
char *textRef = SDLTest_RandomAsciiString();
|
||||||
|
char *text = SDL_strdup(textRef);
|
||||||
|
int result;
|
||||||
|
result = SDL_SetPrimarySelectionText((const char *)text);
|
||||||
|
SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
result == 0,
|
||||||
|
"Validate SDL_SetPrimarySelectionText result, expected 0, got %i",
|
||||||
|
result);
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
SDL_strcmp(textRef, text) == 0,
|
||||||
|
"Verify SDL_SetPrimarySelectionText did not modify input string, expected '%s', got '%s'",
|
||||||
|
textRef, text);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
SDL_free(textRef);
|
||||||
|
SDL_free(text);
|
||||||
|
|
||||||
|
return TEST_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief End-to-end test of SDL_xyzClipboardText functions
|
* \brief End-to-end test of SDL_xyzClipboardText functions
|
||||||
* \sa
|
* \sa
|
||||||
|
@ -153,6 +215,85 @@ clipboard_testClipboardTextFunctions(void *arg)
|
||||||
return TEST_COMPLETED;
|
return TEST_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief End-to-end test of SDL_xyzPrimarySelectionText functions
|
||||||
|
* \sa
|
||||||
|
* http://wiki.libsdl.org/SDL_HasPrimarySelectionText
|
||||||
|
* http://wiki.libsdl.org/SDL_GetPrimarySelectionText
|
||||||
|
* http://wiki.libsdl.org/SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clipboard_testPrimarySelectionTextFunctions(void *arg)
|
||||||
|
{
|
||||||
|
char *textRef = SDLTest_RandomAsciiString();
|
||||||
|
char *text = SDL_strdup(textRef);
|
||||||
|
SDL_bool boolResult;
|
||||||
|
int intResult;
|
||||||
|
char *charResult;
|
||||||
|
|
||||||
|
/* Clear primary selection text state */
|
||||||
|
boolResult = SDL_HasPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_HasPrimarySelectionText succeeded");
|
||||||
|
if (boolResult == SDL_TRUE) {
|
||||||
|
intResult = SDL_SetPrimarySelectionText((const char *)NULL);
|
||||||
|
SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText(NULL) succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
intResult == 0,
|
||||||
|
"Verify result from SDL_SetPrimarySelectionText(NULL), expected 0, got %i",
|
||||||
|
intResult);
|
||||||
|
charResult = SDL_GetPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_GetPrimarySelectionText succeeded");
|
||||||
|
SDL_free(charResult);
|
||||||
|
boolResult = SDL_HasPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_HasPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
boolResult == SDL_FALSE,
|
||||||
|
"Verify SDL_HasPrimarySelectionText returned SDL_FALSE, got %s",
|
||||||
|
(boolResult) ? "SDL_TRUE" : "SDL_FALSE");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty primary selection */
|
||||||
|
charResult = SDL_GetPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_GetPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
charResult != NULL,
|
||||||
|
"Verify SDL_GetPrimarySelectionText did not return NULL");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
charResult[0] == '\0',
|
||||||
|
"Verify SDL_GetPrimarySelectionText returned string with length 0, got length %i",
|
||||||
|
(int) SDL_strlen(charResult));
|
||||||
|
intResult = SDL_SetPrimarySelectionText((const char *)text);
|
||||||
|
SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
intResult == 0,
|
||||||
|
"Verify result from SDL_SetPrimarySelectionText(NULL), expected 0, got %i",
|
||||||
|
intResult);
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
SDL_strcmp(textRef, text) == 0,
|
||||||
|
"Verify SDL_SetPrimarySelectionText did not modify input string, expected '%s', got '%s'",
|
||||||
|
textRef, text);
|
||||||
|
boolResult = SDL_HasPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_HasPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
boolResult == SDL_TRUE,
|
||||||
|
"Verify SDL_HasPrimarySelectionText returned SDL_TRUE, got %s",
|
||||||
|
(boolResult) ? "SDL_TRUE" : "SDL_FALSE");
|
||||||
|
SDL_free(charResult);
|
||||||
|
charResult = SDL_GetPrimarySelectionText();
|
||||||
|
SDLTest_AssertPass("Call to SDL_GetPrimarySelectionText succeeded");
|
||||||
|
SDLTest_AssertCheck(
|
||||||
|
SDL_strcmp(textRef, charResult) == 0,
|
||||||
|
"Verify SDL_GetPrimarySelectionText returned correct string, expected '%s', got '%s'",
|
||||||
|
textRef, charResult);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
SDL_free(textRef);
|
||||||
|
SDL_free(text);
|
||||||
|
SDL_free(charResult);
|
||||||
|
|
||||||
|
return TEST_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ================= Test References ================== */
|
/* ================= Test References ================== */
|
||||||
|
|
||||||
|
@ -161,17 +302,29 @@ static const SDLTest_TestCaseReference clipboardTest1 =
|
||||||
{ (SDLTest_TestCaseFp)clipboard_testHasClipboardText, "clipboard_testHasClipboardText", "Check call to SDL_HasClipboardText", TEST_ENABLED };
|
{ (SDLTest_TestCaseFp)clipboard_testHasClipboardText, "clipboard_testHasClipboardText", "Check call to SDL_HasClipboardText", TEST_ENABLED };
|
||||||
|
|
||||||
static const SDLTest_TestCaseReference clipboardTest2 =
|
static const SDLTest_TestCaseReference clipboardTest2 =
|
||||||
{ (SDLTest_TestCaseFp)clipboard_testGetClipboardText, "clipboard_testGetClipboardText", "Check call to SDL_GetClipboardText", TEST_ENABLED };
|
{ (SDLTest_TestCaseFp)clipboard_testHasPrimarySelectionText, "clipboard_testHasPrimarySelectionText", "Check call to SDL_HasPrimarySelectionText", TEST_ENABLED };
|
||||||
|
|
||||||
static const SDLTest_TestCaseReference clipboardTest3 =
|
static const SDLTest_TestCaseReference clipboardTest3 =
|
||||||
{ (SDLTest_TestCaseFp)clipboard_testSetClipboardText, "clipboard_testSetClipboardText", "Check call to SDL_SetClipboardText", TEST_ENABLED };
|
{ (SDLTest_TestCaseFp)clipboard_testGetClipboardText, "clipboard_testGetClipboardText", "Check call to SDL_GetClipboardText", TEST_ENABLED };
|
||||||
|
|
||||||
static const SDLTest_TestCaseReference clipboardTest4 =
|
static const SDLTest_TestCaseReference clipboardTest4 =
|
||||||
|
{ (SDLTest_TestCaseFp)clipboard_testGetPrimarySelectionText, "clipboard_testGetPrimarySelectionText", "Check call to SDL_GetPrimarySelectionText", TEST_ENABLED };
|
||||||
|
|
||||||
|
static const SDLTest_TestCaseReference clipboardTest5 =
|
||||||
|
{ (SDLTest_TestCaseFp)clipboard_testSetClipboardText, "clipboard_testSetClipboardText", "Check call to SDL_SetClipboardText", TEST_ENABLED };
|
||||||
|
|
||||||
|
static const SDLTest_TestCaseReference clipboardTest6 =
|
||||||
|
{ (SDLTest_TestCaseFp)clipboard_testSetPrimarySelectionText, "clipboard_testSetPrimarySelectionText", "Check call to SDL_SetPrimarySelectionText", TEST_ENABLED };
|
||||||
|
|
||||||
|
static const SDLTest_TestCaseReference clipboardTest7 =
|
||||||
{ (SDLTest_TestCaseFp)clipboard_testClipboardTextFunctions, "clipboard_testClipboardTextFunctions", "End-to-end test of SDL_xyzClipboardText functions", TEST_ENABLED };
|
{ (SDLTest_TestCaseFp)clipboard_testClipboardTextFunctions, "clipboard_testClipboardTextFunctions", "End-to-end test of SDL_xyzClipboardText functions", TEST_ENABLED };
|
||||||
|
|
||||||
|
static const SDLTest_TestCaseReference clipboardTest8 =
|
||||||
|
{ (SDLTest_TestCaseFp)clipboard_testPrimarySelectionTextFunctions, "clipboard_testPrimarySelectionTextFunctions", "End-to-end test of SDL_xyzPrimarySelectionText functions", TEST_ENABLED };
|
||||||
|
|
||||||
/* Sequence of Clipboard test cases */
|
/* Sequence of Clipboard test cases */
|
||||||
static const SDLTest_TestCaseReference *clipboardTests[] = {
|
static const SDLTest_TestCaseReference *clipboardTests[] = {
|
||||||
&clipboardTest1, &clipboardTest2, &clipboardTest3, &clipboardTest4, NULL
|
&clipboardTest1, &clipboardTest2, &clipboardTest3, &clipboardTest4, &clipboardTest5, &clipboardTest6, &clipboardTest7, &clipboardTest8, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Clipboard test suite (global) */
|
/* Clipboard test suite (global) */
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wp_primary_selection_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2015, 2016 Red Hat
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="Primary selection protocol">
|
||||||
|
This protocol provides the ability to have a primary selection device to
|
||||||
|
match that of the X server. This primary selection is a shortcut to the
|
||||||
|
common clipboard selection, where text just needs to be selected in order
|
||||||
|
to allow copying it elsewhere. The de facto way to perform this action
|
||||||
|
is the middle mouse button, although it is not limited to this one.
|
||||||
|
|
||||||
|
Clients wishing to honor primary selection should create a primary
|
||||||
|
selection source and set it as the selection through
|
||||||
|
wp_primary_selection_device.set_selection whenever the text selection
|
||||||
|
changes. In order to minimize calls in pointer-driven text selection,
|
||||||
|
it should happen only once after the operation finished. Similarly,
|
||||||
|
a NULL source should be set when text is unselected.
|
||||||
|
|
||||||
|
wp_primary_selection_offer objects are first announced through the
|
||||||
|
wp_primary_selection_device.data_offer event. Immediately after this event,
|
||||||
|
the primary data offer will emit wp_primary_selection_offer.offer events
|
||||||
|
to let know of the mime types being offered.
|
||||||
|
|
||||||
|
When the primary selection changes, the client with the keyboard focus
|
||||||
|
will receive wp_primary_selection_device.selection events. Only the client
|
||||||
|
with the keyboard focus will receive such events with a non-NULL
|
||||||
|
wp_primary_selection_offer. Across keyboard focus changes, previously
|
||||||
|
focused clients will receive wp_primary_selection_device.events with a
|
||||||
|
NULL wp_primary_selection_offer.
|
||||||
|
|
||||||
|
In order to request the primary selection data, the client must pass
|
||||||
|
a recent serial pertaining to the press event that is triggering the
|
||||||
|
operation, if the compositor deems the serial valid and recent, the
|
||||||
|
wp_primary_selection_source.send event will happen in the other end
|
||||||
|
to let the transfer begin. The client owning the primary selection
|
||||||
|
should write the requested data, and close the file descriptor
|
||||||
|
immediately.
|
||||||
|
|
||||||
|
If the primary selection owner client disappeared during the transfer,
|
||||||
|
the client reading the data will receive a
|
||||||
|
wp_primary_selection_device.selection event with a NULL
|
||||||
|
wp_primary_selection_offer, the client should take this as a hint
|
||||||
|
to finish the reads related to the no longer existing offer.
|
||||||
|
|
||||||
|
The primary selection owner should be checking for errors during
|
||||||
|
writes, merely cancelling the ongoing transfer if any happened.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwp_primary_selection_device_manager_v1" version="1">
|
||||||
|
<description summary="X primary selection emulation">
|
||||||
|
The primary selection device manager is a singleton global object that
|
||||||
|
provides access to the primary selection. It allows to create
|
||||||
|
wp_primary_selection_source objects, as well as retrieving the per-seat
|
||||||
|
wp_primary_selection_device objects.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="create_source">
|
||||||
|
<description summary="create a new primary selection source">
|
||||||
|
Create a new primary selection source.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_primary_selection_source_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="get_device">
|
||||||
|
<description summary="create a new primary selection device">
|
||||||
|
Create a new data device for a given seat.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_primary_selection_device_v1"/>
|
||||||
|
<arg name="seat" type="object" interface="wl_seat"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the primary selection device manager">
|
||||||
|
Destroy the primary selection device manager.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_primary_selection_device_v1" version="1">
|
||||||
|
<request name="set_selection">
|
||||||
|
<description summary="set the primary selection">
|
||||||
|
Replaces the current selection. The previous owner of the primary
|
||||||
|
selection will receive a wp_primary_selection_source.cancelled event.
|
||||||
|
|
||||||
|
To unset the selection, set the source to NULL.
|
||||||
|
</description>
|
||||||
|
<arg name="source" type="object" interface="zwp_primary_selection_source_v1" allow-null="true"/>
|
||||||
|
<arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="data_offer">
|
||||||
|
<description summary="introduce a new wp_primary_selection_offer">
|
||||||
|
Introduces a new wp_primary_selection_offer object that may be used
|
||||||
|
to receive the current primary selection. Immediately following this
|
||||||
|
event, the new wp_primary_selection_offer object will send
|
||||||
|
wp_primary_selection_offer.offer events to describe the offered mime
|
||||||
|
types.
|
||||||
|
</description>
|
||||||
|
<arg name="offer" type="new_id" interface="zwp_primary_selection_offer_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="selection">
|
||||||
|
<description summary="advertise a new primary selection">
|
||||||
|
The wp_primary_selection_device.selection event is sent to notify the
|
||||||
|
client of a new primary selection. This event is sent after the
|
||||||
|
wp_primary_selection.data_offer event introducing this object, and after
|
||||||
|
the offer has announced its mimetypes through
|
||||||
|
wp_primary_selection_offer.offer.
|
||||||
|
|
||||||
|
The data_offer is valid until a new offer or NULL is received
|
||||||
|
or until the client loses keyboard focus. The client must destroy the
|
||||||
|
previous selection data_offer, if any, upon receiving this event.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="object" interface="zwp_primary_selection_offer_v1" allow-null="true"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the primary selection device">
|
||||||
|
Destroy the primary selection device.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_primary_selection_offer_v1" version="1">
|
||||||
|
<description summary="offer to transfer primary selection contents">
|
||||||
|
A wp_primary_selection_offer represents an offer to transfer the contents
|
||||||
|
of the primary selection clipboard to the client. Similar to
|
||||||
|
wl_data_offer, the offer also describes the mime types that the data can
|
||||||
|
be converted to and provides the mechanisms for transferring the data
|
||||||
|
directly to the client.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="receive">
|
||||||
|
<description summary="request that the data is transferred">
|
||||||
|
To transfer the contents of the primary selection clipboard, the client
|
||||||
|
issues this request and indicates the mime type that it wants to
|
||||||
|
receive. The transfer happens through the passed file descriptor
|
||||||
|
(typically created with the pipe system call). The source client writes
|
||||||
|
the data in the mime type representation requested and then closes the
|
||||||
|
file descriptor.
|
||||||
|
|
||||||
|
The receiving client reads from the read end of the pipe until EOF and
|
||||||
|
closes its end, at which point the transfer is complete.
|
||||||
|
</description>
|
||||||
|
<arg name="mime_type" type="string"/>
|
||||||
|
<arg name="fd" type="fd"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the primary selection offer">
|
||||||
|
Destroy the primary selection offer.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="offer">
|
||||||
|
<description summary="advertise offered mime type">
|
||||||
|
Sent immediately after creating announcing the
|
||||||
|
wp_primary_selection_offer through
|
||||||
|
wp_primary_selection_device.data_offer. One event is sent per offered
|
||||||
|
mime type.
|
||||||
|
</description>
|
||||||
|
<arg name="mime_type" type="string"/>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_primary_selection_source_v1" version="1">
|
||||||
|
<description summary="offer to replace the contents of the primary selection">
|
||||||
|
The source side of a wp_primary_selection_offer, it provides a way to
|
||||||
|
describe the offered data and respond to requests to transfer the
|
||||||
|
requested contents of the primary selection clipboard.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="offer">
|
||||||
|
<description summary="add an offered mime type">
|
||||||
|
This request adds a mime type to the set of mime types advertised to
|
||||||
|
targets. Can be called several times to offer multiple types.
|
||||||
|
</description>
|
||||||
|
<arg name="mime_type" type="string"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the primary selection source">
|
||||||
|
Destroy the primary selection source.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="send">
|
||||||
|
<description summary="send the primary selection contents">
|
||||||
|
Request for the current primary selection contents from the client.
|
||||||
|
Send the specified mime type over the passed file descriptor, then
|
||||||
|
close it.
|
||||||
|
</description>
|
||||||
|
<arg name="mime_type" type="string"/>
|
||||||
|
<arg name="fd" type="fd"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="cancelled">
|
||||||
|
<description summary="request for primary selection contents was canceled">
|
||||||
|
This primary selection source is no longer valid. The client should
|
||||||
|
clean up and destroy this primary selection source.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
Loading…
Reference in New Issue