Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-clipboard-adapter"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libvalent-core.h>
10 : :
11 : : #include "valent-clipboard-adapter.h"
12 : :
13 : :
14 : : /**
15 : : * ValentClipboardAdapter:
16 : : *
17 : : * An abstract base class for clipboard selections.
18 : : *
19 : : * `ValentClipboardAdapter` is a base class for plugins that provide an interface
20 : : * to the desktop clipboard. This usually means reading and writing content,
21 : : * including notification of content changes.
22 : : *
23 : : * ## `.plugin` File
24 : : *
25 : : * Implementations may define the following extra fields in the `.plugin` file:
26 : : *
27 : : * - `X-ClipboardAdapterPriority`
28 : : *
29 : : * An integer indicating the adapter priority. The implementation with the
30 : : * lowest value will be used as the primary adapter.
31 : : *
32 : : * Since: 1.0
33 : : */
34 : :
35 : : typedef struct
36 : : {
37 : : int64_t timestamp;
38 : : } ValentClipboardAdapterPrivate;
39 : :
40 [ + + + - ]: 576 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ValentClipboardAdapter, valent_clipboard_adapter, VALENT_TYPE_EXTENSION)
41 : :
42 : : enum {
43 : : CHANGED,
44 : : N_SIGNALS
45 : : };
46 : :
47 : : static guint signals[N_SIGNALS] = { 0, };
48 : :
49 : :
50 : : /* LCOV_EXCL_START */
51 : : static GStrv
52 : : valent_clipboard_adapter_real_get_mimetypes (ValentClipboardAdapter *adapter)
53 : : {
54 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
55 : :
56 : : g_warning ("%s does not implement get_mimetypes",
57 : : G_OBJECT_TYPE_NAME (adapter));
58 : :
59 : : return NULL;
60 : : }
61 : :
62 : : static int64_t
63 : : valent_clipboard_adapter_real_get_timestamp (ValentClipboardAdapter *adapter)
64 : : {
65 : : ValentClipboardAdapterPrivate *priv = valent_clipboard_adapter_get_instance_private (adapter);
66 : :
67 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
68 : :
69 : : return priv->timestamp;
70 : : }
71 : :
72 : : static void
73 : : valent_clipboard_adapter_real_read_bytes (ValentClipboardAdapter *adapter,
74 : : const char *mimetype,
75 : : GCancellable *cancellable,
76 : : GAsyncReadyCallback callback,
77 : : gpointer user_data)
78 : : {
79 : : g_task_report_new_error (adapter, callback, user_data,
80 : : valent_clipboard_adapter_real_read_bytes,
81 : : G_IO_ERROR,
82 : : G_IO_ERROR_NOT_SUPPORTED,
83 : : "%s does not implement read_bytes",
84 : : G_OBJECT_TYPE_NAME (adapter));
85 : : }
86 : :
87 : : GBytes *
88 : : valent_clipboard_adapter_real_read_bytes_finish (ValentClipboardAdapter *adapter,
89 : : GAsyncResult *result,
90 : : GError **error)
91 : : {
92 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
93 : : g_assert (g_task_is_valid (result, adapter));
94 : : g_assert (error == NULL || *error == NULL);
95 : :
96 : : return g_task_propagate_pointer (G_TASK (result), error);
97 : : }
98 : :
99 : : static void
100 : : valent_clipboard_adapter_real_write_bytes (ValentClipboardAdapter *adapter,
101 : : const char *mimetype,
102 : : GBytes *bytes,
103 : : GCancellable *cancellable,
104 : : GAsyncReadyCallback callback,
105 : : gpointer user_data)
106 : : {
107 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
108 : : g_assert (bytes == NULL || (mimetype != NULL && *mimetype != '\0'));
109 : : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
110 : :
111 : : g_task_report_new_error (adapter, callback, user_data,
112 : : valent_clipboard_adapter_real_write_bytes,
113 : : G_IO_ERROR,
114 : : G_IO_ERROR_NOT_SUPPORTED,
115 : : "%s does not implement write_bytes",
116 : : G_OBJECT_TYPE_NAME (adapter));
117 : : }
118 : :
119 : : static gboolean
120 : : valent_clipboard_adapter_real_write_bytes_finish (ValentClipboardAdapter *adapter,
121 : : GAsyncResult *result,
122 : : GError **error)
123 : : {
124 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
125 : : g_assert (g_task_is_valid (result, adapter));
126 : : g_assert (error == NULL || *error == NULL);
127 : :
128 : : return g_task_propagate_boolean (G_TASK (result), error);
129 : : }
130 : :
131 : : static void
132 : : valent_clipboard_adapter_real_changed (ValentClipboardAdapter *adapter)
133 : : {
134 : : ValentClipboardAdapterPrivate *priv = valent_clipboard_adapter_get_instance_private (adapter);
135 : :
136 : : g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
137 : :
138 : : priv->timestamp = valent_timestamp_ms ();
139 : : }
140 : : /* LCOV_EXCL_STOP */
141 : :
142 : : /*
143 : : * GObject
144 : : */
145 : : static void
146 : 58 : valent_clipboard_adapter_class_init (ValentClipboardAdapterClass *klass)
147 : : {
148 : 58 : klass->changed = valent_clipboard_adapter_real_changed;
149 : 58 : klass->get_mimetypes = valent_clipboard_adapter_real_get_mimetypes;
150 : 58 : klass->get_timestamp = valent_clipboard_adapter_real_get_timestamp;
151 : 58 : klass->read_bytes = valent_clipboard_adapter_real_read_bytes;
152 : 58 : klass->read_bytes_finish = valent_clipboard_adapter_real_read_bytes_finish;
153 : 58 : klass->write_bytes = valent_clipboard_adapter_real_write_bytes;
154 : 58 : klass->write_bytes_finish = valent_clipboard_adapter_real_write_bytes_finish;
155 : :
156 : : /**
157 : : * ValentClipboardAdapter::changed:
158 : : * @adapter: a `ValentClipboardAdapter`
159 : : *
160 : : * Emitted when the content of @adapter changes.
161 : : *
162 : : * The default handler for this signal updates the value returned by the
163 : : * default implementation of [vfunc@Valent.ClipboardAdapter.get_timestamp].
164 : : *
165 : : * Since: 1.0
166 : : */
167 : 116 : signals [CHANGED] =
168 : 58 : g_signal_new ("changed",
169 : : G_TYPE_FROM_CLASS (klass),
170 : : G_SIGNAL_RUN_FIRST,
171 : : G_STRUCT_OFFSET (ValentClipboardAdapterClass, changed),
172 : : NULL, NULL, NULL,
173 : : G_TYPE_NONE, 0);
174 : 58 : }
175 : :
176 : : static void
177 : 6 : valent_clipboard_adapter_init (ValentClipboardAdapter *adapter)
178 : : {
179 : 6 : }
180 : :
181 : : /**
182 : : * valent_clipboard_adapter_changed: (virtual changed)
183 : : * @adapter: a `ValentClipboardAdapter`
184 : : *
185 : : * Emits [signal@Valent.ClipboardAdapter::changed] signal on @adapter.
186 : : *
187 : : * The default handler for this signal updates the value returned by the default
188 : : * implementation of [vfunc@Valent.ClipboardAdapter.get_timestamp].
189 : : *
190 : : * This method should only be called by implementations of
191 : : * [class@Valent.ClipboardAdapter].
192 : : *
193 : : * Since: 1.0
194 : : */
195 : : void
196 : 14 : valent_clipboard_adapter_changed (ValentClipboardAdapter *adapter)
197 : : {
198 [ + - ]: 14 : g_return_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
199 : :
200 : 14 : g_signal_emit (G_OBJECT (adapter), signals [CHANGED], 0);
201 : : }
202 : :
203 : : /**
204 : : * valent_clipboard_adapter_get_timestamp: (virtual get_timestamp)
205 : : * @adapter: a `ValentClipboardAdapter`
206 : : *
207 : : * Get the timestamp of the current clipboard content.
208 : : *
209 : : * The default implementation of this method returns the last time
210 : : * [signal@Valent.ClipboardAdapter::changed] was emitted
211 : : *
212 : : * Returns: a UNIX epoch timestamp (ms)
213 : : *
214 : : * Since: 1.0
215 : : */
216 : : int64_t
217 : 17 : valent_clipboard_adapter_get_timestamp (ValentClipboardAdapter *adapter)
218 : : {
219 : 17 : int64_t ret;
220 : :
221 : 17 : VALENT_ENTRY;
222 : :
223 [ + - ]: 17 : g_return_val_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter), 0);
224 : :
225 : 17 : ret = VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->get_timestamp (adapter);
226 : :
227 : 17 : VALENT_RETURN (ret);
228 : : }
229 : :
230 : : /**
231 : : * valent_clipboard_adapter_get_mimetypes: (virtual get_mimetypes)
232 : : * @adapter: a `ValentClipboardAdapter`
233 : : *
234 : : * Get the mime-types of the current clipboard content.
235 : : *
236 : : * Returns: (transfer full) (nullable) (array zero-terminated=1): a list of
237 : : * mime-types
238 : : *
239 : : * Since: 1.0
240 : : */
241 : : GStrv
242 : 21 : valent_clipboard_adapter_get_mimetypes (ValentClipboardAdapter *adapter)
243 : : {
244 : 21 : GStrv ret = NULL;
245 : :
246 : 21 : VALENT_ENTRY;
247 : :
248 [ + - ]: 21 : g_return_val_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter), NULL);
249 : :
250 : 21 : ret = VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->get_mimetypes (adapter);
251 : :
252 : 21 : VALENT_RETURN (g_steal_pointer (&ret));
253 : : }
254 : :
255 : : /**
256 : : * valent_clipboard_adapter_read_bytes: (virtual read_bytes)
257 : : * @adapter: a `ValentClipboardAdapter`
258 : : * @mimetype: a mime-type
259 : : * @cancellable: (nullable): a `GCancellable`
260 : : * @callback: (scope async): a `GAsyncReadyCallback`
261 : : * @user_data: user supplied data
262 : : *
263 : : * Get the content of @adapter.
264 : : *
265 : : * Call [method@Valent.ClipboardAdapter.read_bytes_finish] to get the result.
266 : : *
267 : : * Since: 1.0
268 : : */
269 : : void
270 : 18 : valent_clipboard_adapter_read_bytes (ValentClipboardAdapter *adapter,
271 : : const char *mimetype,
272 : : GCancellable *cancellable,
273 : : GAsyncReadyCallback callback,
274 : : gpointer user_data)
275 : : {
276 : 18 : VALENT_ENTRY;
277 : :
278 [ + - ]: 18 : g_return_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
279 [ + - - + ]: 18 : g_return_if_fail (mimetype != NULL && *mimetype != '\0');
280 [ + + + - : 18 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- + - - ]
281 : :
282 : 18 : VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->read_bytes (adapter,
283 : : mimetype,
284 : : cancellable,
285 : : callback,
286 : : user_data);
287 : 18 : VALENT_EXIT;
288 : : }
289 : :
290 : : /**
291 : : * valent_clipboard_adapter_read_bytes_finish: (virtual read_bytes_finish)
292 : : * @adapter: a `ValentClipboardAdapter`
293 : : * @result: a `GAsyncResult`
294 : : * @error: (nullable): a `GError`
295 : : *
296 : : * Finish an operation started by [method@Valent.ClipboardAdapter.read_bytes].
297 : : *
298 : : * Returns: (transfer full) (nullable): a `GBytes`, or %NULL with @error set
299 : : *
300 : : * Since: 1.0
301 : : */
302 : : GBytes *
303 : 18 : valent_clipboard_adapter_read_bytes_finish (ValentClipboardAdapter *adapter,
304 : : GAsyncResult *result,
305 : : GError **error)
306 : : {
307 : 18 : GBytes *ret;
308 : :
309 : 18 : VALENT_ENTRY;
310 : :
311 [ + - ]: 18 : g_return_val_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter), NULL);
312 [ - + ]: 18 : g_return_val_if_fail (g_task_is_valid (result, adapter), NULL);
313 [ + - - + ]: 18 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
314 : :
315 : 18 : ret = VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->read_bytes_finish (adapter,
316 : : result,
317 : : error);
318 : :
319 : 18 : VALENT_RETURN (g_steal_pointer (&ret));
320 : : }
321 : :
322 : : /**
323 : : * valent_clipboard_adapter_write_bytes: (virtual write_bytes)
324 : : * @adapter: a `ValentClipboardAdapter`
325 : : * @mimetype: (nullable): a mime-type, or %NULL if @bytes is %NULL
326 : : * @bytes: (nullable): a `GBytes`, or %NULL if @mimetype is %NULL
327 : : * @cancellable: (nullable): a `GCancellable`
328 : : * @callback: (scope async): a `GAsyncReadyCallback`
329 : : * @user_data: user supplied data
330 : : *
331 : : * Set the content of the clipboard.
332 : : *
333 : : * Call [method@Valent.ClipboardAdapter.write_bytes_finish] to get the result.
334 : : *
335 : : * Since: 1.0
336 : : */
337 : : void
338 : 11 : valent_clipboard_adapter_write_bytes (ValentClipboardAdapter *adapter,
339 : : const char *mimetype,
340 : : GBytes *bytes,
341 : : GCancellable *cancellable,
342 : : GAsyncReadyCallback callback,
343 : : gpointer user_data)
344 : : {
345 : 11 : VALENT_ENTRY;
346 : :
347 [ + - ]: 11 : g_return_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
348 [ + - + - : 11 : g_return_if_fail (bytes == NULL || (mimetype != NULL && *mimetype != '\0'));
- + ]
349 [ + + + - : 11 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- + - - ]
350 : :
351 : 11 : VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->write_bytes (adapter,
352 : : mimetype,
353 : : bytes,
354 : : cancellable,
355 : : callback,
356 : : user_data);
357 : :
358 : 11 : VALENT_EXIT;
359 : : }
360 : :
361 : : /**
362 : : * valent_clipboard_adapter_write_bytes_finish: (virtual write_bytes_finish)
363 : : * @adapter: a `ValentClipboardAdapter`
364 : : * @result: a `GAsyncResult`
365 : : * @error: (nullable): a `GError`
366 : : *
367 : : * Finish an operation started by [method@Valent.ClipboardAdapter.write_bytes].
368 : : *
369 : : * Returns: %TRUE if successful, or %FALSE with @error set
370 : : *
371 : : * Since: 1.0
372 : : */
373 : : gboolean
374 : 11 : valent_clipboard_adapter_write_bytes_finish (ValentClipboardAdapter *adapter,
375 : : GAsyncResult *result,
376 : : GError **error)
377 : : {
378 : 11 : gboolean ret;
379 : :
380 : 11 : VALENT_ENTRY;
381 : :
382 [ + - ]: 11 : g_return_val_if_fail (VALENT_IS_CLIPBOARD_ADAPTER (adapter), FALSE);
383 [ - + ]: 11 : g_return_val_if_fail (g_task_is_valid (result, adapter), FALSE);
384 [ + - - + ]: 11 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
385 : :
386 : 11 : ret = VALENT_CLIPBOARD_ADAPTER_GET_CLASS (adapter)->write_bytes_finish (adapter,
387 : : result,
388 : : error);
389 : :
390 : 11 : VALENT_RETURN (ret);
391 : : }
392 : :
|