1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "SDL_internal.h" |
22 | |
23 | #ifdef SDL_VIDEO_DRIVER_WAYLAND |
24 | |
25 | #include "SDL_waylanddatamanager.h" |
26 | #include "SDL_waylandevents_c.h" |
27 | #include "SDL_waylandclipboard.h" |
28 | #include "../SDL_clipboard_c.h" |
29 | #include "../../events/SDL_events_c.h" |
30 | |
31 | |
32 | bool Wayland_SetClipboardData(SDL_VideoDevice *_this) |
33 | { |
34 | SDL_VideoData *video_data = _this->internal; |
35 | SDL_WaylandDataDevice *data_device = NULL; |
36 | bool result = true; |
37 | |
38 | if (video_data->input && video_data->input->data_device) { |
39 | data_device = video_data->input->data_device; |
40 | |
41 | if (_this->clipboard_callback && _this->clipboard_mime_types) { |
42 | SDL_WaylandDataSource *source = Wayland_data_source_create(_this); |
43 | Wayland_data_source_set_callback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence); |
44 | |
45 | result = Wayland_data_device_set_selection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types); |
46 | if (!result) { |
47 | Wayland_data_source_destroy(source); |
48 | } |
49 | } else { |
50 | result = Wayland_data_device_clear_selection(data_device); |
51 | } |
52 | } |
53 | |
54 | return result; |
55 | } |
56 | |
57 | void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length) |
58 | { |
59 | SDL_VideoData *video_data = _this->internal; |
60 | SDL_WaylandDataDevice *data_device = NULL; |
61 | void *buffer = NULL; |
62 | |
63 | if (video_data->input && video_data->input->data_device) { |
64 | data_device = video_data->input->data_device; |
65 | if (data_device->selection_source) { |
66 | buffer = SDL_GetInternalClipboardData(_this, mime_type, length); |
67 | } else if (Wayland_data_offer_has_mime(data_device->selection_offer, mime_type)) { |
68 | buffer = Wayland_data_offer_receive(data_device->selection_offer, mime_type, length); |
69 | } |
70 | } |
71 | |
72 | return buffer; |
73 | } |
74 | |
75 | bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) |
76 | { |
77 | SDL_VideoData *video_data = _this->internal; |
78 | SDL_WaylandDataDevice *data_device = NULL; |
79 | bool result = false; |
80 | |
81 | if (video_data->input && video_data->input->data_device) { |
82 | data_device = video_data->input->data_device; |
83 | if (data_device->selection_source) { |
84 | result = SDL_HasInternalClipboardData(_this, mime_type); |
85 | } else { |
86 | result = Wayland_data_offer_has_mime(data_device->selection_offer, mime_type); |
87 | } |
88 | } |
89 | return result; |
90 | } |
91 | |
92 | static const char *text_mime_types[] = { |
93 | TEXT_MIME, |
94 | "text/plain" , |
95 | "TEXT" , |
96 | "UTF8_STRING" , |
97 | "STRING" |
98 | }; |
99 | |
100 | const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types) |
101 | { |
102 | *num_mime_types = SDL_arraysize(text_mime_types); |
103 | return text_mime_types; |
104 | } |
105 | |
106 | bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text) |
107 | { |
108 | SDL_VideoData *video_data = _this->internal; |
109 | SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; |
110 | bool result; |
111 | |
112 | if (video_data->input && video_data->input->primary_selection_device) { |
113 | primary_selection_device = video_data->input->primary_selection_device; |
114 | if (text[0] != '\0') { |
115 | SDL_WaylandPrimarySelectionSource *source = Wayland_primary_selection_source_create(_this); |
116 | Wayland_primary_selection_source_set_callback(source, SDL_ClipboardTextCallback, SDL_strdup(text)); |
117 | |
118 | result = Wayland_primary_selection_device_set_selection(primary_selection_device, |
119 | source, |
120 | text_mime_types, |
121 | SDL_arraysize(text_mime_types)); |
122 | if (!result) { |
123 | Wayland_primary_selection_source_destroy(source); |
124 | } |
125 | } else { |
126 | result = Wayland_primary_selection_device_clear_selection(primary_selection_device); |
127 | } |
128 | } else { |
129 | result = SDL_SetError("Primary selection not supported" ); |
130 | } |
131 | return result; |
132 | } |
133 | |
134 | char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this) |
135 | { |
136 | SDL_VideoData *video_data = _this->internal; |
137 | SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; |
138 | char *text = NULL; |
139 | size_t length = 0; |
140 | |
141 | if (video_data->input && video_data->input->primary_selection_device) { |
142 | primary_selection_device = video_data->input->primary_selection_device; |
143 | if (primary_selection_device->selection_source) { |
144 | text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, TEXT_MIME, &length); |
145 | } else { |
146 | for (size_t i = 0; i < SDL_arraysize(text_mime_types); i++) { |
147 | if (Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, text_mime_types[i])) { |
148 | text = Wayland_primary_selection_offer_receive(primary_selection_device->selection_offer, text_mime_types[i], &length); |
149 | break; |
150 | } |
151 | } |
152 | } |
153 | } |
154 | |
155 | if (!text) { |
156 | text = SDL_strdup("" ); |
157 | } |
158 | |
159 | return text; |
160 | } |
161 | |
162 | bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this) |
163 | { |
164 | SDL_VideoData *video_data = _this->internal; |
165 | SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; |
166 | bool result = false; |
167 | |
168 | if (video_data->input && video_data->input->primary_selection_device) { |
169 | primary_selection_device = video_data->input->primary_selection_device; |
170 | if (primary_selection_device->selection_source) { |
171 | result = true; |
172 | } else { |
173 | size_t mime_count = 0; |
174 | const char **mime_types = Wayland_GetTextMimeTypes(_this, &mime_count); |
175 | for (size_t i = 0; i < mime_count; i++) { |
176 | if (Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, mime_types[i])) { |
177 | result = true; |
178 | break; |
179 | } |
180 | } |
181 | } |
182 | } |
183 | return result; |
184 | } |
185 | |
186 | #endif // SDL_VIDEO_DRIVER_WAYLAND |
187 | |