aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidselect.c
diff options
context:
space:
mode:
authorPo Lu2023-04-06 09:56:23 +0800
committerPo Lu2023-04-06 09:56:23 +0800
commit3b07a4b3158d024c6eb19ce0e7c67b799ae0d1fc (patch)
tree079cb506217df20375835aa72c4bc52095c8c716 /src/androidselect.c
parent458c6e5c9171f41f327ef88f4a4999db586f8e91 (diff)
downloademacs-3b07a4b3158d024c6eb19ce0e7c67b799ae0d1fc.tar.gz
emacs-3b07a4b3158d024c6eb19ce0e7c67b799ae0d1fc.zip
Implement `yank-media' on Android
* doc/emacs/android.texi (Android Windowing): Update selection restrictions. * java/org/gnu/emacs/EmacsClipboard.java (EmacsClipboard): New functions `getClipboardTargets' and `getClipboardData'. * java/org/gnu/emacs/EmacsSdk11Clipboard.java (EmacsSdk11Clipboard, getClipboardTargets, getClipboardData): Implement. * java/org/gnu/emacs/EmacsSdk8Clipboard.java: Stub out new functions. * lisp/term/android-win.el (android-get-clipboard-1): Implement MIME type targets. * src/android.c (android_exception_check) (android_exception_check_1, android_exception_check_2): Fix punctuation in warning message. (android_exception_check_nonnull_1): New function. * src/android.h: Update prototypes. * src/androidselect.c (struct android_emacs_clipboard): New methods. (android_init_emacs_clipboard): Initialize new methods. (Fandroid_get_clipboard_targets, android_xfree_inside) (Fandroid_get_clipboard_data): New functions. (syms_of_androidselect): Define new subrs.
Diffstat (limited to 'src/androidselect.c')
-rw-r--r--src/androidselect.c221
1 files changed, 219 insertions, 2 deletions
diff --git a/src/androidselect.c b/src/androidselect.c
index dfbe0240941..54c712ca93b 100644
--- a/src/androidselect.c
+++ b/src/androidselect.c
@@ -19,6 +19,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20#include <config.h> 20#include <config.h>
21#include <assert.h> 21#include <assert.h>
22#include <minmax.h>
23#include <unistd.h>
22 24
23#include "lisp.h" 25#include "lisp.h"
24#include "blockinput.h" 26#include "blockinput.h"
@@ -27,12 +29,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
27#include "androidterm.h" 29#include "androidterm.h"
28 30
29/* Selection support on Android is confined to copying and pasting of 31/* Selection support on Android is confined to copying and pasting of
30 plain text from the clipboard. There is no primary selection. 32 plain text and MIME data from the clipboard. There is no primary
33 selection.
31 34
32 While newer versions of Android are supposed to have the necessary 35 While newer versions of Android are supposed to have the necessary
33 interfaces for transferring other kinds of selection data, doing so 36 interfaces for transferring other kinds of selection data, doing so
34 is too complicated, and involves registering ``content providers'' 37 is too complicated, and involves registering ``content providers''
35 and all kinds of other stuff. */ 38 and all kinds of other stuff; for this reason, Emacs does not
39 support setting the clipboard contents to anything other than plain
40 text. */
36 41
37 42
38 43
@@ -46,6 +51,8 @@ struct android_emacs_clipboard
46 jmethodID clipboard_exists; 51 jmethodID clipboard_exists;
47 jmethodID get_clipboard; 52 jmethodID get_clipboard;
48 jmethodID make_clipboard; 53 jmethodID make_clipboard;
54 jmethodID get_clipboard_targets;
55 jmethodID get_clipboard_data;
49}; 56};
50 57
51/* Methods associated with the EmacsClipboard class. */ 58/* Methods associated with the EmacsClipboard class. */
@@ -86,6 +93,10 @@ android_init_emacs_clipboard (void)
86 FIND_METHOD (owns_clipboard, "ownsClipboard", "()I"); 93 FIND_METHOD (owns_clipboard, "ownsClipboard", "()I");
87 FIND_METHOD (clipboard_exists, "clipboardExists", "()Z"); 94 FIND_METHOD (clipboard_exists, "clipboardExists", "()Z");
88 FIND_METHOD (get_clipboard, "getClipboard", "()[B"); 95 FIND_METHOD (get_clipboard, "getClipboard", "()[B");
96 FIND_METHOD (get_clipboard_targets, "getClipboardTargets",
97 "()[[B");
98 FIND_METHOD (get_clipboard_data, "getClipboardData",
99 "([B)[J");
89 100
90 clipboard_class.make_clipboard 101 clipboard_class.make_clipboard
91 = (*android_java_env)->GetStaticMethodID (android_java_env, 102 = (*android_java_env)->GetStaticMethodID (android_java_env,
@@ -244,6 +255,210 @@ URL with a scheme specified. Signal an error upon failure. */)
244 255
245 256
246 257
258/* MIME clipboard support. This provides support for reading MIME
259 data (but not text) from the clipboard. */
260
261DEFUN ("android-get-clipboard-targets", Fandroid_get_clipboard_targets,
262 Sandroid_get_clipboard_targets, 0, 0, 0,
263 doc: /* Return a list of data types in the clipboard.
264Value is a list of MIME types as strings, each defining a single extra
265data type available from the clipboard. */)
266 (void)
267{
268 jarray bytes_array;
269 jbyteArray bytes;
270 jmethodID method;
271 size_t length, length1, i;
272 jbyte *data;
273 Lisp_Object targets, tem;
274
275 if (!android_init_gui)
276 error ("No Android display connection!");
277
278 targets = Qnil;
279 block_input ();
280 method = clipboard_class.get_clipboard_targets;
281 bytes_array = (*android_java_env)->CallObjectMethod (android_java_env,
282 clipboard, method);
283 android_exception_check ();
284
285 if (!bytes_array)
286 goto fail;
287
288 length = (*android_java_env)->GetArrayLength (android_java_env,
289 bytes_array);
290 for (i = 0; i < length; ++i)
291 {
292 /* Retireve the MIME type. */
293 bytes
294 = (*android_java_env)->GetObjectArrayElement (android_java_env,
295 bytes_array, i);
296 android_exception_check_nonnull (bytes, bytes_array);
297
298 /* Cons it onto the list of targets. */
299 length1 = (*android_java_env)->GetArrayLength (android_java_env,
300 bytes);
301 data = (*android_java_env)->GetByteArrayElements (android_java_env,
302 bytes, NULL);
303 android_exception_check_nonnull_1 (data, bytes, bytes_array);
304
305 /* Decode the string. */
306 tem = make_unibyte_string ((char *) data, length1);
307 tem = code_convert_string_norecord (tem, Qutf_8, Qnil);
308 targets = Fcons (tem, targets);
309
310 /* Delete the retrieved data. */
311 (*android_java_env)->ReleaseByteArrayElements (android_java_env,
312 bytes, data,
313 JNI_ABORT);
314 ANDROID_DELETE_LOCAL_REF (bytes);
315 }
316 unblock_input ();
317
318 ANDROID_DELETE_LOCAL_REF (bytes_array);
319 return Fnreverse (targets);
320
321 fail:
322 unblock_input ();
323 return Qnil;
324}
325
326/* Free the memory inside PTR, a pointer to a char pointer. */
327
328static void
329android_xfree_inside (void *ptr)
330{
331 xfree (*(char **) ptr);
332}
333
334DEFUN ("android-get-clipboard-data", Fandroid_get_clipboard_data,
335 Sandroid_get_clipboard_data, 1, 1, 0,
336 doc: /* Return the clipboard data of the given MIME TYPE.
337Value is a unibyte string containing the entire contents of the
338clipboard, after its owner has converted the data to the given
339MIME type. Value is nil if the conversion fails, or if the data
340is not present.
341
342Value is also nil if the clipboard data consists of a single URL which
343does not have any corresponding data. In that case, use
344`android-get-clipboard' instead. */)
345 (Lisp_Object type)
346{
347 jlongArray array;
348 jbyteArray bytes;
349 jmethodID method;
350 int fd;
351 ptrdiff_t rc;
352 jlong offset, length, *longs;
353 specpdl_ref ref;
354 char *buffer, *start;
355
356 if (!android_init_gui)
357 error ("No Android display connection!");
358
359 /* Encode the string as UTF-8. */
360 CHECK_STRING (type);
361 type = ENCODE_UTF_8 (type);
362
363 /* Then give it to the selection code. */
364 block_input ();
365 bytes = (*android_java_env)->NewByteArray (android_java_env,
366 SBYTES (type));
367 (*android_java_env)->SetByteArrayRegion (android_java_env, bytes,
368 0, SBYTES (type),
369 (jbyte *) SDATA (type));
370 android_exception_check ();
371
372 method = clipboard_class.get_clipboard_data;
373 array = (*android_java_env)->CallObjectMethod (android_java_env,
374 clipboard, method,
375 bytes);
376 android_exception_check_1 (bytes);
377 ANDROID_DELETE_LOCAL_REF (bytes);
378
379 if (!array)
380 goto fail;
381
382 longs = (*android_java_env)->GetLongArrayElements (android_java_env,
383 array, NULL);
384 android_exception_check_nonnull (longs, array);
385
386 /* longs[0] is the file descriptor.
387 longs[1] is an offset to apply to the file.
388 longs[2] is either -1, or the number of bytes to read from the
389 file. */
390 fd = longs[0];
391 offset = longs[1];
392 length = longs[2];
393
394 (*android_java_env)->ReleaseLongArrayElements (android_java_env,
395 array, longs,
396 JNI_ABORT);
397 ANDROID_DELETE_LOCAL_REF (array);
398 unblock_input ();
399
400 /* Now begin reading from longs[0]. */
401 ref = SPECPDL_INDEX ();
402 record_unwind_protect_int (close_file_unwind, fd);
403
404 if (length != -1)
405 {
406 buffer = xmalloc (MIN (length, PTRDIFF_MAX));
407 record_unwind_protect_ptr (xfree, buffer);
408
409 rc = emacs_read_quit (fd, buffer,
410 MIN (length, PTRDIFF_MAX));
411
412 /* Return nil upon an IO problem. */
413 if (rc < 0)
414 return unbind_to (ref, Qnil);
415
416 /* Return the data as a unibyte string. */
417 return unbind_to (ref, make_unibyte_string (buffer, rc));
418 }
419
420 /* Otherwise, read BUFSIZ bytes at a time. */
421 buffer = xmalloc (BUFSIZ);
422 length = 0;
423 start = buffer;
424
425 record_unwind_protect_ptr (android_xfree_inside, &buffer);
426
427 /* Seek to the start of the data. */
428
429 if (offset)
430 {
431 if (lseek (fd, offset, SEEK_SET) < 0)
432 return unbind_to (ref, Qnil);
433 }
434
435 while (true)
436 {
437 rc = emacs_read_quit (fd, start, BUFSIZ);
438
439 if (!INT_ADD_OK (rc, length, &length)
440 || PTRDIFF_MAX - length < BUFSIZ)
441 memory_full (PTRDIFF_MAX);
442
443 if (rc < 0)
444 return unbind_to (ref, Qnil);
445
446 if (rc < BUFSIZ)
447 break;
448
449 buffer = xrealloc (buffer, length + BUFSIZ);
450 start = buffer + length;
451 }
452
453 return unbind_to (ref, make_unibyte_string (buffer, rc));
454
455 fail:
456 unblock_input ();
457 return Qnil;
458}
459
460
461
247void 462void
248init_androidselect (void) 463init_androidselect (void)
249{ 464{
@@ -279,4 +494,6 @@ syms_of_androidselect (void)
279 defsubr (&Sandroid_get_clipboard); 494 defsubr (&Sandroid_get_clipboard);
280 defsubr (&Sandroid_clipboard_exists_p); 495 defsubr (&Sandroid_clipboard_exists_p);
281 defsubr (&Sandroid_browse_url); 496 defsubr (&Sandroid_browse_url);
497 defsubr (&Sandroid_get_clipboard_targets);
498 defsubr (&Sandroid_get_clipboard_data);
282} 499}